From 5651828bf74edb760d67700942fc65d51c816e0a Mon Sep 17 00:00:00 2001 From: Neo2003 Date: Sat, 4 Oct 2008 06:17:19 -0500 Subject: [svn] * Added ACE for Linux and Windows (Thanks Derex for Linux part and partial Windows part) * Updated to 6721 and 676 * Fixed TrinityScript logo * Version updated to 0.2.6721.676 --HG-- branch : trunk rename : 6700-670 => 6721-676 --- src/bindings/scripts/ScriptMgr.cpp | 5 +- src/bindings/scripts/VC71/71ScriptDev2.vcproj | 4 +- src/bindings/scripts/VC80/80ScriptDev2.vcproj | 8 +- src/bindings/scripts/VC90/90ScriptDev2.vcproj | 8 +- src/bindings/scripts/include/sc_creature.cpp | 1224 +- src/bindings/scripts/include/sc_gossip.h | 366 +- .../scripts/areatrigger/areatrigger_scripts.cpp | 88 +- src/bindings/scripts/scripts/boss/boss_emeriss.cpp | 312 +- src/bindings/scripts/scripts/boss/boss_lethon.cpp | 48 +- src/bindings/scripts/scripts/boss/boss_taerar.cpp | 612 +- src/bindings/scripts/scripts/boss/boss_ysondre.cpp | 492 +- .../scripts/scripts/creature/mob_event_ai.cpp | 2750 +- .../scripts/scripts/creature/mob_event_ai.h | 430 +- .../scripts/creature/mob_generic_creature.cpp | 344 +- .../scripts/scripts/creature/simple_ai.cpp | 588 +- src/bindings/scripts/scripts/creature/simple_ai.h | 148 +- .../scripts/scripts/custom/custom_example.cpp | 554 +- .../scripts/custom/custom_gossip_codebox.cpp | 162 +- src/bindings/scripts/scripts/custom/test.cpp | 402 +- src/bindings/scripts/scripts/go/go_scripts.cpp | 418 +- src/bindings/scripts/scripts/guard/guard_ai.cpp | 320 +- src/bindings/scripts/scripts/guard/guard_ai.h | 50 +- src/bindings/scripts/scripts/guard/guards.cpp | 8234 ++--- src/bindings/scripts/scripts/item/item_scripts.cpp | 1058 +- src/bindings/scripts/scripts/item/item_test.cpp | 84 +- src/bindings/scripts/scripts/npc/npc_escortAI.cpp | 608 +- src/bindings/scripts/scripts/npc/npc_escortAI.h | 170 +- src/bindings/scripts/scripts/npc/npc_innkeeper.cpp | 288 +- .../scripts/scripts/npc/npc_professions.cpp | 2410 +- src/bindings/scripts/scripts/npc/npcs_special.cpp | 1756 +- .../zone/alterac_mountains/alterac_mountains.cpp | 124 +- .../auchenai_crypts/boss_exarch_maladaar.cpp | 810 +- .../mana_tombs/boss_nexusprince_shaffar.cpp | 626 +- .../aunchindoun/mana_tombs/boss_pandemonius.cpp | 318 +- .../sethekk_halls/boss_darkweaver_syth.cpp | 882 +- .../sethekk_halls/boss_tailonking_ikiss.cpp | 512 +- .../aunchindoun/sethekk_halls/def_sethekk_halls.h | 18 +- .../sethekk_halls/instance_sethekk_halls.cpp | 148 +- .../shadow_labyrinth/boss_ambassador_hellmaw.cpp | 446 +- .../boss_blackheart_the_inciter.cpp | 382 +- .../shadow_labyrinth/boss_grandmaster_vorpil.cpp | 588 +- .../aunchindoun/shadow_labyrinth/boss_murmur.cpp | 384 +- .../shadow_labyrinth/def_shadow_labyrinth.h | 26 +- .../shadow_labyrinth/instance_shadow_labyrinth.cpp | 336 +- .../scripts/scripts/zone/azshara/azshara.cpp | 328 +- .../scripts/scripts/zone/azshara/boss_azuregos.cpp | 306 +- .../scripts/zone/azuremyst_isle/azuremyst_isle.cpp | 744 +- .../scripts/scripts/zone/barrens/the_barrens.cpp | 378 +- .../scripts/zone/black_temple/black_temple.cpp | 136 +- .../scripts/zone/black_temple/boss_bloodboil.cpp | 730 +- .../scripts/zone/black_temple/boss_illidan.cpp | 4933 +-- .../zone/black_temple/boss_mother_shahraz.cpp | 706 +- .../zone/black_temple/boss_reliquary_of_souls.cpp | 2102 +- .../zone/black_temple/boss_shade_of_akama.cpp | 1626 +- .../scripts/zone/black_temple/boss_supremus.cpp | 812 +- .../zone/black_temple/boss_teron_gorefiend.cpp | 1178 +- .../zone/black_temple/boss_warlord_najentus.cpp | 870 +- .../scripts/zone/black_temple/def_black_temple.h | 68 +- .../scripts/zone/black_temple/illidari_council.cpp | 1770 +- .../zone/black_temple/instance_black_temple.cpp | 504 +- .../zone/blackrock_depths/blackrock_depths.cpp | 474 +- .../blackrock_depths/boss_ambassador_flamelash.cpp | 212 +- .../zone/blackrock_depths/boss_angerrel.cpp | 182 +- .../zone/blackrock_depths/boss_anubshiah.cpp | 230 +- .../scripts/zone/blackrock_depths/boss_doomrel.cpp | 278 +- .../scripts/zone/blackrock_depths/boss_doperel.cpp | 182 +- .../boss_emperor_dagran_thaurissan.cpp | 208 +- .../blackrock_depths/boss_general_angerforge.cpp | 334 +- .../zone/blackrock_depths/boss_gloomrel.cpp | 284 +- .../blackrock_depths/boss_gorosh_the_dervish.cpp | 162 +- .../scripts/zone/blackrock_depths/boss_grizzle.cpp | 172 +- .../scripts/zone/blackrock_depths/boss_haterel.cpp | 210 +- .../boss_high_interrogator_gerstahn.cpp | 210 +- .../scripts/zone/blackrock_depths/boss_magmus.cpp | 168 +- .../blackrock_depths/boss_moira_bronzebeard.cpp | 198 +- .../zone/blackrock_depths/boss_seethrel.cpp | 230 +- .../scripts/zone/blackrock_depths/boss_vilerel.cpp | 202 +- .../zone/blackrock_spire/boss_drakkisath.cpp | 202 +- .../scripts/zone/blackrock_spire/boss_gyth.cpp | 410 +- .../scripts/zone/blackrock_spire/boss_halycon.cpp | 190 +- .../zone/blackrock_spire/boss_highlord_omokk.cpp | 262 +- .../blackrock_spire/boss_mother_smolderweb.cpp | 172 +- .../blackrock_spire/boss_overlord_wyrmthalak.cpp | 254 +- .../blackrock_spire/boss_pyroguard_emberseer.cpp | 186 +- .../blackrock_spire/boss_quartermaster_zigris.cpp | 170 +- .../zone/blackrock_spire/boss_rend_blackhand.cpp | 182 +- .../boss_shadow_hunter_voshgajin.cpp | 190 +- .../zone/blackrock_spire/boss_the_beast.cpp | 186 +- .../zone/blackrock_spire/boss_warmaster_voone.cpp | 242 +- .../blackwing_lair/boss_broodlord_lashlayer.cpp | 260 +- .../zone/blackwing_lair/boss_chromaggus.cpp | 640 +- .../scripts/zone/blackwing_lair/boss_ebonroc.cpp | 206 +- .../scripts/zone/blackwing_lair/boss_firemaw.cpp | 188 +- .../scripts/zone/blackwing_lair/boss_flamegor.cpp | 188 +- .../scripts/zone/blackwing_lair/boss_nefarian.cpp | 500 +- .../scripts/zone/blackwing_lair/boss_razorgore.cpp | 252 +- .../zone/blackwing_lair/boss_vaelastrasz.cpp | 556 +- .../zone/blackwing_lair/boss_victor_nefarius.cpp | 798 +- .../blackwing_lair/instance_blackwing_lair.cpp | 16 +- .../blades_edge_mountains.cpp | 882 +- .../scripts/zone/blasted_lands/blasted_lands.cpp | 318 +- .../scripts/zone/blasted_lands/boss_kruul.cpp | 364 +- .../scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp | 282 +- .../zone/burning_steppes/burning_steppes.cpp | 314 +- .../caverns_of_time/dark_portal/boss_aeonus.cpp | 274 +- .../dark_portal/boss_chrono_lord_deja.cpp | 248 +- .../caverns_of_time/dark_portal/boss_temporus.cpp | 335 +- .../zone/caverns_of_time/hyjal/boss_archimonde.cpp | 1576 +- .../scripts/zone/caverns_of_time/hyjal/def_hyjal.h | 50 +- .../scripts/zone/caverns_of_time/hyjal/hyjal.cpp | 434 +- .../scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp | 916 +- .../scripts/zone/caverns_of_time/hyjal/hyjalAI.h | 572 +- .../zone/caverns_of_time/hyjal/instance_hyjal.cpp | 406 +- .../old_hillsbrad/boss_captain_skarloc.cpp | 354 +- .../old_hillsbrad/boss_epoch_hunter.cpp | 366 +- .../old_hillsbrad/boss_leutenant_drake.cpp | 492 +- .../old_hillsbrad/def_old_hillsbrad.h | 32 +- .../old_hillsbrad/instance_old_hillsbrad.cpp | 356 +- .../old_hillsbrad/old_hillsbrad.cpp | 1832 +- .../serpent_shrine/boss_fathomlord_karathress.cpp | 1118 +- .../serpent_shrine/boss_hydross_the_unstable.cpp | 714 +- .../serpent_shrine/boss_lady_vashj.cpp | 1862 +- .../serpent_shrine/boss_leotheras_the_blind.cpp | 697 +- .../serpent_shrine/boss_morogrim_tidewalker.cpp | 812 +- .../serpent_shrine/def_serpent_shrine.h | 52 +- .../serpent_shrine/instance_serpent_shrine.cpp | 454 +- .../coilfang_resevoir/slave_pens/boss_rokmar.cpp | 130 +- .../steam_vault/boss_hydromancer_thespia.cpp | 446 +- .../steam_vault/boss_mekgineer_steamrigger.cpp | 594 +- .../steam_vault/boss_warlord_kalithresh.cpp | 510 +- .../steam_vault/def_steam_vault.h | 32 +- .../steam_vault/instance_steam_vault.cpp | 340 +- .../coilfang_resevoir/underbog/boss_ghazan.cpp | 156 +- .../coilfang_resevoir/underbog/boss_hungarfen.cpp | 312 +- .../scripts/scripts/zone/darkshore/darkshore.cpp | 48 +- .../scripts/scripts/zone/deadmines/deadmines.cpp | 48 +- .../scripts/zone/deadmines/instance_deadmines.cpp | 44 +- .../scripts/scripts/zone/dun_morogh/dun_morogh.cpp | 196 +- .../zone/dustwallow_marsh/dustwallow_marsh.cpp | 462 +- .../eastern_plaguelands/eastern_plaguelands.cpp | 360 +- .../scripts/zone/elwynn_forest/elwynn_forest.cpp | 196 +- .../scripts/zone/eversong_woods/eversong_woods.cpp | 326 +- .../scripts/scripts/zone/felwood/felwood.cpp | 178 +- .../scripts/scripts/zone/feralas/feralas.cpp | 170 +- .../scripts/scripts/zone/ghostlands/ghostlands.cpp | 268 +- .../scripts/zone/gruuls_lair/boss_gruul.cpp | 562 +- .../zone/gruuls_lair/boss_high_king_maulgar.cpp | 1374 +- .../scripts/zone/gruuls_lair/def_gruuls_lair.h | 30 +- .../zone/gruuls_lair/instance_gruuls_lair.cpp | 278 +- .../blood_furnace/boss_broggok.cpp | 264 +- .../blood_furnace/boss_kelidan_the_breaker.cpp | 506 +- .../blood_furnace/boss_the_maker.cpp | 320 +- .../hellfire_ramparts/boss_omor_the_unscarred.cpp | 556 +- .../boss_watchkeeper_gargolmar.cpp | 400 +- .../magtheridons_lair/boss_magtheridon.cpp | 874 +- .../magtheridons_lair/def_magtheridons_lair.h | 26 +- .../instance_magtheridons_lair.cpp | 232 +- .../shattered_halls/boss_nethekurse.cpp | 1010 +- .../shattered_halls/boss_warbringer_omrogg.cpp | 828 +- .../shattered_halls/def_shattered_halls.h | 26 +- .../shattered_halls/instance_shattered_halls.cpp | 228 +- .../hellfire_peninsula/boss_doomlord_kazzak.cpp | 282 +- .../zone/hellfire_peninsula/hellfire_peninsula.cpp | 374 +- .../scripts/scripts/zone/ironforge/ironforge.cpp | 186 +- .../zone/isle_of_queldanas/isle_of_queldanas.cpp | 310 +- .../scripts/scripts/zone/karazhan/boss_curator.cpp | 400 +- .../zone/karazhan/boss_maiden_of_virtue.cpp | 352 +- .../scripts/zone/karazhan/boss_midnight.cpp | 742 +- .../scripts/scripts/zone/karazhan/boss_moroes.cpp | 1736 +- .../scripts/zone/karazhan/boss_netherspite.cpp | 74 +- .../scripts/zone/karazhan/boss_nightbane.cpp | 66 +- .../zone/karazhan/boss_prince_malchezaar.cpp | 1292 +- .../scripts/zone/karazhan/boss_shade_of_aran.cpp | 1346 +- .../zone/karazhan/boss_terestian_illhoof.cpp | 908 +- .../scripts/scripts/zone/karazhan/bosses_opera.cpp | 2942 +- .../scripts/scripts/zone/karazhan/def_karazhan.h | 80 +- .../scripts/zone/karazhan/instance_karazhan.cpp | 506 +- .../scripts/scripts/zone/karazhan/karazhan.cpp | 940 +- .../scripts/scripts/zone/loch_modan/loch_modan.cpp | 182 +- .../magisters_terrace/boss_felblood_kaelthas.cpp | 1182 +- .../magisters_terrace/boss_priestess_delrissa.cpp | 2734 +- .../magisters_terrace/boss_selin_fireheart.cpp | 770 +- .../zone/magisters_terrace/boss_vexallus.cpp | 466 +- .../zone/magisters_terrace/def_magisters_terrace.h | 58 +- .../instance_magisters_terrace.cpp | 390 +- .../zone/maraudon/boss_celebras_the_cursed.cpp | 194 +- .../scripts/zone/maraudon/boss_landslide.cpp | 188 +- .../scripts/scripts/zone/maraudon/boss_noxxion.cpp | 298 +- .../zone/maraudon/boss_princess_theradras.cpp | 216 +- .../scripts/zone/molten_core/boss_baron_geddon.cpp | 210 +- .../scripts/scripts/zone/molten_core/boss_garr.cpp | 317 +- .../scripts/zone/molten_core/boss_gehennas.cpp | 182 +- .../scripts/zone/molten_core/boss_golemagg.cpp | 420 +- .../scripts/zone/molten_core/boss_lucifron.cpp | 180 +- .../scripts/zone/molten_core/boss_magmadar.cpp | 194 +- .../zone/molten_core/boss_majordomo_executus.cpp | 266 +- .../scripts/zone/molten_core/boss_ragnaros.cpp | 634 +- .../scripts/zone/molten_core/boss_shazzrah.cpp | 242 +- .../zone/molten_core/boss_sulfuron_harbinger.cpp | 430 +- .../scripts/zone/molten_core/def_molten_core.h | 42 +- .../zone/molten_core/instance_molten_core.cpp | 520 +- .../scripts/zone/molten_core/molten_core.cpp | 176 +- .../scripts/scripts/zone/moonglade/moonglade.cpp | 434 +- .../scripts/scripts/zone/mulgore/mulgore.cpp | 128 +- .../scripts/scripts/zone/nagrand/nagrand.cpp | 1136 +- .../scripts/zone/naxxramas/boss_anubrekhan.cpp | 430 +- .../scripts/zone/naxxramas/boss_faerlina.cpp | 404 +- .../scripts/scripts/zone/naxxramas/boss_feugen.cpp | 66 +- .../scripts/scripts/zone/naxxramas/boss_gluth.cpp | 348 +- .../scripts/scripts/zone/naxxramas/boss_gothik.cpp | 124 +- .../scripts/zone/naxxramas/boss_grobbulus.cpp | 60 +- .../scripts/scripts/zone/naxxramas/boss_heigan.cpp | 92 +- .../zone/naxxramas/boss_highlord_mograine.cpp | 356 +- .../scripts/zone/naxxramas/boss_kelthuzad.cpp | 1084 +- .../scripts/zone/naxxramas/boss_lady_blaumeux.cpp | 294 +- .../scripts/zone/naxxramas/boss_loatheb.cpp | 432 +- .../scripts/zone/naxxramas/boss_maexxna.cpp | 492 +- .../scripts/scripts/zone/naxxramas/boss_noth.cpp | 360 +- .../scripts/zone/naxxramas/boss_patchwerk.cpp | 320 +- .../scripts/zone/naxxramas/boss_razuvious.cpp | 334 +- .../scripts/zone/naxxramas/boss_sapphiron.cpp | 398 +- .../scripts/zone/naxxramas/boss_sir_zeliek.cpp | 292 +- .../scripts/zone/naxxramas/boss_stalagg.cpp | 70 +- .../scripts/zone/naxxramas/boss_thaddius.cpp | 98 +- .../scripts/zone/naxxramas/boss_thane_korthazz.cpp | 294 +- .../scripts/zone/naxxramas/instance_naxxramas.cpp | 48 +- .../scripts/zone/netherstorm/netherstorm.cpp | 846 +- .../scripts/zone/onyxias_lair/boss_onyxia.cpp | 458 +- .../scripts/scripts/zone/orgrimmar/orgrimmar.cpp | 530 +- .../boss_amnennar_the_coldbringer.cpp | 280 +- .../zone/ruins_of_ahnqiraj/boss_ayamiss.cpp | 214 +- .../scripts/zone/ruins_of_ahnqiraj/boss_buru.cpp | 48 +- .../zone/ruins_of_ahnqiraj/boss_kurinnaxx.cpp | 186 +- .../scripts/zone/ruins_of_ahnqiraj/boss_moam.cpp | 234 +- .../zone/ruins_of_ahnqiraj/boss_ossirian.cpp | 72 +- .../scripts/zone/ruins_of_ahnqiraj/boss_rajaxx.cpp | 84 +- .../instance_ruins_of_ahnqiraj.cpp | 48 +- .../zone/scarlet_monastery/boss_arcanist_doan.cpp | 342 +- .../boss_azshir_the_sleepless.cpp | 194 +- .../scarlet_monastery/boss_bloodmage_thalnos.cpp | 272 +- .../scripts/zone/scarlet_monastery/boss_herod.cpp | 394 +- .../boss_high_inquisitor_fairbanks.cpp | 264 +- .../boss_high_inquisitor_whitemane.cpp | 354 +- .../scarlet_monastery/boss_houndmaster_loksey.cpp | 156 +- .../scarlet_monastery/boss_interrogator_vishas.cpp | 226 +- .../boss_scarlet_commander_mograine.cpp | 320 +- .../scripts/zone/scarlet_monastery/boss_scorn.cpp | 200 +- .../zone/scholomance/boss_darkmaster_gandling.cpp | 384 +- .../scholomance/boss_death_knight_darkreaver.cpp | 118 +- .../scholomance/boss_doctor_theolen_krastinov.cpp | 216 +- .../zone/scholomance/boss_illucia_barov.cpp | 232 +- .../zone/scholomance/boss_instructor_malicia.cpp | 304 +- .../zone/scholomance/boss_jandice_barov.cpp | 434 +- .../scripts/zone/scholomance/boss_kormok.cpp | 310 +- .../zone/scholomance/boss_lord_alexei_barov.cpp | 196 +- .../zone/scholomance/boss_lorekeeper_polkelt.cpp | 226 +- .../zone/scholomance/boss_ras_frostwhisper.cpp | 250 +- .../scripts/zone/scholomance/boss_the_ravenian.cpp | 236 +- .../scripts/zone/scholomance/boss_vectus.cpp | 190 +- .../scripts/zone/scholomance/def_scholomance.h | 30 +- .../zone/scholomance/instance_scholomance.cpp | 204 +- .../scripts/zone/searing_gorge/searing_gorge.cpp | 318 +- .../zone/shadowfang_keep/def_shadowfang_keep.h | 24 +- .../shadowfang_keep/instance_shadowfang_keep.cpp | 304 +- .../zone/shadowfang_keep/shadowfang_keep.cpp | 234 +- .../zone/shadowmoon_valley/boss_doomwalker.cpp | 422 +- .../zone/shadowmoon_valley/shadowmoon_valley.cpp | 1496 +- .../scripts/zone/shattrath/shattrath_city.cpp | 536 +- .../scripts/scripts/zone/silithus/silithus.cpp | 298 +- .../scripts/zone/silvermoon/silvermoon_city.cpp | 206 +- .../zone/silverpine_forest/silverpine_forest.cpp | 200 +- .../stonetalon_mountains/stonetalon_mountains.cpp | 160 +- .../scripts/zone/stormwind/stormwind_city.cpp | 544 +- .../zone/stranglethorn_vale/stranglethorn_vale.cpp | 214 +- .../zone/stratholme/boss_baron_rivendare.cpp | 430 +- .../zone/stratholme/boss_baroness_anastari.cpp | 248 +- .../zone/stratholme/boss_cannon_master_willey.cpp | 442 +- .../zone/stratholme/boss_dathrohan_balnazzar.cpp | 632 +- .../zone/stratholme/boss_magistrate_barthilas.cpp | 228 +- .../zone/stratholme/boss_maleki_the_pallid.cpp | 238 +- .../scripts/zone/stratholme/boss_nerubenkan.cpp | 276 +- .../zone/stratholme/boss_order_of_silver_hand.cpp | 322 +- .../zone/stratholme/boss_postmaster_malown.cpp | 288 +- .../zone/stratholme/boss_ramstein_the_gorger.cpp | 184 +- .../zone/stratholme/boss_timmy_the_cruel.cpp | 206 +- .../scripts/zone/stratholme/def_stratholme.h | 28 +- .../zone/stratholme/instance_stratholme.cpp | 154 +- .../scripts/scripts/zone/stratholme/stratholme.cpp | 670 +- .../zone/sunwell_plateau/boss_brutallus.cpp | 376 +- .../scripts/zone/sunwell_plateau/boss_kalecgos.cpp | 1314 +- .../zone/sunwell_plateau/def_sunwell_plateau.h | 86 +- .../sunwell_plateau/instance_sunwell_plateau.cpp | 550 +- .../scripts/scripts/zone/tanaris/tanaris.cpp | 804 +- .../zone/tempest_keep/arcatraz/arcatraz.cpp | 1224 +- .../arcatraz/boss_harbinger_skyriss.cpp | 760 +- .../zone/tempest_keep/arcatraz/def_arcatraz.h | 38 +- .../tempest_keep/arcatraz/instance_arcatraz.cpp | 448 +- .../botanica/boss_high_botanist_freywinn.cpp | 430 +- .../zone/tempest_keep/botanica/boss_laj.cpp | 396 +- .../tempest_keep/botanica/boss_warp_splinter.cpp | 576 +- .../zone/tempest_keep/the_eye/boss_astromancer.cpp | 1108 +- .../zone/tempest_keep/the_eye/boss_kaelthas.cpp | 3260 +- .../zone/tempest_keep/the_eye/boss_void_reaver.cpp | 406 +- .../zone/tempest_keep/the_eye/def_the_eye.h | 40 +- .../zone/tempest_keep/the_eye/instance_the_eye.cpp | 356 +- .../scripts/zone/tempest_keep/the_eye/the_eye.cpp | 196 +- .../the_mechanar/boss_gatewatcher_gyrokill.cpp | 48 +- .../the_mechanar/boss_gatewatcher_ironhand.cpp | 294 +- .../the_mechanar/boss_nethermancer_sepethrea.cpp | 446 +- .../zone/temple_of_ahnqiraj/boss_bug_trio.cpp | 732 +- .../scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp | 2720 +- .../zone/temple_of_ahnqiraj/boss_fankriss.cpp | 380 +- .../zone/temple_of_ahnqiraj/boss_huhuran.cpp | 286 +- .../scripts/zone/temple_of_ahnqiraj/boss_ouro.cpp | 280 +- .../zone/temple_of_ahnqiraj/boss_sartura.cpp | 542 +- .../zone/temple_of_ahnqiraj/boss_skeram.cpp | 628 +- .../zone/temple_of_ahnqiraj/boss_twinemperors.cpp | 1396 +- .../zone/temple_of_ahnqiraj/boss_viscidus.cpp | 58 +- .../temple_of_ahnqiraj/def_temple_of_ahnqiraj.h | 44 +- .../instance_temple_of_ahnqiraj.cpp | 330 +- .../temple_of_ahnqiraj/mob_anubisath_sentinel.cpp | 688 +- .../zone/terokkar_forest/terokkar_forest.cpp | 798 +- .../scripts/zone/thunder_bluff/thunder_bluff.cpp | 272 +- .../zone/tirisfal_glades/tirisfal_glades.cpp | 176 +- .../scripts/scripts/zone/uldaman/boss_ironaya.cpp | 214 +- .../scripts/scripts/zone/uldaman/uldaman.cpp | 374 +- .../scripts/scripts/zone/undercity/undercity.cpp | 520 +- .../wailing_caverns/instance_wailing_caverns.cpp | 48 +- .../western_plaguelands/western_plaguelands.cpp | 352 +- .../scripts/zone/winterspring/winterspring.cpp | 314 +- .../scripts/zone/zangarmarsh/zangarmarsh.cpp | 566 +- .../scripts/scripts/zone/zulaman/boss_janalai.cpp | 1537 +- .../scripts/scripts/zone/zulaman/boss_nalorakk.cpp | 544 +- .../scripts/scripts/zone/zulaman/def_zulaman.h | 34 +- .../scripts/zone/zulaman/instance_zulaman.cpp | 274 +- .../scripts/scripts/zone/zulaman/zulaman.cpp | 216 +- .../scripts/scripts/zone/zulfarrak/zulfarrak.cpp | 448 +- .../scripts/scripts/zone/zulgurub/boss_arlokk.cpp | 422 +- .../scripts/zone/zulgurub/boss_gahzranka.cpp | 184 +- .../scripts/scripts/zone/zulgurub/boss_grilek.cpp | 184 +- .../scripts/scripts/zone/zulgurub/boss_hakkar.cpp | 512 +- .../scripts/zone/zulgurub/boss_hazzarah.cpp | 200 +- .../scripts/scripts/zone/zulgurub/boss_jeklik.cpp | 594 +- .../scripts/scripts/zone/zulgurub/boss_jindo.cpp | 580 +- .../scripts/zone/zulgurub/boss_mandokir.cpp | 622 +- .../scripts/scripts/zone/zulgurub/boss_marli.cpp | 520 +- .../scripts/zone/zulgurub/boss_renataki.cpp | 302 +- .../scripts/scripts/zone/zulgurub/boss_thekal.cpp | 1090 +- .../scripts/scripts/zone/zulgurub/boss_venoxis.cpp | 400 +- .../scripts/zone/zulgurub/boss_wushoolay.cpp | 168 +- .../scripts/scripts/zone/zulgurub/def_zulgurub.h | 72 +- .../scripts/zone/zulgurub/instance_zulgurub.cpp | 476 +- src/game/AggressorAI.cpp | 312 +- src/game/CharacterHandler.cpp | 10 +- src/game/Chat.cpp | 2234 +- src/game/Chat.h | 827 +- src/game/Creature.cpp | 3921 +- src/game/Creature.h | 1223 +- src/game/CreatureAISelector.cpp | 238 +- src/game/GossipDef.cpp | 1527 +- src/game/GossipDef.h | 399 +- src/game/GridNotifiers.h | 1624 +- src/game/GuardAI.cpp | 304 +- src/game/Guild.cpp | 3903 +- src/game/Guild.h | 872 +- src/game/Language.h | 1333 +- src/game/Level1.cpp | 4642 ++- src/game/Level2.cpp | 7994 ++-- src/game/Level3.cpp | 10883 +++--- src/game/Makefile.am | 2 + src/game/NPCHandler.cpp | 1658 +- src/game/ObjectMgr.cpp | 13370 +++---- src/game/ObjectMgr.h | 1640 +- src/game/Player.cpp | 36263 ++++++++++--------- src/game/Player.h | 4623 +-- src/game/SharedDefines.h | 104 + src/game/Spell.cpp | 10185 +++--- src/game/Spell.h | 1389 +- src/game/SpellEffects.cpp | 12188 +++---- src/game/StatSystem.cpp | 1920 +- src/game/Unit.cpp | 21620 +++++------ src/game/Unit.h | 2667 +- src/game/WaypointMovementGenerator.cpp | 1300 +- src/game/World.cpp | 5006 +-- src/game/World.h | 12 +- src/game/WorldSession.cpp | 82 +- src/game/WorldSession.h | 10 +- src/game/WorldSocket.cpp | 1369 +- src/game/WorldSocket.h | 340 +- src/game/WorldSocketMgr.cpp | 353 +- src/game/WorldSocketMgr.h | 62 +- src/shared/Common.h | 46 +- src/shared/Database/DBCStructure.h | 1874 +- src/shared/Database/DBCfmt.cpp | 156 +- src/shared/Database/DatabaseEnv.h | 106 +- src/shared/Makefile.am | 2 + src/shared/Timer.h | 2 +- src/trinitycore/Makefile.am | 3 + src/trinitycore/Master.cpp | 181 +- src/trinitycore/TrinityCore.rc | 8 +- src/trinitycore/WorldRunnable.cpp | 3 + src/trinityrealm/Makefile.am | 3 + src/trinityrealm/TrinityRealm.rc | 8 +- 403 files changed, 165634 insertions(+), 164255 deletions(-) (limited to 'src') diff --git a/src/bindings/scripts/ScriptMgr.cpp b/src/bindings/scripts/ScriptMgr.cpp index fb156a313aa..4dff1b7c374 100644 --- a/src/bindings/scripts/ScriptMgr.cpp +++ b/src/bindings/scripts/ScriptMgr.cpp @@ -1119,9 +1119,10 @@ void ScriptsFree() MANGOS_DLL_EXPORT void ScriptsInit() { - //Trinity Script startup + //Trinity Script startup + outstring_log(" _____ _ _ _ ____ _ _"); outstring_log("|_ _| __(_)_ __ (_) |_ _ _/ ___| ___ _ __(_)_ __ | |_ "); - outstring_log(" | || '__| | '_ \\| | __| | | \\___ \\ / __| \\'__| | \\'_ \\| __|"); + outstring_log(" | || '__| | '_ \\| | __| | | \\___ \\ / __| \'__| | \'_ \\| __|"); outstring_log(" | || | | | | | | | |_| |_| |___) | (__| | | | |_) | |_ "); outstring_log(" |_||_| |_|_| |_|_|\\__|\\__, |____/ \\___|_| |_| .__/ \\__|"); outstring_log(" |___/ |_| "); diff --git a/src/bindings/scripts/VC71/71ScriptDev2.vcproj b/src/bindings/scripts/VC71/71ScriptDev2.vcproj index 4b015248add..9ea083bc56e 100644 --- a/src/bindings/scripts/VC71/71ScriptDev2.vcproj +++ b/src/bindings/scripts/VC71/71ScriptDev2.vcproj @@ -20,7 +20,7 @@ - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#include "precompiled.h" -#include "Item.h" -#include "Spell.h" -#include "WorldPacket.h" - -// Spell summary for ScriptedAI::SelectSpell -struct TSpellSummary { - uint8 Targets; // set of enum SelectTarget - uint8 Effects; // set of enum SelectEffect -} *SpellSummary; - -bool ScriptedAI::IsVisible(Unit* who) const -{ - if (!who) - return false; - - return (m_creature->GetDistance(who) < VISIBLE_RANGE) && who->isVisibleForOrDetect(m_creature,true); -} - -void ScriptedAI::MoveInLineOfSight(Unit *who) -{ - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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) ) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } -} - -void ScriptedAI::AttackStart(Unit* who) -{ - if (!who) - return; - - if (who->isTargetableForAttack()) - { - //Begin attack - DoStartAttackAndMovement(who); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } -} - -void ScriptedAI::UpdateAI(const uint32 diff) -{ - //Check if we have a current target - if( m_creature->isAlive() && m_creature->SelectHostilTarget() && m_creature->getVictim()) - { - 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::EnterEvadeMode() -{ - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - m_creature->LoadCreaturesAddon(); - - if( m_creature->isAlive() ) - m_creature->GetMotionMaster()->MoveTargetedHome(); - - m_creature->SetLootRecipient(NULL); - - InCombat = false; - Reset(); -} - -void ScriptedAI::JustRespawned() -{ - InCombat = false; - Reset(); -} - -void ScriptedAI::DoStartAttackAndMovement(Unit* victim, float distance, float angle) -{ - if (!victim) - return; - - if ( m_creature->Attack(victim, true) ) - { - m_creature->GetMotionMaster()->MoveChase(victim, distance, angle); - m_creature->AddThreat(victim, 0.0f); - } -} - -void ScriptedAI::DoStartAttackNoMovement(Unit* victim) -{ - if (!victim) - return; - - if ( m_creature->Attack(victim, true) ) - { - m_creature->AddThreat(victim, 0.0f); - } -} - - -void ScriptedAI::DoMeleeAttackIfReady() -{ - //Make sure our attack is ready and we aren't currently casting before checking distance - 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)) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - } -} - -void ScriptedAI::DoStopAttack() -{ - if( m_creature->getVictim() != NULL ) - { - m_creature->AttackStop(); - } -} - -void ScriptedAI::DoCast(Unit* victim, uint32 spellId, bool triggered) -{ - if (!victim || m_creature->IsNonMeleeSpellCasted(false)) - return; - - m_creature->StopMoving(); - m_creature->CastSpell(victim, spellId, triggered); -} - -void ScriptedAI::DoCastSpell(Unit* who,SpellEntry const *spellInfo, bool triggered) -{ - if (!who || m_creature->IsNonMeleeSpellCasted(false)) - return; - - m_creature->StopMoving(); - m_creature->CastSpell(who, spellInfo, triggered); -} - -void ScriptedAI::DoSay(const char* text, uint32 language, Unit* target) -{ - if (target)m_creature->Say(text, language, target->GetGUID()); - else m_creature->Say(text, language, 0); -} - -void ScriptedAI::DoYell(const char* text, uint32 language, Unit* target) -{ - if (target)m_creature->Yell(text, language, target->GetGUID()); - else m_creature->Yell(text, language, 0); -} - -void ScriptedAI::DoTextEmote(const char* text, Unit* target, bool IsBossEmote) -{ - if (target)m_creature->TextEmote(text, target->GetGUID(), IsBossEmote); - else m_creature->TextEmote(text, 0, IsBossEmote); -} - -void ScriptedAI::DoWhisper(const char* text, Unit* reciever, bool IsBossWhisper) -{ - if (!reciever || reciever->GetTypeId() != TYPEID_PLAYER) - return; - - m_creature->Whisper(text, reciever->GetGUID(), IsBossWhisper); -} - -void ScriptedAI::DoPlaySoundToSet(Unit* unit, uint32 sound) -{ - if (!unit) - return; - - if (!GetSoundEntriesStore()->LookupEntry(sound)) - { - error_log("SD2: Invalid soundId %u used in DoPlaySoundToSet (by unit TypeId %u, guid %u)", sound, unit->GetTypeId(), unit->GetGUID()); - return; - } - - WorldPacket data(4); - data.SetOpcode(SMSG_PLAY_SOUND); - data << uint32(sound); - unit->SendMessageToSet(&data,false); -} - -Creature* ScriptedAI::DoSpawnCreature(uint32 id, float x, float y, float z, float angle, uint32 type, uint32 despawntime) -{ - return m_creature->SummonCreature(id,m_creature->GetPositionX() + x,m_creature->GetPositionY() + y,m_creature->GetPositionZ() + z, angle, (TempSummonType)type, despawntime); -} - -Unit* ScriptedAI::SelectUnit(SelectAggroTarget target, uint32 position) -{ - //ThreatList m_threatlist; - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list::iterator i = m_threatlist.begin(); - std::list::reverse_iterator r = m_threatlist.rbegin(); - - if (position >= m_threatlist.size() || !m_threatlist.size()) - return NULL; - - switch (target) - { - case SELECT_TARGET_RANDOM: - advance ( i , position + (rand() % (m_threatlist.size() - position ) )); - return Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); - break; - - case SELECT_TARGET_TOPAGGRO: - advance ( i , position); - return Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); - break; - - case SELECT_TARGET_BOTTOMAGGRO: - advance ( r , position); - return Unit::GetUnit((*m_creature),(*r)->getUnitGuid()); - break; - } - - return NULL; -} - -SpellEntry const* ScriptedAI::SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTarget Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effects) -{ - //No target so we can't cast - if (!Target) - return false; - - //Silenced so we can't cast - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) - return false; - - //Using the extended script system we first create a list of viable spells - SpellEntry const* Spell[4]; - Spell[0] = 0; - Spell[1] = 0; - Spell[2] = 0; - Spell[3] = 0; - - uint32 SpellCount = 0; - - SpellEntry const* TempSpell; - SpellRangeEntry const* TempRange; - - //Check if each spell is viable(set it to null if not) - for (uint32 i = 0; i < 4; i++) - { - TempSpell = GetSpellStore()->LookupEntry(m_creature->m_spells[i]); - - //This spell doesn't exist - if (!TempSpell) - continue; - - // Targets and Effects checked first as most used restrictions - //Check the spell targets if specified - if ( Targets && !(SpellSummary[m_creature->m_spells[i]].Targets & (1 << (Targets-1))) ) - continue; - - //Check the type of spell if we are looking for a specific spell type - if ( Effects && !(SpellSummary[m_creature->m_spells[i]].Effects & (1 << (Effects-1))) ) - continue; - - //Check for school if specified - if (School >= 0 && TempSpell->SchoolMask & School) - continue; - - //Check for spell mechanic if specified - if (Mechanic >= 0 && TempSpell->Mechanic != Mechanic) - continue; - - //Make sure that the spell uses the requested amount of power - if (PowerCostMin && TempSpell->manaCost < PowerCostMin) - continue; - - if (PowerCostMax && TempSpell->manaCost > PowerCostMax) - continue; - - //Continue if we don't have the mana to actually cast this spell - if (TempSpell->manaCost > m_creature->GetPower((Powers)TempSpell->powerType)) - continue; - - //Get the Range - TempRange = GetSpellRangeStore()->LookupEntry(TempSpell->rangeIndex); - - //Spell has invalid range store so we can't use it - if (!TempRange) - continue; - - //Check if the spell meets our range requirements - if (RangeMin && TempRange->maxRange < RangeMin) - continue; - if (RangeMax && TempRange->maxRange > RangeMax) - continue; - - //Check if our target is in range - if (m_creature->IsWithinDistInMap(Target, TempRange->minRange) || !m_creature->IsWithinDistInMap(Target, TempRange->maxRange)) - continue; - - //All good so lets add it to the spell list - Spell[SpellCount] = TempSpell; - SpellCount++; - } - - //We got our usable spells so now lets randomly pick one - if (!SpellCount) - return NULL; - - return Spell[rand()%SpellCount]; -} - -bool ScriptedAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered) -{ - //No target so we can't cast - if (!Target || !Spell) - return false; - - //Silenced so we can't cast - if (!Triggered && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) - return false; - - //Check for power - if (!Triggered && m_creature->GetPower((Powers)Spell->powerType) < Spell->manaCost) - return false; - - SpellRangeEntry const *TempRange = NULL; - - TempRange = GetSpellRangeStore()->LookupEntry(Spell->rangeIndex); - - //Spell has invalid range store so we can't use it - if (!TempRange) - return false; - - //Unit is out of range of this spell - if (m_creature->GetDistance(Target) > TempRange->maxRange || m_creature->GetDistance(Target) < TempRange->minRange) - return false; - - return true; -} - -void FillSpellSummary() -{ - SpellSummary = new TSpellSummary[GetSpellStore()->GetNumRows()]; - - SpellEntry const* TempSpell; - - for (int i=0; i < GetSpellStore()->GetNumRows(); i++ ) - { - SpellSummary[i].Effects = 0; - SpellSummary[i].Targets = 0; - - TempSpell = GetSpellStore()->LookupEntry(i); - //This spell doesn't exist - if (!TempSpell) - continue; - - for (int j=0; j<3; j++) - { - //Spell targets self - if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF ) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); - - //Spell targets a single enemy - if ( TempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || - TempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES ) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1); - - //Spell targets AoE at enemy - if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED ) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); - - //Spell targets an enemy - if ( TempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || - TempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER || - TempSpell->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 ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF || - TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND || - TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY ) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1); - - //Spell targets aoe friends - if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || - TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); - - //Spell targets any friend(or self) - if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF || - TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND || - TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || - TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); - - //Make sure that this spell includes a damage effect - if ( TempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || - TempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || - TempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || - TempSpell->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 ( TempSpell->Effect[j] == SPELL_EFFECT_HEAL || - TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || - TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL || - (TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA && TempSpell->EffectApplyAuraName[j]== 8 )) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1); - - //Make sure that this spell applies an aura - if ( TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA ) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); - } - } -} - -void ScriptedAI::DoZoneInCombat(Unit* pUnit) -{ - if (!pUnit) - pUnit = m_creature; - - Map *map = pUnit->GetMap(); - - if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated - { - error_log("SD2: DoZoneInCombat call for map that isn't an instance (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0); - return; - } - - if (!pUnit->CanHaveThreatList() || pUnit->getThreatManager().isThreatListEmpty()) - { - error_log("SD2: DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0); - - return; - } - - InstanceMap::PlayerList const &PlayerList = ((InstanceMap*)map)->GetPlayers(); - InstanceMap::PlayerList::const_iterator i; - for (i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if(!(*i)->isGameMaster()) - pUnit->AddThreat(*i, 0.0f); - } -} - -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()); - - return; - } - - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list::iterator itr; - - for(itr = m_threatlist.begin(); itr != m_threatlist.end(); ++itr) - { - Unit* pUnit = NULL; - pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); - if(pUnit && m_creature->getThreatManager().getThreat(pUnit)) - m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); - } -} - -void ScriptedAI::DoTeleportPlayer(Unit* pUnit, float x, float y, float z, float o) -{ - if(!pUnit || pUnit->GetTypeId() != TYPEID_PLAYER) - { - if(pUnit) - error_log("SD2: Creature %u (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: %u) to x: %f y:%f z: %f o: %f. Aborted.", m_creature->GetGUID(), m_creature->GetEntry(), pUnit->GetTypeId(), pUnit->GetGUID(), x, y, z, o); - return; - } - - ((Player*)pUnit)->TeleportTo(pUnit->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT); -} - -Unit* ScriptedAI::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) -{ - CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Unit* pUnit = NULL; - - MostHPMissingInRange u_check(m_creature, range, MinHPDiff); - MaNGOS::UnitLastSearcher searcher(pUnit, u_check); - - /* - typedef TYPELIST_4(GameObject, Creature*except pets*, DynamicObject, Corpse*Bones*) AllGridObjectTypes; - This means that if we only search grid then we cannot possibly return pets or players so this is safe - */ - TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_unit_searcher, *(m_creature->GetMap())); - return pUnit; -} - -std::list ScriptedAI::DoFindFriendlyCC(float range) -{ - CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list pList; - - FriendlyCCedInRange u_check(m_creature, range); - MaNGOS::CreatureListSearcher searcher(pList, u_check); - - TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap())); - - return pList; -} - -std::list ScriptedAI::DoFindFriendlyMissingBuff(float range, uint32 spellid) -{ - CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list pList; - - FriendlyMissingBuffInRange u_check(m_creature, range, spellid); - MaNGOS::CreatureListSearcher searcher(pList, u_check); - - TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap())); - - return pList; -} - -void Scripted_NoMovementAI::MoveInLineOfSight(Unit *who) -{ - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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) ) - { - DoStartAttackNoMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } -} - -void Scripted_NoMovementAI::AttackStart(Unit* who) -{ - if (!who) - return; - - if (who->isTargetableForAttack()) - { - //Begin attack - DoStartAttackNoMovement(who); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } -} +/* Copyright (C) 2006 - 2008 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 "Item.h" +#include "Spell.h" +#include "WorldPacket.h" + +// Spell summary for ScriptedAI::SelectSpell +struct TSpellSummary { + uint8 Targets; // set of enum SelectTarget + uint8 Effects; // set of enum SelectEffect +} *SpellSummary; + +bool ScriptedAI::IsVisible(Unit* who) const +{ + if (!who) + return false; + + return (m_creature->GetDistance(who) < VISIBLE_RANGE) && who->isVisibleForOrDetect(m_creature,true); +} + +void ScriptedAI::MoveInLineOfSight(Unit *who) +{ + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } +} + +void ScriptedAI::AttackStart(Unit* who) +{ + if (!who) + return; + + if (who->isTargetableForAttack()) + { + //Begin attack + DoStartAttackAndMovement(who); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } +} + +void ScriptedAI::UpdateAI(const uint32 diff) +{ + //Check if we have a current target + if( m_creature->isAlive() && m_creature->SelectHostilTarget() && m_creature->getVictim()) + { + 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::EnterEvadeMode() +{ + m_creature->InterruptNonMeleeSpells(true); + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + m_creature->LoadCreaturesAddon(); + + if( m_creature->isAlive() ) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + m_creature->SetLootRecipient(NULL); + + InCombat = false; + Reset(); +} + +void ScriptedAI::JustRespawned() +{ + InCombat = false; + Reset(); +} + +void ScriptedAI::DoStartAttackAndMovement(Unit* victim, float distance, float angle) +{ + if (!victim) + return; + + if ( m_creature->Attack(victim, true) ) + { + m_creature->GetMotionMaster()->MoveChase(victim, distance, angle); + m_creature->AddThreat(victim, 0.0f); + } +} + +void ScriptedAI::DoStartAttackNoMovement(Unit* victim) +{ + if (!victim) + return; + + if ( m_creature->Attack(victim, true) ) + { + m_creature->AddThreat(victim, 0.0f); + } +} + + +void ScriptedAI::DoMeleeAttackIfReady() +{ + //Make sure our attack is ready and we aren't currently casting before checking distance + 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)) + { + m_creature->AttackerStateUpdate(m_creature->getVictim()); + m_creature->resetAttackTimer(); + } + } +} + +void ScriptedAI::DoStopAttack() +{ + if( m_creature->getVictim() != NULL ) + { + m_creature->AttackStop(); + } +} + +void ScriptedAI::DoCast(Unit* victim, uint32 spellId, bool triggered) +{ + if (!victim || m_creature->IsNonMeleeSpellCasted(false)) + return; + + m_creature->StopMoving(); + m_creature->CastSpell(victim, spellId, triggered); +} + +void ScriptedAI::DoCastSpell(Unit* who,SpellEntry const *spellInfo, bool triggered) +{ + if (!who || m_creature->IsNonMeleeSpellCasted(false)) + return; + + m_creature->StopMoving(); + m_creature->CastSpell(who, spellInfo, triggered); +} + +void ScriptedAI::DoSay(const char* text, uint32 language, Unit* target) +{ + if (target)m_creature->Say(text, language, target->GetGUID()); + else m_creature->Say(text, language, 0); +} + +void ScriptedAI::DoYell(const char* text, uint32 language, Unit* target) +{ + if (target)m_creature->Yell(text, language, target->GetGUID()); + else m_creature->Yell(text, language, 0); +} + +void ScriptedAI::DoTextEmote(const char* text, Unit* target, bool IsBossEmote) +{ + if (target)m_creature->TextEmote(text, target->GetGUID(), IsBossEmote); + else m_creature->TextEmote(text, 0, IsBossEmote); +} + +void ScriptedAI::DoWhisper(const char* text, Unit* reciever, bool IsBossWhisper) +{ + if (!reciever || reciever->GetTypeId() != TYPEID_PLAYER) + return; + + m_creature->Whisper(text, reciever->GetGUID(), IsBossWhisper); +} + +void ScriptedAI::DoPlaySoundToSet(Unit* unit, uint32 sound) +{ + if (!unit) + return; + + if (!GetSoundEntriesStore()->LookupEntry(sound)) + { + error_log("SD2: Invalid soundId %u used in DoPlaySoundToSet (by unit TypeId %u, guid %u)", sound, unit->GetTypeId(), unit->GetGUID()); + return; + } + + WorldPacket data(4); + data.SetOpcode(SMSG_PLAY_SOUND); + data << uint32(sound); + unit->SendMessageToSet(&data,false); +} + +Creature* ScriptedAI::DoSpawnCreature(uint32 id, float x, float y, float z, float angle, uint32 type, uint32 despawntime) +{ + return m_creature->SummonCreature(id,m_creature->GetPositionX() + x,m_creature->GetPositionY() + y,m_creature->GetPositionZ() + z, angle, (TempSummonType)type, despawntime); +} + +Unit* ScriptedAI::SelectUnit(SelectAggroTarget target, uint32 position) +{ + //ThreatList m_threatlist; + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + std::list::iterator i = m_threatlist.begin(); + std::list::reverse_iterator r = m_threatlist.rbegin(); + + if (position >= m_threatlist.size() || !m_threatlist.size()) + return NULL; + + switch (target) + { + case SELECT_TARGET_RANDOM: + advance ( i , position + (rand() % (m_threatlist.size() - position ) )); + return Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); + break; + + case SELECT_TARGET_TOPAGGRO: + advance ( i , position); + return Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); + break; + + case SELECT_TARGET_BOTTOMAGGRO: + advance ( r , position); + return Unit::GetUnit((*m_creature),(*r)->getUnitGuid()); + break; + } + + return NULL; +} + +SpellEntry const* ScriptedAI::SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTarget Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effects) +{ + //No target so we can't cast + if (!Target) + return false; + + //Silenced so we can't cast + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) + return false; + + //Using the extended script system we first create a list of viable spells + SpellEntry const* Spell[4]; + Spell[0] = 0; + Spell[1] = 0; + Spell[2] = 0; + Spell[3] = 0; + + uint32 SpellCount = 0; + + SpellEntry const* TempSpell; + SpellRangeEntry const* TempRange; + + //Check if each spell is viable(set it to null if not) + for (uint32 i = 0; i < 4; i++) + { + TempSpell = GetSpellStore()->LookupEntry(m_creature->m_spells[i]); + + //This spell doesn't exist + if (!TempSpell) + continue; + + // Targets and Effects checked first as most used restrictions + //Check the spell targets if specified + if ( Targets && !(SpellSummary[m_creature->m_spells[i]].Targets & (1 << (Targets-1))) ) + continue; + + //Check the type of spell if we are looking for a specific spell type + if ( Effects && !(SpellSummary[m_creature->m_spells[i]].Effects & (1 << (Effects-1))) ) + continue; + + //Check for school if specified + if (School >= 0 && TempSpell->SchoolMask & School) + continue; + + //Check for spell mechanic if specified + if (Mechanic >= 0 && TempSpell->Mechanic != Mechanic) + continue; + + //Make sure that the spell uses the requested amount of power + if (PowerCostMin && TempSpell->manaCost < PowerCostMin) + continue; + + if (PowerCostMax && TempSpell->manaCost > PowerCostMax) + continue; + + //Continue if we don't have the mana to actually cast this spell + if (TempSpell->manaCost > m_creature->GetPower((Powers)TempSpell->powerType)) + continue; + + //Get the Range + TempRange = GetSpellRangeStore()->LookupEntry(TempSpell->rangeIndex); + + //Spell has invalid range store so we can't use it + if (!TempRange) + continue; + + //Check if the spell meets our range requirements + if (RangeMin && TempRange->maxRange < RangeMin) + continue; + if (RangeMax && TempRange->maxRange > RangeMax) + continue; + + //Check if our target is in range + if (m_creature->IsWithinDistInMap(Target, TempRange->minRange) || !m_creature->IsWithinDistInMap(Target, TempRange->maxRange)) + continue; + + //All good so lets add it to the spell list + Spell[SpellCount] = TempSpell; + SpellCount++; + } + + //We got our usable spells so now lets randomly pick one + if (!SpellCount) + return NULL; + + return Spell[rand()%SpellCount]; +} + +bool ScriptedAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered) +{ + //No target so we can't cast + if (!Target || !Spell) + return false; + + //Silenced so we can't cast + if (!Triggered && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) + return false; + + //Check for power + if (!Triggered && m_creature->GetPower((Powers)Spell->powerType) < Spell->manaCost) + return false; + + SpellRangeEntry const *TempRange = NULL; + + TempRange = GetSpellRangeStore()->LookupEntry(Spell->rangeIndex); + + //Spell has invalid range store so we can't use it + if (!TempRange) + return false; + + //Unit is out of range of this spell + if (m_creature->GetDistance(Target) > TempRange->maxRange || m_creature->GetDistance(Target) < TempRange->minRange) + return false; + + return true; +} + +void FillSpellSummary() +{ + SpellSummary = new TSpellSummary[GetSpellStore()->GetNumRows()]; + + SpellEntry const* TempSpell; + + for (int i=0; i < GetSpellStore()->GetNumRows(); i++ ) + { + SpellSummary[i].Effects = 0; + SpellSummary[i].Targets = 0; + + TempSpell = GetSpellStore()->LookupEntry(i); + //This spell doesn't exist + if (!TempSpell) + continue; + + for (int j=0; j<3; j++) + { + //Spell targets self + if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF ) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); + + //Spell targets a single enemy + if ( TempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || + TempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES ) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1); + + //Spell targets AoE at enemy + if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED ) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); + + //Spell targets an enemy + if ( TempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || + TempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER || + TempSpell->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 ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF || + TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND || + TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY ) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1); + + //Spell targets aoe friends + if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || + TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); + + //Spell targets any friend(or self) + if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF || + TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND || + TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || + TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || + TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); + + //Make sure that this spell includes a damage effect + if ( TempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || + TempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || + TempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || + TempSpell->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 ( TempSpell->Effect[j] == SPELL_EFFECT_HEAL || + TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || + TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL || + (TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA && TempSpell->EffectApplyAuraName[j]== 8 )) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1); + + //Make sure that this spell applies an aura + if ( TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA ) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); + } + } +} + +void ScriptedAI::DoZoneInCombat(Unit* pUnit) +{ + if (!pUnit) + pUnit = m_creature; + + Map *map = pUnit->GetMap(); + + if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated + { + error_log("SD2: DoZoneInCombat call for map that isn't an instance (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0); + return; + } + + if (!pUnit->CanHaveThreatList() || pUnit->getThreatManager().isThreatListEmpty()) + { + error_log("SD2: DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0); + + return; + } + + InstanceMap::PlayerList const &PlayerList = ((InstanceMap*)map)->GetPlayers(); + InstanceMap::PlayerList::const_iterator i; + for (i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if(!(*i)->isGameMaster()) + pUnit->AddThreat(*i, 0.0f); + } +} + +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()); + + return; + } + + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + std::list::iterator itr; + + for(itr = m_threatlist.begin(); itr != m_threatlist.end(); ++itr) + { + Unit* pUnit = NULL; + pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if(pUnit && m_creature->getThreatManager().getThreat(pUnit)) + m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); + } +} + +void ScriptedAI::DoTeleportPlayer(Unit* pUnit, float x, float y, float z, float o) +{ + if(!pUnit || pUnit->GetTypeId() != TYPEID_PLAYER) + { + if(pUnit) + error_log("SD2: Creature %u (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: %u) to x: %f y:%f z: %f o: %f. Aborted.", m_creature->GetGUID(), m_creature->GetEntry(), pUnit->GetTypeId(), pUnit->GetGUID(), x, y, z, o); + return; + } + + ((Player*)pUnit)->TeleportTo(pUnit->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT); +} + +Unit* ScriptedAI::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) +{ + CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Unit* pUnit = NULL; + + MostHPMissingInRange u_check(m_creature, range, MinHPDiff); + MaNGOS::UnitLastSearcher searcher(pUnit, u_check); + + /* + typedef TYPELIST_4(GameObject, Creature*except pets*, DynamicObject, Corpse*Bones*) AllGridObjectTypes; + This means that if we only search grid then we cannot possibly return pets or players so this is safe + */ + TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_unit_searcher, *(m_creature->GetMap())); + return pUnit; +} + +std::list ScriptedAI::DoFindFriendlyCC(float range) +{ + CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + std::list pList; + + FriendlyCCedInRange u_check(m_creature, range); + MaNGOS::CreatureListSearcher searcher(pList, u_check); + + TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap())); + + return pList; +} + +std::list ScriptedAI::DoFindFriendlyMissingBuff(float range, uint32 spellid) +{ + CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + std::list pList; + + FriendlyMissingBuffInRange u_check(m_creature, range, spellid); + MaNGOS::CreatureListSearcher searcher(pList, u_check); + + TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap())); + + return pList; +} + +void Scripted_NoMovementAI::MoveInLineOfSight(Unit *who) +{ + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + { + DoStartAttackNoMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } +} + +void Scripted_NoMovementAI::AttackStart(Unit* who) +{ + if (!who) + return; + + if (who->isTargetableForAttack()) + { + //Begin attack + DoStartAttackNoMovement(who); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } +} diff --git a/src/bindings/scripts/include/sc_gossip.h b/src/bindings/scripts/include/sc_gossip.h index af304a2d63f..48d9786a4ed 100644 --- a/src/bindings/scripts/include/sc_gossip.h +++ b/src/bindings/scripts/include/sc_gossip.h @@ -1,183 +1,183 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software licensed under GPL version 2 -* Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_PLAYER_H -#define SC_PLAYER_H - -#include "Player.h" -#include "GossipDef.h" -#include "QuestDef.h" - -// Gossip Item Text -#define GOSSIP_TEXT_BROWSE_GOODS "I'd like to browse your goods." -#define GOSSIP_TEXT_TRAIN "Train me!" - -#define GOSSIP_TEXT_BANK "The Bank" -#define GOSSIP_TEXT_WINDRIDER "Wind rider master" -#define GOSSIP_TEXT_GRYPHON "Gryphon Master" -#define GOSSIP_TEXT_BATHANDLER "Bat Handler" -#define GOSSIP_TEXT_HIPPOGRYPH "Hippogryph Master" -#define GOSSIP_TEXT_FLIGHTMASTER "Flight Master" -#define GOSSIP_TEXT_AUCTIONHOUSE "Auction House" -#define GOSSIP_TEXT_GUILDMASTER "Guild Master" -#define GOSSIP_TEXT_INN "The Inn" -#define GOSSIP_TEXT_MAILBOX "Mailbox" -#define GOSSIP_TEXT_STABLEMASTER "Stable Master" -#define GOSSIP_TEXT_WEAPONMASTER "Weapons Trainer" -#define GOSSIP_TEXT_BATTLEMASTER "Battlemaster" -#define GOSSIP_TEXT_CLASSTRAINER "Class Trainer" -#define GOSSIP_TEXT_PROFTRAINER "Profession Trainer" -#define GOSSIP_TEXT_OFFICERS "The officers` lounge" - -#define GOSSIP_TEXT_ALTERACVALLEY "Alterac Valley" -#define GOSSIP_TEXT_ARATHIBASIN "Arathi Basin" -#define GOSSIP_TEXT_WARSONGULCH "Warsong Gulch" -#define GOSSIP_TEXT_ARENA "Arena" -#define GOSSIP_TEXT_EYEOFTHESTORM "Eye of The Storm" - -#define GOSSIP_TEXT_DRUID "Druid" -#define GOSSIP_TEXT_HUNTER "Hunter" -#define GOSSIP_TEXT_PRIEST "Priest" -#define GOSSIP_TEXT_ROGUE "Rogue" -#define GOSSIP_TEXT_WARRIOR "Warrior" -#define GOSSIP_TEXT_PALADIN "Paladin" -#define GOSSIP_TEXT_SHAMAN "Shaman" -#define GOSSIP_TEXT_MAGE "Mage" -#define GOSSIP_TEXT_WARLOCK "Warlock" - -#define GOSSIP_TEXT_ALCHEMY "Alchemy" -#define GOSSIP_TEXT_BLACKSMITHING "Blacksmithing" -#define GOSSIP_TEXT_COOKING "Cooking" -#define GOSSIP_TEXT_ENCHANTING "Enchanting" -#define GOSSIP_TEXT_ENGINEERING "Engineering" -#define GOSSIP_TEXT_FIRSTAID "First Aid" -#define GOSSIP_TEXT_HERBALISM "Herbalism" -#define GOSSIP_TEXT_LEATHERWORKING "Leatherworking" -#define GOSSIP_TEXT_POISONS "Poisons" -#define GOSSIP_TEXT_TAILORING "Tailoring" -#define GOSSIP_TEXT_MINING "Mining" -#define GOSSIP_TEXT_FISHING "Fishing" -#define GOSSIP_TEXT_SKINNING "Skinning" -#define GOSSIP_TEXT_JEWELCRAFTING "Jewelcrafting" - -#define GOSSIP_TEXT_IRONFORGE_BANK "Bank of Ironforge" -#define GOSSIP_TEXT_STORMWIND_BANK "Bank of Stormwind" -#define GOSSIP_TEXT_DEEPRUNTRAM "Deeprun Tram" -#define GOSSIP_TEXT_ZEPPLINMASTER "Zeppelin master" -#define GOSSIP_TEXT_FERRY "Rut'theran Ferry" - -// Skill defines - -#define TRADESKILL_ALCHEMY 1 -#define TRADESKILL_BLACKSMITHING 2 -#define TRADESKILL_COOKING 3 -#define TRADESKILL_ENCHANTING 4 -#define TRADESKILL_ENGINEERING 5 -#define TRADESKILL_FIRSTAID 6 -#define TRADESKILL_HERBALISM 7 -#define TRADESKILL_LEATHERWORKING 8 -#define TRADESKILL_POISONS 9 -#define TRADESKILL_TAILORING 10 -#define TRADESKILL_MINING 11 -#define TRADESKILL_FISHING 12 -#define TRADESKILL_SKINNING 13 -#define TRADESKILL_JEWLCRAFTING 14 - -#define TRADESKILL_LEVEL_NONE 0 -#define TRADESKILL_LEVEL_APPRENTICE 1 -#define TRADESKILL_LEVEL_JOURNEYMAN 2 -#define TRADESKILL_LEVEL_EXPERT 3 -#define TRADESKILL_LEVEL_ARTISAN 4 -#define TRADESKILL_LEVEL_MASTER 5 - -// Gossip defines - -#define GOSSIP_ACTION_TRADE 1 -#define GOSSIP_ACTION_TRAIN 2 -#define GOSSIP_ACTION_TAXI 3 -#define GOSSIP_ACTION_GUILD 4 -#define GOSSIP_ACTION_BATTLE 5 -#define GOSSIP_ACTION_BANK 6 -#define GOSSIP_ACTION_INN 7 -#define GOSSIP_ACTION_HEAL 8 -#define GOSSIP_ACTION_TABARD 9 -#define GOSSIP_ACTION_AUCTION 10 -#define GOSSIP_ACTION_INN_INFO 11 -#define GOSSIP_ACTION_UNLEARN 12 -#define GOSSIP_ACTION_INFO_DEF 1000 - -#define GOSSIP_SENDER_MAIN 1 -#define GOSSIP_SENDER_INN_INFO 2 -#define GOSSIP_SENDER_INFO 3 -#define GOSSIP_SENDER_SEC_PROFTRAIN 4 -#define GOSSIP_SENDER_SEC_CLASSTRAIN 5 -#define GOSSIP_SENDER_SEC_BATTLEINFO 6 -#define GOSSIP_SENDER_SEC_BANK 7 -#define GOSSIP_SENDER_SEC_INN 8 -#define GOSSIP_SENDER_SEC_MAILBOX 9 -#define GOSSIP_SENDER_SEC_STABLEMASTER 10 - -#define DEFAULT_GOSSIP_MESSAGE 0xffffff - -extern uint32 GetSkillLevel(Player *player,uint32 skill); - -// Defined fuctions to use with player. - -// This fuction add's a menu item, -// a - Icon Id -// b - Text -// c - Sender(this is to identify the current Menu with this item) -// d - Action (identifys this Menu Item) -// e - Text to be displayed in pop up box -// f - Money value in pop up box -#define ADD_GOSSIP_ITEM(a,b,c,d) PlayerTalkClass->GetGossipMenu()->AddMenuItem(a,b,c,d,"",0) -#define ADD_GOSSIP_ITEM_EXTENDED(a,b,c,d,e,f) PlayerTalkClass->GetGossipMenu()->AddMenuItem(a,b,c,d,e,f) - -// This fuction Sends the current menu to show to client, a - NPCTEXTID(uint32) , b - npc guid(uint64) -#define SEND_GOSSIP_MENU(a,b) PlayerTalkClass->SendGossipMenu(a,b) - -// 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) - -// 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) -#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_AUCTIONLIST(a) GetSession()->SendAuctionHello(a) -#define SEND_TAXILIST(a) GetSession()->SendTaxiStatus(a) - -// Ressurect's the player if is dead. -#define SEND_SPRESURRECT() GetSession()->SendSpiritResurrect() - -// Get the player's honor rank. -#define GET_HONORRANK() GetHonorRank() -// ----------------------------------- - -// defined fuctions to use with Creature - -#define QUEST_DIALOG_STATUS(a,b,c) GetSession()->getDialogStatus(a,b,c) -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_PLAYER_H +#define SC_PLAYER_H + +#include "Player.h" +#include "GossipDef.h" +#include "QuestDef.h" + +// Gossip Item Text +#define GOSSIP_TEXT_BROWSE_GOODS "I'd like to browse your goods." +#define GOSSIP_TEXT_TRAIN "Train me!" + +#define GOSSIP_TEXT_BANK "The Bank" +#define GOSSIP_TEXT_WINDRIDER "Wind rider master" +#define GOSSIP_TEXT_GRYPHON "Gryphon Master" +#define GOSSIP_TEXT_BATHANDLER "Bat Handler" +#define GOSSIP_TEXT_HIPPOGRYPH "Hippogryph Master" +#define GOSSIP_TEXT_FLIGHTMASTER "Flight Master" +#define GOSSIP_TEXT_AUCTIONHOUSE "Auction House" +#define GOSSIP_TEXT_GUILDMASTER "Guild Master" +#define GOSSIP_TEXT_INN "The Inn" +#define GOSSIP_TEXT_MAILBOX "Mailbox" +#define GOSSIP_TEXT_STABLEMASTER "Stable Master" +#define GOSSIP_TEXT_WEAPONMASTER "Weapons Trainer" +#define GOSSIP_TEXT_BATTLEMASTER "Battlemaster" +#define GOSSIP_TEXT_CLASSTRAINER "Class Trainer" +#define GOSSIP_TEXT_PROFTRAINER "Profession Trainer" +#define GOSSIP_TEXT_OFFICERS "The officers` lounge" + +#define GOSSIP_TEXT_ALTERACVALLEY "Alterac Valley" +#define GOSSIP_TEXT_ARATHIBASIN "Arathi Basin" +#define GOSSIP_TEXT_WARSONGULCH "Warsong Gulch" +#define GOSSIP_TEXT_ARENA "Arena" +#define GOSSIP_TEXT_EYEOFTHESTORM "Eye of The Storm" + +#define GOSSIP_TEXT_DRUID "Druid" +#define GOSSIP_TEXT_HUNTER "Hunter" +#define GOSSIP_TEXT_PRIEST "Priest" +#define GOSSIP_TEXT_ROGUE "Rogue" +#define GOSSIP_TEXT_WARRIOR "Warrior" +#define GOSSIP_TEXT_PALADIN "Paladin" +#define GOSSIP_TEXT_SHAMAN "Shaman" +#define GOSSIP_TEXT_MAGE "Mage" +#define GOSSIP_TEXT_WARLOCK "Warlock" + +#define GOSSIP_TEXT_ALCHEMY "Alchemy" +#define GOSSIP_TEXT_BLACKSMITHING "Blacksmithing" +#define GOSSIP_TEXT_COOKING "Cooking" +#define GOSSIP_TEXT_ENCHANTING "Enchanting" +#define GOSSIP_TEXT_ENGINEERING "Engineering" +#define GOSSIP_TEXT_FIRSTAID "First Aid" +#define GOSSIP_TEXT_HERBALISM "Herbalism" +#define GOSSIP_TEXT_LEATHERWORKING "Leatherworking" +#define GOSSIP_TEXT_POISONS "Poisons" +#define GOSSIP_TEXT_TAILORING "Tailoring" +#define GOSSIP_TEXT_MINING "Mining" +#define GOSSIP_TEXT_FISHING "Fishing" +#define GOSSIP_TEXT_SKINNING "Skinning" +#define GOSSIP_TEXT_JEWELCRAFTING "Jewelcrafting" + +#define GOSSIP_TEXT_IRONFORGE_BANK "Bank of Ironforge" +#define GOSSIP_TEXT_STORMWIND_BANK "Bank of Stormwind" +#define GOSSIP_TEXT_DEEPRUNTRAM "Deeprun Tram" +#define GOSSIP_TEXT_ZEPPLINMASTER "Zeppelin master" +#define GOSSIP_TEXT_FERRY "Rut'theran Ferry" + +// Skill defines + +#define TRADESKILL_ALCHEMY 1 +#define TRADESKILL_BLACKSMITHING 2 +#define TRADESKILL_COOKING 3 +#define TRADESKILL_ENCHANTING 4 +#define TRADESKILL_ENGINEERING 5 +#define TRADESKILL_FIRSTAID 6 +#define TRADESKILL_HERBALISM 7 +#define TRADESKILL_LEATHERWORKING 8 +#define TRADESKILL_POISONS 9 +#define TRADESKILL_TAILORING 10 +#define TRADESKILL_MINING 11 +#define TRADESKILL_FISHING 12 +#define TRADESKILL_SKINNING 13 +#define TRADESKILL_JEWLCRAFTING 14 + +#define TRADESKILL_LEVEL_NONE 0 +#define TRADESKILL_LEVEL_APPRENTICE 1 +#define TRADESKILL_LEVEL_JOURNEYMAN 2 +#define TRADESKILL_LEVEL_EXPERT 3 +#define TRADESKILL_LEVEL_ARTISAN 4 +#define TRADESKILL_LEVEL_MASTER 5 + +// Gossip defines + +#define GOSSIP_ACTION_TRADE 1 +#define GOSSIP_ACTION_TRAIN 2 +#define GOSSIP_ACTION_TAXI 3 +#define GOSSIP_ACTION_GUILD 4 +#define GOSSIP_ACTION_BATTLE 5 +#define GOSSIP_ACTION_BANK 6 +#define GOSSIP_ACTION_INN 7 +#define GOSSIP_ACTION_HEAL 8 +#define GOSSIP_ACTION_TABARD 9 +#define GOSSIP_ACTION_AUCTION 10 +#define GOSSIP_ACTION_INN_INFO 11 +#define GOSSIP_ACTION_UNLEARN 12 +#define GOSSIP_ACTION_INFO_DEF 1000 + +#define GOSSIP_SENDER_MAIN 1 +#define GOSSIP_SENDER_INN_INFO 2 +#define GOSSIP_SENDER_INFO 3 +#define GOSSIP_SENDER_SEC_PROFTRAIN 4 +#define GOSSIP_SENDER_SEC_CLASSTRAIN 5 +#define GOSSIP_SENDER_SEC_BATTLEINFO 6 +#define GOSSIP_SENDER_SEC_BANK 7 +#define GOSSIP_SENDER_SEC_INN 8 +#define GOSSIP_SENDER_SEC_MAILBOX 9 +#define GOSSIP_SENDER_SEC_STABLEMASTER 10 + +#define DEFAULT_GOSSIP_MESSAGE 0xffffff + +extern uint32 GetSkillLevel(Player *player,uint32 skill); + +// Defined fuctions to use with player. + +// This fuction add's a menu item, +// a - Icon Id +// b - Text +// c - Sender(this is to identify the current Menu with this item) +// d - Action (identifys this Menu Item) +// e - Text to be displayed in pop up box +// f - Money value in pop up box +#define ADD_GOSSIP_ITEM(a,b,c,d) PlayerTalkClass->GetGossipMenu().AddMenuItem(a,b,c,d,"",0) +#define ADD_GOSSIP_ITEM_EXTENDED(a,b,c,d,e,f,g) PlayerTalkClass->GetGossipMenu().AddMenuItem(a,b,c,d,e,f,g) + +// This fuction Sends the current menu to show to client, a - NPCTEXTID(uint32) , b - npc guid(uint64) +#define SEND_GOSSIP_MENU(a,b) PlayerTalkClass->SendGossipMenu(a,b) + +// 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) + +// 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) +#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_AUCTIONLIST(a) GetSession()->SendAuctionHello(a) +#define SEND_TAXILIST(a) GetSession()->SendTaxiStatus(a) + +// Ressurect's the player if is dead. +#define SEND_SPRESURRECT() GetSession()->SendSpiritResurrect() + +// Get the player's honor rank. +#define GET_HONORRANK() GetHonorRank() +// ----------------------------------- + +// defined fuctions to use with Creature + +#define QUEST_DIALOG_STATUS(a,b,c) GetSession()->getDialogStatus(a,b,c) +#endif diff --git a/src/bindings/scripts/scripts/areatrigger/areatrigger_scripts.cpp b/src/bindings/scripts/scripts/areatrigger/areatrigger_scripts.cpp index c62d7c33bed..28ad1eafdbe 100644 --- a/src/bindings/scripts/scripts/areatrigger/areatrigger_scripts.cpp +++ b/src/bindings/scripts/scripts/areatrigger/areatrigger_scripts.cpp @@ -1,44 +1,44 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Areatrigger_Scripts -SD%Complete: 100 -SDComment: Scripts for areatriggers -SDCategory: Areatrigger -EndScriptData */ - -/* ContentData -at_test script test only -EndContentData */ - -#include "precompiled.h" - -bool ATtest(Player *player, AreaTriggerEntry *at) -{ - player->Say("Hi!",LANG_UNIVERSAL); - return true; -} - -void AddSC_areatrigger_scripts() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="at_test"; - newscript->pAreaTrigger = ATtest; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Areatrigger_Scripts +SD%Complete: 100 +SDComment: Scripts for areatriggers +SDCategory: Areatrigger +EndScriptData */ + +/* ContentData +at_test script test only +EndContentData */ + +#include "precompiled.h" + +bool ATtest(Player *player, AreaTriggerEntry *at) +{ + player->Say("Hi!",LANG_UNIVERSAL); + return true; +} + +void AddSC_areatrigger_scripts() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="at_test"; + newscript->pAreaTrigger = ATtest; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/boss/boss_emeriss.cpp b/src/bindings/scripts/scripts/boss/boss_emeriss.cpp index 0870be567c5..14686f02a6e 100644 --- a/src/bindings/scripts/scripts/boss/boss_emeriss.cpp +++ b/src/bindings/scripts/scripts/boss/boss_emeriss.cpp @@ -1,156 +1,156 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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" - -#define SPELL_SLEEP 24777 -#define SPELL_NOXIOUSBREATH 24818 -#define SPELL_TAILSWEEP 15847 -//#define SPELL_MARKOFNATURE 25040 // Not working -#define SPELL_VOLATILEINFECTION 24928 -#define SPELL_CORRUPTIONOFEARTH 24910 - -struct MANGOS_DLL_DECL boss_emerissAI : public ScriptedAI -{ - boss_emerissAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Sleep_Timer; - uint32 NoxiousBreath_Timer; - uint32 TailSweep_Timer; - //uint32 MarkOfNature_Timer; - uint32 VolatileInfection_Timer; - uint32 CorruptionofEarth1_Timer; - uint32 CorruptionofEarth2_Timer; - uint32 CorruptionofEarth3_Timer; - - void Reset() - { - Sleep_Timer = 15000 + rand()%5000; - NoxiousBreath_Timer = 8000; - TailSweep_Timer = 4000; - //MarkOfNature_Timer = 45000; - VolatileInfection_Timer = 12000; - CorruptionofEarth1_Timer = 0; - CorruptionofEarth2_Timer = 0; - CorruptionofEarth3_Timer = 0; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Sleep_Timer - if (Sleep_Timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_SLEEP); - - Sleep_Timer = 8000 + rand()%8000; - }else Sleep_Timer -= diff; - - //NoxiousBreath_Timer - if (NoxiousBreath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_NOXIOUSBREATH); - NoxiousBreath_Timer = 14000 + rand()%6000; - }else NoxiousBreath_Timer -= diff; - - //Tailsweep every 2 seconds - if (TailSweep_Timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_TAILSWEEP); - - TailSweep_Timer = 2000; - }else TailSweep_Timer -= diff; - - //MarkOfNature_Timer - //if (MarkOfNature_Timer < diff) - //{ - // DoCast(m_creature->getVictim(),SPELL_MARKOFNATURE); - // MarkOfNature_Timer = 45000; - //}else MarkOfNature_Timer -= diff; - - //VolatileInfection_Timer - if (VolatileInfection_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_VOLATILEINFECTION); - VolatileInfection_Timer = 7000 + rand()%5000; - }else VolatileInfection_Timer -= diff; - - //CorruptionofEarth_Timer - if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 75) - { - if (CorruptionofEarth1_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CORRUPTIONOFEARTH); - - //1 minutes for next one. Means not again with this health value - CorruptionofEarth1_Timer = 60000; - } else CorruptionofEarth1_Timer -= diff; - } - - //CorruptionofEarth_Timer - if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 50) - { - if (CorruptionofEarth2_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CORRUPTIONOFEARTH); - - //1 minutes for next one. Means not again with this health value - CorruptionofEarth2_Timer = 60000; - } else CorruptionofEarth2_Timer -= diff; - } - - //CorruptionofEarth_Timer - if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 25) - { - if (CorruptionofEarth3_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CORRUPTIONOFEARTH); - - //1 minutes for next one. Means not again with this health value - CorruptionofEarth3_Timer = 60000; - } else CorruptionofEarth3_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_emeriss(Creature *_Creature) -{ - return new boss_emerissAI (_Creature); -} - -void AddSC_boss_emeriss() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_emeriss"; - newscript->GetAI = GetAI_boss_emeriss; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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" + +#define SPELL_SLEEP 24777 +#define SPELL_NOXIOUSBREATH 24818 +#define SPELL_TAILSWEEP 15847 +//#define SPELL_MARKOFNATURE 25040 // Not working +#define SPELL_VOLATILEINFECTION 24928 +#define SPELL_CORRUPTIONOFEARTH 24910 + +struct MANGOS_DLL_DECL boss_emerissAI : public ScriptedAI +{ + boss_emerissAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Sleep_Timer; + uint32 NoxiousBreath_Timer; + uint32 TailSweep_Timer; + //uint32 MarkOfNature_Timer; + uint32 VolatileInfection_Timer; + uint32 CorruptionofEarth1_Timer; + uint32 CorruptionofEarth2_Timer; + uint32 CorruptionofEarth3_Timer; + + void Reset() + { + Sleep_Timer = 15000 + rand()%5000; + NoxiousBreath_Timer = 8000; + TailSweep_Timer = 4000; + //MarkOfNature_Timer = 45000; + VolatileInfection_Timer = 12000; + CorruptionofEarth1_Timer = 0; + CorruptionofEarth2_Timer = 0; + CorruptionofEarth3_Timer = 0; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Sleep_Timer + if (Sleep_Timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_SLEEP); + + Sleep_Timer = 8000 + rand()%8000; + }else Sleep_Timer -= diff; + + //NoxiousBreath_Timer + if (NoxiousBreath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_NOXIOUSBREATH); + NoxiousBreath_Timer = 14000 + rand()%6000; + }else NoxiousBreath_Timer -= diff; + + //Tailsweep every 2 seconds + if (TailSweep_Timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_TAILSWEEP); + + TailSweep_Timer = 2000; + }else TailSweep_Timer -= diff; + + //MarkOfNature_Timer + //if (MarkOfNature_Timer < diff) + //{ + // DoCast(m_creature->getVictim(),SPELL_MARKOFNATURE); + // MarkOfNature_Timer = 45000; + //}else MarkOfNature_Timer -= diff; + + //VolatileInfection_Timer + if (VolatileInfection_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_VOLATILEINFECTION); + VolatileInfection_Timer = 7000 + rand()%5000; + }else VolatileInfection_Timer -= diff; + + //CorruptionofEarth_Timer + if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 75) + { + if (CorruptionofEarth1_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CORRUPTIONOFEARTH); + + //1 minutes for next one. Means not again with this health value + CorruptionofEarth1_Timer = 60000; + } else CorruptionofEarth1_Timer -= diff; + } + + //CorruptionofEarth_Timer + if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 50) + { + if (CorruptionofEarth2_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CORRUPTIONOFEARTH); + + //1 minutes for next one. Means not again with this health value + CorruptionofEarth2_Timer = 60000; + } else CorruptionofEarth2_Timer -= diff; + } + + //CorruptionofEarth_Timer + if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 25) + { + if (CorruptionofEarth3_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CORRUPTIONOFEARTH); + + //1 minutes for next one. Means not again with this health value + CorruptionofEarth3_Timer = 60000; + } else CorruptionofEarth3_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_emeriss(Creature *_Creature) +{ + return new boss_emerissAI (_Creature); +} + +void AddSC_boss_emeriss() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_emeriss"; + newscript->GetAI = GetAI_boss_emeriss; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/boss/boss_lethon.cpp b/src/bindings/scripts/scripts/boss/boss_lethon.cpp index 66822e5a920..c921eac1e97 100644 --- a/src/bindings/scripts/scripts/boss/boss_lethon.cpp +++ b/src/bindings/scripts/scripts/boss/boss_lethon.cpp @@ -1,24 +1,24 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Lethon -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Bosses -EndScriptData */ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Lethon +SD%Complete: 0 +SDComment: Place Holder +SDCategory: Bosses +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/boss/boss_taerar.cpp b/src/bindings/scripts/scripts/boss/boss_taerar.cpp index 8c7f8471880..8bff4300a43 100644 --- a/src/bindings/scripts/scripts/boss/boss_taerar.cpp +++ b/src/bindings/scripts/scripts/boss/boss_taerar.cpp @@ -1,306 +1,306 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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: 90 -SDComment: Mark of Nature & Teleport NYI -SDCategory: Bosses -EndScriptData */ - -#include "precompiled.h" - -//Spells of Taerar - -#define SPELL_SLEEP 24777 -#define SPELL_NOXIOUSBREATH 24818 -#define SPELL_TAILSWEEP 15847 -//#define SPELL_MARKOFNATURE 25040 // Not working -#define SPELL_ARCANEBLAST 24857 -#define SPELL_BELLOWINGROAR 22686 -#define SPELL_SUMMONSHADE 24843 - -//Spells of Shades of Taerar - -#define SPELL_POSIONCLOUD 24840 -#define SPELL_POSIONBREATH 20667 - -struct MANGOS_DLL_DECL boss_taerarAI : public ScriptedAI -{ - boss_taerarAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Sleep_Timer; - uint32 NoxiousBreath_Timer; - uint32 TailSweep_Timer; - //uint32 MarkOfNature_Timer; - uint32 ArcaneBlast_Timer; - uint32 BellowingRoar_Timer; - uint32 Shades_Timer; - uint32 Summon1_Timer; - uint32 Summon2_Timer; - uint32 Summon3_Timer; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - bool Shades; - - void Reset() - { - Sleep_Timer = 15000 + rand()%5000; - NoxiousBreath_Timer = 8000; - TailSweep_Timer = 4000; - //MarkOfNature_Timer = 45000; - ArcaneBlast_Timer = 12000; - BellowingRoar_Timer = 30000; - Summon1_Timer = 0; - Summon2_Timer = 0; - Summon3_Timer = 0; - Shades_Timer = 60000; //The time that Taerar is banished - Shades = false; - } - - void Aggro(Unit *who) - { - } - - void SummonShades(Unit* victim) - { - Rand = rand()%15; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%15; - switch (rand()%2) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - Summoned = DoSpawnCreature(15302, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - if(Summoned) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - if (Shades && Shades_Timer < diff) - { - //Become unbanished again - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //m_creature->m_canMove = true; - Shades = false; - } else if (Shades) - { - Shades_Timer -= diff; - //Do nothing while banished - return; - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Sleep_Timer - if (Sleep_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_SLEEP); - - Sleep_Timer = 8000 + rand()%7000; - }else Sleep_Timer -= diff; - - //NoxiousBreath_Timer - if (NoxiousBreath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_NOXIOUSBREATH); - NoxiousBreath_Timer = 14000 + rand()%6000; - } else NoxiousBreath_Timer -= diff; - - //Tailsweep every 2 seconds - if (TailSweep_Timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_TAILSWEEP); - - TailSweep_Timer = 2000; - }else TailSweep_Timer -= diff; - - //MarkOfNature_Timer - //if (MarkOfNature_Timer < diff) - //{ - // DoCast(m_creature->getVictim(),SPELL_MARKOFNATURE); - // MarkOfNature_Timer = 45000; - //}else MarkOfNature_Timer -= diff; - - //ArcaneBlast_Timer - if (ArcaneBlast_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ARCANEBLAST); - ArcaneBlast_Timer = 7000 + rand()%5000; - }else ArcaneBlast_Timer -= diff; - - //BellowingRoar_Timer - if (BellowingRoar_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_BELLOWINGROAR); - BellowingRoar_Timer = 20000 + rand()%10000; - } else BellowingRoar_Timer -= diff; - - //Summon 3 Shades - if ( !Shades && (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 75) - { - if (Summon1_Timer < diff) - { - //Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //m_creature->m_canMove = false; - - //Cast - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - SummonShades(target); - SummonShades(target); - SummonShades(target); - Summon1_Timer = 120000; - Shades = true; - Shades_Timer = 60000; - } else Summon1_Timer -= diff; - } - - //Summon 3 Shades - if ( !Shades && (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 50) - { - if (Summon2_Timer < diff) - { - //Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //m_creature->m_canMove = false; - - //Cast - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - SummonShades(target); - SummonShades(target); - SummonShades(target); - Summon2_Timer = 120000; - Shades = true; - Shades_Timer = 60000; - } else Summon2_Timer -= diff; - } - - //Summon 3 Shades - if ( !Shades && (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 25) - { - if (Summon3_Timer < diff) - { - //Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //m_creature->m_canMove = false; - - //Cast - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - SummonShades(target); - SummonShades(target); - SummonShades(target); - Summon3_Timer = 120000; - Shades = true; - Shades_Timer = 60000; - } else Summon3_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; - -// Shades of Taerar Script - -struct MANGOS_DLL_DECL boss_shadeoftaerarAI : public ScriptedAI -{ - boss_shadeoftaerarAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 PoisonCloud_Timer; - uint32 PosionBreath_Timer; - - void Reset() - { - PoisonCloud_Timer = 8000; - PosionBreath_Timer = 12000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //PoisonCloud_Timer - if (PoisonCloud_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POSIONCLOUD); - PoisonCloud_Timer = 30000; - }else PoisonCloud_Timer -= diff; - - //PosionBreath_Timer - if (PosionBreath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POSIONBREATH); - PosionBreath_Timer = 12000; - }else PosionBreath_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_taerar(Creature *_Creature) -{ - return new boss_taerarAI (_Creature); -} - -CreatureAI* GetAI_boss_shadeoftaerar(Creature *_Creature) -{ - return new boss_shadeoftaerarAI (_Creature); -} - -void AddSC_boss_taerar() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_taerar"; - newscript->GetAI = GetAI_boss_taerar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_shade_of_taerar"; - newscript->GetAI = GetAI_boss_shadeoftaerar; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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: 90 +SDComment: Mark of Nature & Teleport NYI +SDCategory: Bosses +EndScriptData */ + +#include "precompiled.h" + +//Spells of Taerar + +#define SPELL_SLEEP 24777 +#define SPELL_NOXIOUSBREATH 24818 +#define SPELL_TAILSWEEP 15847 +//#define SPELL_MARKOFNATURE 25040 // Not working +#define SPELL_ARCANEBLAST 24857 +#define SPELL_BELLOWINGROAR 22686 +#define SPELL_SUMMONSHADE 24843 + +//Spells of Shades of Taerar + +#define SPELL_POSIONCLOUD 24840 +#define SPELL_POSIONBREATH 20667 + +struct MANGOS_DLL_DECL boss_taerarAI : public ScriptedAI +{ + boss_taerarAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Sleep_Timer; + uint32 NoxiousBreath_Timer; + uint32 TailSweep_Timer; + //uint32 MarkOfNature_Timer; + uint32 ArcaneBlast_Timer; + uint32 BellowingRoar_Timer; + uint32 Shades_Timer; + uint32 Summon1_Timer; + uint32 Summon2_Timer; + uint32 Summon3_Timer; + int Rand; + int RandX; + int RandY; + Creature* Summoned; + bool Shades; + + void Reset() + { + Sleep_Timer = 15000 + rand()%5000; + NoxiousBreath_Timer = 8000; + TailSweep_Timer = 4000; + //MarkOfNature_Timer = 45000; + ArcaneBlast_Timer = 12000; + BellowingRoar_Timer = 30000; + Summon1_Timer = 0; + Summon2_Timer = 0; + Summon3_Timer = 0; + Shades_Timer = 60000; //The time that Taerar is banished + Shades = false; + } + + void Aggro(Unit *who) + { + } + + void SummonShades(Unit* victim) + { + Rand = rand()%15; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%15; + switch (rand()%2) + { + case 0: RandY = 0 - Rand; break; + case 1: RandY = 0 + Rand; break; + } + Rand = 0; + Summoned = DoSpawnCreature(15302, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); + if(Summoned) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + if (Shades && Shades_Timer < diff) + { + //Become unbanished again + m_creature->setFaction(14); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //m_creature->m_canMove = true; + Shades = false; + } else if (Shades) + { + Shades_Timer -= diff; + //Do nothing while banished + return; + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Sleep_Timer + if (Sleep_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_SLEEP); + + Sleep_Timer = 8000 + rand()%7000; + }else Sleep_Timer -= diff; + + //NoxiousBreath_Timer + if (NoxiousBreath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_NOXIOUSBREATH); + NoxiousBreath_Timer = 14000 + rand()%6000; + } else NoxiousBreath_Timer -= diff; + + //Tailsweep every 2 seconds + if (TailSweep_Timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_TAILSWEEP); + + TailSweep_Timer = 2000; + }else TailSweep_Timer -= diff; + + //MarkOfNature_Timer + //if (MarkOfNature_Timer < diff) + //{ + // DoCast(m_creature->getVictim(),SPELL_MARKOFNATURE); + // MarkOfNature_Timer = 45000; + //}else MarkOfNature_Timer -= diff; + + //ArcaneBlast_Timer + if (ArcaneBlast_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ARCANEBLAST); + ArcaneBlast_Timer = 7000 + rand()%5000; + }else ArcaneBlast_Timer -= diff; + + //BellowingRoar_Timer + if (BellowingRoar_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_BELLOWINGROAR); + BellowingRoar_Timer = 20000 + rand()%10000; + } else BellowingRoar_Timer -= diff; + + //Summon 3 Shades + if ( !Shades && (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 75) + { + if (Summon1_Timer < diff) + { + //Inturrupt any spell casting + m_creature->InterruptNonMeleeSpells(false); + m_creature->setFaction(35); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //m_creature->m_canMove = false; + + //Cast + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + SummonShades(target); + SummonShades(target); + SummonShades(target); + Summon1_Timer = 120000; + Shades = true; + Shades_Timer = 60000; + } else Summon1_Timer -= diff; + } + + //Summon 3 Shades + if ( !Shades && (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 50) + { + if (Summon2_Timer < diff) + { + //Inturrupt any spell casting + m_creature->InterruptNonMeleeSpells(false); + m_creature->setFaction(35); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //m_creature->m_canMove = false; + + //Cast + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + SummonShades(target); + SummonShades(target); + SummonShades(target); + Summon2_Timer = 120000; + Shades = true; + Shades_Timer = 60000; + } else Summon2_Timer -= diff; + } + + //Summon 3 Shades + if ( !Shades && (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 25) + { + if (Summon3_Timer < diff) + { + //Inturrupt any spell casting + m_creature->InterruptNonMeleeSpells(false); + m_creature->setFaction(35); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //m_creature->m_canMove = false; + + //Cast + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + SummonShades(target); + SummonShades(target); + SummonShades(target); + Summon3_Timer = 120000; + Shades = true; + Shades_Timer = 60000; + } else Summon3_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +// Shades of Taerar Script + +struct MANGOS_DLL_DECL boss_shadeoftaerarAI : public ScriptedAI +{ + boss_shadeoftaerarAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 PoisonCloud_Timer; + uint32 PosionBreath_Timer; + + void Reset() + { + PoisonCloud_Timer = 8000; + PosionBreath_Timer = 12000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //PoisonCloud_Timer + if (PoisonCloud_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POSIONCLOUD); + PoisonCloud_Timer = 30000; + }else PoisonCloud_Timer -= diff; + + //PosionBreath_Timer + if (PosionBreath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POSIONBREATH); + PosionBreath_Timer = 12000; + }else PosionBreath_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_taerar(Creature *_Creature) +{ + return new boss_taerarAI (_Creature); +} + +CreatureAI* GetAI_boss_shadeoftaerar(Creature *_Creature) +{ + return new boss_shadeoftaerarAI (_Creature); +} + +void AddSC_boss_taerar() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_taerar"; + newscript->GetAI = GetAI_boss_taerar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_shade_of_taerar"; + newscript->GetAI = GetAI_boss_shadeoftaerar; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/boss/boss_ysondre.cpp b/src/bindings/scripts/scripts/boss/boss_ysondre.cpp index a5348630af2..7a811c3535f 100644 --- a/src/bindings/scripts/scripts/boss/boss_ysondre.cpp +++ b/src/bindings/scripts/scripts/boss/boss_ysondre.cpp @@ -1,246 +1,246 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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" - -#define SPELL_SLEEP 24777 -#define SPELL_NOXIOUSBREATH 24818 -#define SPELL_TAILSWEEP 15847 -//#define SPELL_MARKOFNATURE 25040 // Not working -#define SPELL_LIGHTNINGWAVE 24819 -#define SPELL_SUMMONDRUIDS 24795 - -//druid spells -#define SPELL_MOONFIRE 21669 - -// Ysondre script -struct MANGOS_DLL_DECL boss_ysondreAI : public ScriptedAI -{ - boss_ysondreAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Sleep_Timer; - uint32 NoxiousBreath_Timer; - uint32 TailSweep_Timer; - //uint32 MarkOfNature_Timer; - uint32 LightningWave_Timer; - uint32 SummonDruids1_Timer; - uint32 SummonDruids2_Timer; - uint32 SummonDruids3_Timer; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - Sleep_Timer = 15000 + rand()%5000; - NoxiousBreath_Timer = 8000; - TailSweep_Timer = 4000; - //MarkOfNature_Timer = 45000; - LightningWave_Timer = 12000; - SummonDruids1_Timer = 0; - SummonDruids2_Timer = 0; - SummonDruids3_Timer = 0; - } - - void Aggro(Unit *who) - { - } - - void SummonDruids(Unit* victim) - { - Rand = rand()%10; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%10; - switch (rand()%2) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - Summoned = DoSpawnCreature(15260, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - if(Summoned) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Sleep_Timer - if (Sleep_Timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_SLEEP); - - Sleep_Timer = 8000 + rand()%7000; - }else Sleep_Timer -= diff; - - //NoxiousBreath_Timer - if (NoxiousBreath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_NOXIOUSBREATH); - NoxiousBreath_Timer = 14000 + rand()%6000; - }else NoxiousBreath_Timer -= diff; - - //Tailsweep every 2 seconds - if (TailSweep_Timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_TAILSWEEP); - - TailSweep_Timer = 2000; - }else TailSweep_Timer -= diff; - - //MarkOfNature_Timer - //if (MarkOfNature_Timer < diff) - //{ - // DoCast(m_creature->getVictim(),SPELL_MARKOFNATURE); - // MarkOfNature_Timer = 45000; - //}else MarkOfNature_Timer -= diff; - - //LightningWave_Timer - if (LightningWave_Timer < diff) - { - //Cast LIGHTNINGWAVE on a Random target - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_LIGHTNINGWAVE); - - LightningWave_Timer = 7000 + rand()%5000; - }else LightningWave_Timer -= diff; - - //Summon Druids - if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 75) - { - if (SummonDruids1_Timer < diff) - { - // summon 10 druids - Unit* target = NULL; - for(int i = 0; i < 10;i++) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - SummonDruids(target); - } - - SummonDruids1_Timer = 60000; - } else SummonDruids1_Timer -= diff; - } - - //Summon Druids - if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 50) - { - if (SummonDruids2_Timer < diff) - { - // summon 10 druids - Unit* target = NULL; - for(int i = 0; i < 10;i++) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - SummonDruids(target); - } - - SummonDruids2_Timer = 60000; - } else SummonDruids2_Timer -= diff; - } - - //Summon Druids - if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 25) - { - if (SummonDruids3_Timer < diff) - { - // summon 10 druids - Unit* target = NULL; - for(int i = 0; i < 10;i++) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - SummonDruids(target); - } - - SummonDruids3_Timer = 60000; - } else SummonDruids3_Timer -= diff; - } - DoMeleeAttackIfReady(); - } -}; -// Summoned druid script -struct MANGOS_DLL_DECL mob_dementeddruidsAI : public ScriptedAI -{ - mob_dementeddruidsAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 MoonFire_Timer; - - void Reset() - { - MoonFire_Timer = 3000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //MoonFire_Timer - if (MoonFire_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MOONFIRE); - MoonFire_Timer = 5000; - }else MoonFire_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_ysondre(Creature *_Creature) -{ - return new boss_ysondreAI (_Creature); -} - -CreatureAI* GetAI_mob_dementeddruids(Creature *_Creature) -{ - return new mob_dementeddruidsAI (_Creature); -} - -void AddSC_boss_ysondre() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_ysondre"; - newscript->GetAI = GetAI_boss_ysondre; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_dementeddruids"; - newscript->GetAI = GetAI_mob_dementeddruids; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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" + +#define SPELL_SLEEP 24777 +#define SPELL_NOXIOUSBREATH 24818 +#define SPELL_TAILSWEEP 15847 +//#define SPELL_MARKOFNATURE 25040 // Not working +#define SPELL_LIGHTNINGWAVE 24819 +#define SPELL_SUMMONDRUIDS 24795 + +//druid spells +#define SPELL_MOONFIRE 21669 + +// Ysondre script +struct MANGOS_DLL_DECL boss_ysondreAI : public ScriptedAI +{ + boss_ysondreAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Sleep_Timer; + uint32 NoxiousBreath_Timer; + uint32 TailSweep_Timer; + //uint32 MarkOfNature_Timer; + uint32 LightningWave_Timer; + uint32 SummonDruids1_Timer; + uint32 SummonDruids2_Timer; + uint32 SummonDruids3_Timer; + int Rand; + int RandX; + int RandY; + Creature* Summoned; + + void Reset() + { + Sleep_Timer = 15000 + rand()%5000; + NoxiousBreath_Timer = 8000; + TailSweep_Timer = 4000; + //MarkOfNature_Timer = 45000; + LightningWave_Timer = 12000; + SummonDruids1_Timer = 0; + SummonDruids2_Timer = 0; + SummonDruids3_Timer = 0; + } + + void Aggro(Unit *who) + { + } + + void SummonDruids(Unit* victim) + { + Rand = rand()%10; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%10; + switch (rand()%2) + { + case 0: RandY = 0 - Rand; break; + case 1: RandY = 0 + Rand; break; + } + Rand = 0; + Summoned = DoSpawnCreature(15260, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); + if(Summoned) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Sleep_Timer + if (Sleep_Timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_SLEEP); + + Sleep_Timer = 8000 + rand()%7000; + }else Sleep_Timer -= diff; + + //NoxiousBreath_Timer + if (NoxiousBreath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_NOXIOUSBREATH); + NoxiousBreath_Timer = 14000 + rand()%6000; + }else NoxiousBreath_Timer -= diff; + + //Tailsweep every 2 seconds + if (TailSweep_Timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_TAILSWEEP); + + TailSweep_Timer = 2000; + }else TailSweep_Timer -= diff; + + //MarkOfNature_Timer + //if (MarkOfNature_Timer < diff) + //{ + // DoCast(m_creature->getVictim(),SPELL_MARKOFNATURE); + // MarkOfNature_Timer = 45000; + //}else MarkOfNature_Timer -= diff; + + //LightningWave_Timer + if (LightningWave_Timer < diff) + { + //Cast LIGHTNINGWAVE on a Random target + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_LIGHTNINGWAVE); + + LightningWave_Timer = 7000 + rand()%5000; + }else LightningWave_Timer -= diff; + + //Summon Druids + if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 75) + { + if (SummonDruids1_Timer < diff) + { + // summon 10 druids + Unit* target = NULL; + for(int i = 0; i < 10;i++) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + SummonDruids(target); + } + + SummonDruids1_Timer = 60000; + } else SummonDruids1_Timer -= diff; + } + + //Summon Druids + if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 50) + { + if (SummonDruids2_Timer < diff) + { + // summon 10 druids + Unit* target = NULL; + for(int i = 0; i < 10;i++) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + SummonDruids(target); + } + + SummonDruids2_Timer = 60000; + } else SummonDruids2_Timer -= diff; + } + + //Summon Druids + if ( (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5) == 25) + { + if (SummonDruids3_Timer < diff) + { + // summon 10 druids + Unit* target = NULL; + for(int i = 0; i < 10;i++) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + SummonDruids(target); + } + + SummonDruids3_Timer = 60000; + } else SummonDruids3_Timer -= diff; + } + DoMeleeAttackIfReady(); + } +}; +// Summoned druid script +struct MANGOS_DLL_DECL mob_dementeddruidsAI : public ScriptedAI +{ + mob_dementeddruidsAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 MoonFire_Timer; + + void Reset() + { + MoonFire_Timer = 3000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //MoonFire_Timer + if (MoonFire_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MOONFIRE); + MoonFire_Timer = 5000; + }else MoonFire_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ysondre(Creature *_Creature) +{ + return new boss_ysondreAI (_Creature); +} + +CreatureAI* GetAI_mob_dementeddruids(Creature *_Creature) +{ + return new mob_dementeddruidsAI (_Creature); +} + +void AddSC_boss_ysondre() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_ysondre"; + newscript->GetAI = GetAI_boss_ysondre; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_dementeddruids"; + newscript->GetAI = GetAI_mob_dementeddruids; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/creature/mob_event_ai.cpp b/src/bindings/scripts/scripts/creature/mob_event_ai.cpp index f86931df766..4e772ed4b23 100644 --- a/src/bindings/scripts/scripts/creature/mob_event_ai.cpp +++ b/src/bindings/scripts/scripts/creature/mob_event_ai.cpp @@ -1,1389 +1,1361 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Mob_Event_AI -SD%Complete: 90 -SDComment: Database Event AI -SDCategory: Creatures -EndScriptData */ - -#include "precompiled.h" -#include "mob_event_ai.h" - -#define EVENT_UPDATE_TIME 500 -#define SPELL_RUN_AWAY 8225 - -struct EventHolder -{ - EventHolder(EventAI_Event p) : Event(p), Time(0), Enabled(true){} - - EventAI_Event Event; - uint32 Time; - bool Enabled; -}; - -struct MANGOS_DLL_DECL Mob_EventAI : public ScriptedAI -{ - Mob_EventAI(Creature *c, std::list pEventList) : ScriptedAI(c) - { - EventList = pEventList; - Phase = 0; - CombatMovementEnabled = true; - MeleeEnabled = true; - AttackDistance = 0; - AttackAngle = 0.0f; - - //Handle Spawned Events - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - case EVENT_T_SPAWNED: - ProcessEvent(*i); - break; - } - } - - Reset(); - } - - ~Mob_EventAI() - { - EventList.clear(); - } - - //Variables used by EventAI for handling events - std::list EventList; //Holder for events (stores enabled, time, and eventid) - uint32 EventUpdateTime; //Time between event updates - uint32 EventDiff; //Time between the last event call - - //Variables used by Events themselves - uint8 Phase; //Current phase, max 32 phases - bool CombatMovementEnabled; //If we allow targeted movment gen (movement twoards top threat) - bool MeleeEnabled; //If we allow melee auto attack - uint32 AttackDistance; //Distance to attack from - float AttackAngle; //Angle of attack - - void AttackTarget(Unit* pTarget, bool Follow) - { - if (!pTarget) - return; - - if ( m_creature->Attack(pTarget, true) ) - { - if (Follow) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveChase(pTarget, AttackDistance, AttackAngle); - } - - m_creature->AddThreat(pTarget, 0.0f); - } - } - - bool ProcessEvent(EventHolder& pHolder, Unit* pActionInvoker = NULL) - { - if (!pHolder.Enabled || pHolder.Time) - return false; - - //Check the inverse phase mask (event doesn't trigger if current phase bit is set in mask) - if (pHolder.Event.event_inverse_phase_mask & (1 << Phase)) - return false; - - //Store random here so that all random actions match up - uint32 rnd = rand(); - - //Return if chance for event is not met - if (pHolder.Event.event_chance <= rnd % 100) - return false; - - union - { - uint32 param1; - int32 param1_s; - }; - - union - { - uint32 param2; - int32 param2_s; - }; - - union - { - uint32 param3; - int32 param3_s; - }; - - union - { - uint32 param4; - int32 param4_s; - }; - - param1 = pHolder.Event.event_param1; - param2 = pHolder.Event.event_param2; - param3 = pHolder.Event.event_param3; - param4 = pHolder.Event.event_param4; - - //Check event conditions based on the event type, also reset events - switch (pHolder.Event.event_type) - { - case EVENT_T_TIMER: - { - if (!InCombat) - return false; - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_TIMER_OOC: - { - if (InCombat) - return false; - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_HP: - { - if (!InCombat || !m_creature->GetMaxHealth()) - return false; - - uint32 perc = (m_creature->GetHealth()*100) / m_creature->GetMaxHealth(); - - if (perc > param1 || perc < param2) - return false; - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_MANA: - { - if (!InCombat || !m_creature->GetMaxPower(POWER_MANA)) - return false; - - uint32 perc = (m_creature->GetPower(POWER_MANA)*100) / m_creature->GetMaxPower(POWER_MANA); - - if (perc > param1 || perc < param2) - return false; - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_AGGRO: - { - } - break; - case EVENT_T_KILL: - { - //Repeat Timers - if (param1 == param2) - { - pHolder.Time = param1; - - }else if (param2 > param1) - pHolder.Time = urand(param1, param2); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - case EVENT_T_DEATH: - { - } - break; - case EVENT_T_EVADE: - { - } - break; - case EVENT_T_SPELLHIT: - { - //Spell hit is special case, param1 and param2 handled within EventAI::SpellHit - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_RANGE: - { - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_OOC_LOS: - { - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_SPAWNED: - { - } - break; - case EVENT_T_TARGET_HP: - { - if (!InCombat || !m_creature->getVictim() || !m_creature->getVictim()->GetMaxHealth()) - return false; - - uint32 perc = (m_creature->getVictim()->GetHealth()*100) / m_creature->getVictim()->GetMaxHealth(); - - if (perc > param1 || perc < param2) - return false; - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_TARGET_CASTING: - { - if (!InCombat || !m_creature->getVictim() || !m_creature->getVictim()->IsNonMeleeSpellCasted(false, false, true)) - return false; - - //Repeat Timers - if (param1 == param2) - { - pHolder.Time = param1; - - }else if (param2 > param1) - pHolder.Time = urand(param1, param2); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - case EVENT_T_FRIENDLY_HP: - { - if (!InCombat) - return false; - - Unit* pUnit = DoSelectLowestHpFriendly(param2, param1); - - if (!pUnit) - return false; - - pActionInvoker = pUnit; - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - - case EVENT_T_FRIENDLY_IS_CC: - { - if (!InCombat) - return false; - - std::list pList = DoFindFriendlyCC(param2); - - //List is empty - if (pList.empty()) - return false; - - //We don't really care about the whole list, just return first available - pActionInvoker = *(pList.begin()); - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - - case EVENT_T_FRIENDLY_MISSING_BUFF: - { - std::list pList = DoFindFriendlyMissingBuff(param2, param1); - - //List is empty - if (pList.empty()) - return false; - - //We don't really care about the whole list, just return first available - pActionInvoker = *(pList.begin()); - - //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - - case EVENT_T_SUMMONED_UNIT: - { - //Prevent event from occuring on no unit or non creatures - if (!pActionInvoker || pActionInvoker->GetTypeId()!=TYPEID_UNIT) - return false; - - //Creature id doesn't match up - if (param1 && ((Creature*)pActionInvoker)->GetEntry() != param1) - return false; - - //Repeat Timers - if (param2 == param3) - { - pHolder.Time = param2; - - }else if (param3 > param2) - pHolder.Time = urand(param2, param3); - else - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; - default: - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - break; - } - - //Disable non-repeatable events - if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE)) - pHolder.Enabled = false; - - //Process actions - for (uint32 j = 0; j < MAX_ACTIONS; j++) - ProcessAction(pHolder.Event.action[j].type, pHolder.Event.action[j].param1, pHolder.Event.action[j].param2, pHolder.Event.action[j].param3, rnd, pHolder.Event.event_id, pActionInvoker); - - return true; - } - - inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3) - { - switch (rnd % 3) - { - case 0: - return param1; - break; - - case 1: - return param2; - break; - - case 2: - return param3; - break; - } - return 0; - } - - inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker) - { - switch (Target) - { - case TARGET_T_SELF: - return m_creature; - break; - case TARGET_T_HOSTILE: - return m_creature->getVictim(); - break; - case TARGET_T_HOSTILE_SECOND_AGGRO: - return SelectUnit(SELECT_TARGET_TOPAGGRO,1); - break; - case TARGET_T_HOSTILE_LAST_AGGRO: - return SelectUnit(SELECT_TARGET_BOTTOMAGGRO,0); - break; - case TARGET_T_HOSTILE_RANDOM: - return SelectUnit(SELECT_TARGET_RANDOM,0); - break; - case TARGET_T_HOSTILE_RANDOM_NOT_TOP: - return SelectUnit(SELECT_TARGET_RANDOM,1); - break; - case TARGET_T_ACTION_INVOKER: - return pActionInvoker; - break; - default: - return NULL; - break; - }; - } - - void ProcessAction(uint16 type, uint32 param1, uint32 param2, uint32 param3, uint32 rnd, uint32 EventId, Unit* pActionInvoker) - { - switch (type) - { - case ACTION_T_SAY: - DoSay(GetEventAIText(param1), LANG_UNIVERSAL, pActionInvoker ? pActionInvoker : m_creature->getVictim()); - break; - - case ACTION_T_YELL: - DoYell(GetEventAIText(param1), LANG_UNIVERSAL, pActionInvoker ? pActionInvoker : m_creature->getVictim()); - break; - - case ACTION_T_TEXTEMOTE: - DoTextEmote(GetEventAIText(param1), pActionInvoker ? pActionInvoker : m_creature->getVictim()); - break; - - case ACTION_T_SOUND: - DoPlaySoundToSet(m_creature, param1); - break; - - case ACTION_T_EMOTE: - m_creature->HandleEmoteCommand(param1); - break; - - case ACTION_T_RANDOM_SAY: - { - uint32 temp = GetRandActionParam(rnd, param1, param2, param3); - - if (temp != 0xffffffff) - DoSay(GetEventAIText(temp), LANG_UNIVERSAL, pActionInvoker ? pActionInvoker : m_creature->getVictim()); - } - break; - - case ACTION_T_RANDOM_YELL: - { - uint32 temp = GetRandActionParam(rnd, param1, param2, param3); - - if (temp != 0xffffffff) - DoYell(GetEventAIText(temp), LANG_UNIVERSAL, pActionInvoker ? pActionInvoker : m_creature->getVictim()); - } - break; - - case ACTION_T_RANDOM_TEXTEMOTE: - { - uint32 temp = GetRandActionParam(rnd, param1, param2, param3); - - if (temp != 0xffffffff) - DoTextEmote(GetEventAIText(temp), pActionInvoker ? pActionInvoker : m_creature->getVictim()); - } - break; - - case ACTION_T_RANDOM_SOUND: - { - uint32 temp = GetRandActionParam(rnd, param1, param2, param3); - - if (temp != 0xffffffff) - DoPlaySoundToSet(m_creature, temp); - } - break; - - case ACTION_T_RANDOM_EMOTE: - { - uint32 temp = GetRandActionParam(rnd, param1, param2, param3); - - if (temp != 0xffffffff) - m_creature->HandleEmoteCommand(temp); - } - break; - - case ACTION_T_CAST: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - Unit* caster = m_creature; - - if (!target) - return; - - //Cast is always triggered if target is forced to cast on self - if (param3 & CAST_FORCE_TARGET_SELF) - { - param3 |= CAST_TRIGGERED; - caster = target; - } - - //Interrupt any previous spell - if (caster->IsNonMeleeSpellCasted(false) && param3 & CAST_INTURRUPT_PREVIOUS) - caster->InterruptNonMeleeSpells(false); - - //Cast only if not casting or if spell is triggered - if (param3 & CAST_TRIGGERED || !caster->IsNonMeleeSpellCasted(false)) - { - const SpellEntry* tSpell = GetSpellStore()->LookupEntry(param1); - - //Verify that spell exists - if (tSpell) - { - //Check if cannot cast spell - if (!(param3 & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST)) && - !CanCast(target, tSpell, (param3 & CAST_TRIGGERED))) - { - //Melee current victim if flag not set - if (!(param3 & CAST_NO_MELEE_IF_OOM)) - { - AttackDistance = 0; - AttackAngle = 0; - - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle); - } - - }else caster->CastSpell(target, param1, (param3 & CAST_TRIGGERED)); - - }else if (EAI_ErrorLevel > 0) - error_db_log("SD2: EventAI event %d creature %d attempt to cast spell that doesn't exist %d", EventId, m_creature->GetEntry(), param1); - } - } - break; - - case ACTION_T_SUMMON: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - - Creature* pCreature = NULL; - - if (param3) - pCreature = DoSpawnCreature(param1, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, param3); - else pCreature = pCreature = DoSpawnCreature(param1, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - - if (!pCreature) - { - if (EAI_ErrorLevel > 0) - error_db_log( "SD2: EventAI failed to spawn creature %u. Spawn event %d is on creature %d", param1, EventId, m_creature->GetEntry()); - } - else if (param2 != TARGET_T_SELF && target) - pCreature->AI()->AttackStart(target); - } - break; - - case ACTION_T_THREAT_SINGLE_PCT: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - - if (target) - m_creature->getThreatManager().modifyThreatPercent(target, param1); - } - break; - - case ACTION_T_THREAT_ALL_PCT: - { - Unit* Temp = NULL; - - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - Temp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); - if (Temp) - m_creature->getThreatManager().modifyThreatPercent(Temp, param1); - } - } - break; - - case ACTION_T_QUEST_EVENT: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - - if (target && target->GetTypeId() == TYPEID_PLAYER) - ((Player*)target)->AreaExploredOrEventHappens(param1); - } - break; - - case ACTION_T_CASTCREATUREGO: - { - Unit* target = GetTargetByType(param3, pActionInvoker); - - if (target && target->GetTypeId() == TYPEID_PLAYER) - ((Player*)target)->CastedCreatureOrGO(param1, m_creature->GetGUID(), param2); - } - break; - - case ACTION_T_SET_UNIT_FIELD: - { - Unit* target = GetTargetByType(param3, pActionInvoker); - - if (target) - target->SetUInt32Value(param1, param2); - } - break; - - case ACTION_T_SET_UNIT_FLAG: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - - if (target) - target->SetFlag(UNIT_FIELD_FLAGS, param1); - } - break; - - case ACTION_T_REMOVE_UNIT_FLAG: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - - if (target) - target->RemoveFlag(UNIT_FIELD_FLAGS, param1); - } - break; - - case ACTION_T_AUTO_ATTACK: - { - if (param1) - MeleeEnabled = true; - else MeleeEnabled = false; - } - break; - - case ACTION_T_COMBAT_MOVEMENT: - { - CombatMovementEnabled = param1; - - //Allow movement (create new targeted movement gen if none exist already) - if (CombatMovementEnabled) - { - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle); - } - } - else - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->StopMoving(); - } - } - break; - case ACTION_T_SET_PHASE: - { - Phase = param1; - } - break; - case ACTION_T_INC_PHASE: - { - Phase += param1; - - if (Phase > 31) - if (EAI_ErrorLevel > 0) - error_db_log( "SD2: Event %d incremented Phase above 31. Phase mask cannot be used with phases past 31. CreatureEntry = %d", EventId, m_creature->GetEntry()); - } - break; - - case ACTION_T_EVADE: - { - EnterEvadeMode(); - } - break; - case ACTION_T_FLEE: - { - //TODO: Replace with Flee movement generator - m_creature->CastSpell(m_creature, SPELL_RUN_AWAY, true); - } - break; - case ACTION_T_QUEST_EVENT_ALL: - { - Unit* Temp = NULL; - if( pActionInvoker && pActionInvoker->GetTypeId() == TYPEID_PLAYER ) - { - Temp = Unit::GetUnit((*m_creature),pActionInvoker->GetGUID()); - if( Temp ) - ((Player*)Temp)->GroupEventHappens(param1,m_creature); - } - } - break; - - case ACTION_T_CASTCREATUREGO_ALL: - { - Unit* Temp = NULL; - - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - Temp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); - if (Temp && Temp->GetTypeId() == TYPEID_PLAYER) - ((Player*)Temp)->CastedCreatureOrGO(param1, m_creature->GetGUID(), param2); - } - } - break; - - case ACTION_T_REMOVEAURASFROMSPELL: - { - Unit* target = GetTargetByType(param1, pActionInvoker); - - if (target) - target->RemoveAurasDueToSpell(param2); - } - break; - - case ACTION_T_RANGED_MOVEMENT: - { - AttackDistance = param1; - AttackAngle = ((float)param2/180)*M_PI; - - if (CombatMovementEnabled) - { - //Drop current movement gen - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle); - } - } - break; - - case ACTION_T_RANDOM_PHASE: - { - uint32 temp = GetRandActionParam(rnd, param1, param2, param3); - - Phase = temp; - } - break; - - case ACTION_T_RANDOM_PHASE_RANGE: - { - if (param2 > param1) - { - Phase = param1 + (rnd % (param2 - param1)); - } - else if (EAI_ErrorLevel > 0) - error_db_log( "SD2: ACTION_T_RANDOM_PHASE_RANGE cannot have Param2 <= Param1. Divide by Zero. Event = %d. CreatureEntry = %d", EventId, m_creature->GetEntry()); - } - break; - case ACTION_T_SUMMON_ID: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - - //Duration - Creature* pCreature = NULL; - - HM_NAMESPACE::hash_map::iterator i = EventAI_Summon_Map.find(param3); - - if (i == EventAI_Summon_Map.end()) - { - if (EAI_ErrorLevel > 0) - error_db_log( "SD2: EventAI failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", param1, param3, EventId, m_creature->GetEntry()); - return; - } - - if ((*i).second.SpawnTimeSecs) - pCreature = m_creature->SummonCreature(param1, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs); - else pCreature = m_creature->SummonCreature(param1, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - - if (!pCreature) - { - if (EAI_ErrorLevel > 0) - error_db_log( "SD2: EventAI failed to spawn creature %u. EventId %d.Creature %d", param1, EventId, m_creature->GetEntry()); - } - else if (param2 != TARGET_T_SELF && target) - pCreature->AI()->AttackStart(target); - } - break; - - case ACTION_T_KILLED_MONSTER: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - - if (target && target->GetTypeId() == TYPEID_PLAYER) - ((Player*)target)->KilledMonster(param1, m_creature->GetGUID()); - } - break; - - case ACTION_T_SET_INST_DATA: - { - ScriptedInstance* pInst = (ScriptedInstance*)m_creature->GetInstanceData(); - if (!pInst) - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Event %d attempt to set instance data without instance script. Creature %d", EventId, m_creature->GetEntry()); - return; - } - - pInst->SetData(param1, param2); - } - break; - - case ACTION_T_SET_INST_DATA64: - { - Unit* target = GetTargetByType(param2, pActionInvoker); - - if (!target) - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, m_creature->GetEntry()); - return; - } - - ScriptedInstance* pInst = (ScriptedInstance*)m_creature->GetInstanceData(); - - if (!pInst) - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Event %d attempt to set instance data64 without instance script. Creature %d", EventId, m_creature->GetEntry()); - return; - } - - pInst->SetData64(param1, target->GetGUID()); - } - break; - - case ACTION_T_UPDATE_TEMPLATE: - { - if (m_creature->GetEntry() == param1) - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Event %d ACTION_T_UPDATE_TEMPLATE call with param1 == current entry. Creature %d", EventId, m_creature->GetEntry()); - return; - } - - m_creature->UpdateEntry(param1, param2 ? HORDE : ALLIANCE); - } - break; - - case ACTION_T_DIE: - { - if (m_creature->isDead()) - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Event %d ACTION_T_DIE on dead creature. Creature %d", EventId, m_creature->GetEntry()); - return; - } - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - break; - - case ACTION_T_ZONE_COMBAT_PULSE: - { - if (!m_creature->isInCombat() || !m_creature->GetMap()->IsDungeon()) - { - if (EAI_ErrorLevel > 0) - error_db_log("SD2: Event %d ACTION_T_ZONE_COMBAT_PULSE on creature out of combat or in non-dungeon map. Creature %d", EventId, m_creature->GetEntry()); - return; - } - - DoZoneInCombat(); - } - break; - }; - } - - void JustRespawned() - { - InCombat = false; - Reset(); - - //Handle Spawned Events - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - case EVENT_T_SPAWNED: - ProcessEvent(*i); - break; - } - } - } - - void Reset() - { - EventUpdateTime = EVENT_UPDATE_TIME; - EventDiff = 0; - - //Handle Evade events and reset all events to enabled - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - //Reset all out of combat timers - case EVENT_T_TIMER_OOC: - { - if ((*i).Event.event_param2 == (*i).Event.event_param1) - { - (*i).Time = (*i).Event.event_param1; - (*i).Enabled = true; - - }else if ((*i).Event.event_param2 > (*i).Event.event_param1) - { - (*i).Time = urand((*i).Event.event_param1, (*i).Event.event_param2); - (*i).Enabled = true; - }else if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has InitialMax < InitialMin. Event disabled.", m_creature->GetEntry(), (*i).Event.event_id, (*i).Event.event_type); - - }break; - } - } - } - - void EnterEvadeMode() - { - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - m_creature->LoadCreaturesAddon(); - if( m_creature->isAlive() ) - m_creature->GetMotionMaster()->MoveTargetedHome(); - - m_creature->SetLootRecipient(NULL); - - InCombat = false; - Reset(); - - //Handle Evade events - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - //Evade - case EVENT_T_EVADE: - ProcessEvent(*i); - break; - } - } - } - - void JustDied(Unit* killer) - { - InCombat = false; - Reset(); - - //Handle Evade events - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - //Evade - case EVENT_T_DEATH: - ProcessEvent(*i, killer); - break; - } - } - } - - void KilledUnit(Unit* victim) - { - if (victim->GetTypeId() != TYPEID_PLAYER) - return; - - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - //Kill - case EVENT_T_KILL: - ProcessEvent(*i, victim); - break; - } - } - - } - - void JustSummoned(Creature* pUnit) - { - if (!pUnit) - return; - - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - //Summoned - case EVENT_T_SUMMONED_UNIT: - ProcessEvent(*i, pUnit); - break; - } - } - } - - void Aggro(Unit *who) - { - //Check for on combat start events - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - case EVENT_T_AGGRO: - ProcessEvent(*i, who); - break; - - //Reset all in combat timers - case EVENT_T_TIMER: - - if ((*i).Event.event_param2 == (*i).Event.event_param1) - { - (*i).Time = (*i).Event.event_param1; - (*i).Enabled = true; - - }else if ((*i).Event.event_param2 > (*i).Event.event_param1) - { - (*i).Time = urand((*i).Event.event_param1, (*i).Event.event_param2); - (*i).Enabled = true; - }else if (EAI_ErrorLevel > 0) - error_db_log("SD2: Creature %u using Event %u (Type = %u) has InitialMax < InitialMin. Event disabled.", m_creature->GetEntry(), (*i).Event.event_id, (*i).Event.event_type); - - break; - - //All normal events need to be re-enabled and their time set to 0 - default: - (*i).Enabled = true; - (*i).Time = 0; - break; - } - } - - EventUpdateTime = EVENT_UPDATE_TIME; - EventDiff = 0; - } - - void AttackStart(Unit *who) - { - if (!who) - return; - - if (who->isTargetableForAttack()) - { - //Begin melee attack if we are within range - if (CombatMovementEnabled) - AttackTarget(who, true); - else AttackTarget(who, false); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || InCombat) - return; - - //Check for OOC LOS Event - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - case EVENT_T_OOC_LOS: - { - if ((*i).Event.event_param1 && m_creature->IsHostileTo(who)) - break; - - if ((*i).Event.event_param2 && !m_creature->IsHostileTo(who)) - break; - - ProcessEvent(*i, who); - } - break; - } - } - - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - //Begin melee attack if we are within range - if (CombatMovementEnabled) - AttackTarget(who, true); - else AttackTarget(who, false); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void SpellHit(Unit* pUnit, const SpellEntry* pSpell) - { - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - //Spell hit - case EVENT_T_SPELLHIT: - { - //If spell id matches (or no spell id) & if spell school matches (or no spell school) - if (!(*i).Event.event_param1 || pSpell->Id == (*i).Event.event_param1) - if ((*i).Event.event_param2_s == -1 || pSpell->SchoolMask == (*i).Event.event_param2) - ProcessEvent(*i, pUnit); - } - break; - } - } - } - - void UpdateAI(const uint32 diff) - { - //Check if we are in combat (also updates calls threat update code) - bool Combat = InCombat ? (m_creature->SelectHostilTarget() && m_creature->getVictim()) : false; - - //Must return if creature isn't alive. Normally select hostil target and get victim prevent this - if (!m_creature->isAlive()) - return; - - //Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events - if (EventUpdateTime < diff) - { - EventDiff += diff; - - //Check for range based events - //if (m_creature->GetDistance(m_creature->getVictim()) > - if (Combat) - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - switch ((*i).Event.event_type) - { - case EVENT_T_RANGE: - float dist = m_creature->GetDistance(m_creature->getVictim()); - if (dist > (*i).Event.event_param1 && dist < (*i).Event.event_param2) - ProcessEvent(*i); - break; - } - } - - //Check for time based events - for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) - { - //Decrement Timers - if ((*i).Time) - if ((*i).Time > EventDiff) - { - //Do not decrement timers if event cannot trigger in this phase - if (!((*i).Event.event_inverse_phase_mask & (1 << Phase))) - (*i).Time -= EventDiff; - - //Skip processing of events that have time remaining - continue; - } - else (*i).Time = 0; - - switch ((*i).Event.event_type) - { - //Events that are updated every EVENT_UPDATE_TIME - case EVENT_T_TIMER: - case EVENT_T_TIMER_OOC: - case EVENT_T_MANA: - case EVENT_T_HP: - case EVENT_T_TARGET_HP: - case EVENT_T_TARGET_CASTING: - case EVENT_T_FRIENDLY_HP: - ProcessEvent(*i); - break; - } - } - - EventDiff = 0; - EventUpdateTime = EVENT_UPDATE_TIME; - }else - { - EventDiff += diff; - EventUpdateTime -= diff; - } - - //Melee Auto-Attack - if (Combat && MeleeEnabled) - DoMeleeAttackIfReady(); - - } -}; - -CreatureAI* GetAI_Mob_EventAI(Creature *_Creature) -{ - //Select events by creature id - std::list EventList; - uint32 ID = _Creature->GetEntry(); - - std::list::iterator i; - - for (i = EventAI_Event_List.begin(); i != EventAI_Event_List.end(); ++i) - { - if ((*i).creature_id == ID) - { - //Debug check -#ifndef _DEBUG - if ((*i).event_flags & EFLAG_DEBUG_ONLY) - continue; -#endif - - //Heroic Instance Difficulty check - if ((*i).event_flags & EFLAG_HEROIC) - { - //Creature isn't even in a dungeon - if (!_Creature->GetMap() || !_Creature->GetMap()->IsDungeon()) - { - if (EAI_ErrorLevel > 1) - error_db_log("SD2: Creature %u, Event %u using EFLAG_HEROIC but creature is not inside of an instance. Event skipped.", _Creature->GetEntry(), (*i).event_id); - continue; - } - - if (!_Creature->GetMap()->IsHeroic()) - continue; - } else - - //Normal Instance Difficulty check - if ((*i).event_flags & EFLAG_NORMAL) - { - //Creature isn't even in a dungeon - if (!_Creature->GetMap() || !_Creature->GetMap()->IsDungeon()) - { - if (EAI_ErrorLevel > 1) - error_db_log("SD2: Creature %u, Event %u using EFLAG_NORMAL but creature is not inside of an instance. Event skipped.", _Creature->GetEntry(), (*i).event_id); - continue; - } - - if (_Creature->GetMap()->IsHeroic()) - continue; - } else if (_Creature->GetMap() && _Creature->GetMap()->IsDungeon() && EAI_ErrorLevel > 1) - error_db_log("SD2: Creature %u, Event %u. Creature is in instance but neither EFLAG_NORMAL or EFLAG_HEROIC are set.", _Creature->GetEntry(), (*i).event_id); - - //Push back event - EventList.push_back(EventHolder(*i)); - } - } - - //EventAI is pointless to use without events and may cause crashes - if (EventList.empty()) - { - if (EAI_ErrorLevel > 1) - error_db_log("SD2: Eventlist for Creature %u is empty but creature is using Mob_EventAI. Preventing EventAI on this creature.", _Creature->GetEntry()); - - return NULL; - } - - return new Mob_EventAI (_Creature, EventList); -} - -void AddSC_mob_event() -{ - Script *newscript; - newscript = new Script; - newscript->Name="mob_eventai"; - newscript->GetAI = GetAI_Mob_EventAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Mob_Event_AI +SD%Complete: 90 +SDComment: Database Event AI +SDCategory: Creatures +EndScriptData */ + +#include "precompiled.h" +#include "mob_event_ai.h" + +#define EVENT_UPDATE_TIME 500 +#define SPELL_RUN_AWAY 8225 + +struct EventHolder +{ + EventHolder(EventAI_Event p) : Event(p), Time(0), Enabled(true){} + + EventAI_Event Event; + uint32 Time; + bool Enabled; +}; + +struct MANGOS_DLL_DECL Mob_EventAI : public ScriptedAI +{ + Mob_EventAI(Creature *c, std::list pEventList) : ScriptedAI(c) + { + EventList = pEventList; + Phase = 0; + CombatMovementEnabled = true; + MeleeEnabled = true; + AttackDistance = 0; + AttackAngle = 0.0f; + + //Handle Spawned Events + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + case EVENT_T_SPAWNED: + ProcessEvent(*i); + break; + default: + break; + } + } + + Reset(); + } + + ~Mob_EventAI() + { + EventList.clear(); + } + + //Variables used by EventAI for handling events + std::list EventList; //Holder for events (stores enabled, time, and eventid) + uint32 EventUpdateTime; //Time between event updates + uint32 EventDiff; //Time between the last event call + + //Variables used by Events themselves + uint8 Phase; //Current phase, max 32 phases + bool CombatMovementEnabled; //If we allow targeted movment gen (movement twoards top threat) + bool MeleeEnabled; //If we allow melee auto attack + uint32 AttackDistance; //Distance to attack from + float AttackAngle; //Angle of attack + + void AttackTarget(Unit* pTarget, bool Follow) + { + if (!pTarget) + return; + + if ( m_creature->Attack(pTarget, true) ) + { + if (Follow) + { + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveChase(pTarget, AttackDistance, AttackAngle); + } + + m_creature->AddThreat(pTarget, 0.0f); + } + } + + bool ProcessEvent(EventHolder& pHolder, Unit* pActionInvoker = NULL) + { + if (!pHolder.Enabled || pHolder.Time) + return false; + + //Check the inverse phase mask (event doesn't trigger if current phase bit is set in mask) + if (pHolder.Event.event_inverse_phase_mask & (1 << Phase)) + return false; + + //Store random here so that all random actions match up + uint32 rnd = rand(); + + //Return if chance for event is not met + if (pHolder.Event.event_chance <= rnd % 100) + return false; + + union + { + uint32 param1; + int32 param1_s; + }; + + union + { + uint32 param2; + int32 param2_s; + }; + + union + { + uint32 param3; + int32 param3_s; + }; + + union + { + uint32 param4; + int32 param4_s; + }; + + param1 = pHolder.Event.event_param1; + param2 = pHolder.Event.event_param2; + param3 = pHolder.Event.event_param3; + param4 = pHolder.Event.event_param4; + + //Check event conditions based on the event type, also reset events + switch (pHolder.Event.event_type) + { + case EVENT_T_TIMER: + { + if (!InCombat) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_TIMER_OOC: + { + if (InCombat) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_HP: + { + if (!InCombat || !m_creature->GetMaxHealth()) + return false; + + uint32 perc = (m_creature->GetHealth()*100) / m_creature->GetMaxHealth(); + + if (perc > param1 || perc < param2) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_MANA: + { + if (!InCombat || !m_creature->GetMaxPower(POWER_MANA)) + return false; + + uint32 perc = (m_creature->GetPower(POWER_MANA)*100) / m_creature->GetMaxPower(POWER_MANA); + + if (perc > param1 || perc < param2) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_AGGRO: + { + } + break; + case EVENT_T_KILL: + { + //Repeat Timers + if (param1 == param2) + { + pHolder.Time = param1; + + }else if (param2 > param1) + pHolder.Time = urand(param1, param2); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + case EVENT_T_DEATH: + { + } + break; + case EVENT_T_EVADE: + { + } + break; + case EVENT_T_SPELLHIT: + { + //Spell hit is special case, param1 and param2 handled within EventAI::SpellHit + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_RANGE: + { + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_OOC_LOS: + { + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_SPAWNED: + { + } + break; + case EVENT_T_TARGET_HP: + { + if (!InCombat || !m_creature->getVictim() || !m_creature->getVictim()->GetMaxHealth()) + return false; + + uint32 perc = (m_creature->getVictim()->GetHealth()*100) / m_creature->getVictim()->GetMaxHealth(); + + if (perc > param1 || perc < param2) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_TARGET_CASTING: + { + if (!InCombat || !m_creature->getVictim() || !m_creature->getVictim()->IsNonMeleeSpellCasted(false, false, true)) + return false; + + //Repeat Timers + if (param1 == param2) + { + pHolder.Time = param1; + + }else if (param2 > param1) + pHolder.Time = urand(param1, param2); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_FRIENDLY_HP: + { + if (!InCombat) + return false; + + Unit* pUnit = DoSelectLowestHpFriendly(param2, param1); + + if (!pUnit) + return false; + + pActionInvoker = pUnit; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_FRIENDLY_IS_CC: + { + if (!InCombat) + return false; + + std::list pList = DoFindFriendlyCC(param2); + + //List is empty + if (pList.empty()) + return false; + + //We don't really care about the whole list, just return first available + pActionInvoker = *(pList.begin()); + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_FRIENDLY_MISSING_BUFF: + { + std::list pList = DoFindFriendlyMissingBuff(param2, param1); + + //List is empty + if (pList.empty()) + return false; + + //We don't really care about the whole list, just return first available + pActionInvoker = *(pList.begin()); + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_SUMMONED_UNIT: + { + //Prevent event from occuring on no unit or non creatures + if (!pActionInvoker || pActionInvoker->GetTypeId()!=TYPEID_UNIT) + return false; + + //Creature id doesn't match up + if (param1 && ((Creature*)pActionInvoker)->GetEntry() != param1) + return false; + + //Repeat Timers + if (param2 == param3) + { + pHolder.Time = param2; + + }else if (param3 > param2) + pHolder.Time = urand(param2, param3); + else + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + default: + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + break; + } + + //Disable non-repeatable events + if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE)) + pHolder.Enabled = false; + + //Process actions + for (uint32 j = 0; j < MAX_ACTIONS; j++) + ProcessAction(pHolder.Event.action[j].type, pHolder.Event.action[j].param1, pHolder.Event.action[j].param2, pHolder.Event.action[j].param3, rnd, pHolder.Event.event_id, pActionInvoker); + + return true; + } + + inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3) + { + switch (rnd % 3) + { + case 0: + return param1; + break; + case 1: + return param2; + break; + case 2: + return param3; + break; + } + return 0; + } + + inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker) + { + switch (Target) + { + case TARGET_T_SELF: + return m_creature; + break; + case TARGET_T_HOSTILE: + return m_creature->getVictim(); + break; + case TARGET_T_HOSTILE_SECOND_AGGRO: + return SelectUnit(SELECT_TARGET_TOPAGGRO,1); + break; + case TARGET_T_HOSTILE_LAST_AGGRO: + return SelectUnit(SELECT_TARGET_BOTTOMAGGRO,0); + break; + case TARGET_T_HOSTILE_RANDOM: + return SelectUnit(SELECT_TARGET_RANDOM,0); + break; + case TARGET_T_HOSTILE_RANDOM_NOT_TOP: + return SelectUnit(SELECT_TARGET_RANDOM,1); + break; + case TARGET_T_ACTION_INVOKER: + return pActionInvoker; + break; + default: + return NULL; + break; + }; + } + + void ProcessAction(uint16 type, uint32 param1, uint32 param2, uint32 param3, uint32 rnd, uint32 EventId, Unit* pActionInvoker) + { + switch (type) + { + case ACTION_T_SAY: + DoSay(GetEventAIText(param1), LANG_UNIVERSAL, pActionInvoker ? pActionInvoker : m_creature->getVictim()); + break; + case ACTION_T_YELL: + DoYell(GetEventAIText(param1), LANG_UNIVERSAL, pActionInvoker ? pActionInvoker : m_creature->getVictim()); + break; + case ACTION_T_TEXTEMOTE: + DoTextEmote(GetEventAIText(param1), pActionInvoker ? pActionInvoker : m_creature->getVictim()); + break; + case ACTION_T_SOUND: + DoPlaySoundToSet(m_creature, param1); + break; + case ACTION_T_EMOTE: + m_creature->HandleEmoteCommand(param1); + break; + case ACTION_T_RANDOM_SAY: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + if (temp != 0xffffffff) + DoSay(GetEventAIText(temp), LANG_UNIVERSAL, pActionInvoker ? pActionInvoker : m_creature->getVictim()); + } + break; + case ACTION_T_RANDOM_YELL: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + if (temp != 0xffffffff) + DoYell(GetEventAIText(temp), LANG_UNIVERSAL, pActionInvoker ? pActionInvoker : m_creature->getVictim()); + } + break; + case ACTION_T_RANDOM_TEXTEMOTE: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + if (temp != 0xffffffff) + DoTextEmote(GetEventAIText(temp), pActionInvoker ? pActionInvoker : m_creature->getVictim()); + } + break; + case ACTION_T_RANDOM_SOUND: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + if (temp != 0xffffffff) + DoPlaySoundToSet(m_creature, temp); + } + break; + case ACTION_T_RANDOM_EMOTE: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + if (temp != 0xffffffff) + m_creature->HandleEmoteCommand(temp); + } + break; + case ACTION_T_CAST: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + Unit* caster = m_creature; + + if (!target) + return; + + //Cast is always triggered if target is forced to cast on self + if (param3 & CAST_FORCE_TARGET_SELF) + { + param3 |= CAST_TRIGGERED; + caster = target; + } + + //Interrupt any previous spell + if (caster->IsNonMeleeSpellCasted(false) && param3 & CAST_INTURRUPT_PREVIOUS) + caster->InterruptNonMeleeSpells(false); + + //Cast only if not casting or if spell is triggered + if (param3 & CAST_TRIGGERED || !caster->IsNonMeleeSpellCasted(false)) + { + const SpellEntry* tSpell = GetSpellStore()->LookupEntry(param1); + + //Verify that spell exists + if (tSpell) + { + //Check if cannot cast spell + if (!(param3 & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST)) && + !CanCast(target, tSpell, (param3 & CAST_TRIGGERED))) + { + //Melee current victim if flag not set + if (!(param3 & CAST_NO_MELEE_IF_OOM)) + { + AttackDistance = 0; + AttackAngle = 0; + + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle); + } + + }else caster->CastSpell(target, param1, (param3 & CAST_TRIGGERED)); + + }else if (EAI_ErrorLevel > 0) + error_db_log("SD2: EventAI event %d creature %d attempt to cast spell that doesn't exist %d", EventId, m_creature->GetEntry(), param1); + } + } + break; + case ACTION_T_SUMMON: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + Creature* pCreature = NULL; + + if (param3) + pCreature = DoSpawnCreature(param1, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, param3); + else pCreature = pCreature = DoSpawnCreature(param1, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); + + if (!pCreature) + { + if (EAI_ErrorLevel > 0) + error_db_log( "SD2: EventAI failed to spawn creature %u. Spawn event %d is on creature %d", param1, EventId, m_creature->GetEntry()); + } + else if (param2 != TARGET_T_SELF && target) + pCreature->AI()->AttackStart(target); + } + break; + case ACTION_T_THREAT_SINGLE_PCT: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target) + m_creature->getThreatManager().modifyThreatPercent(target, param1); + } + break; + case ACTION_T_THREAT_ALL_PCT: + { + Unit* Temp = NULL; + + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Temp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); + if (Temp) + m_creature->getThreatManager().modifyThreatPercent(Temp, param1); + } + } + break; + case ACTION_T_QUEST_EVENT: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target && target->GetTypeId() == TYPEID_PLAYER) + ((Player*)target)->AreaExploredOrEventHappens(param1); + } + break; + case ACTION_T_CASTCREATUREGO: + { + Unit* target = GetTargetByType(param3, pActionInvoker); + + if (target && target->GetTypeId() == TYPEID_PLAYER) + ((Player*)target)->CastedCreatureOrGO(param1, m_creature->GetGUID(), param2); + } + break; + case ACTION_T_SET_UNIT_FIELD: + { + Unit* target = GetTargetByType(param3, pActionInvoker); + + if (target) + target->SetUInt32Value(param1, param2); + } + break; + case ACTION_T_SET_UNIT_FLAG: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target) + target->SetFlag(UNIT_FIELD_FLAGS, param1); + } + break; + case ACTION_T_REMOVE_UNIT_FLAG: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target) + target->RemoveFlag(UNIT_FIELD_FLAGS, param1); + } + break; + case ACTION_T_AUTO_ATTACK: + { + if (param1) + MeleeEnabled = true; + else MeleeEnabled = false; + } + break; + case ACTION_T_COMBAT_MOVEMENT: + { + CombatMovementEnabled = param1; + + //Allow movement (create new targeted movement gen if none exist already) + if (CombatMovementEnabled) + { + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) + { + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle); + } + } + else + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + { + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->StopMoving(); + } + } + break; + case ACTION_T_SET_PHASE: + { + Phase = param1; + } + break; + case ACTION_T_INC_PHASE: + { + Phase += param1; + + if (Phase > 31) + if (EAI_ErrorLevel > 0) + error_db_log( "SD2: Event %d incremented Phase above 31. Phase mask cannot be used with phases past 31. CreatureEntry = %d", EventId, m_creature->GetEntry()); + } + break; + case ACTION_T_EVADE: + { + EnterEvadeMode(); + } + break; + case ACTION_T_FLEE: + { + //TODO: Replace with Flee movement generator + m_creature->CastSpell(m_creature, SPELL_RUN_AWAY, true); + } + break; + case ACTION_T_QUEST_EVENT_ALL: + { + Unit* Temp = NULL; + if( pActionInvoker && pActionInvoker->GetTypeId() == TYPEID_PLAYER ) + { + Temp = Unit::GetUnit((*m_creature),pActionInvoker->GetGUID()); + if( Temp ) + ((Player*)Temp)->GroupEventHappens(param1,m_creature); + } + } + break; + case ACTION_T_CASTCREATUREGO_ALL: + { + Unit* Temp = NULL; + + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Temp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); + if (Temp && Temp->GetTypeId() == TYPEID_PLAYER) + ((Player*)Temp)->CastedCreatureOrGO(param1, m_creature->GetGUID(), param2); + } + } + break; + case ACTION_T_REMOVEAURASFROMSPELL: + { + Unit* target = GetTargetByType(param1, pActionInvoker); + + if (target) + target->RemoveAurasDueToSpell(param2); + } + break; + case ACTION_T_RANGED_MOVEMENT: + { + AttackDistance = param1; + AttackAngle = ((float)param2/180)*M_PI; + + if (CombatMovementEnabled) + { + //Drop current movement gen + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle); + } + } + break; + case ACTION_T_RANDOM_PHASE: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + Phase = temp; + } + break; + case ACTION_T_RANDOM_PHASE_RANGE: + { + if (param2 > param1) + { + Phase = param1 + (rnd % (param2 - param1)); + } + else if (EAI_ErrorLevel > 0) + error_db_log( "SD2: ACTION_T_RANDOM_PHASE_RANGE cannot have Param2 <= Param1. Divide by Zero. Event = %d. CreatureEntry = %d", EventId, m_creature->GetEntry()); + } + break; + case ACTION_T_SUMMON_ID: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + //Duration + Creature* pCreature = NULL; + + HM_NAMESPACE::hash_map::iterator i = EventAI_Summon_Map.find(param3); + + if (i == EventAI_Summon_Map.end()) + { + if (EAI_ErrorLevel > 0) + error_db_log( "SD2: EventAI failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", param1, param3, EventId, m_creature->GetEntry()); + return; + } + + if ((*i).second.SpawnTimeSecs) + pCreature = m_creature->SummonCreature(param1, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs); + else pCreature = m_creature->SummonCreature(param1, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); + + if (!pCreature) + { + if (EAI_ErrorLevel > 0) + error_db_log( "SD2: EventAI failed to spawn creature %u. EventId %d.Creature %d", param1, EventId, m_creature->GetEntry()); + } + else if (param2 != TARGET_T_SELF && target) + pCreature->AI()->AttackStart(target); + } + break; + case ACTION_T_KILLED_MONSTER: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target && target->GetTypeId() == TYPEID_PLAYER) + ((Player*)target)->KilledMonster(param1, m_creature->GetGUID()); + } + break; + case ACTION_T_SET_INST_DATA: + { + ScriptedInstance* pInst = (ScriptedInstance*)m_creature->GetInstanceData(); + if (!pInst) + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Event %d attempt to set instance data without instance script. Creature %d", EventId, m_creature->GetEntry()); + return; + } + + pInst->SetData(param1, param2); + } + break; + case ACTION_T_SET_INST_DATA64: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (!target) + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, m_creature->GetEntry()); + return; + } + + ScriptedInstance* pInst = (ScriptedInstance*)m_creature->GetInstanceData(); + + if (!pInst) + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Event %d attempt to set instance data64 without instance script. Creature %d", EventId, m_creature->GetEntry()); + return; + } + + pInst->SetData64(param1, target->GetGUID()); + } + break; + case ACTION_T_UPDATE_TEMPLATE: + { + if (m_creature->GetEntry() == param1) + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Event %d ACTION_T_UPDATE_TEMPLATE call with param1 == current entry. Creature %d", EventId, m_creature->GetEntry()); + return; + } + + m_creature->UpdateEntry(param1, param2 ? HORDE : ALLIANCE); + } + break; + case ACTION_T_DIE: + { + if (m_creature->isDead()) + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Event %d ACTION_T_DIE on dead creature. Creature %d", EventId, m_creature->GetEntry()); + return; + } + m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + break; + case ACTION_T_ZONE_COMBAT_PULSE: + { + if (!m_creature->isInCombat() || !m_creature->GetMap()->IsDungeon()) + { + if (EAI_ErrorLevel > 0) + error_db_log("SD2: Event %d ACTION_T_ZONE_COMBAT_PULSE on creature out of combat or in non-dungeon map. Creature %d", EventId, m_creature->GetEntry()); + return; + } + + DoZoneInCombat(); + } + break; + } + } + + void JustRespawned() + { + InCombat = false; + Reset(); + + //Handle Spawned Events + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + case EVENT_T_SPAWNED: + ProcessEvent(*i); + break; + } + } + } + + void Reset() + { + EventUpdateTime = EVENT_UPDATE_TIME; + EventDiff = 0; + + //Handle Evade events and reset all events to enabled + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + //Reset all out of combat timers + case EVENT_T_TIMER_OOC: + { + if ((*i).Event.event_param2 == (*i).Event.event_param1) + { + (*i).Time = (*i).Event.event_param1; + (*i).Enabled = true; + }else if ((*i).Event.event_param2 > (*i).Event.event_param1) + { + (*i).Time = urand((*i).Event.event_param1, (*i).Event.event_param2); + (*i).Enabled = true; + }else if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has InitialMax < InitialMin. Event disabled.", m_creature->GetEntry(), (*i).Event.event_id, (*i).Event.event_type); + } + break; + default: + //TODO: enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void Aggro() + //(*i).Enabled = true; + //(*i).Time = 0; + break; + } + } + } + + void EnterEvadeMode() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + m_creature->LoadCreaturesAddon(); + if( m_creature->isAlive() ) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + m_creature->SetLootRecipient(NULL); + + InCombat = false; + Reset(); + + //Handle Evade events + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + //Evade + case EVENT_T_EVADE: + ProcessEvent(*i); + break; + default: + break; + } + } + } + + void JustDied(Unit* killer) + { + InCombat = false; + Reset(); + + //Handle Evade events + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + //Evade + case EVENT_T_DEATH: + ProcessEvent(*i, killer); + break; + default: + break; + } + } + } + + void KilledUnit(Unit* victim) + { + if (victim->GetTypeId() != TYPEID_PLAYER) + return; + + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + //Kill + case EVENT_T_KILL: + ProcessEvent(*i, victim); + break; + default: + break; + } + } + + } + + void JustSummoned(Creature* pUnit) + { + if (!pUnit) + return; + + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + //Summoned + case EVENT_T_SUMMONED_UNIT: + ProcessEvent(*i, pUnit); + break; + default: + break; + } + } + } + + void Aggro(Unit *who) + { + //Check for on combat start events + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + case EVENT_T_AGGRO: + (*i).Enabled = true; + ProcessEvent(*i, who); + break; + //Reset all in combat timers + case EVENT_T_TIMER: + if ((*i).Event.event_param2 == (*i).Event.event_param1) + { + (*i).Time = (*i).Event.event_param1; + (*i).Enabled = true; + }else if ((*i).Event.event_param2 > (*i).Event.event_param1) + { + (*i).Time = urand((*i).Event.event_param1, (*i).Event.event_param2); + (*i).Enabled = true; + }else if (EAI_ErrorLevel > 0) + error_db_log("SD2: Creature %u using Event %u (Type = %u) has InitialMax < InitialMin. Event disabled.", m_creature->GetEntry(), (*i).Event.event_id, (*i).Event.event_type); + break; + //All normal events need to be re-enabled and their time set to 0 + default: + (*i).Enabled = true; + (*i).Time = 0; + break; + } + } + + EventUpdateTime = EVENT_UPDATE_TIME; + EventDiff = 0; + } + + void AttackStart(Unit *who) + { + if (!who) + return; + + if (who->isTargetableForAttack()) + { + //Begin melee attack if we are within range + if (CombatMovementEnabled) + AttackTarget(who, true); + else AttackTarget(who, false); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + + void MoveInLineOfSight(Unit *who) + { + if (!who || InCombat) + return; + + //Check for OOC LOS Event + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + case EVENT_T_OOC_LOS: + { + if ((*i).Event.event_param1 && m_creature->IsHostileTo(who)) + break; + + if ((*i).Event.event_param2 && !m_creature->IsHostileTo(who)) + break; + + ProcessEvent(*i, who); + } + break; + } + } + + 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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + //Begin melee attack if we are within range + if (CombatMovementEnabled) + AttackTarget(who, true); + else AttackTarget(who, false); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void SpellHit(Unit* pUnit, const SpellEntry* pSpell) + { + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + //Spell hit + case EVENT_T_SPELLHIT: + { + //If spell id matches (or no spell id) & if spell school matches (or no spell school) + if (!(*i).Event.event_param1 || pSpell->Id == (*i).Event.event_param1) + if ((*i).Event.event_param2_s == -1 || pSpell->SchoolMask == (*i).Event.event_param2) + ProcessEvent(*i, pUnit); + } + break; + default: + break; + } + } + } + + void UpdateAI(const uint32 diff) + { + //Check if we are in combat (also updates calls threat update code) + bool Combat = InCombat ? (m_creature->SelectHostilTarget() && m_creature->getVictim()) : false; + + //Must return if creature isn't alive. Normally select hostil target and get victim prevent this + if (!m_creature->isAlive()) + return; + + //Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events + if (EventUpdateTime < diff) + { + EventDiff += diff; + + //Check for range based events + //if (m_creature->GetDistance(m_creature->getVictim()) > + if (Combat) + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + switch ((*i).Event.event_type) + { + case EVENT_T_RANGE: + float dist = m_creature->GetDistance(m_creature->getVictim()); + if (dist > (*i).Event.event_param1 && dist < (*i).Event.event_param2) + ProcessEvent(*i); + break; + } + } + + //Check for time based events + for (std::list::iterator i = EventList.begin(); i != EventList.end(); ++i) + { + //Decrement Timers + if ((*i).Time) + if ((*i).Time > EventDiff) + { + //Do not decrement timers if event cannot trigger in this phase + if (!((*i).Event.event_inverse_phase_mask & (1 << Phase))) + (*i).Time -= EventDiff; + + //Skip processing of events that have time remaining + continue; + } + else (*i).Time = 0; + + switch ((*i).Event.event_type) + { + //Events that are updated every EVENT_UPDATE_TIME + case EVENT_T_TIMER: + case EVENT_T_TIMER_OOC: + case EVENT_T_MANA: + case EVENT_T_HP: + case EVENT_T_TARGET_HP: + case EVENT_T_TARGET_CASTING: + case EVENT_T_FRIENDLY_HP: + ProcessEvent(*i); + break; + } + } + + EventDiff = 0; + EventUpdateTime = EVENT_UPDATE_TIME; + }else + { + EventDiff += diff; + EventUpdateTime -= diff; + } + + //Melee Auto-Attack + if (Combat && MeleeEnabled) + DoMeleeAttackIfReady(); + + } +}; + +CreatureAI* GetAI_Mob_EventAI(Creature *_Creature) +{ + //Select events by creature id + std::list EventList; + uint32 ID = _Creature->GetEntry(); + + std::list::iterator i; + + for (i = EventAI_Event_List.begin(); i != EventAI_Event_List.end(); ++i) + { + if ((*i).creature_id == ID) + { +//Debug check +#ifndef _DEBUG + if ((*i).event_flags & EFLAG_DEBUG_ONLY) + continue; +#endif + if( _Creature->GetMap()->IsDungeon() ) + { + if( _Creature->GetMap()->IsHeroic() ) + { + if( (*i).event_flags & EFLAG_HEROIC ) + { + EventList.push_back(EventHolder(*i)); + continue; + }else if( (*i).event_flags & EFLAG_NORMAL ) + continue; + } + else + { + if( (*i).event_flags & EFLAG_NORMAL ) + { + EventList.push_back(EventHolder(*i)); + continue; + }else if( (*i).event_flags & EFLAG_HEROIC ) + continue; + } + + if (EAI_ErrorLevel > 1) + error_db_log("SD2: Creature %u Event %u. Creature are in instance but neither EFLAG_NORMAL or EFLAG_HEROIC are set. Event Disabled.", _Creature->GetEntry(), (*i).event_id); + + continue; + } + + EventList.push_back(EventHolder(*i)); + } + } + + //EventAI is pointless to use without events and may cause crashes + if (EventList.empty()) + { + if (EAI_ErrorLevel > 1) + error_db_log("SD2: Eventlist for Creature %u is empty but creature is using Mob_EventAI. Preventing EventAI on this creature.", _Creature->GetEntry()); + + return NULL; + } + + return new Mob_EventAI (_Creature, EventList); +} + +void AddSC_mob_event() +{ + Script *newscript; + newscript = new Script; + newscript->Name="mob_eventai"; + newscript->GetAI = GetAI_Mob_EventAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/creature/mob_event_ai.h b/src/bindings/scripts/scripts/creature/mob_event_ai.h index 05b0b6d7b45..8c9b06cd5ce 100644 --- a/src/bindings/scripts/scripts/creature/mob_event_ai.h +++ b/src/bindings/scripts/scripts/creature/mob_event_ai.h @@ -1,215 +1,215 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software licensed under GPL version 2 -* Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_EVENTAI_H -#define SC_EVENTAI_H - -#define MAX_ACTIONS 3 - -enum Event_Types -{ - EVENT_T_TIMER = 0, //InitialMin, InitialMax, RepeatMin, RepeatMax - EVENT_T_TIMER_OOC = 1, //InitialMin, InitialMax, RepeatMin, RepeatMax - EVENT_T_HP = 2, //HPMax%, HPMin%, RepeatMin, RepeatMax - EVENT_T_MANA = 3, //ManaMax%,ManaMin% RepeatMin, RepeatMax - EVENT_T_AGGRO = 4, //NONE - EVENT_T_KILL = 5, //RepeatMin, RepeatMax - EVENT_T_DEATH = 6, //NONE - EVENT_T_EVADE = 7, //NONE - EVENT_T_SPELLHIT = 8, //SpellID, School, RepeatMin, RepeatMax - EVENT_T_RANGE = 9, //MinDist, MaxDist, RepeatMin, RepeatMax - EVENT_T_OOC_LOS = 10, //NoHostile, NoFriendly, RepeatMin, RepeatMax - EVENT_T_SPAWNED = 11, //NONE - EVENT_T_TARGET_HP = 12, //HPMax%, HPMin%, RepeatMin, RepeatMax - EVENT_T_TARGET_CASTING = 13, //RepeatMin, RepeatMax - EVENT_T_FRIENDLY_HP = 14, //HPDeficit, Radius, RepeatMin, RepeatMax - EVENT_T_FRIENDLY_IS_CC = 15, //DispelType, Radius, RepeatMin, RepeatMax - EVENT_T_FRIENDLY_MISSING_BUFF = 16, //SpellId, Radius, RepeatMin, RepeatMax - EVENT_T_SUMMONED_UNIT = 17, //CreatureId, RepeatMin, RepeatMax - EVENT_T_TARGET_MANA = 18, //ManaMax%, ManaMin%, RepeatMin, RepeatMax - EVENT_T_QUEST_ACCEPT = 19, //QuestID - EVENT_T_QUEST_COMPLETE = 20, // - - EVENT_T_END, -}; - -enum Action_Types -{ - ACTION_T_NONE = 0, //No action - ACTION_T_SAY = 1, //TextId - ACTION_T_YELL = 2, //TextId - ACTION_T_TEXTEMOTE = 3, //TextId - ACTION_T_SOUND = 4, //SoundId - ACTION_T_EMOTE = 5, //EmoteId - ACTION_T_RANDOM_SAY = 6, //TextId1, TextId2, TextId3 (-1 in any field means no output if randomed that field) - ACTION_T_RANDOM_YELL = 7, //TextId1, TextId2, TextId3 (-1 in any field means no output if randomed that field) - ACTION_T_RANDOM_TEXTEMOTE = 8, //TextId1, TextId2, TextId3 (-1 in any field means no output if randomed that field) - ACTION_T_RANDOM_SOUND = 9, //SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field) - ACTION_T_RANDOM_EMOTE = 10, //EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field) - ACTION_T_CAST = 11, //SpellId, Target, CastFlags - ACTION_T_SUMMON = 12, //CreatureID, Target, Duration in ms - ACTION_T_THREAT_SINGLE_PCT = 13, //Threat%, Target - ACTION_T_THREAT_ALL_PCT = 14, //Threat% - ACTION_T_QUEST_EVENT = 15, //QuestID, Target - ACTION_T_CASTCREATUREGO = 16, //QuestID, SpellId, Target - ACTION_T_SET_UNIT_FIELD = 17, //Field_Number, Value, Target - ACTION_T_SET_UNIT_FLAG = 18, //Flags (may be more than one field OR'd together), Target - ACTION_T_REMOVE_UNIT_FLAG = 19, //Flags (may be more than one field OR'd together), Target - ACTION_T_AUTO_ATTACK = 20, //AllowAttackState (0 = stop attack, anything else means continue attacking) - ACTION_T_COMBAT_MOVEMENT = 21, //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking) - ACTION_T_SET_PHASE = 22, //Phase - ACTION_T_INC_PHASE = 23, //Value (may be negative to decrement phase, should not be 0) - ACTION_T_EVADE = 24, //No Params - ACTION_T_FLEE = 25, //No Params - ACTION_T_QUEST_EVENT_ALL = 26, //QuestID - ACTION_T_CASTCREATUREGO_ALL = 27, //QuestId, SpellId - ACTION_T_REMOVEAURASFROMSPELL = 28, //Target, Spellid - ACTION_T_RANGED_MOVEMENT = 29, //Distance, Angle - ACTION_T_RANDOM_PHASE = 30, //PhaseId1, PhaseId2, PhaseId3 - ACTION_T_RANDOM_PHASE_RANGE = 31, //PhaseMin, PhaseMax - ACTION_T_SUMMON_ID = 32, //CreatureId, Target, SpawnId - ACTION_T_KILLED_MONSTER = 33, //CreatureId, Target - ACTION_T_SET_INST_DATA = 34, //Field, Data - ACTION_T_SET_INST_DATA64 = 35, //Field, Target - ACTION_T_UPDATE_TEMPLATE = 36, //Entry, Team - ACTION_T_DIE = 37, //No Params - ACTION_T_ZONE_COMBAT_PULSE = 38, //No Params - - ACTION_T_END, -}; - -enum Target -{ - //Self (m_creature) - TARGET_T_SELF = 0, //Self cast - - //Hostile targets (if pet then returns pet owner) - TARGET_T_HOSTILE, //Our current target (ie: highest aggro) - TARGET_T_HOSTILE_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks) - TARGET_T_HOSTILE_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for) - TARGET_T_HOSTILE_RANDOM, //Just any random target on our threat list - TARGET_T_HOSTILE_RANDOM_NOT_TOP, //Any random target except top threat - - //Invoker targets (if pet then returns pet owner) - TARGET_T_ACTION_INVOKER, //Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) - - //Hostile targets (including pets) - TARGET_T_HOSTILE_WPET, //Current target (can be a pet) - TARGET_T_HOSTILE_WPET_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks) - TARGET_T_HOSTILE_WPET_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for) - TARGET_T_HOSTILE_WPET_RANDOM, //Just any random target on our threat list - TARGET_T_HOSTILE_WPET_RANDOM_NOT_TOP, //Any random target except top threat - - TARGET_T_ACTION_INVOKER_WPET, - - TARGET_T_END -}; - -enum CastFlags -{ - CAST_INTURRUPT_PREVIOUS = 0x01, //Interrupt any spell casting - CAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time) - CAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range - CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range - CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself -}; - -enum EventFlags -{ - EFLAG_REPEATABLE = 0x01, //Event repeats - EFLAG_NORMAL = 0x02, //Event only occurs in Normal instance difficulty - EFLAG_HEROIC = 0x04, //Event only occurs in Heroic instance difficulty - EFLAG_RESERVED_3 = 0x08, - EFLAG_RESERVED_4 = 0x10, - EFLAG_RESERVED_5 = 0x20, - EFLAG_RESERVED_6 = 0x40, - EFLAG_DEBUG_ONLY = 0x80, //Event only occurs in debug build of SD2 only -}; - -struct EventAI_Event -{ - uint32 event_id; - - uint32 creature_id; - - uint16 event_type; - uint32 event_inverse_phase_mask; - uint8 event_chance; - uint8 event_flags; - union - { - uint32 event_param1; - int32 event_param1_s; - }; - union - { - uint32 event_param2; - int32 event_param2_s; - }; - union - { - uint32 event_param3; - int32 event_param3_s; - }; - union - { - uint32 event_param4; - int32 event_param4_s; - }; - - struct _action - { - uint16 type; - union - { - uint32 param1; - int32 param1_s; - }; - union - { - uint32 param2; - int32 param2_s; - }; - union - { - uint32 param3; - int32 param3_s; - }; - }action[MAX_ACTIONS]; -}; - -//Event_Map -extern std::list EventAI_Event_List; - -struct EventAI_Summon -{ - uint32 id; - - float position_x; - float position_y; - float position_z; - float orientation; - uint32 SpawnTimeSecs; -}; - -//EventSummon_Map -extern HM_NAMESPACE::hash_map EventAI_Summon_Map; - -//EventAI Error handling -extern uint32 EAI_ErrorLevel; -/* - -struct EventAI_CreatureError -{ - bool ListEmpty; - bool NoInstance; -}; - -//Error prevention list -extern HM_NAMESPACE::hash_map EventAI_CreatureErrorPreventionList; - -//Defines -#define EVENTAI_EMPTY_EVENTLIST "SD2: Eventlist for Creature %i is empty but creature is using Mob_EventAI. Preventing EventAI on this creature." -*/ -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software licensed under GPL version 2 +* Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_EVENTAI_H +#define SC_EVENTAI_H + +#define MAX_ACTIONS 3 + +enum Event_Types +{ + EVENT_T_TIMER = 0, //InitialMin, InitialMax, RepeatMin, RepeatMax + EVENT_T_TIMER_OOC = 1, //InitialMin, InitialMax, RepeatMin, RepeatMax + EVENT_T_HP = 2, //HPMax%, HPMin%, RepeatMin, RepeatMax + EVENT_T_MANA = 3, //ManaMax%,ManaMin% RepeatMin, RepeatMax + EVENT_T_AGGRO = 4, //NONE + EVENT_T_KILL = 5, //RepeatMin, RepeatMax + EVENT_T_DEATH = 6, //NONE + EVENT_T_EVADE = 7, //NONE + EVENT_T_SPELLHIT = 8, //SpellID, School, RepeatMin, RepeatMax + EVENT_T_RANGE = 9, //MinDist, MaxDist, RepeatMin, RepeatMax + EVENT_T_OOC_LOS = 10, //NoHostile, NoFriendly, RepeatMin, RepeatMax + EVENT_T_SPAWNED = 11, //NONE + EVENT_T_TARGET_HP = 12, //HPMax%, HPMin%, RepeatMin, RepeatMax + EVENT_T_TARGET_CASTING = 13, //RepeatMin, RepeatMax + EVENT_T_FRIENDLY_HP = 14, //HPDeficit, Radius, RepeatMin, RepeatMax + EVENT_T_FRIENDLY_IS_CC = 15, //DispelType, Radius, RepeatMin, RepeatMax + EVENT_T_FRIENDLY_MISSING_BUFF = 16, //SpellId, Radius, RepeatMin, RepeatMax + EVENT_T_SUMMONED_UNIT = 17, //CreatureId, RepeatMin, RepeatMax + EVENT_T_TARGET_MANA = 18, //ManaMax%, ManaMin%, RepeatMin, RepeatMax + EVENT_T_QUEST_ACCEPT = 19, //QuestID + EVENT_T_QUEST_COMPLETE = 20, // + + EVENT_T_END, +}; + +enum Action_Types +{ + ACTION_T_NONE = 0, //No action + ACTION_T_SAY = 1, //TextId + ACTION_T_YELL = 2, //TextId + ACTION_T_TEXTEMOTE = 3, //TextId + ACTION_T_SOUND = 4, //SoundId + ACTION_T_EMOTE = 5, //EmoteId + ACTION_T_RANDOM_SAY = 6, //TextId1, TextId2, TextId3 (-1 in any field means no output if randomed that field) + ACTION_T_RANDOM_YELL = 7, //TextId1, TextId2, TextId3 (-1 in any field means no output if randomed that field) + ACTION_T_RANDOM_TEXTEMOTE = 8, //TextId1, TextId2, TextId3 (-1 in any field means no output if randomed that field) + ACTION_T_RANDOM_SOUND = 9, //SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field) + ACTION_T_RANDOM_EMOTE = 10, //EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field) + ACTION_T_CAST = 11, //SpellId, Target, CastFlags + ACTION_T_SUMMON = 12, //CreatureID, Target, Duration in ms + ACTION_T_THREAT_SINGLE_PCT = 13, //Threat%, Target + ACTION_T_THREAT_ALL_PCT = 14, //Threat% + ACTION_T_QUEST_EVENT = 15, //QuestID, Target + ACTION_T_CASTCREATUREGO = 16, //QuestID, SpellId, Target + ACTION_T_SET_UNIT_FIELD = 17, //Field_Number, Value, Target + ACTION_T_SET_UNIT_FLAG = 18, //Flags (may be more than one field OR'd together), Target + ACTION_T_REMOVE_UNIT_FLAG = 19, //Flags (may be more than one field OR'd together), Target + ACTION_T_AUTO_ATTACK = 20, //AllowAttackState (0 = stop attack, anything else means continue attacking) + ACTION_T_COMBAT_MOVEMENT = 21, //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking) + ACTION_T_SET_PHASE = 22, //Phase + ACTION_T_INC_PHASE = 23, //Value (may be negative to decrement phase, should not be 0) + ACTION_T_EVADE = 24, //No Params + ACTION_T_FLEE = 25, //No Params + ACTION_T_QUEST_EVENT_ALL = 26, //QuestID + ACTION_T_CASTCREATUREGO_ALL = 27, //QuestId, SpellId + ACTION_T_REMOVEAURASFROMSPELL = 28, //Target, Spellid + ACTION_T_RANGED_MOVEMENT = 29, //Distance, Angle + ACTION_T_RANDOM_PHASE = 30, //PhaseId1, PhaseId2, PhaseId3 + ACTION_T_RANDOM_PHASE_RANGE = 31, //PhaseMin, PhaseMax + ACTION_T_SUMMON_ID = 32, //CreatureId, Target, SpawnId + ACTION_T_KILLED_MONSTER = 33, //CreatureId, Target + ACTION_T_SET_INST_DATA = 34, //Field, Data + ACTION_T_SET_INST_DATA64 = 35, //Field, Target + ACTION_T_UPDATE_TEMPLATE = 36, //Entry, Team + ACTION_T_DIE = 37, //No Params + ACTION_T_ZONE_COMBAT_PULSE = 38, //No Params + + ACTION_T_END, +}; + +enum Target +{ + //Self (m_creature) + TARGET_T_SELF = 0, //Self cast + + //Hostile targets (if pet then returns pet owner) + TARGET_T_HOSTILE, //Our current target (ie: highest aggro) + TARGET_T_HOSTILE_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks) + TARGET_T_HOSTILE_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for) + TARGET_T_HOSTILE_RANDOM, //Just any random target on our threat list + TARGET_T_HOSTILE_RANDOM_NOT_TOP, //Any random target except top threat + + //Invoker targets (if pet then returns pet owner) + TARGET_T_ACTION_INVOKER, //Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) + + //Hostile targets (including pets) + TARGET_T_HOSTILE_WPET, //Current target (can be a pet) + TARGET_T_HOSTILE_WPET_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks) + TARGET_T_HOSTILE_WPET_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for) + TARGET_T_HOSTILE_WPET_RANDOM, //Just any random target on our threat list + TARGET_T_HOSTILE_WPET_RANDOM_NOT_TOP, //Any random target except top threat + + TARGET_T_ACTION_INVOKER_WPET, + + TARGET_T_END +}; + +enum CastFlags +{ + CAST_INTURRUPT_PREVIOUS = 0x01, //Interrupt any spell casting + CAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time) + CAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range + CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range + CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself +}; + +enum EventFlags +{ + EFLAG_REPEATABLE = 0x01, //Event repeats + EFLAG_NORMAL = 0x02, //Event only occurs in Normal instance difficulty + EFLAG_HEROIC = 0x04, //Event only occurs in Heroic instance difficulty + EFLAG_RESERVED_3 = 0x08, + EFLAG_RESERVED_4 = 0x10, + EFLAG_RESERVED_5 = 0x20, + EFLAG_RESERVED_6 = 0x40, + EFLAG_DEBUG_ONLY = 0x80, //Event only occurs in debug build of SD2 only +}; + +struct EventAI_Event +{ + uint32 event_id; + + uint32 creature_id; + + uint16 event_type; + uint32 event_inverse_phase_mask; + uint8 event_chance; + uint8 event_flags; + union + { + uint32 event_param1; + int32 event_param1_s; + }; + union + { + uint32 event_param2; + int32 event_param2_s; + }; + union + { + uint32 event_param3; + int32 event_param3_s; + }; + union + { + uint32 event_param4; + int32 event_param4_s; + }; + + struct _action + { + uint16 type; + union + { + uint32 param1; + int32 param1_s; + }; + union + { + uint32 param2; + int32 param2_s; + }; + union + { + uint32 param3; + int32 param3_s; + }; + }action[MAX_ACTIONS]; +}; + +//Event_Map +extern std::list EventAI_Event_List; + +struct EventAI_Summon +{ + uint32 id; + + float position_x; + float position_y; + float position_z; + float orientation; + uint32 SpawnTimeSecs; +}; + +//EventSummon_Map +extern HM_NAMESPACE::hash_map EventAI_Summon_Map; + +//EventAI Error handling +extern uint32 EAI_ErrorLevel; +/* + +struct EventAI_CreatureError +{ + bool ListEmpty; + bool NoInstance; +}; + +//Error prevention list +extern HM_NAMESPACE::hash_map EventAI_CreatureErrorPreventionList; + +//Defines +#define EVENTAI_EMPTY_EVENTLIST "SD2: Eventlist for Creature %i is empty but creature is using Mob_EventAI. Preventing EventAI on this creature." +*/ +#endif diff --git a/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp b/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp index 6c05ceffc80..74162537fdf 100644 --- a/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp +++ b/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp @@ -1,172 +1,172 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* ScriptData -SDName: Generic_Creature -SD%Complete: 80 -SDComment: Should be replaced with core based AI -SDCategory: Creatures -EndScriptData */ - -#include "precompiled.h" - -#define GENERIC_CREATURE_COOLDOWN 5000 - -struct MANGOS_DLL_DECL generic_creatureAI : public ScriptedAI -{ - generic_creatureAI(Creature *c) : ScriptedAI(c) {Reset();} - - 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() - { - GlobalCooldown = 0; - BuffTimer = 0; //Rebuff as soon as we can - IsSelfRooted = false; - } - - void Aggro(Unit *who) - { - if (!m_creature->IsWithinDistInMap(who, ATTACK_DISTANCE)) - { - IsSelfRooted = true; - } - } - - void UpdateAI(const uint32 diff) - { - //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 - if (!InCombat && 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); - - if (info && !GlobalCooldown) - { - //Cast the buff spell - DoCastSpell(m_creature, info); - - //Set our global cooldown - GlobalCooldown = GENERIC_CREATURE_COOLDOWN; - - //Set our timer to 10 minutes before rebuff - BuffTimer = 600000; - }//Try agian in 30 seconds - else BuffTimer = 30000; - }else BuffTimer -= diff; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //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)) - { - bool Healing = false; - SpellEntry const *info = NULL; - - //Select a healing spell if less than 30% hp - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30) - 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 - 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) - { - //Cast the spell - if (Healing)DoCastSpell(m_creature, info); - else DoCastSpell(m_creature->getVictim(), info); - - //Set our global cooldown - GlobalCooldown = GENERIC_CREATURE_COOLDOWN; - } - else m_creature->AttackerStateUpdate(m_creature->getVictim()); - - m_creature->resetAttackTimer(); - } - } - else - { - //Only run this code if we arn't already casting - if (!m_creature->IsNonMeleeSpellCasted(false)) - { - bool Healing = false; - SpellEntry const *info = NULL; - - //Select a healing spell if less than 30% hp ONLY 33% of the time - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30 && rand() % 3 == 0) - 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); - - //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) - { - IsSelfRooted = true; - } - - //Cast spell - if (Healing) DoCastSpell(m_creature,info); - else DoCastSpell(m_creature->getVictim(),info); - - //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; - } - } - } - } -}; -CreatureAI* GetAI_generic_creature(Creature *_Creature) -{ - return new generic_creatureAI (_Creature); -} - - -void AddSC_generic_creature() -{ - Script *newscript; - newscript = new Script; - newscript->Name="generic_creature"; - newscript->GetAI = GetAI_generic_creature; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: Generic_Creature +SD%Complete: 80 +SDComment: Should be replaced with core based AI +SDCategory: Creatures +EndScriptData */ + +#include "precompiled.h" + +#define GENERIC_CREATURE_COOLDOWN 5000 + +struct MANGOS_DLL_DECL generic_creatureAI : public ScriptedAI +{ + generic_creatureAI(Creature *c) : ScriptedAI(c) {Reset();} + + 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() + { + GlobalCooldown = 0; + BuffTimer = 0; //Rebuff as soon as we can + IsSelfRooted = false; + } + + void Aggro(Unit *who) + { + if (!m_creature->IsWithinDistInMap(who, ATTACK_DISTANCE)) + { + IsSelfRooted = true; + } + } + + void UpdateAI(const uint32 diff) + { + //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 + if (!InCombat && 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); + + if (info && !GlobalCooldown) + { + //Cast the buff spell + DoCastSpell(m_creature, info); + + //Set our global cooldown + GlobalCooldown = GENERIC_CREATURE_COOLDOWN; + + //Set our timer to 10 minutes before rebuff + BuffTimer = 600000; + }//Try agian in 30 seconds + else BuffTimer = 30000; + }else BuffTimer -= diff; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //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)) + { + bool Healing = false; + SpellEntry const *info = NULL; + + //Select a healing spell if less than 30% hp + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30) + 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 + 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) + { + //Cast the spell + if (Healing)DoCastSpell(m_creature, info); + else DoCastSpell(m_creature->getVictim(), info); + + //Set our global cooldown + GlobalCooldown = GENERIC_CREATURE_COOLDOWN; + } + else m_creature->AttackerStateUpdate(m_creature->getVictim()); + + m_creature->resetAttackTimer(); + } + } + else + { + //Only run this code if we arn't already casting + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + bool Healing = false; + SpellEntry const *info = NULL; + + //Select a healing spell if less than 30% hp ONLY 33% of the time + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30 && rand() % 3 == 0) + 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); + + //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) + { + IsSelfRooted = true; + } + + //Cast spell + if (Healing) DoCastSpell(m_creature,info); + else DoCastSpell(m_creature->getVictim(),info); + + //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; + } + } + } + } +}; +CreatureAI* GetAI_generic_creature(Creature *_Creature) +{ + return new generic_creatureAI (_Creature); +} + + +void AddSC_generic_creature() +{ + Script *newscript; + newscript = new Script; + newscript->Name="generic_creature"; + newscript->GetAI = GetAI_generic_creature; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/creature/simple_ai.cpp b/src/bindings/scripts/scripts/creature/simple_ai.cpp index e93bfba6425..a341510b63e 100644 --- a/src/bindings/scripts/scripts/creature/simple_ai.cpp +++ b/src/bindings/scripts/scripts/creature/simple_ai.cpp @@ -1,294 +1,294 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* ScriptData -SDName: SimpleAI -SD%Complete: 100 -SDComment: Base Class for SimpleAI creatures -SDCategory: Creatures -EndScriptData */ - -#include "precompiled.h" -#include "simple_ai.h" - -SimpleAI::SimpleAI(Creature *c) : ScriptedAI(c) -{ - //Clear all data - Aggro_Text[0] = NULL; - Aggro_Text[1] = NULL; - Aggro_Text[2] = NULL; - Aggro_Say[0] = false; - Aggro_Say[1] = false; - Aggro_Say[2] = false; - Aggro_Sound[0] = 0; - Aggro_Sound[1] = 0; - Aggro_Sound[2] = 0; - - Death_Text[0] = NULL; - Death_Text[1] = NULL; - Death_Text[2] = NULL; - Death_Say[0] = false; - Death_Say[1] = false; - Death_Say[2] = false; - Death_Sound[0] = 0; - Death_Sound[1] = 0; - Death_Sound[2] = 0; - Death_Spell = 0; - Death_Target_Type = 0; - - Kill_Text[0] = NULL; - Kill_Text[1] = NULL; - Kill_Text[2] = NULL; - Kill_Say[0] = false; - Kill_Say[1] = false; - Kill_Say[2] = false; - Kill_Sound[0] = 0; - Kill_Sound[1] = 0; - Kill_Sound[2] = 0; - Kill_Spell = 0; - Kill_Target_Type = 0; - - memset(Spell,0,sizeof(Spell)); - - EnterEvadeMode(); -} - -void SimpleAI::Reset() -{ -} - -void SimpleAI::Aggro(Unit *who) -{ - //Reset cast timers - if (Spell[0].First_Cast >= 0) - Spell_Timer[0] = Spell[0].First_Cast; - else Spell_Timer[0] = 1000; - if (Spell[1].First_Cast >= 0) - Spell_Timer[1] = Spell[1].First_Cast; - else Spell_Timer[1] = 1000; - if (Spell[2].First_Cast >= 0) - Spell_Timer[2] = Spell[2].First_Cast; - else Spell_Timer[2] = 1000; - if (Spell[3].First_Cast >= 0) - Spell_Timer[3] = Spell[3].First_Cast; - else Spell_Timer[3] = 1000; - if (Spell[4].First_Cast >= 0) - Spell_Timer[4] = Spell[4].First_Cast; - else Spell_Timer[4] = 1000; - if (Spell[5].First_Cast >= 0) - Spell_Timer[5] = Spell[5].First_Cast; - else Spell_Timer[5] = 1000; - if (Spell[6].First_Cast >= 0) - Spell_Timer[6] = Spell[6].First_Cast; - else Spell_Timer[6] = 1000; - if (Spell[7].First_Cast >= 0) - Spell_Timer[7] = Spell[7].First_Cast; - else Spell_Timer[7] = 1000; - if (Spell[8].First_Cast >= 0) - Spell_Timer[8] = Spell[8].First_Cast; - else Spell_Timer[8] = 1000; - if (Spell[9].First_Cast >= 0) - Spell_Timer[9] = Spell[9].First_Cast; - else Spell_Timer[9] = 1000; - - uint32 random_text = rand()%3; - - //Random yell - if (Aggro_Text[random_text]) - if (Aggro_Say[random_text]) - DoSay(Aggro_Text[random_text], LANG_UNIVERSAL, who); - else DoYell(Aggro_Text[random_text], LANG_UNIVERSAL, who); - - //Random sound - if (Aggro_Sound[random_text]) - DoPlaySoundToSet(m_creature, Aggro_Sound[random_text]); -} - -void SimpleAI::KilledUnit(Unit *victim) -{ - uint32 random_text = rand()%3; - - //Random yell - if (Kill_Text[random_text]) - if (Kill_Say[random_text]) - DoSay(Kill_Text[random_text], LANG_UNIVERSAL, victim); - else DoYell(Kill_Text[random_text], LANG_UNIVERSAL, victim); - - //Random sound - if (Kill_Sound[random_text]) - DoPlaySoundToSet(m_creature, Kill_Sound[random_text]); - - if (!Kill_Spell) - return; - - Unit* target = NULL; - - switch (Kill_Target_Type) - { - case CAST_SELF: - target = m_creature; - break; - case CAST_HOSTILE_TARGET: - target = m_creature->getVictim(); - break; - case CAST_HOSTILE_SECOND_AGGRO: - target = SelectUnit(SELECT_TARGET_TOPAGGRO,1); - break; - case CAST_HOSTILE_LAST_AGGRO: - target = SelectUnit(SELECT_TARGET_BOTTOMAGGRO,0); - break; - case CAST_HOSTILE_RANDOM: - target = SelectUnit(SELECT_TARGET_RANDOM,0); - break; - case CAST_KILLEDUNIT_VICTIM: - target = victim; - break; - } - - //Target is ok, cast a spell on it - if (target) - DoCast(target, Kill_Spell); -} - -void SimpleAI::DamageTaken(Unit *killer, uint32 &damage) -{ - //Return if damage taken won't kill us - if (m_creature->GetHealth() > damage) - return; - - uint32 random_text = rand()%3; - - //Random yell - if (Death_Text[random_text]) - if (Death_Say[random_text]) - DoSay(Death_Text[random_text], LANG_UNIVERSAL, killer); - else DoYell(Death_Text[random_text], LANG_UNIVERSAL, killer); - - //Random sound - if (Death_Sound[random_text]) - DoPlaySoundToSet(m_creature, Death_Sound[random_text]); - - if (!Death_Spell) - return; - - Unit* target = NULL; - - switch (Death_Target_Type) - { - case CAST_SELF: - target = m_creature; - break; - case CAST_HOSTILE_TARGET: - target = m_creature->getVictim(); - break; - case CAST_HOSTILE_SECOND_AGGRO: - target = SelectUnit(SELECT_TARGET_TOPAGGRO,1); - break; - case CAST_HOSTILE_LAST_AGGRO: - target = SelectUnit(SELECT_TARGET_BOTTOMAGGRO,0); - break; - case CAST_HOSTILE_RANDOM: - target = SelectUnit(SELECT_TARGET_RANDOM,0); - break; - case CAST_JUSTDIED_KILLER: - target = killer; - break; - } - - //Target is ok, cast a spell on it - if (target) - DoCast(target, Death_Spell); -} - -void SimpleAI::UpdateAI(const uint32 diff) -{ - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Spells - for (uint32 i = 0; i < 10; ++i) - { - //Spell not valid - if (!Spell[i].Enabled || !Spell[i].Spell_Id) - continue; - - if (Spell_Timer[i] < diff) - { - //Check if this is a percentage based - if (Spell[i].First_Cast < 0 && Spell[i].First_Cast > -100 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > -Spell[i].First_Cast) - continue; - - //Check Current spell - if (!(Spell[i].InterruptPreviousCast && m_creature->IsNonMeleeSpellCasted(false))) - { - Unit* target = NULL; - - switch (Spell[i].Cast_Target_Type) - { - case CAST_SELF: - target = m_creature; - break; - case CAST_HOSTILE_TARGET: - target = m_creature->getVictim(); - break; - case CAST_HOSTILE_SECOND_AGGRO: - target = SelectUnit(SELECT_TARGET_TOPAGGRO,1); - break; - case CAST_HOSTILE_LAST_AGGRO: - target = SelectUnit(SELECT_TARGET_BOTTOMAGGRO,0); - break; - case CAST_HOSTILE_RANDOM: - target = SelectUnit(SELECT_TARGET_RANDOM,0); - break; - } - - //Target is ok, cast a spell on it and then do our random yell - if (target) - { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCast(target, Spell[i].Spell_Id); - - //Yell and sound use the same number so that you can make - //the creature yell with the correct sound effect attached - uint32 random_text = rand()%3; - - //Random yell - if (Spell[i].Text[random_text]) - if (Spell[i].Say[random_text]) - DoSay(Spell[i].Text[random_text], LANG_UNIVERSAL, target); - else DoYell(Spell[i].Text[random_text], LANG_UNIVERSAL, target); - - //Random sound - if (Spell[i].Text_Sound[random_text]) - DoPlaySoundToSet(m_creature, Spell[i].Text_Sound[random_text]); - } - - } - - //Spell will cast agian when the cooldown is up - if (Spell[i].CooldownRandomAddition) - Spell_Timer[i] = Spell[i].Cooldown + (rand() % Spell[i].CooldownRandomAddition); - else Spell_Timer[i] = Spell[i].Cooldown; - - }else Spell_Timer[i] -= diff; - - } - - DoMeleeAttackIfReady(); -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: SimpleAI +SD%Complete: 100 +SDComment: Base Class for SimpleAI creatures +SDCategory: Creatures +EndScriptData */ + +#include "precompiled.h" +#include "simple_ai.h" + +SimpleAI::SimpleAI(Creature *c) : ScriptedAI(c) +{ + //Clear all data + Aggro_Text[0] = NULL; + Aggro_Text[1] = NULL; + Aggro_Text[2] = NULL; + Aggro_Say[0] = false; + Aggro_Say[1] = false; + Aggro_Say[2] = false; + Aggro_Sound[0] = 0; + Aggro_Sound[1] = 0; + Aggro_Sound[2] = 0; + + Death_Text[0] = NULL; + Death_Text[1] = NULL; + Death_Text[2] = NULL; + Death_Say[0] = false; + Death_Say[1] = false; + Death_Say[2] = false; + Death_Sound[0] = 0; + Death_Sound[1] = 0; + Death_Sound[2] = 0; + Death_Spell = 0; + Death_Target_Type = 0; + + Kill_Text[0] = NULL; + Kill_Text[1] = NULL; + Kill_Text[2] = NULL; + Kill_Say[0] = false; + Kill_Say[1] = false; + Kill_Say[2] = false; + Kill_Sound[0] = 0; + Kill_Sound[1] = 0; + Kill_Sound[2] = 0; + Kill_Spell = 0; + Kill_Target_Type = 0; + + memset(Spell,0,sizeof(Spell)); + + EnterEvadeMode(); +} + +void SimpleAI::Reset() +{ +} + +void SimpleAI::Aggro(Unit *who) +{ + //Reset cast timers + if (Spell[0].First_Cast >= 0) + Spell_Timer[0] = Spell[0].First_Cast; + else Spell_Timer[0] = 1000; + if (Spell[1].First_Cast >= 0) + Spell_Timer[1] = Spell[1].First_Cast; + else Spell_Timer[1] = 1000; + if (Spell[2].First_Cast >= 0) + Spell_Timer[2] = Spell[2].First_Cast; + else Spell_Timer[2] = 1000; + if (Spell[3].First_Cast >= 0) + Spell_Timer[3] = Spell[3].First_Cast; + else Spell_Timer[3] = 1000; + if (Spell[4].First_Cast >= 0) + Spell_Timer[4] = Spell[4].First_Cast; + else Spell_Timer[4] = 1000; + if (Spell[5].First_Cast >= 0) + Spell_Timer[5] = Spell[5].First_Cast; + else Spell_Timer[5] = 1000; + if (Spell[6].First_Cast >= 0) + Spell_Timer[6] = Spell[6].First_Cast; + else Spell_Timer[6] = 1000; + if (Spell[7].First_Cast >= 0) + Spell_Timer[7] = Spell[7].First_Cast; + else Spell_Timer[7] = 1000; + if (Spell[8].First_Cast >= 0) + Spell_Timer[8] = Spell[8].First_Cast; + else Spell_Timer[8] = 1000; + if (Spell[9].First_Cast >= 0) + Spell_Timer[9] = Spell[9].First_Cast; + else Spell_Timer[9] = 1000; + + uint32 random_text = rand()%3; + + //Random yell + if (Aggro_Text[random_text]) + if (Aggro_Say[random_text]) + DoSay(Aggro_Text[random_text], LANG_UNIVERSAL, who); + else DoYell(Aggro_Text[random_text], LANG_UNIVERSAL, who); + + //Random sound + if (Aggro_Sound[random_text]) + DoPlaySoundToSet(m_creature, Aggro_Sound[random_text]); +} + +void SimpleAI::KilledUnit(Unit *victim) +{ + uint32 random_text = rand()%3; + + //Random yell + if (Kill_Text[random_text]) + if (Kill_Say[random_text]) + DoSay(Kill_Text[random_text], LANG_UNIVERSAL, victim); + else DoYell(Kill_Text[random_text], LANG_UNIVERSAL, victim); + + //Random sound + if (Kill_Sound[random_text]) + DoPlaySoundToSet(m_creature, Kill_Sound[random_text]); + + if (!Kill_Spell) + return; + + Unit* target = NULL; + + switch (Kill_Target_Type) + { + case CAST_SELF: + target = m_creature; + break; + case CAST_HOSTILE_TARGET: + target = m_creature->getVictim(); + break; + case CAST_HOSTILE_SECOND_AGGRO: + target = SelectUnit(SELECT_TARGET_TOPAGGRO,1); + break; + case CAST_HOSTILE_LAST_AGGRO: + target = SelectUnit(SELECT_TARGET_BOTTOMAGGRO,0); + break; + case CAST_HOSTILE_RANDOM: + target = SelectUnit(SELECT_TARGET_RANDOM,0); + break; + case CAST_KILLEDUNIT_VICTIM: + target = victim; + break; + } + + //Target is ok, cast a spell on it + if (target) + DoCast(target, Kill_Spell); +} + +void SimpleAI::DamageTaken(Unit *killer, uint32 &damage) +{ + //Return if damage taken won't kill us + if (m_creature->GetHealth() > damage) + return; + + uint32 random_text = rand()%3; + + //Random yell + if (Death_Text[random_text]) + if (Death_Say[random_text]) + DoSay(Death_Text[random_text], LANG_UNIVERSAL, killer); + else DoYell(Death_Text[random_text], LANG_UNIVERSAL, killer); + + //Random sound + if (Death_Sound[random_text]) + DoPlaySoundToSet(m_creature, Death_Sound[random_text]); + + if (!Death_Spell) + return; + + Unit* target = NULL; + + switch (Death_Target_Type) + { + case CAST_SELF: + target = m_creature; + break; + case CAST_HOSTILE_TARGET: + target = m_creature->getVictim(); + break; + case CAST_HOSTILE_SECOND_AGGRO: + target = SelectUnit(SELECT_TARGET_TOPAGGRO,1); + break; + case CAST_HOSTILE_LAST_AGGRO: + target = SelectUnit(SELECT_TARGET_BOTTOMAGGRO,0); + break; + case CAST_HOSTILE_RANDOM: + target = SelectUnit(SELECT_TARGET_RANDOM,0); + break; + case CAST_JUSTDIED_KILLER: + target = killer; + break; + } + + //Target is ok, cast a spell on it + if (target) + DoCast(target, Death_Spell); +} + +void SimpleAI::UpdateAI(const uint32 diff) +{ + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Spells + for (uint32 i = 0; i < 10; ++i) + { + //Spell not valid + if (!Spell[i].Enabled || !Spell[i].Spell_Id) + continue; + + if (Spell_Timer[i] < diff) + { + //Check if this is a percentage based + if (Spell[i].First_Cast < 0 && Spell[i].First_Cast > -100 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > -Spell[i].First_Cast) + continue; + + //Check Current spell + if (!(Spell[i].InterruptPreviousCast && m_creature->IsNonMeleeSpellCasted(false))) + { + Unit* target = NULL; + + switch (Spell[i].Cast_Target_Type) + { + case CAST_SELF: + target = m_creature; + break; + case CAST_HOSTILE_TARGET: + target = m_creature->getVictim(); + break; + case CAST_HOSTILE_SECOND_AGGRO: + target = SelectUnit(SELECT_TARGET_TOPAGGRO,1); + break; + case CAST_HOSTILE_LAST_AGGRO: + target = SelectUnit(SELECT_TARGET_BOTTOMAGGRO,0); + break; + case CAST_HOSTILE_RANDOM: + target = SelectUnit(SELECT_TARGET_RANDOM,0); + break; + } + + //Target is ok, cast a spell on it and then do our random yell + if (target) + { + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + + DoCast(target, Spell[i].Spell_Id); + + //Yell and sound use the same number so that you can make + //the creature yell with the correct sound effect attached + uint32 random_text = rand()%3; + + //Random yell + if (Spell[i].Text[random_text]) + if (Spell[i].Say[random_text]) + DoSay(Spell[i].Text[random_text], LANG_UNIVERSAL, target); + else DoYell(Spell[i].Text[random_text], LANG_UNIVERSAL, target); + + //Random sound + if (Spell[i].Text_Sound[random_text]) + DoPlaySoundToSet(m_creature, Spell[i].Text_Sound[random_text]); + } + + } + + //Spell will cast agian when the cooldown is up + if (Spell[i].CooldownRandomAddition) + Spell_Timer[i] = Spell[i].Cooldown + (rand() % Spell[i].CooldownRandomAddition); + else Spell_Timer[i] = Spell[i].Cooldown; + + }else Spell_Timer[i] -= diff; + + } + + DoMeleeAttackIfReady(); +} diff --git a/src/bindings/scripts/scripts/creature/simple_ai.h b/src/bindings/scripts/scripts/creature/simple_ai.h index 0ac78dc1222..74cd6e1d56b 100644 --- a/src/bindings/scripts/scripts/creature/simple_ai.h +++ b/src/bindings/scripts/scripts/creature/simple_ai.h @@ -1,74 +1,74 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software licensed under GPL version 2 -* Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_SIMPLEAI_H -#define SC_SIMPLEAI_H - -enum CastTarget -{ - CAST_SELF = 0, //Self cast - CAST_HOSTILE_TARGET, //Our current target (ie: highest aggro) - CAST_HOSTILE_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks) - CAST_HOSTILE_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for) - CAST_HOSTILE_RANDOM, //Just any random target on our threat list - CAST_FRIENDLY_RANDOM, //NOT YET IMPLEMENTED - - //Special cases - CAST_KILLEDUNIT_VICTIM, //Only works within KilledUnit function - CAST_JUSTDIED_KILLER, //Only works within JustDied function -}; - -struct MANGOS_DLL_DECL SimpleAI : public ScriptedAI -{ - SimpleAI(Creature *c);// : ScriptedAI(c); - - void Reset(); - - void Aggro(Unit *who); - - void KilledUnit(Unit *victim); - - void DamageTaken(Unit *killer, uint32 &damage); - - void UpdateAI(const uint32 diff); - -public: - - char* Aggro_Text[3]; - bool Aggro_Say[3]; - uint32 Aggro_Sound[3]; - - char* Death_Text[3]; - bool Death_Say[3]; - uint32 Death_Sound[3]; - uint32 Death_Spell; - uint32 Death_Target_Type; - - char* Kill_Text[3]; - bool Kill_Say[3]; - uint32 Kill_Sound[3]; - uint32 Kill_Spell; - uint32 Kill_Target_Type; - - struct SimpleAI_Spell - { - uint32 Spell_Id; //Spell ID to cast - int32 First_Cast; //Delay for first cast - uint32 Cooldown; //Cooldown between casts - uint32 CooldownRandomAddition; //Random addition to cooldown (in range from 0 - CooldownRandomAddition) - uint32 Cast_Target_Type; //Target type (note that certain spells may ignore this) - bool InterruptPreviousCast; //Interrupt a previous cast if this spell needs to be cast - bool Enabled; //Spell enabled or disabled (default: false) - - //3 texts to many? - char* Text[3]; - bool Say[3]; - uint32 Text_Sound[3]; - }Spell[10]; - -protected: - uint32 Spell_Timer[10]; -}; - -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software licensed under GPL version 2 +* Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_SIMPLEAI_H +#define SC_SIMPLEAI_H + +enum CastTarget +{ + CAST_SELF = 0, //Self cast + CAST_HOSTILE_TARGET, //Our current target (ie: highest aggro) + CAST_HOSTILE_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks) + CAST_HOSTILE_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for) + CAST_HOSTILE_RANDOM, //Just any random target on our threat list + CAST_FRIENDLY_RANDOM, //NOT YET IMPLEMENTED + + //Special cases + CAST_KILLEDUNIT_VICTIM, //Only works within KilledUnit function + CAST_JUSTDIED_KILLER, //Only works within JustDied function +}; + +struct MANGOS_DLL_DECL SimpleAI : public ScriptedAI +{ + SimpleAI(Creature *c);// : ScriptedAI(c); + + void Reset(); + + void Aggro(Unit *who); + + void KilledUnit(Unit *victim); + + void DamageTaken(Unit *killer, uint32 &damage); + + void UpdateAI(const uint32 diff); + +public: + + char* Aggro_Text[3]; + bool Aggro_Say[3]; + uint32 Aggro_Sound[3]; + + char* Death_Text[3]; + bool Death_Say[3]; + uint32 Death_Sound[3]; + uint32 Death_Spell; + uint32 Death_Target_Type; + + char* Kill_Text[3]; + bool Kill_Say[3]; + uint32 Kill_Sound[3]; + uint32 Kill_Spell; + uint32 Kill_Target_Type; + + struct SimpleAI_Spell + { + uint32 Spell_Id; //Spell ID to cast + int32 First_Cast; //Delay for first cast + uint32 Cooldown; //Cooldown between casts + uint32 CooldownRandomAddition; //Random addition to cooldown (in range from 0 - CooldownRandomAddition) + uint32 Cast_Target_Type; //Target type (note that certain spells may ignore this) + bool InterruptPreviousCast; //Interrupt a previous cast if this spell needs to be cast + bool Enabled; //Spell enabled or disabled (default: false) + + //3 texts to many? + char* Text[3]; + bool Say[3]; + uint32 Text_Sound[3]; + }Spell[10]; + +protected: + uint32 Spell_Timer[10]; +}; + +#endif diff --git a/src/bindings/scripts/scripts/custom/custom_example.cpp b/src/bindings/scripts/scripts/custom/custom_example.cpp index e6cdd2f8e62..9a185612d37 100644 --- a/src/bindings/scripts/scripts/custom/custom_example.cpp +++ b/src/bindings/scripts/scripts/custom/custom_example.cpp @@ -1,277 +1,277 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Custom_Example -SD%Complete: 100 -SDComment: Short custom scripting example -SDCategory: Script Examples -EndScriptData */ - -#include "precompiled.h" - -// **** This script is designed as an example for others to build on **** -// **** Please modify whatever you'd like to as this script is only for developement **** - -// **** Script Info **** -// This script is written in a way that it can be used for both friendly and hostile monsters -// Its primary purpose is to show just how much you can really do with scripts -// I recommend trying it out on both an agressive NPC and on friendly npc - -// **** Quick Info **** -// Functions with Handled Function marked above them are functions that are called automatically by the core -// Functions that are marked Custom Function are functions I've created to simplify code - -#define SPELL_BUFF 25661 -#define SPELL_ONE 12555 -#define SPELL_ONE_ALT 24099 -#define SPELL_TWO 10017 -#define SPELL_THREE 26027 -#define SPELL_ENRAGE 23537 -#define SPELL_BESERK 32309 - -#define SAY_AGGRO "Let the games begin." -#define SAY_RANDOM_0 "I see endless suffering. I see torment. I see rage. I see everything." -#define SAY_RANDOM_1 "Muahahahaha" -#define SAY_RANDOM_2 "These mortal infedels my lord, they have invaded your sanctum and seek to steal your secrets." -#define SAY_RANDOM_3 "You are already dead." -#define SAY_RANDOM_4 "Where to go? What to do? So many choices that all end in pain, end in death." -#define SAY_BESERK "$N, I sentance you to death!" -#define SAY_PHASE "The suffering has just begun!" - -#define GOSSIP_ITEM "I'm looking for a fight" -#define SAY_DANCE "I always thought I was a good dancer" -#define SAY_SALUTE "Move out Soldier!" - -struct MANGOS_DLL_DECL custom_exampleAI : public ScriptedAI -{ - //*** HANDLED FUNCTION *** - //This is the constructor, called only once when the creature is first created - custom_exampleAI(Creature *c) : ScriptedAI(c) {Reset();} - - //*** CUSTOM VARIABLES **** - //These variables are for use only by this individual script. - //Nothing else will ever call them but us. - - uint32 Say_Timer; //Timer for random chat - uint32 Rebuff_Timer; //Timer for rebuffing - uint32 Spell_1_Timer; //Timer for spell 1 when in combat - uint32 Spell_2_Timer; //Timer for spell 1 when in combat - uint32 Spell_3_Timer; //Timer for spell 1 when in combat - uint32 Beserk_Timer; //Timer until we go into Beserk (enraged) mode - uint32 Phase; //The current battle phase we are in - uint32 Phase_Timer; //Timer until phase transition - - //*** HANDLED FUNCTION *** - //This is called whenever the core decides we need to evade - void Reset() - { - Phase = 1; //Start in phase 1 - Phase_Timer = 60000; //60 seconds - Spell_1_Timer = 5000; //5 seconds - Spell_2_Timer = 37000; //37 seconds - Spell_3_Timer = 19000; //19 seconds - Beserk_Timer = 120000; //2 minutes - } - - //*** HANDLED FUNCTION *** - //Attack Start is called whenever someone hits us. - void Aggro(Unit *who) - { - //Say some stuff - DoSay(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,8280); - } - - //*** 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 diff) - { - //Out of combat timers - if (!m_creature->getVictim()) - { - //Random Say timer - if (Say_Timer < diff) - { - //Random switch between 5 outcomes - switch (rand()%5) - { - case 0: - DoYell(SAY_RANDOM_0,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,8831); //8831 is the index of the sound we are playing. You find these numbers in SoundEntries.dbc - break; - - case 1: - DoYell(SAY_RANDOM_1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,8818); - break; - - case 2: - DoYell(SAY_RANDOM_2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,8041); - break; - - case 3: - DoYell(SAY_RANDOM_3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,8581); - break; - - case 4: - DoYell(SAY_RANDOM_4,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,8791); - break; - } - - Say_Timer = 45000; //Say something agian in 45 seconds - }else Say_Timer -= diff; - - //Rebuff timer - if (Rebuff_Timer < diff) - { - DoCast(m_creature,SPELL_BUFF); - Rebuff_Timer = 900000; //Rebuff agian in 15 minutes - }else Rebuff_Timer -= diff; - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Spell 1 timer - if (Spell_1_Timer < diff) - { - //Cast spell one on our current target. - if (rand()%50 > 10) - DoCast(m_creature->getVictim(),SPELL_ONE_ALT); - else if (m_creature->GetDistance(m_creature->getVictim()) < 25) - DoCast(m_creature->getVictim(),SPELL_ONE); - - Spell_1_Timer = 5000; - }else Spell_1_Timer -= diff; - - //Spell 2 timer - if (Spell_2_Timer < diff) - { - //Cast spell one on our current target. - DoCast(m_creature->getVictim(),SPELL_TWO); - - Spell_2_Timer = 37000; - }else Spell_2_Timer -= diff; - - //Spell 3 timer - if (Phase > 1) - if (Spell_3_Timer < diff) - { - //Cast spell one on our current target. - DoCast(m_creature->getVictim(),SPELL_THREE); - - Spell_3_Timer = 19000; - }else Spell_3_Timer -= diff; - - //Beserk timer - if (Phase > 1) - if (Beserk_Timer < diff) - { - //Say our line then cast uber death spell - DoPlaySoundToSet(m_creature,8588); - DoYell(SAY_BESERK,LANG_UNIVERSAL,m_creature->getVictim()); - DoCast(m_creature->getVictim(),SPELL_BESERK); - - //Cast our beserk spell agian in 12 seconds if we didn't kill everyone - Beserk_Timer = 12000; - }else Beserk_Timer -= diff; - - //Phase timer - if (Phase == 1) - if (Phase_Timer < diff) - { - //Go to next phase - Phase++; - DoYell(SAY_PHASE,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_ENRAGE); - }else Phase_Timer -= diff; - - 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 -CreatureAI* GetAI_custom_example(Creature *_Creature) -{ - return new custom_exampleAI (_Creature); -} - -//This function is called when the player clicks an option on the gossip menu -void SendDefaultMenu_custom_example(Player *player, Creature *_Creature, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) //Fight time - { - //Set our faction to hostile twoards all - _Creature->setFaction(24); - _Creature->Attack(player, true); - player->PlayerTalkClass->CloseGossip(); - } -} - -//This function is called when the player clicks an option on the gossip menu -bool GossipSelect_custom_example(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (sender == GOSSIP_SENDER_MAIN) - SendDefaultMenu_custom_example(player, _Creature, action); - - return true; -} - -//This function is called when the player opens the gossip menu -bool GossipHello_custom_example(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->PlayerTalkClass->SendGossipMenu(907,_Creature->GetGUID()); - - return true; -} - -//Our Recive emote function -bool ReceiveEmote_custom_example(Player *player, Creature *_Creature, uint32 emote) -{ - _Creature->HandleEmoteCommand(emote); - - if (emote == TEXTEMOTE_DANCE) - ((custom_exampleAI*)_Creature->AI())->DoSay(SAY_DANCE,LANG_UNIVERSAL,NULL); - - if (emote == TEXTEMOTE_SALUTE) - ((custom_exampleAI*)_Creature->AI())->DoSay(SAY_SALUTE,LANG_UNIVERSAL,NULL); - - 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 -//For example if you want this Script to handle Emotes you must include -//newscript->ReciveEmote = My_Emote_Function; -void AddSC_custom_example() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="custom_example"; - newscript->GetAI = GetAI_custom_example; - newscript->pGossipHello = &GossipHello_custom_example; - newscript->pGossipSelect = &GossipSelect_custom_example; - newscript->pReceiveEmote = &ReceiveEmote_custom_example; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Custom_Example +SD%Complete: 100 +SDComment: Short custom scripting example +SDCategory: Script Examples +EndScriptData */ + +#include "precompiled.h" + +// **** This script is designed as an example for others to build on **** +// **** Please modify whatever you'd like to as this script is only for developement **** + +// **** Script Info **** +// This script is written in a way that it can be used for both friendly and hostile monsters +// Its primary purpose is to show just how much you can really do with scripts +// I recommend trying it out on both an agressive NPC and on friendly npc + +// **** Quick Info **** +// Functions with Handled Function marked above them are functions that are called automatically by the core +// Functions that are marked Custom Function are functions I've created to simplify code + +#define SPELL_BUFF 25661 +#define SPELL_ONE 12555 +#define SPELL_ONE_ALT 24099 +#define SPELL_TWO 10017 +#define SPELL_THREE 26027 +#define SPELL_ENRAGE 23537 +#define SPELL_BESERK 32309 + +#define SAY_AGGRO "Let the games begin." +#define SAY_RANDOM_0 "I see endless suffering. I see torment. I see rage. I see everything." +#define SAY_RANDOM_1 "Muahahahaha" +#define SAY_RANDOM_2 "These mortal infedels my lord, they have invaded your sanctum and seek to steal your secrets." +#define SAY_RANDOM_3 "You are already dead." +#define SAY_RANDOM_4 "Where to go? What to do? So many choices that all end in pain, end in death." +#define SAY_BESERK "$N, I sentance you to death!" +#define SAY_PHASE "The suffering has just begun!" + +#define GOSSIP_ITEM "I'm looking for a fight" +#define SAY_DANCE "I always thought I was a good dancer" +#define SAY_SALUTE "Move out Soldier!" + +struct MANGOS_DLL_DECL custom_exampleAI : public ScriptedAI +{ + //*** HANDLED FUNCTION *** + //This is the constructor, called only once when the creature is first created + custom_exampleAI(Creature *c) : ScriptedAI(c) {Reset();} + + //*** CUSTOM VARIABLES **** + //These variables are for use only by this individual script. + //Nothing else will ever call them but us. + + uint32 Say_Timer; //Timer for random chat + uint32 Rebuff_Timer; //Timer for rebuffing + uint32 Spell_1_Timer; //Timer for spell 1 when in combat + uint32 Spell_2_Timer; //Timer for spell 1 when in combat + uint32 Spell_3_Timer; //Timer for spell 1 when in combat + uint32 Beserk_Timer; //Timer until we go into Beserk (enraged) mode + uint32 Phase; //The current battle phase we are in + uint32 Phase_Timer; //Timer until phase transition + + //*** HANDLED FUNCTION *** + //This is called whenever the core decides we need to evade + void Reset() + { + Phase = 1; //Start in phase 1 + Phase_Timer = 60000; //60 seconds + Spell_1_Timer = 5000; //5 seconds + Spell_2_Timer = 37000; //37 seconds + Spell_3_Timer = 19000; //19 seconds + Beserk_Timer = 120000; //2 minutes + } + + //*** HANDLED FUNCTION *** + //Attack Start is called whenever someone hits us. + void Aggro(Unit *who) + { + //Say some stuff + DoSay(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,8280); + } + + //*** 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 diff) + { + //Out of combat timers + if (!m_creature->getVictim()) + { + //Random Say timer + if (Say_Timer < diff) + { + //Random switch between 5 outcomes + switch (rand()%5) + { + case 0: + DoYell(SAY_RANDOM_0,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,8831); //8831 is the index of the sound we are playing. You find these numbers in SoundEntries.dbc + break; + + case 1: + DoYell(SAY_RANDOM_1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,8818); + break; + + case 2: + DoYell(SAY_RANDOM_2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,8041); + break; + + case 3: + DoYell(SAY_RANDOM_3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,8581); + break; + + case 4: + DoYell(SAY_RANDOM_4,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,8791); + break; + } + + Say_Timer = 45000; //Say something agian in 45 seconds + }else Say_Timer -= diff; + + //Rebuff timer + if (Rebuff_Timer < diff) + { + DoCast(m_creature,SPELL_BUFF); + Rebuff_Timer = 900000; //Rebuff agian in 15 minutes + }else Rebuff_Timer -= diff; + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Spell 1 timer + if (Spell_1_Timer < diff) + { + //Cast spell one on our current target. + if (rand()%50 > 10) + DoCast(m_creature->getVictim(),SPELL_ONE_ALT); + else if (m_creature->GetDistance(m_creature->getVictim()) < 25) + DoCast(m_creature->getVictim(),SPELL_ONE); + + Spell_1_Timer = 5000; + }else Spell_1_Timer -= diff; + + //Spell 2 timer + if (Spell_2_Timer < diff) + { + //Cast spell one on our current target. + DoCast(m_creature->getVictim(),SPELL_TWO); + + Spell_2_Timer = 37000; + }else Spell_2_Timer -= diff; + + //Spell 3 timer + if (Phase > 1) + if (Spell_3_Timer < diff) + { + //Cast spell one on our current target. + DoCast(m_creature->getVictim(),SPELL_THREE); + + Spell_3_Timer = 19000; + }else Spell_3_Timer -= diff; + + //Beserk timer + if (Phase > 1) + if (Beserk_Timer < diff) + { + //Say our line then cast uber death spell + DoPlaySoundToSet(m_creature,8588); + DoYell(SAY_BESERK,LANG_UNIVERSAL,m_creature->getVictim()); + DoCast(m_creature->getVictim(),SPELL_BESERK); + + //Cast our beserk spell agian in 12 seconds if we didn't kill everyone + Beserk_Timer = 12000; + }else Beserk_Timer -= diff; + + //Phase timer + if (Phase == 1) + if (Phase_Timer < diff) + { + //Go to next phase + Phase++; + DoYell(SAY_PHASE,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_ENRAGE); + }else Phase_Timer -= diff; + + 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 +CreatureAI* GetAI_custom_example(Creature *_Creature) +{ + return new custom_exampleAI (_Creature); +} + +//This function is called when the player clicks an option on the gossip menu +void SendDefaultMenu_custom_example(Player *player, Creature *_Creature, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) //Fight time + { + //Set our faction to hostile twoards all + _Creature->setFaction(24); + _Creature->Attack(player, true); + player->PlayerTalkClass->CloseGossip(); + } +} + +//This function is called when the player clicks an option on the gossip menu +bool GossipSelect_custom_example(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (sender == GOSSIP_SENDER_MAIN) + SendDefaultMenu_custom_example(player, _Creature, action); + + return true; +} + +//This function is called when the player opens the gossip menu +bool GossipHello_custom_example(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->PlayerTalkClass->SendGossipMenu(907,_Creature->GetGUID()); + + return true; +} + +//Our Recive emote function +bool ReceiveEmote_custom_example(Player *player, Creature *_Creature, uint32 emote) +{ + _Creature->HandleEmoteCommand(emote); + + if (emote == TEXTEMOTE_DANCE) + ((custom_exampleAI*)_Creature->AI())->DoSay(SAY_DANCE,LANG_UNIVERSAL,NULL); + + if (emote == TEXTEMOTE_SALUTE) + ((custom_exampleAI*)_Creature->AI())->DoSay(SAY_SALUTE,LANG_UNIVERSAL,NULL); + + 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 +//For example if you want this Script to handle Emotes you must include +//newscript->ReciveEmote = My_Emote_Function; +void AddSC_custom_example() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="custom_example"; + newscript->GetAI = GetAI_custom_example; + newscript->pGossipHello = &GossipHello_custom_example; + newscript->pGossipSelect = &GossipSelect_custom_example; + newscript->pReceiveEmote = &ReceiveEmote_custom_example; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/custom/custom_gossip_codebox.cpp b/src/bindings/scripts/scripts/custom/custom_gossip_codebox.cpp index a61871a71c3..31be3a284b0 100644 --- a/src/bindings/scripts/scripts/custom/custom_gossip_codebox.cpp +++ b/src/bindings/scripts/scripts/custom/custom_gossip_codebox.cpp @@ -1,81 +1,81 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Custom_Gossip_Codebox -SD%Complete: 100 -SDComment: Show a codebox in gossip option -SDCategory: Script Examples -EndScriptData */ - -#include "precompiled.h" -#include - -//This function is called when the player opens the gossip menubool -bool GossipHello_custom_gossip_codebox(Player *player, Creature *_Creature) -{ - player->PlayerTalkClass->GetGossipMenu()->AddMenuItem(0, "A quiz: what's your name?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1, "", 0, true); - player->ADD_GOSSIP_ITEM(0, "I'm not interested", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - player->PlayerTalkClass->SendGossipMenu(907,_Creature->GetGUID()); - return true; -} - -//This function is called when the player clicks an option on the gossip menubool -bool GossipSelect_custom_gossip_codebox(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if(action == GOSSIP_ACTION_INFO_DEF+2) - { - _Creature->Say("Normal select, guess you're not interested.", LANG_UNIVERSAL, 0); - player->CLOSE_GOSSIP_MENU(); - } - return true; -} - -bool GossipSelectWithCode_custom_gossip_codebox( Player *player, Creature *_Creature, uint32 sender, uint32 action, const char* sCode ) -{ - if(sender == GOSSIP_SENDER_MAIN) - { - if(action == GOSSIP_ACTION_INFO_DEF+1) - { - if(std::strcmp(sCode, player->GetName())!=0) - { - _Creature->Say("Wrong!", LANG_UNIVERSAL, 0); - _Creature->CastSpell(player, 12826, true); - } - else - { - _Creature->Say("You're right, you are allowed to see my inner secrets.", LANG_UNIVERSAL, 0); - _Creature->CastSpell(player, 26990, true); - } - player->CLOSE_GOSSIP_MENU(); - return true; - } - } - return false; -} - -void AddSC_custom_gossip_codebox() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="custom_gossip_codebox"; - newscript->pGossipHello = &GossipHello_custom_gossip_codebox; - newscript->pGossipSelect = &GossipSelect_custom_gossip_codebox; - newscript->pGossipSelectWithCode = &GossipSelectWithCode_custom_gossip_codebox; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Custom_Gossip_Codebox +SD%Complete: 100 +SDComment: Show a codebox in gossip option +SDCategory: Script Examples +EndScriptData */ + +#include "precompiled.h" +#include + +//This function is called when the player opens the gossip menubool +bool GossipHello_custom_gossip_codebox(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM_EXTENDED(0, "A quiz: what's your name?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1, "", 0, true); + player->ADD_GOSSIP_ITEM(0, "I'm not interested", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + + player->PlayerTalkClass->SendGossipMenu(907,_Creature->GetGUID()); + return true; +} + +//This function is called when the player clicks an option on the gossip menubool +bool GossipSelect_custom_gossip_codebox(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if(action == GOSSIP_ACTION_INFO_DEF+2) + { + _Creature->Say("Normal select, guess you're not interested.", LANG_UNIVERSAL, 0); + player->CLOSE_GOSSIP_MENU(); + } + return true; +} + +bool GossipSelectWithCode_custom_gossip_codebox( Player *player, Creature *_Creature, uint32 sender, uint32 action, const char* sCode ) +{ + if(sender == GOSSIP_SENDER_MAIN) + { + if(action == GOSSIP_ACTION_INFO_DEF+1) + { + if(std::strcmp(sCode, player->GetName())!=0) + { + _Creature->Say("Wrong!", LANG_UNIVERSAL, 0); + _Creature->CastSpell(player, 12826, true); + } + else + { + _Creature->Say("You're right, you are allowed to see my inner secrets.", LANG_UNIVERSAL, 0); + _Creature->CastSpell(player, 26990, true); + } + player->CLOSE_GOSSIP_MENU(); + return true; + } + } + return false; +} + +void AddSC_custom_gossip_codebox() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="custom_gossip_codebox"; + newscript->pGossipHello = &GossipHello_custom_gossip_codebox; + newscript->pGossipSelect = &GossipSelect_custom_gossip_codebox; + newscript->pGossipSelectWithCode = &GossipSelectWithCode_custom_gossip_codebox; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/custom/test.cpp b/src/bindings/scripts/scripts/custom/test.cpp index 97876ca0c90..0adf1a07c5a 100644 --- a/src/bindings/scripts/scripts/custom/test.cpp +++ b/src/bindings/scripts/scripts/custom/test.cpp @@ -1,202 +1,200 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Test -SD%Complete: 100 -SDComment: Script used for testing escortAI -SDCategory: Script Examples -EndScriptData */ - -#include "precompiled.h" -#include "../npc/npc_escortAI.h" - -struct MANGOS_DLL_DECL npc_testAI : public npc_escortAI -{ - public: - - // CreatureAI functions - npc_testAI(Creature *c) : npc_escortAI(c) {Reset();} - - uint32 DeathCoilTimer; - uint32 ChatTimer; - - // Pure Virtual Functions - void WaypointReached(uint32 i) - { - switch (i) - { - case 1: - m_creature->Say("Hmm a nice day for a walk alright", LANG_UNIVERSAL, 0); - break; - - case 3: - { - m_creature->Say("Wild Felboar attack!", LANG_UNIVERSAL, 0); - Creature* temp = m_creature->SummonCreature(21878, m_creature->GetPositionX()+5, m_creature->GetPositionY()+7, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000); - - temp->AI()->AttackStart(m_creature); - } - break; - - case 4: - { - m_creature->Say("Time for me to go! See ya around $N!", LANG_UNIVERSAL, PlayerGUID); - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); - - Unit* temp = Unit::GetUnit(*m_creature, PlayerGUID); - if (temp) - { - temp->MonsterSay("Bye Bye!", LANG_UNIVERSAL, 0); - temp->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); - } - } - break; - } - } - - void Aggro(Unit*) - { - if (IsBeingEscorted) - m_creature->Say("Help $N! I'm under attack!", LANG_UNIVERSAL, PlayerGUID); - else m_creature->Say("Die scum!", LANG_UNIVERSAL, 0); - } - - void Reset() - { - DeathCoilTimer = 4000; - ChatTimer = 4000; - } - - void JustDied(Unit* killer) - { - if (IsBeingEscorted) - { - //killer = m_creature when player got to far from creature - if (killer == m_creature) - { - Unit *pTemp = Unit::GetUnit(*m_creature,PlayerGUID); - if( pTemp ) - DoWhisper("How dare you leave me like that! I hate you! =*(", pTemp); - } - else m_creature->Say("...no...how could you let me die $N", LANG_UNIVERSAL, PlayerGUID); - } - else m_creature->Say("ugh...", LANG_UNIVERSAL, 0); - } - - void UpdateAI(const uint32 diff) - { - //Must update npc_escortAI - npc_escortAI::UpdateAI(diff); - - //Combat check - if (InCombat && m_creature->getVictim()) - { - if (DeathCoilTimer < diff) - { - m_creature->Say("Taste death!", LANG_UNIVERSAL, 0); - m_creature->CastSpell(m_creature->getVictim(), 33130, false); - - DeathCoilTimer = 4000; - }else DeathCoilTimer -= diff; - }else - { - //Out of combat but being escorted - if (IsBeingEscorted) - if (ChatTimer < diff) - { - if (m_creature->HasAura(3593, 0)) - { - m_creature->Say("Fireworks!", LANG_UNIVERSAL, 0); - m_creature->CastSpell(m_creature, 11540, false); - }else - { - m_creature->Say("Hmm, I think I could use a buff", LANG_UNIVERSAL, 0); - m_creature->CastSpell(m_creature, 3593, false); - } - - ChatTimer = 12000; - }else ChatTimer -= diff; - } - } -}; - -CreatureAI* GetAI_test(Creature *_Creature) -{ - npc_testAI* testAI = new npc_testAI(_Creature); - - testAI->AddWaypoint(0, 1231, -4419, 23); - testAI->AddWaypoint(1, 1198, -4440, 23, 0); - testAI->AddWaypoint(2, 1208, -4392, 23); - testAI->AddWaypoint(3, 1231, -4419, 23, 5000); - testAI->AddWaypoint(4, 1208, -4392, 23, 5000); - - return (CreatureAI*)testAI; -} - -bool GossipHello_npc_test(Player *player, Creature *_Creature) -{ - player->TalkedToCreature(_Creature->GetEntry(),_Creature->GetGUID()); - _Creature->prepareGossipMenu(player,0); - - player->PlayerTalkClass->GetGossipMenu()->AddMenuItem(0, "Click to Test Escort(Attack, Defend, Run)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1,"",0); - - player->PlayerTalkClass->GetGossipMenu()->AddMenuItem(0, "Click to Test Escort(NoAttack, NoDefend, Walk)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2,"",0); - - player->PlayerTalkClass->GetGossipMenu()->AddMenuItem(0, "Click to Test Escort(NoAttack, Defend, Walk)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3,"",0); - - _Creature->sendPreparedGossip( player ); - return true; -} - -bool GossipSelect_npc_test(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - ((npc_escortAI*)(_Creature->AI()))->Start(true, true, true, player->GetGUID()); - - return true; // prevent mangos core handling - } - - if (action == GOSSIP_ACTION_INFO_DEF+2) - { - player->CLOSE_GOSSIP_MENU(); - ((npc_escortAI*)(_Creature->AI()))->Start(false, false, false, player->GetGUID()); - - return true; // prevent mangos core handling - } - - if (action == GOSSIP_ACTION_INFO_DEF+3) - { - player->CLOSE_GOSSIP_MENU(); - ((npc_escortAI*)(_Creature->AI()))->Start(false, true, false, player->GetGUID()); - - return true; // prevent mangos core handling - } - return false; -} - -void AddSC_test() -{ - Script *newscript; - newscript = new Script; - newscript->Name="test"; - newscript->GetAI = GetAI_test; - newscript->pGossipHello = &GossipHello_npc_test; - newscript->pGossipSelect = &GossipSelect_npc_test; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Test +SD%Complete: 100 +SDComment: Script used for testing escortAI +SDCategory: Script Examples +EndScriptData */ + +#include "precompiled.h" +#include "../npc/npc_escortAI.h" + +struct MANGOS_DLL_DECL npc_testAI : public npc_escortAI +{ + public: + + // CreatureAI functions + npc_testAI(Creature *c) : npc_escortAI(c) {Reset();} + + uint32 DeathCoilTimer; + uint32 ChatTimer; + + // Pure Virtual Functions + void WaypointReached(uint32 i) + { + switch (i) + { + case 1: + m_creature->Say("Hmm a nice day for a walk alright", LANG_UNIVERSAL, 0); + break; + + case 3: + { + m_creature->Say("Wild Felboar attack!", LANG_UNIVERSAL, 0); + Creature* temp = m_creature->SummonCreature(21878, m_creature->GetPositionX()+5, m_creature->GetPositionY()+7, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000); + + temp->AI()->AttackStart(m_creature); + } + break; + + case 4: + { + m_creature->Say("Time for me to go! See ya around $N!", LANG_UNIVERSAL, PlayerGUID); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); + + Unit* temp = Unit::GetUnit(*m_creature, PlayerGUID); + if (temp) + { + temp->MonsterSay("Bye Bye!", LANG_UNIVERSAL, 0); + temp->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); + } + } + break; + } + } + + void Aggro(Unit*) + { + if (IsBeingEscorted) + m_creature->Say("Help $N! I'm under attack!", LANG_UNIVERSAL, PlayerGUID); + else m_creature->Say("Die scum!", LANG_UNIVERSAL, 0); + } + + void Reset() + { + DeathCoilTimer = 4000; + ChatTimer = 4000; + } + + void JustDied(Unit* killer) + { + if (IsBeingEscorted) + { + //killer = m_creature when player got to far from creature + if (killer == m_creature) + { + Unit *pTemp = Unit::GetUnit(*m_creature,PlayerGUID); + if( pTemp ) + DoWhisper("How dare you leave me like that! I hate you! =*(", pTemp); + } + else m_creature->Say("...no...how could you let me die $N", LANG_UNIVERSAL, PlayerGUID); + } + else m_creature->Say("ugh...", LANG_UNIVERSAL, 0); + } + + void UpdateAI(const uint32 diff) + { + //Must update npc_escortAI + npc_escortAI::UpdateAI(diff); + + //Combat check + if (InCombat && m_creature->getVictim()) + { + if (DeathCoilTimer < diff) + { + m_creature->Say("Taste death!", LANG_UNIVERSAL, 0); + m_creature->CastSpell(m_creature->getVictim(), 33130, false); + + DeathCoilTimer = 4000; + }else DeathCoilTimer -= diff; + }else + { + //Out of combat but being escorted + if (IsBeingEscorted) + if (ChatTimer < diff) + { + if (m_creature->HasAura(3593, 0)) + { + m_creature->Say("Fireworks!", LANG_UNIVERSAL, 0); + m_creature->CastSpell(m_creature, 11540, false); + }else + { + m_creature->Say("Hmm, I think I could use a buff", LANG_UNIVERSAL, 0); + m_creature->CastSpell(m_creature, 3593, false); + } + + ChatTimer = 12000; + }else ChatTimer -= diff; + } + } +}; + +CreatureAI* GetAI_test(Creature *_Creature) +{ + npc_testAI* testAI = new npc_testAI(_Creature); + + testAI->AddWaypoint(0, 1231, -4419, 23); + testAI->AddWaypoint(1, 1198, -4440, 23, 0); + testAI->AddWaypoint(2, 1208, -4392, 23); + testAI->AddWaypoint(3, 1231, -4419, 23, 5000); + testAI->AddWaypoint(4, 1208, -4392, 23, 5000); + + return (CreatureAI*)testAI; +} + +bool GossipHello_npc_test(Player *player, Creature *_Creature) +{ + player->TalkedToCreature(_Creature->GetEntry(),_Creature->GetGUID()); + _Creature->prepareGossipMenu(player,0); + + player->ADD_GOSSIP_ITEM(0, "Click to Test Escort(Attack, Defend, Run)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM(0, "Click to Test Escort(NoAttack, NoDefend, Walk)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->ADD_GOSSIP_ITEM(0, "Click to Test Escort(NoAttack, Defend, Walk)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + + _Creature->sendPreparedGossip( player ); + return true; +} + +bool GossipSelect_npc_test(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + ((npc_escortAI*)(_Creature->AI()))->Start(true, true, true, player->GetGUID()); + + return true; // prevent mangos core handling + } + + if (action == GOSSIP_ACTION_INFO_DEF+2) + { + player->CLOSE_GOSSIP_MENU(); + ((npc_escortAI*)(_Creature->AI()))->Start(false, false, false, player->GetGUID()); + + return true; // prevent mangos core handling + } + + if (action == GOSSIP_ACTION_INFO_DEF+3) + { + player->CLOSE_GOSSIP_MENU(); + ((npc_escortAI*)(_Creature->AI()))->Start(false, true, false, player->GetGUID()); + + return true; // prevent mangos core handling + } + return false; +} + +void AddSC_test() +{ + Script *newscript; + newscript = new Script; + newscript->Name="test"; + newscript->GetAI = GetAI_test; + newscript->pGossipHello = &GossipHello_npc_test; + newscript->pGossipSelect = &GossipSelect_npc_test; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/go/go_scripts.cpp b/src/bindings/scripts/scripts/go/go_scripts.cpp index 158f7fbca36..88949f08392 100644 --- a/src/bindings/scripts/scripts/go/go_scripts.cpp +++ b/src/bindings/scripts/scripts/go/go_scripts.cpp @@ -1,209 +1,209 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: GO_Scripts -SD%Complete: 100 -SDComment: Quest support: 4285,4287,4288(crystal pylons), 4296. Field_Repair_Bot->Teaches spell 22704. Barov_journal->Teaches spell 26089 -SDCategory: Game Objects -EndScriptData */ - -/* ContentData -go_northern_crystal_pylon -go_eastern_crystal_pylon -go_western_crystal_pylon -go_barov_journal -go_field_repair_bot_74A -go_orb_of_command -go_tablet_of_madness -go_tablet_of_the_seven -go_teleporter -EndContentData */ - -#include "precompiled.h" - -/*###### -## go_crystal_pylons (3x) -######*/ - -bool GOHello_go_northern_crystal_pylon(Player *player, GameObject* _GO) -{ - if (_GO->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) - { - player->PrepareQuestMenu(_GO->GetGUID()); - player->SendPreparedQuest(_GO->GetGUID()); - } - - if (player->GetQuestStatus(4285) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(4285); - - return true; -} - -bool GOHello_go_eastern_crystal_pylon(Player *player, GameObject* _GO) -{ - if (_GO->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) - { - player->PrepareQuestMenu(_GO->GetGUID()); - player->SendPreparedQuest(_GO->GetGUID()); - } - - if (player->GetQuestStatus(4287) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(4287); - - return true; -} - -bool GOHello_go_western_crystal_pylon(Player *player, GameObject* _GO) -{ - if (_GO->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) - { - player->PrepareQuestMenu(_GO->GetGUID()); - player->SendPreparedQuest(_GO->GetGUID()); - } - - if (player->GetQuestStatus(4288) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(4288); - - return true; -} - -/*###### -## go_barov_journal -######*/ - -bool GOHello_go_barov_journal(Player *player, GameObject* _GO) -{ - if(player->HasSkill(SKILL_TAILORING) && player->GetBaseSkillValue(SKILL_TAILORING) >= 280 && !player->HasSpell(26086)) - { - player->CastSpell(player,26095,false); - } - return true; -} - -/*###### -## go_field_repair_bot_74A -######*/ - -bool GOHello_go_field_repair_bot_74A(Player *player, GameObject* _GO) -{ - if(player->HasSkill(SKILL_ENGINERING) && player->GetBaseSkillValue(SKILL_ENGINERING) >= 300 && !player->HasSpell(22704)) - { - player->CastSpell(player,22864,false); - } - return true; -} - -/*###### -## go_orb_of_command -######*/ - -bool GOHello_go_orb_of_command(Player *player, GameObject* _GO) -{ - if( player->GetQuestRewardStatus(7761) ) - player->CastSpell(player,23460,true); - - return true; -} - -/*###### -## go_tablet_of_madness -######*/ - -bool GOHello_go_tablet_of_madness(Player *player, GameObject* _GO) -{ - if (player->HasSkill(SKILL_ALCHEMY) && player->GetSkillValue(SKILL_ALCHEMY) >= 300 && !player->HasSpell(24266)) - { - player->CastSpell(player,24267,false); - } - return true; -} - -/*###### -## go_tablet_of_the_seven -######*/ - -//TODO: use gossip option ("Transcript the Tablet") instead, if Mangos adds support. -bool GOHello_go_tablet_of_the_seven(Player *player, GameObject* _GO) -{ - if (_GO->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) - return true; - - if (player->GetQuestStatus(4296) == QUEST_STATUS_INCOMPLETE) - player->CastSpell(player,15065,false); - - return true; -} - -/*###### -## go_teleporter -######*/ - -bool GOHello_go_teleporter(Player *player, GameObject* _GO) -{ - player->TeleportTo(0, 1807.07f,336.105f,70.3975f,0.0f); - return false; -} - -void AddSC_go_scripts() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="go_northern_crystal_pylon"; - newscript->pGOHello = &GOHello_go_northern_crystal_pylon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_eastern_crystal_pylon"; - newscript->pGOHello = &GOHello_go_eastern_crystal_pylon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_western_crystal_pylon"; - newscript->pGOHello = &GOHello_go_western_crystal_pylon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_barov_journal"; - newscript->pGOHello = &GOHello_go_barov_journal; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_field_repair_bot_74A"; - newscript->pGOHello = &GOHello_go_field_repair_bot_74A; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_orb_of_command"; - newscript->pGOHello = &GOHello_go_orb_of_command; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_tablet_of_madness"; - newscript->pGOHello = GOHello_go_tablet_of_madness; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_tablet_of_the_seven"; - newscript->pGOHello = GOHello_go_tablet_of_the_seven; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_teleporter"; - newscript->pGOHello = GOHello_go_teleporter; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: GO_Scripts +SD%Complete: 100 +SDComment: Quest support: 4285,4287,4288(crystal pylons), 4296. Field_Repair_Bot->Teaches spell 22704. Barov_journal->Teaches spell 26089 +SDCategory: Game Objects +EndScriptData */ + +/* ContentData +go_northern_crystal_pylon +go_eastern_crystal_pylon +go_western_crystal_pylon +go_barov_journal +go_field_repair_bot_74A +go_orb_of_command +go_tablet_of_madness +go_tablet_of_the_seven +go_teleporter +EndContentData */ + +#include "precompiled.h" + +/*###### +## go_crystal_pylons (3x) +######*/ + +bool GOHello_go_northern_crystal_pylon(Player *player, GameObject* _GO) +{ + if (_GO->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) + { + player->PrepareQuestMenu(_GO->GetGUID()); + player->SendPreparedQuest(_GO->GetGUID()); + } + + if (player->GetQuestStatus(4285) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(4285); + + return true; +} + +bool GOHello_go_eastern_crystal_pylon(Player *player, GameObject* _GO) +{ + if (_GO->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) + { + player->PrepareQuestMenu(_GO->GetGUID()); + player->SendPreparedQuest(_GO->GetGUID()); + } + + if (player->GetQuestStatus(4287) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(4287); + + return true; +} + +bool GOHello_go_western_crystal_pylon(Player *player, GameObject* _GO) +{ + if (_GO->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) + { + player->PrepareQuestMenu(_GO->GetGUID()); + player->SendPreparedQuest(_GO->GetGUID()); + } + + if (player->GetQuestStatus(4288) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(4288); + + return true; +} + +/*###### +## go_barov_journal +######*/ + +bool GOHello_go_barov_journal(Player *player, GameObject* _GO) +{ + if(player->HasSkill(SKILL_TAILORING) && player->GetBaseSkillValue(SKILL_TAILORING) >= 280 && !player->HasSpell(26086)) + { + player->CastSpell(player,26095,false); + } + return true; +} + +/*###### +## go_field_repair_bot_74A +######*/ + +bool GOHello_go_field_repair_bot_74A(Player *player, GameObject* _GO) +{ + if(player->HasSkill(SKILL_ENGINERING) && player->GetBaseSkillValue(SKILL_ENGINERING) >= 300 && !player->HasSpell(22704)) + { + player->CastSpell(player,22864,false); + } + return true; +} + +/*###### +## go_orb_of_command +######*/ + +bool GOHello_go_orb_of_command(Player *player, GameObject* _GO) +{ + if( player->GetQuestRewardStatus(7761) ) + player->CastSpell(player,23460,true); + + return true; +} + +/*###### +## go_tablet_of_madness +######*/ + +bool GOHello_go_tablet_of_madness(Player *player, GameObject* _GO) +{ + if (player->HasSkill(SKILL_ALCHEMY) && player->GetSkillValue(SKILL_ALCHEMY) >= 300 && !player->HasSpell(24266)) + { + player->CastSpell(player,24267,false); + } + return true; +} + +/*###### +## go_tablet_of_the_seven +######*/ + +//TODO: use gossip option ("Transcript the Tablet") instead, if Mangos adds support. +bool GOHello_go_tablet_of_the_seven(Player *player, GameObject* _GO) +{ + if (_GO->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) + return true; + + if (player->GetQuestStatus(4296) == QUEST_STATUS_INCOMPLETE) + player->CastSpell(player,15065,false); + + return true; +} + +/*###### +## go_teleporter +######*/ + +bool GOHello_go_teleporter(Player *player, GameObject* _GO) +{ + player->TeleportTo(0, 1807.07f,336.105f,70.3975f,0.0f); + return false; +} + +void AddSC_go_scripts() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="go_northern_crystal_pylon"; + newscript->pGOHello = &GOHello_go_northern_crystal_pylon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_eastern_crystal_pylon"; + newscript->pGOHello = &GOHello_go_eastern_crystal_pylon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_western_crystal_pylon"; + newscript->pGOHello = &GOHello_go_western_crystal_pylon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_barov_journal"; + newscript->pGOHello = &GOHello_go_barov_journal; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_field_repair_bot_74A"; + newscript->pGOHello = &GOHello_go_field_repair_bot_74A; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_orb_of_command"; + newscript->pGOHello = &GOHello_go_orb_of_command; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_tablet_of_madness"; + newscript->pGOHello = GOHello_go_tablet_of_madness; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_tablet_of_the_seven"; + newscript->pGOHello = GOHello_go_tablet_of_the_seven; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_teleporter"; + newscript->pGOHello = GOHello_go_teleporter; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/guard/guard_ai.cpp b/src/bindings/scripts/scripts/guard/guard_ai.cpp index 7a9d1210bf1..18b18d69fdf 100644 --- a/src/bindings/scripts/scripts/guard/guard_ai.cpp +++ b/src/bindings/scripts/scripts/guard/guard_ai.cpp @@ -1,160 +1,160 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Guard_AI -SD%Complete: 90 -SDComment: -SDCategory: Guards -EndScriptData */ - -#include "precompiled.h" -#include "guard_ai.h" - -// **** This script is for use within every single guard to save coding time **** - -#define GENERIC_CREATURE_COOLDOWN 5000 - -void guardAI::Reset() -{ - GlobalCooldown = 0; - BuffTimer = 0; //Rebuff as soon as we can -} - -void guardAI::Aggro(Unit *who) -{ -} - -void guardAI::JustDied(Unit *Killer) -{ - //Send Zone Under Attack message to the LocalDefense and WorldDefense Channels - if( Killer->GetTypeId() == TYPEID_PLAYER ) - m_creature->SendZoneUnderAttackMessage((Player*)Killer); - else if( Unit *owner = Killer->GetOwner() ) - { - if( owner->GetTypeId() == TYPEID_PLAYER ) - m_creature->SendZoneUnderAttackMessage((Player*)owner); - } -} - -void guardAI::UpdateAI(const uint32 diff) -{ - //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 - if (m_creature->isAlive() && !InCombat) - 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); - - if (info && !GlobalCooldown) - { - //Cast the buff spell - DoCastSpell(m_creature, info); - - //Set our global cooldown - GlobalCooldown = GENERIC_CREATURE_COOLDOWN; - - //Set our timer to 10 minutes before rebuff - BuffTimer = 600000; - } //Try agian in 30 seconds - else BuffTimer = 30000; - }else BuffTimer -= diff; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - // Make sure our attack is ready and we arn't currently casting - if( m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false)) - { - //If we are within range melee the target - if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - bool Healing = false; - SpellEntry const *info = NULL; - - //Select a healing spell if less than 30% hp - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30) - 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 - if (info) Healing = true; - else info = 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 - if (info && rand() % 5 == 0 && !GlobalCooldown) - { - //Cast the spell - if (Healing)DoCastSpell(m_creature, info); - else DoCastSpell(m_creature->getVictim(), info); - - //Set our global cooldown - GlobalCooldown = GENERIC_CREATURE_COOLDOWN; - } - else m_creature->AttackerStateUpdate(m_creature->getVictim()); - - m_creature->resetAttackTimer(); - } - } - else - { - //Only run this code if we arn't already casting - if (!m_creature->IsNonMeleeSpellCasted(false)) - { - bool Healing = false; - SpellEntry const *info = NULL; - - //Select a healing spell if less than 30% hp ONLY 33% of the time - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30 && rand() % 3 == 0) - 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); - - //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 ((*m_creature).GetMotionMaster()->GetCurrentMovementGeneratorType()!=IDLE_MOTION_TYPE) - { - (*m_creature).GetMotionMaster()->Clear(false); - (*m_creature).GetMotionMaster()->MoveIdle(); - } - - //Cast spell - if (Healing) DoCastSpell(m_creature,info); - else DoCastSpell(m_creature->getVictim(),info); - - //Set our global cooldown - GlobalCooldown = GENERIC_CREATURE_COOLDOWN; - - } //If no spells available and we arn't moving run to target - else if ((*m_creature).GetMotionMaster()->GetCurrentMovementGeneratorType()!=TARGETED_MOTION_TYPE) - { - //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()); - } - } - } -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Guard_AI +SD%Complete: 90 +SDComment: +SDCategory: Guards +EndScriptData */ + +#include "precompiled.h" +#include "guard_ai.h" + +// **** This script is for use within every single guard to save coding time **** + +#define GENERIC_CREATURE_COOLDOWN 5000 + +void guardAI::Reset() +{ + GlobalCooldown = 0; + BuffTimer = 0; //Rebuff as soon as we can +} + +void guardAI::Aggro(Unit *who) +{ +} + +void guardAI::JustDied(Unit *Killer) +{ + //Send Zone Under Attack message to the LocalDefense and WorldDefense Channels + if( Killer->GetTypeId() == TYPEID_PLAYER ) + m_creature->SendZoneUnderAttackMessage((Player*)Killer); + else if( Unit *owner = Killer->GetOwner() ) + { + if( owner->GetTypeId() == TYPEID_PLAYER ) + m_creature->SendZoneUnderAttackMessage((Player*)owner); + } +} + +void guardAI::UpdateAI(const uint32 diff) +{ + //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 + if (m_creature->isAlive() && !InCombat) + 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); + + if (info && !GlobalCooldown) + { + //Cast the buff spell + DoCastSpell(m_creature, info); + + //Set our global cooldown + GlobalCooldown = GENERIC_CREATURE_COOLDOWN; + + //Set our timer to 10 minutes before rebuff + BuffTimer = 600000; + } //Try agian in 30 seconds + else BuffTimer = 30000; + }else BuffTimer -= diff; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + // Make sure our attack is ready and we arn't currently casting + if( m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false)) + { + //If we are within range melee the target + if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + { + bool Healing = false; + SpellEntry const *info = NULL; + + //Select a healing spell if less than 30% hp + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30) + 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 + if (info) Healing = true; + else info = 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 + if (info && rand() % 5 == 0 && !GlobalCooldown) + { + //Cast the spell + if (Healing)DoCastSpell(m_creature, info); + else DoCastSpell(m_creature->getVictim(), info); + + //Set our global cooldown + GlobalCooldown = GENERIC_CREATURE_COOLDOWN; + } + else m_creature->AttackerStateUpdate(m_creature->getVictim()); + + m_creature->resetAttackTimer(); + } + } + else + { + //Only run this code if we arn't already casting + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + bool Healing = false; + SpellEntry const *info = NULL; + + //Select a healing spell if less than 30% hp ONLY 33% of the time + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30 && rand() % 3 == 0) + 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); + + //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 ((*m_creature).GetMotionMaster()->GetCurrentMovementGeneratorType()!=IDLE_MOTION_TYPE) + { + (*m_creature).GetMotionMaster()->Clear(false); + (*m_creature).GetMotionMaster()->MoveIdle(); + } + + //Cast spell + if (Healing) DoCastSpell(m_creature,info); + else DoCastSpell(m_creature->getVictim(),info); + + //Set our global cooldown + GlobalCooldown = GENERIC_CREATURE_COOLDOWN; + + } //If no spells available and we arn't moving run to target + else if ((*m_creature).GetMotionMaster()->GetCurrentMovementGeneratorType()!=TARGETED_MOTION_TYPE) + { + //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()); + } + } + } +} diff --git a/src/bindings/scripts/scripts/guard/guard_ai.h b/src/bindings/scripts/scripts/guard/guard_ai.h index 80f88247945..9c6cca8f8ce 100644 --- a/src/bindings/scripts/scripts/guard/guard_ai.h +++ b/src/bindings/scripts/scripts/guard/guard_ai.h @@ -1,25 +1,25 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_GUARDAI_H -#define SC_GUARDAI_H - -#define GENERIC_CREATURE_COOLDOWN 5000 - -struct MANGOS_DLL_DECL guardAI : public ScriptedAI -{ - guardAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 GlobalCooldown; //This variable acts like the global cooldown that players have (1.5 seconds) - uint32 BuffTimer; //This variable keeps track of buffs - - void Reset(); - - void Aggro(Unit *who); - - void JustDied(Unit *Killer); - - void UpdateAI(const uint32 diff); -}; -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_GUARDAI_H +#define SC_GUARDAI_H + +#define GENERIC_CREATURE_COOLDOWN 5000 + +struct MANGOS_DLL_DECL guardAI : public ScriptedAI +{ + guardAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 GlobalCooldown; //This variable acts like the global cooldown that players have (1.5 seconds) + uint32 BuffTimer; //This variable keeps track of buffs + + void Reset(); + + void Aggro(Unit *who); + + void JustDied(Unit *Killer); + + void UpdateAI(const uint32 diff); +}; +#endif diff --git a/src/bindings/scripts/scripts/guard/guards.cpp b/src/bindings/scripts/scripts/guard/guards.cpp index ccd231fc166..7b528c1392a 100644 --- a/src/bindings/scripts/scripts/guard/guards.cpp +++ b/src/bindings/scripts/scripts/guard/guards.cpp @@ -1,4117 +1,4117 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Guards -SD%Complete: 100 -SDComment: All Guard gossip data, quite some npc_text-id's still missing, adding constantly as new id's are known. CombatAI should be organized better for future. -SDCategory: Guards -EndScriptData */ - -/* ContentData -guard_azuremyst -guard_bluffwatcher -guard_contested -guard_darnassus -guard_dunmorogh -guard_durotar -guard_elwynnforest -guard_eversong -guard_exodar -guard_ironforge -guard_mulgore -guard_orgrimmar -guard_shattrath -guard_shattrath_aldor -guard_shattrath_scryer -guard_silvermoon -guard_stormwind -guard_teldrassil -guard_tirisfal -guard_undercity -EndContentData */ - -#include "precompiled.h" -#include "guard_ai.h" - -//script spesific action -#define GOSSIP_ACTION_TAVERN 101 -#define GOSSIP_ACTION_GEMMERCHANT 102 -#define GOSSIP_ACTION_MANALOOM 103 - -//script spesific sender -#define GOSSIP_SENDER_SEC_GEMMERCHANT 101 -#define GOSSIP_SENDER_SEC_AUCTIONHOUSE 102 - -//script spesific gossip text -#define GOSSIP_TEXT_TAVERN "Worlds End Tavern" -#define GOSSIP_TEXT_BANKSCYERS "Scyers bank" -#define GOSSIP_TEXT_BANKALDOR "Aldor Bank" -#define GOSSIP_TEXT_INNSCYERS "Scyers Inn" -#define GOSSIP_TEXT_INNALDOR "Aldor Inn" -#define GOSSIP_TEXT_STABLESCYERS "Scyers Stable" -#define GOSSIP_TEXT_STABLEALDOR "Aldor Stable" -#define GOSSIP_TEXT_BATTLEMASTERALLIANCE "Alliance Battlemasters" -#define GOSSIP_TEXT_BATTLEMASTERHORDE "Horde Battlemasters" -#define GOSSIP_TEXT_BATTLEMASTERARENA "Arena Battlemasters" -#define GOSSIP_TEXT_MANALOOM "Mana Loom" -#define GOSSIP_TEXT_ALCHEMYLAB "Alchemy Lab" -#define GOSSIP_TEXT_GEMMERCHANT "Gem Merchant" -#define GOSSIP_TEXT_GEMSCYERS "Scyers Gem Merchant" -#define GOSSIP_TEXT_GEMALDOR "Aldor Gem Merchant" - -#define GOSSIP_TEXT_AH_SILVERMOON_1 "Western Auction House" -#define GOSSIP_TEXT_AH_SILVERMOON_2 "Royal Exchange Auction House" - -#define GOSSIP_TEXT_INN_SILVERMOON_1 "Silvermoon City Inn" -#define GOSSIP_TEXT_INN_SILVERMOON_2 "Wayfarer's Rest tavern" - -//common used for guards in main cities -void DoReplyToTextEmote(Creature *_Creature,uint32 em) -{ - switch(em) - { - case TEXTEMOTE_KISS: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_BOW); break; - case TEXTEMOTE_WAVE: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); break; - case TEXTEMOTE_SALUTE: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); break; - case TEXTEMOTE_SHY: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_FLEX); break; - case TEXTEMOTE_RUDE: - case TEXTEMOTE_CHICKEN: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_POINT); break; - } -} - -/******************************************************* - * guard_azuremyst start - *******************************************************/ - -bool GossipHello_guard_azuremyst(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HIPPOGRYPH , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(10066,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_azuremyst(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_POI(-3918.95, -11544.7, 6, 6, 0, "Bank"); - player->SEND_GOSSIP_MENU(10067,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hippogryph Master - player->SEND_POI(-4057.15, -11788.6, 6, 6, 0, "Stephanos"); - player->SEND_GOSSIP_MENU(10071,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Guild master - player->SEND_POI(-4092.43, -11626.6, 6, 6, 0, "Funaam"); - player->SEND_GOSSIP_MENU(10073,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->SEND_POI(-4129.43, -12469, 6, 6, 0, "Caregiver Chellan"); - player->SEND_GOSSIP_MENU(10074,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Stable Master - player->SEND_POI(-4146.42, -12492.7, 6, 6, 0, "Esbina"); - player->SEND_GOSSIP_MENU(10075,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(10076,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 13); - player->SEND_GOSSIP_MENU(10087,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_azuremyst(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_POI(-4274.81, -11495.3, 6, 6, 0, "Shalannius"); - player->SEND_GOSSIP_MENU(10077,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_POI(-4203.65, -12526.5, 6, 6, 0, "Acteon"); - player->SEND_GOSSIP_MENU(10078,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Mage - player->SEND_POI(-4149.62, -12530.1, 6, 6, 0, "Semid"); - player->SEND_GOSSIP_MENU(10081,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Paladin - player->SEND_POI(-4138.98, -12468.5, 6, 6, 0, "Tullas"); - player->SEND_GOSSIP_MENU(10083,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Priest - player->SEND_POI(-4131.66, -12478.6, 6, 6, 0, "Guvan"); - player->SEND_GOSSIP_MENU(10084,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Shaman - player->SEND_POI(-4162.33, -12456.1, 6, 6, 0, "Tuluun"); - player->SEND_GOSSIP_MENU(10085,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warrior - player->SEND_POI(-4165.05, -12536.4, 6, 6, 0, "Ruada"); - player->SEND_GOSSIP_MENU(10086,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_azuremyst(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-4191.15, -12470, 6, 6, 0, "Daedal"); - player->SEND_GOSSIP_MENU(10088,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-4726.29, -12387, 6, 6, 0, "Blacksmith Calypso"); - player->SEND_GOSSIP_MENU(10089,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-4710.87, -12400.6, 6, 6, 0, "'Cookie' McWeaksauce"); - player->SEND_GOSSIP_MENU(10090,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(-3882.85, -11496.7, 6, 6, 0, "Nahogg"); - player->SEND_GOSSIP_MENU(10091,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(-4157.57, -12470.2, 6, 6, 0, "Artificer Daelo"); - player->SEND_GOSSIP_MENU(10092,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(-4199.11, -12469.9, 6, 6, 0, "Anchorite Fateema"); - player->SEND_GOSSIP_MENU(10093,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(-4266.38, -12985.1, 6, 6, 0, "Diktynna"); - player->SEND_GOSSIP_MENU(10094,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_GOSSIP_MENU(10095,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Jewelcrafting - player->SEND_POI(-3781.55, -11541.8, 6, 6, 0, "Farii"); - player->SEND_GOSSIP_MENU(10097,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Leatherworking - player->SEND_POI(-3442.68, -12322.2, 6, 6, 0, "Moordo"); - player->SEND_GOSSIP_MENU(10098,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Mining - player->SEND_POI(-4179.89, -12493.1, 6, 6, 0, "Dulvi"); - player->SEND_GOSSIP_MENU(10097,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Skinning - player->SEND_POI(-3431.17, -12316.5, 6, 6, 0, "Gurf"); - player->SEND_GOSSIP_MENU(10098,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: //Tailoring - player->SEND_POI(-4711.54, -12386.7, 6, 6, 0, "Erin Kelly"); - player->SEND_GOSSIP_MENU(10099,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_azuremyst(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_azuremyst(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_azuremyst(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_azuremyst(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_azuremyst end - *******************************************************/ - -CreatureAI* GetAI_guard_azuremyst(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_bluffwatcher start - *******************************************************/ - -bool GossipHello_guard_bluffwatcher(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(3543,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_POI(-1257.8, 24.14, 6, 6, 0, "Thunder Bluff Bank"); - player->SEND_GOSSIP_MENU(1292,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Wind master - player->SEND_POI(-1196.43, 28.26, 6, 6, 0, "Wind Rider Roost"); - player->SEND_GOSSIP_MENU(1293,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Guild master - player->SEND_POI(-1296.5, 127.57, 6, 6, 0, "Thunder Bluff Civic Information"); - player->SEND_GOSSIP_MENU(1291,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->SEND_POI(-1296, 39.7, 6, 6, 0, "Thunder Bluff Inn"); - player->SEND_GOSSIP_MENU(3153,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox - player->SEND_POI(-1263.59, 44.36, 6, 6, 0, "Thunder Bluff Mailbox"); - player->SEND_GOSSIP_MENU(3154,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Auction House - player->SEND_POI(1381.77, -4371.16, 6, 6, 0, GOSSIP_TEXT_AUCTIONHOUSE); - player->SEND_GOSSIP_MENU(3155,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Weapon master - player->SEND_POI(-1282.31, 89.56, 6, 6, 0, "Ansekhwa"); - player->SEND_GOSSIP_MENU(4520,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Stable master - player->SEND_POI(-1270.19, 48.84, 6, 6, 0, "Bulrug"); - player->SEND_GOSSIP_MENU(5977,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(7527,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(3542,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(3541,_Creature->GetGUID()); - break; - } -} - -void SendBattleMasterMenu_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //AV - player->SEND_POI(-1387.82, -97.55, 6, 6, 0, "Taim Ragetotem"); - player->SEND_GOSSIP_MENU(7522,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //AB - player->SEND_POI(-997, 214.12, 6, 6, 0, "Martin Lindsey"); - player->SEND_GOSSIP_MENU(7648,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //WSG - player->SEND_POI(-1384.94, -75.91, 6, 6, 0, "Kergul Bloodaxe"); - player->SEND_GOSSIP_MENU(7523,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_POI(-1054.47, -285, 6, 6, 0, "Hall of Elders"); - player->SEND_GOSSIP_MENU(1294,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_POI(-1416.32, -114.28, 6, 6, 0, "Hunter's Hall"); - player->SEND_GOSSIP_MENU(1295,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Mage - player->SEND_POI(-1061.2, 195.5, 6, 6, 0, "Pools of Vision"); - player->SEND_GOSSIP_MENU(1296,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Priest - player->SEND_POI(-1061.2, 195.5, 6, 6, 0, "Pools of Vision"); - player->SEND_GOSSIP_MENU(1297,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Shaman - player->SEND_POI(-989.54, 278.25, 6, 6, 0, "Hall of Spirits"); - player->SEND_GOSSIP_MENU(1298,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Warrior - player->SEND_POI(-1416.32, -114.28, 6, 6, 0, "Hunter's Hall"); - player->SEND_GOSSIP_MENU(1299,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-1085.56, 27.29, 6, 6, 0, "Bena's Alchemy"); - player->SEND_GOSSIP_MENU(1332,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-1239.75, 104.88, 6, 6, 0, "Karn's Smithy"); - player->SEND_GOSSIP_MENU(1333,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-1214.5, -21.23, 6, 6, 0, "Aska's Kitchen"); - player->SEND_GOSSIP_MENU(1334,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(-1112.65, 48.26, 6, 6, 0, "Dawnstrider Enchanters"); - player->SEND_GOSSIP_MENU(1335,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //First Aid - player->SEND_POI(-996.58, 200.5, 6, 6, 0, "Spiritual Healing"); - player->SEND_GOSSIP_MENU(1336,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Fishing - player->SEND_POI(-1169.35, -68.87, 6, 6, 0, "Mountaintop Bait & Tackle"); - player->SEND_GOSSIP_MENU(1337,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Herbalism - player->SEND_POI(-1137.7, -1.51, 6, 6, 0, "Holistic Herbalism"); - player->SEND_GOSSIP_MENU(1338,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Leatherworking - player->SEND_POI(-1156.22, 66.86, 6, 6, 0, "Thunder Bluff Armorers"); - player->SEND_GOSSIP_MENU(1339,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Mining - player->SEND_POI(-1249.17, 155, 6, 6, 0, "Stonehoof Geology"); - player->SEND_GOSSIP_MENU(1340,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Skinning - player->SEND_POI(-1148.56, 51.18, 6, 6, 0, "Mooranta"); - player->SEND_GOSSIP_MENU(1343,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Tailoring - player->SEND_POI(-1156.22, 66.86, 6, 6, 0, "Thunder Bluff Armorers"); - player->SEND_GOSSIP_MENU(1341,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_bluffwatcher(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_bluffwatcher(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_bluffwatcher(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_bluffwatcher(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_bluffwatcher end - *******************************************************/ - -CreatureAI* GetAI_guard_bluffwatcher(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_contested start - *******************************************************/ - -struct MANGOS_DLL_DECL guard_contested : public guardAI -{ - guard_contested(Creature *c) : guardAI(c) {} - - void MoveInLineOfSight(Unit *who) - { - if ( who->isAttackingPlayer() ) - { - if(who->GetTypeId() == TYPEID_PLAYER || who->GetOwnerGUID() && GUID_HIPART(who->GetOwnerGUID())==HIGHGUID_PLAYER) - { - m_creature->AddThreat(who, 0.0f); - if(Unit* owner = who->GetOwner()) - m_creature->AddThreat(owner, 0.0f); - - if(!m_creature->isInCombat()) - { - if (m_creature->GetEntry() == 15184) //Cenarion Hold Infantry - { - srand (time(NULL)); - if (rand()%100 <= 30) - { - DoSay("Taste blade, mongrel!", LANG_UNIVERSAL,NULL); - } - else if (rand()%100 > 30 && rand()%100 < 50) - { - DoSay("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...", LANG_UNIVERSAL,NULL); - } - else if (rand()%100 >= 50) - { - DoSay("As if we don`t have enough problems, you go and create more!", LANG_UNIVERSAL,NULL); - } - } - else - { - SpellEntry const *spell = m_creature->reachWithSpellAttack(who); - DoCastSpell(who, spell); - } - } - DoStartAttackAndMovement(who); - } - } - } -}; -/******************************************************* - * guard_contested end - *******************************************************/ - -CreatureAI* GetAI_guard_contested(Creature *_Creature) -{ - return new guard_contested (_Creature); -} - -/******************************************************* - * guard_darnassus start - *******************************************************/ - -bool GossipHello_guard_darnassus(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HIPPOGRYPH , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(3016, _Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_darnassus(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Auction house - player->SEND_POI(9861.23, 2334.55, 6, 6, 0, "Darnassus Auction House"); - player->SEND_GOSSIP_MENU(3833, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bank - player->SEND_POI(9938.45, 2512.35, 6, 6, 0, "Darnassus Bank"); - player->SEND_GOSSIP_MENU(3017, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Wind master - player->SEND_POI(9945.65, 2618.94, 6, 6, 0, "Rut'theran Village"); - player->SEND_GOSSIP_MENU(3018, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Guild master - player->SEND_POI(10076.40, 2199.59, 6, 6, 0, "Darnassus Guild Master"); - player->SEND_GOSSIP_MENU(3019, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Inn - player->SEND_POI(10133.29, 2222.52, 6, 6, 0, "Darnassus Inn"); - player->SEND_GOSSIP_MENU(3020, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Mailbox - player->SEND_POI(9942.17, 2495.48, 6, 6, 0, "Darnassus Mailbox"); - player->SEND_GOSSIP_MENU(3021, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Stable master - player->SEND_POI(10167.20, 2522.66, 6, 6, 0, "Alassin"); - player->SEND_GOSSIP_MENU(5980, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Weapon trainer - player->SEND_POI(9907.11, 2329.70, 6, 6, 0, "Ilyenia Moonfire"); - player->SEND_GOSSIP_MENU(4517, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(7519, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(4264, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->SEND_GOSSIP_MENU(4273, _Creature->GetGUID()); - break; - } -} - -void SendBattleMasterMenu_guard_darnassus(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //AV - player->SEND_POI(9923.61, 2327.43, 6, 6, 0, "Brogun Stoneshield"); - player->SEND_GOSSIP_MENU(7518, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //AB - player->SEND_POI(9977.37, 2324.39, 6, 6, 0, "Keras Wolfheart"); - player->SEND_GOSSIP_MENU(7651, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //WSG - player->SEND_POI(9979.84, 2315.79, 6, 6, 0, "Aethalas"); - player->SEND_GOSSIP_MENU(7482, _Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_darnassus(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_POI(10186, 2570.46, 6, 6, 0, "Darnassus Druid Trainer"); - player->SEND_GOSSIP_MENU(3024, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_POI(10177.29, 2511.10, 6, 6, 0, "Darnassus Hunter Trainer"); - player->SEND_GOSSIP_MENU(3023, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Priest - player->SEND_POI(9659.12, 2524.88, 6, 6, 0, "Temple of the Moon"); - player->SEND_GOSSIP_MENU(3025, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Rogue - player->SEND_POI(10122, 2599.12, 6, 6, 0, "Darnassus Rogue Trainer"); - player->SEND_GOSSIP_MENU(3026, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Warrior - player->SEND_POI(9951.91, 2280.38, 6, 6, 0, "Warrior's Terrace"); - player->SEND_GOSSIP_MENU(3033, _Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_darnassus(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(10075.90, 2356.76, 6, 6, 0, "Darnassus Alchemy Trainer"); - player->SEND_GOSSIP_MENU(3035, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Cooking - player->SEND_POI(10088.59, 2419.21, 6, 6, 0, "Darnassus Cooking Trainer"); - player->SEND_GOSSIP_MENU(3036, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Enchanting - player->SEND_POI(10146.09, 2313.42, 6, 6, 0, "Darnassus Enchanting Trainer"); - player->SEND_GOSSIP_MENU(3337, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //First Aid - player->SEND_POI(10150.09, 2390.43, 6, 6, 0, "Darnassus First Aid Trainer"); - player->SEND_GOSSIP_MENU(3037, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Fishing - player->SEND_POI(9836.20, 2432.17, 6, 6, 0, "Darnassus Fishing Trainer"); - player->SEND_GOSSIP_MENU(3038, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Herbalism - player->SEND_POI(9757.17, 2430.16, 6, 6, 0, "Darnassus Herbalism Trainer"); - player->SEND_GOSSIP_MENU(3039, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking - player->SEND_POI(10086.59, 2255.77, 6, 6, 0, "Darnassus Leatherworking Trainer"); - player->SEND_GOSSIP_MENU(3040, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Skinning - player->SEND_POI(10081.40, 2257.18, 6, 6, 0, "Darnassus Skinning Trainer"); - player->SEND_GOSSIP_MENU(3042, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Tailoring - player->SEND_POI(10079.70, 2268.19, 6, 6, 0, "Darnassus Tailor"); - player->SEND_GOSSIP_MENU(3044, _Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_darnassus(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_darnassus(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_darnassus(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_darnassus(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_darnassus(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_darnassus end - *******************************************************/ - -CreatureAI* GetAI_guard_darnassus(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_dunmorogh start - *******************************************************/ - -bool GossipHello_guard_dunmorogh(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HIPPOGRYPH , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(4287,_Creature->GetGUID()); - - return true; -} - -void SendDefaultMenu_guard_dunmorogh(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_GOSSIP_MENU(4288,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Gryphon master - player->SEND_GOSSIP_MENU(4289,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Guild master - player->SEND_GOSSIP_MENU(4290,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->SEND_POI(-5582.66, -525.89, 6, 6, 0, "Thunderbrew Distillery"); - player->SEND_GOSSIP_MENU(4291,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Stable Master - player->SEND_POI(-5604, -509.58, 6, 6, 0, "Shelby Stoneflint"); - player->SEND_GOSSIP_MENU(5985,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(4292,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(4300,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_dunmorogh(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Hunter - player->SEND_POI(-5618.29, -454.25, 6, 6, 0, "Grif Wildheart"); - player->SEND_GOSSIP_MENU(4293,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Mage - player->SEND_POI(-5585.6, -539.99, 6, 6, 0, "Magis Sparkmantle"); - player->SEND_GOSSIP_MENU(4294,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Paladin - player->SEND_POI(-5585.6, -539.99, 6, 6, 0, "Azar Stronghammer"); - player->SEND_GOSSIP_MENU(4295,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Priest - player->SEND_POI(-5591.74, -525.61, 6, 6, 0, "Maxan Anvol"); - player->SEND_GOSSIP_MENU(4296,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Rogue - player->SEND_POI(-5602.75, -542.4, 6, 6, 0, "Hogral Bakkan"); - player->SEND_GOSSIP_MENU(4297,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Warlock - player->SEND_POI(-5641.97, -523.76, 6, 6, 0, "Gimrizz Shadowcog"); - player->SEND_GOSSIP_MENU(4298,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warrior - player->SEND_POI(-5604.79, -529.38, 6, 6, 0, "Granis Swiftaxe"); - player->SEND_GOSSIP_MENU(4299,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_dunmorogh(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_GOSSIP_MENU(4301,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-5584.72, -428.41, 6, 6, 0, "Tognus Flintfire"); - player->SEND_GOSSIP_MENU(4302,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-5596.85, -541.43, 6, 6, 0, "Gremlock Pilsnor"); - player->SEND_GOSSIP_MENU(4303,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_GOSSIP_MENU(4304,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(-5531, -666.53, 6, 6, 0, "Bronk Guzzlegear"); - player->SEND_GOSSIP_MENU(4305,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(-5603.67, -523.57, 6, 6, 0, "Thamner Pol"); - player->SEND_GOSSIP_MENU(4306,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(-5199.9, 58.58, 6, 6, 0, "Paxton Ganter"); - player->SEND_GOSSIP_MENU(4307,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_GOSSIP_MENU(4308,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_GOSSIP_MENU(4310,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Mining - player->SEND_POI(-5531, -666.53, 6, 6, 0, "Yarr Hamerstone"); - player->SEND_GOSSIP_MENU(4311,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_GOSSIP_MENU(4312,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_GOSSIP_MENU(4313,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_dunmorogh(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_dunmorogh(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_dunmorogh(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_dunmorogh(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_dunmorogh end - *******************************************************/ - -CreatureAI* GetAI_guard_dunmorogh(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_durotar start - *******************************************************/ - -bool GossipHello_guard_durotar(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(4037,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_durotar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_GOSSIP_MENU(4032,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Wind rider - player->SEND_GOSSIP_MENU(4033,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Inn - player->SEND_POI(338.7, -4688.87, 6, 6, 0, "Razor Hill Inn"); - player->SEND_GOSSIP_MENU(4034,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Stable master - player->SEND_POI(330.31, -4710.66, 6, 6, 0, "Shoja'my"); - player->SEND_GOSSIP_MENU(5973,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(4035,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(4036,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_durotar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Hunter - player->SEND_POI(276, -4706.72, 6, 6, 0, "Thotar"); - player->SEND_GOSSIP_MENU(4013,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Mage - player->SEND_POI(-839.33, -4935.6, 6, 6, 0, "Un'Thuwa"); - player->SEND_GOSSIP_MENU(4014,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Priest - player->SEND_POI(296.22, -4828.1, 6, 6, 0, "Tai'jin"); - player->SEND_GOSSIP_MENU(4015,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Rogue - player->SEND_POI(265.76, -4709, 6, 6, 0, "Kaplak"); - player->SEND_GOSSIP_MENU(4016,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Shaman - player->SEND_POI(307.79, -4836.97, 6, 6, 0, "Swart"); - player->SEND_GOSSIP_MENU(4017,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Warlock - player->SEND_POI(355.88, -4836.45, 6, 6, 0, "Dhugru Gorelust"); - player->SEND_GOSSIP_MENU(4018,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warrior - player->SEND_POI(312.3, -4824.66, 6, 6, 0, "Tarshaw Jaggedscar"); - player->SEND_GOSSIP_MENU(4019,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_durotar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-800.25, -4894.33, 6, 6, 0, "Miao'zan"); - player->SEND_GOSSIP_MENU(4020,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(373.24, -4716.45, 6, 6, 0, "Dwukk"); - player->SEND_GOSSIP_MENU(4021,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_GOSSIP_MENU(4022,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_GOSSIP_MENU(4023,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(368.95, -4723.95, 6, 6, 0, "Mukdrak"); - player->SEND_GOSSIP_MENU(4024,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(327.17, -4825.62, 6, 6, 0, "Rawrk"); - player->SEND_GOSSIP_MENU(4025,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(-1065.48, -4777.43, 6, 6, 0, "Lau'Tiki"); - player->SEND_GOSSIP_MENU(4026,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_POI(-836.25, -4896.89, 6, 6, 0, "Mishiki"); - player->SEND_GOSSIP_MENU(4027,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_GOSSIP_MENU(4028,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Mining - player->SEND_POI(366.94, -4705, 6, 6, 0, "Krunn"); - player->SEND_GOSSIP_MENU(4029,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_GOSSIP_MENU(4030,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_GOSSIP_MENU(4031,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_durotar(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_durotar(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_durotar(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_durotar(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_durotar end - *******************************************************/ - -CreatureAI* GetAI_guard_durotar(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_elwynnforest start - *******************************************************/ - -bool GossipHello_guard_elwynnforest(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GRYPHON , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(933,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_elwynnforest(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_GOSSIP_MENU(4260,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Gryphon master - player->SEND_GOSSIP_MENU(4261,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Guild master - player->SEND_GOSSIP_MENU(4262,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->SEND_POI(-9459.34, 42.08, 6, 6, 0, "Lion's Pride Inn"); - player->SEND_GOSSIP_MENU(4263,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Stable Master - player->SEND_POI(-9466.62, 45.87, 6, 6, 0, "Erma"); - player->SEND_GOSSIP_MENU(5983,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(4264,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(4273,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_elwynnforest(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_GOSSIP_MENU(4265,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_GOSSIP_MENU(4266,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Mage - player->SEND_POI(-9471.12, 33.44, 6, 6, 0, "Zaldimar Wefhellt"); - player->SEND_GOSSIP_MENU(4268,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Paladin - player->SEND_POI(-9469, 108.05, 6, 6, 0, "Brother Wilhelm"); - player->SEND_GOSSIP_MENU(4269,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Priest - player->SEND_POI(-9461.07, 32.6, 6, 6, 0, "Priestess Josetta"); - player->SEND_GOSSIP_MENU(4267,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Rogue - player->SEND_POI(-9465.13, 13.29, 6, 6, 0, "Keryn Sylvius"); - player->SEND_GOSSIP_MENU(4270,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warlock - player->SEND_POI(-9473.21, -4.08, 6, 6, 0, "Maximillian Crowe"); - player->SEND_GOSSIP_MENU(4272,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Warrior - player->SEND_POI(-9461.82, 109.50, 6, 6, 0, "Lyria Du Lac"); - player->SEND_GOSSIP_MENU(4271,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_elwynnforest(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-9057.04, 153.63, 6, 6, 0, "Alchemist Mallory"); - player->SEND_GOSSIP_MENU(4274,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-9456.58, 87.90, 6, 6, 0, "Smith Argus"); - player->SEND_GOSSIP_MENU(4275,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-9467.54, -3.16, 6, 6, 0, "Tomas"); - player->SEND_GOSSIP_MENU(4276,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_GOSSIP_MENU(4277,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_GOSSIP_MENU(4278,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(-9456.82, 30.49, 6, 6, 0, "Michelle Belle"); - player->SEND_GOSSIP_MENU(4279,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(-9386.54, -118.73, 6, 6, 0, "Lee Brown"); - player->SEND_GOSSIP_MENU(4280,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_POI(-9060.70, 149.23, 6, 6, 0, "Herbalist Pomeroy"); - player->SEND_GOSSIP_MENU(4281,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_POI(-9376.12, -75.23, 6, 6, 0, "Adele Fielder"); - player->SEND_GOSSIP_MENU(4282,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Mining - player->SEND_GOSSIP_MENU(4283,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_POI(-9536.91, -1212.76, 6, 6, 0, "Helene Peltskinner"); - player->SEND_GOSSIP_MENU(4284,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_POI(-9376.12, -75.23, 6, 6, 0, "Eldrin"); - player->SEND_GOSSIP_MENU(4285,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_elwynnforest(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_elwynnforest(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_elwynnforest(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_elwynnforest(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_elwynnforest end - *******************************************************/ - -CreatureAI* GetAI_guard_elwynnforest(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_eversong start - *******************************************************/ - -bool GossipHello_guard_eversong(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATHANDLER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(10180,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_eversong(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bat Handler - player->SEND_POI(9371.93, -7164.80, 6, 6, 0, "Skymistress Gloaming"); - player->SEND_GOSSIP_MENU(10181,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Guild master - player->SEND_GOSSIP_MENU(10182,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Inn - player->SEND_POI(9483.74, -6844.58, 6, 6, 0, "Delaniel's inn"); - player->SEND_GOSSIP_MENU(10183,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Stable Master - player->SEND_POI(9489.62, -6829.93, 6, 6, 0, "Anathos"); - player->SEND_GOSSIP_MENU(10184,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(10180,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(10180,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_eversong(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_GOSSIP_MENU(10185,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_POI(9527.44, -6865.25, 6, 6, 0, "Hannovia"); - player->SEND_GOSSIP_MENU(10186,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Mage - player->SEND_POI(9464.24, -6855.52, 6, 6, 0, "Garridel"); - player->SEND_GOSSIP_MENU(10187,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Paladin - player->SEND_POI(9517.61, -6871.04, 6, 6, 0, "Noellene"); - player->SEND_GOSSIP_MENU(10189,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Priest - player->SEND_POI(9467.39, -6845.72, 6, 6, 0, "Ponaris"); - player->SEND_GOSSIP_MENU(10190,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Rogue - player->SEND_POI(9533.67, -6877.39, 6, 6, 0, "Tannaria"); - player->SEND_GOSSIP_MENU(10191,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warlock - player->SEND_POI(9468.99, -6865.60, 6, 6, 0, "Celoenus"); - player->SEND_GOSSIP_MENU(10192,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_eversong(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(8659.90, -6368.12, 6, 6, 0, "Arcanist Sheynathren"); - player->SEND_GOSSIP_MENU(10193,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(8984.21, -7419.21, 6, 6, 0, "Arathel Sunforge"); - player->SEND_GOSSIP_MENU(10194,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(9494.04, -6881.51, 6, 6, 0, "Quarelestra"); - player->SEND_GOSSIP_MENU(10195,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Engineering - player->SEND_GOSSIP_MENU(10197,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //First Aid - player->SEND_POI(9479.46, -6879.16, 6, 6, 0, "Kanaria"); - player->SEND_GOSSIP_MENU(10198,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Fishing - player->SEND_GOSSIP_MENU(10199,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Herbalism - player->SEND_POI(8678.92, -6329.09, 6, 6, 0, "Botanist Tyniarrel"); - player->SEND_GOSSIP_MENU(10200,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Jewelcrafting - player->SEND_POI(9484.32, -6874.98, 6, 6, 0, "Aleinia"); - player->SEND_GOSSIP_MENU(10203,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_POI(9362.04, -7130.33, 6, 6, 0, "Sathein"); - player->SEND_GOSSIP_MENU(10204,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Mining - player->SEND_GOSSIP_MENU(10205,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_POI(9362.04, -7130.33, 6, 6, 0, "Mathreyn"); - player->SEND_GOSSIP_MENU(10206,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_POI(8680.36, -6327.51, 6, 6, 0, "Sempstress Ambershine"); - player->SEND_GOSSIP_MENU(10207,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_eversong(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_eversong(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_eversong(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_eversong(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_eversong end - *******************************************************/ - -CreatureAI* GetAI_guard_eversong(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_exodar start - *******************************************************/ - -bool GossipHello_guard_exodar(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HIPPOGRYPH , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(9551, _Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_exodar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Auction house - player->SEND_POI(-4023.6, -11739.3, 6, 6, 0, "Exodar Auction House"); - player->SEND_GOSSIP_MENU(9528, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bank - player->SEND_POI(-3923.89, -11544.5, 6, 6, 0, "Exodar Bank"); - player->SEND_GOSSIP_MENU(9529, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Guild master - player->SEND_POI(-4092.57, -11626.5, 6, 6, 0, "Exodar Guild Master"); - player->SEND_GOSSIP_MENU(9539, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Hippogryph master - player->SEND_POI(-4060.46, -11787.1, 6, 6, 0, "Exodar Hippogryph Master"); - player->SEND_GOSSIP_MENU(9530, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Inn - player->SEND_POI(-3741.87, -11695.1, 6, 6, 0, "Exodar Inn"); - player->SEND_GOSSIP_MENU(9545, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Mailbox - player->SEND_POI(-3972.5, -11696.0, 6, 6, 0, "Mailbox"); - player->SEND_GOSSIP_MENU(10254, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Stable master - player->SEND_POI(-3786.5, -11702.5, 6, 6, 0, "Stable Master Arthaid"); - player->SEND_GOSSIP_MENU(9558, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Weapon trainer - player->SEND_POI(-4215.68, -11628.9, 6, 6, 0, "Weapon Master Handiir"); - player->SEND_GOSSIP_MENU(9565, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_EYEOFTHESTORM , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(9533, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 13); - player->SEND_GOSSIP_MENU(9555, _Creature->GetGUID()); - break; - } -} - -void SendBattleMasterMenu_guard_exodar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //AV - player->SEND_POI(-3978.1, -11357, 6, 6, 0, "Alterac Valley Battlemaster"); - player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //AB - player->SEND_POI(-3998.9, -11345.2, 6, 6, 0, "Arathi Basin Battlemaster"); - player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //A - player->SEND_POI(-3759.27, -11695.63, 6, 6, 0, "Miglik Blotstrom"); - player->SEND_GOSSIP_MENU(10223, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //EOS - player->SEND_POI(-3978.1, -11357, 6, 6, 0, "Eye Of The Storm Battlemaster"); - player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //WSG - player->SEND_POI(-3977.5, -11381.2, 6, 6, 0, "Warsong Gulch Battlemaster"); - player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_exodar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_POI(-4276.0, -11495, 6, 6, 0, "Exodar Druid Trainer"); - player->SEND_GOSSIP_MENU(9534, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_POI(-4210.6, -11575.2, 6, 6, 0, "Exodar Hunter Trainer"); - player->SEND_GOSSIP_MENU(9544, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Mage - player->SEND_POI(-4057.32, -11556.5, 6, 6, 0, "Exodar Mage Trainer"); - player->SEND_GOSSIP_MENU(9550, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Paladin - player->SEND_POI(-4191.2, -11470.4, 6, 6, 0, "Exodar Paladin Trainer"); - player->SEND_GOSSIP_MENU(9553, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Priest - player->SEND_POI(-3969.63, -11482.8, 6, 6, 0, "Exodar Priest Trainer"); - player->SEND_GOSSIP_MENU(9554, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Shaman - player->SEND_POI(-3805.5, -11380.7, 6, 6, 0, "Exodar Shaman Trainer"); - player->SEND_GOSSIP_MENU(9556, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warrior - player->SEND_POI(-4189.43, -11653.7, 6, 6, 0, "Exodar Warrior Trainer"); - player->SEND_GOSSIP_MENU(9562, _Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_exodar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-4040.6, -11364.5, 6, 6, 0, "Exodar Alchemy Trainer"); - player->SEND_GOSSIP_MENU(9527, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-4229.5, -11706, 6, 6, 0, "Exodar Blacksmithing Trainer"); - player->SEND_GOSSIP_MENU(9532, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-3798.3, -11651.7, 6, 6, 0, "Exodar Cooking Trainer"); - player->SEND_GOSSIP_MENU(9551, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(-3889.3, -11495, 6, 6, 0, "Exodar Enchanting Trainer"); - player->SEND_GOSSIP_MENU(9535, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(-4257.68, -11640.3, 6, 6, 0, "Exodar Engineering Trainer"); - player->SEND_GOSSIP_MENU(9536, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(-3769.5, -11479.6, 6, 6, 0, "Exodar First Aid Trainer"); - player->SEND_GOSSIP_MENU(9537, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(-3725.5, -11385.2, 6, 6, 0, "Exodar Fishing Trainer"); - player->SEND_GOSSIP_MENU(9538, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Jewelcrafting - player->SEND_POI(-3783, -11546, 6, 6, 0, "Exodar Jewelcrafting Trainer"); - player->SEND_GOSSIP_MENU(9547, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Herbalism - player->SEND_POI(-4040.6, -11364.5, 6, 6, 0, "Exodar Herbalist Trainer"); - player->SEND_GOSSIP_MENU(9543, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Leatherworking - player->SEND_POI(-4140.6, -11776.7, 6, 6, 0, "Exodar Leatherworking Trainer"); - player->SEND_GOSSIP_MENU(9549, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Mining - player->SEND_POI(-4228, -11697, 6, 6, 0, "Exodar Mining Trainer"); - player->SEND_GOSSIP_MENU(9552, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Skinning - player->SEND_POI(-4134.97, -11760.5, 6, 6, 0, "Exodar Skinning Trainer"); - player->SEND_GOSSIP_MENU(9557, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: //Tailoring - player->SEND_POI(-4092.5, -11744.5, 6, 6, 0, "Exodar Tailor Trainer"); - player->SEND_GOSSIP_MENU(9559, _Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_exodar(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_exodar(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_exodar(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_exodar(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_exodar(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_exodar end - *******************************************************/ - -CreatureAI* GetAI_guard_exodar(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_ironforge start - *******************************************************/ - -bool GossipHello_guard_ironforge(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_IRONFORGE_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DEEPRUNTRAM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GRYPHON , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(2760, _Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_ironforge(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Auction House - player->SEND_POI(-4957.39, -911.6, 6, 6, 0, "Ironforge Auction House"); - player->SEND_GOSSIP_MENU(3014, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bank - player->SEND_POI(-4891.91, -991.47, 6, 6, 0, "The Vault"); - player->SEND_GOSSIP_MENU(2761, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Tram - player->SEND_POI(-4835.27, -1294.69, 6, 6, 0, "Deeprun Tram"); - player->SEND_GOSSIP_MENU(3814, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Gryphon Master - player->SEND_POI(-4821.52, -1152.3, 6, 6, 0, "Ironforge Gryphon Master"); - player->SEND_GOSSIP_MENU(2762, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Guild Master - player->SEND_POI(-5021, -996.45, 6, 6, 0, "Ironforge Visitor's Center"); - player->SEND_GOSSIP_MENU(2764, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Inn - player->SEND_POI(-4850.47, -872.57, 6, 6, 0, "Stonefire Tavern"); - player->SEND_GOSSIP_MENU(2768, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Mailbox - player->SEND_POI(-4845.7, -880.55, 6, 6, 0, "Ironforge Mailbox"); - player->SEND_GOSSIP_MENU(2769, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Stable Master - player->SEND_POI(-5010.2, -1262, 6, 6, 0, "Ulbrek Firehand"); - player->SEND_GOSSIP_MENU(5986, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Weapons Trainer - player->SEND_POI(-5040, -1201.88, 6, 6, 0, "Bixi and Buliwyf"); - player->SEND_GOSSIP_MENU(4518, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(7529, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Class Trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(2766, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Profession Trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(2793, _Creature->GetGUID()); - break; - } -} - -void SendBattleMasterMenu_guard_ironforge(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //AV - player->SEND_POI(-5047.87, -1263.77, 6, 6, 0, "Glordrum Steelbeard"); - player->SEND_GOSSIP_MENU(7483, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //AB - player->SEND_POI(-5038.37, -1266.39, 6, 6, 0, "Donal Osgood"); - player->SEND_GOSSIP_MENU(7649, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //WSG - player->SEND_POI(-5037.24, -1274.82, 6, 6, 0, "Lylandris"); - player->SEND_GOSSIP_MENU(7528, _Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_ironforge(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Hunter - player->SEND_POI(-5023, -1253.68, 6, 6, 0, "Hall of Arms"); - player->SEND_GOSSIP_MENU(2770, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Mage - player->SEND_POI(-4627, -926.45, 6, 6, 0, "Hall of Mysteries"); - player->SEND_GOSSIP_MENU(2771, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Paladin - player->SEND_POI(-4627.02, -926.45, 6, 6, 0, "Hall of Mysteries"); - player->SEND_GOSSIP_MENU(2773, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Priest - player->SEND_POI(-4627, -926.45, 6, 6, 0, "Hall of Mysteries"); - player->SEND_GOSSIP_MENU(2772, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Rogue - player->SEND_POI(-4647.83, -1124, 6, 6, 0, "Ironforge Rogue Trainer"); - player->SEND_GOSSIP_MENU(2774, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Warlock - player->SEND_POI(-4605, -1110.45, 6, 6, 0, "Ironforge Warlock Trainer"); - player->SEND_GOSSIP_MENU(2775, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warrior - player->SEND_POI(-5023.08, -1253.68, 6, 6, 0, "Hall of Arms"); - player->SEND_GOSSIP_MENU(2776, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Shaman - player->SEND_POI(-4732, -1147, 6, 6, 0, "Ironforge Shaman Trainer"); - //incorrect id - player->SEND_GOSSIP_MENU(2766, _Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_ironforge(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-4858.5, -1241.83, 6, 6, 0, "Berryfizz's Potions and Mixed Drinks"); - player->SEND_GOSSIP_MENU(2794, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-4796.97, -1110.17, 6, 6, 0, "The Great Forge"); - player->SEND_GOSSIP_MENU(2795, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-4767.83, -1184.59, 6, 6, 0, "The Bronze Kettle"); - player->SEND_GOSSIP_MENU(2796, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(-4803.72, -1196.53, 6, 6, 0, "Thistlefuzz Arcanery"); - player->SEND_GOSSIP_MENU(2797, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(-4799.56, -1250.23, 6, 6, 0, "Springspindle's Gadgets"); - player->SEND_GOSSIP_MENU(2798, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(-4881.6, -1153.13, 6, 6, 0, "Ironforge Physician"); - player->SEND_GOSSIP_MENU(2799, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(-4597.91, -1091.93, 6, 6, 0, "Traveling Fisherman"); - player->SEND_GOSSIP_MENU(2800, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_POI(-4876.9, -1151.92, 6, 6, 0, "Ironforge Physician"); - player->SEND_GOSSIP_MENU(2801, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_POI(-4745, -1027.57, 6, 6, 0, "Finespindle's Leather Goods"); - player->SEND_GOSSIP_MENU(2802, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Minning - player->SEND_POI(-4705.06, -1116.43, 6, 6, 0, "Deepmountain Mining Guild"); - player->SEND_GOSSIP_MENU(2804, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_POI(-4745, -1027.57, 6, 6, 0, "Finespindle's Leather Goods"); - player->SEND_GOSSIP_MENU(2805, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_POI(-4719.60, -1056.96, 6, 6, 0, "Stonebrow's Clothier"); - player->SEND_GOSSIP_MENU(2807, _Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_ironforge(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_ironforge(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_ironforge(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_ironforge(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_ironforge(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_ironforge end - *******************************************************/ - -CreatureAI* GetAI_guard_ironforge(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_mulgore start - *******************************************************/ - -bool GossipHello_guard_mulgore(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(3543,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_mulgore(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_GOSSIP_MENU(4051,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Wind rider - player->SEND_GOSSIP_MENU(4052,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Inn - player->SEND_POI(-2361.38, -349.19, 6, 6, 0, "Bloodhoof Village Inn"); - player->SEND_GOSSIP_MENU(4053,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Stable master - player->SEND_POI(-2338.86, -357.56, 6, 6, 0, "Seikwa"); - player->SEND_GOSSIP_MENU(5976,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(4069,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(4070,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_mulgore(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_POI(-2312.15, -443.69, 6, 6, 0, "Gennia Runetotem"); - player->SEND_GOSSIP_MENU(4054,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_POI(-2178.14, -406.14, 6, 6, 0, "Yaw Sharpmane"); - player->SEND_GOSSIP_MENU(4055,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Shaman - player->SEND_POI(-2301.5, -439.87, 6, 6, 0, "Narm Skychaser"); - player->SEND_GOSSIP_MENU(4056,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Warrior - player->SEND_POI(-2345.43, -494.11, 6, 6, 0, "Krang Stonehoof"); - player->SEND_GOSSIP_MENU(4057,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_mulgore(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_GOSSIP_MENU(4058,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_GOSSIP_MENU(4059,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-2263.34, -287.91, 6, 6, 0, "Pyall Silentstride"); - player->SEND_GOSSIP_MENU(4060,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_GOSSIP_MENU(4061,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //First Aid - player->SEND_POI(-2353.52, -355.82, 6, 6, 0, "Vira Younghoof"); - player->SEND_GOSSIP_MENU(4062,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Fishing - player->SEND_POI(-2349.21, -241.37, 6, 6, 0, "Uthan Stillwater"); - player->SEND_GOSSIP_MENU(4063,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Herbalism - player->SEND_GOSSIP_MENU(4064,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Leatherworking - player->SEND_POI(-2257.12, -288.63, 6, 6, 0, "Chaw Stronghide"); - player->SEND_GOSSIP_MENU(4065,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Mining - player->SEND_GOSSIP_MENU(4066,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Skinning - player->SEND_POI(-2252.94, -291.32, 6, 6, 0, "Yonn Deepcut"); - player->SEND_GOSSIP_MENU(4067,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Tailoring - player->SEND_GOSSIP_MENU(4068,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_mulgore(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_mulgore(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_mulgore(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_mulgore(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_mulgore end - *******************************************************/ - -CreatureAI* GetAI_guard_mulgore(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_orgrimmar start - *******************************************************/ - -bool GossipHello_guard_orgrimmar(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ZEPPLINMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_OFFICERS , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); - player->SEND_GOSSIP_MENU(2593,_Creature->GetGUID()); - - return true; -} - -void SendDefaultMenu_guard_orgrimmar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_POI(1631.51, -4375.33, 6, 6, 0, "Bank of Orgrimmar"); - player->SEND_GOSSIP_MENU(2554,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //wind rider - player->SEND_POI(1676.6, -4332.72, 6, 6, 0, "The Sky Tower"); - player->SEND_GOSSIP_MENU(2555,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //guild master - player->SEND_POI(1576.93, -4294.75, 6, 6, 0, "Horde Embassy"); - player->SEND_GOSSIP_MENU(2556,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->SEND_POI(1644.51, -4447.27, 6, 6, 0, "Orgrimmar Inn"); - player->SEND_GOSSIP_MENU(2557,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //mailbox - player->SEND_POI(1622.53, -4388.79, 6, 6, 0, "Orgrimmar Mailbox"); - player->SEND_GOSSIP_MENU(2558,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //auction house - player->SEND_POI(1679.21, -4450.1, 6, 6, 0, "Orgrimmar Auction House"); - player->SEND_GOSSIP_MENU(3075,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //zeppelin - player->SEND_POI(1337.36, -4632.7, 6, 6, 0, "Orgrimmar Zeppelin Tower"); - player->SEND_GOSSIP_MENU(3173,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //weapon master - player->SEND_POI(2092.56, -4823.95, 6, 6, 0, "Sayoc & Hanashi"); - player->SEND_GOSSIP_MENU(4519,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //stable master - player->SEND_POI(2133.12, -4663.93, 6, 6, 0, "Xon'cha"); - player->SEND_GOSSIP_MENU(5974,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //officers lounge - player->SEND_POI(1633.56, -4249.37, 6, 6, 0, "Hall of Legends"); - player->SEND_GOSSIP_MENU(7046,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(7521,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(2599,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: //profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(2594,_Creature->GetGUID()); - break; - } -} - -void SendBattleMasterMenu_guard_orgrimmar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //AV - player->SEND_POI(1983.92, -4794.2, 6, 6, 0, "Hall of the Brave"); - player->SEND_GOSSIP_MENU(7484,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //AB - player->SEND_POI(1983.92, -4794.2, 6, 6, 0, "Hall of the Brave"); - player->SEND_GOSSIP_MENU(7644,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //WSG - player->SEND_POI(1983.92, -4794.2, 6, 6, 0, "Hall of the Brave"); - player->SEND_GOSSIP_MENU(7520,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_orgrimmar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Hunter - player->SEND_POI(2114.84, -4625.31, 6, 6, 0, "Orgrimmar Hunter's Hall"); - player->SEND_GOSSIP_MENU(2559,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Mage - player->SEND_POI(1451.26, -4223.33, 6, 6, 0, "Darkbriar Lodge"); - player->SEND_GOSSIP_MENU(2560,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Priest - player->SEND_POI(1442.21, -4183.24, 6, 6, 0, "Spirit Lodge"); - player->SEND_GOSSIP_MENU(2561,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Shaman - player->SEND_POI(1925.34, -4181.89, 6, 6, 0, "Thrall's Fortress"); - player->SEND_GOSSIP_MENU(2562,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Rogue - player->SEND_POI(1773.39, -4278.97, 6, 6, 0, "Shadowswift Brotherhood"); - player->SEND_GOSSIP_MENU(2563,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Warlock - player->SEND_POI(1849.57, -4359.68, 6, 6, 0, "Darkfire Enclave"); - player->SEND_GOSSIP_MENU(2564,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warrior - player->SEND_POI(1983.92, -4794.2, 6, 6, 0, "Hall of the Brave"); - player->SEND_GOSSIP_MENU(2565,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Paladin - player->SEND_POI(1906.65, -4134.26, 6, 6, 0, "Valley of Wisdom"); - player->SEND_GOSSIP_MENU(10843,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_orgrimmar(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(1955.17, -4475.79, 6, 6, 0, "Yelmak's Alchemy and Potions"); - player->SEND_GOSSIP_MENU(2497,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(2054.34, -4831.85, 6, 6, 0, "The Burning Anvil"); - player->SEND_GOSSIP_MENU(2499,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(1780.96, -4481.31, 6, 6, 0, "Borstan's Firepit"); - player->SEND_GOSSIP_MENU(2500,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(1917.5, -4434.95, 6, 6, 0, "Godan's Runeworks"); - player->SEND_GOSSIP_MENU(2501,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(2038.45, -4744.75, 6, 6, 0, "Nogg's Machine Shop"); - player->SEND_GOSSIP_MENU(2653,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(1485.21, -4160.91, 6, 6, 0, "Survival of the Fittest"); - player->SEND_GOSSIP_MENU(2502,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(1994.15, -4655.7, 6, 6, 0, "Lumak's Fishing"); - player->SEND_GOSSIP_MENU(2503,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_POI(1898.61, -4454.93, 6, 6, 0, "Jandi's Arboretum"); - player->SEND_GOSSIP_MENU(2504,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_POI(1852.82, -4562.31, 6, 6, 0, "Kodohide Leatherworkers"); - player->SEND_GOSSIP_MENU(2513,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Mining - player->SEND_POI(2029.79, -4704, 6, 6, 0, "Red Canyon Mining"); - player->SEND_GOSSIP_MENU(2515,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_POI(1852.82, -4562.31, 6, 6, 0, "Kodohide Leatherworkers"); - player->SEND_GOSSIP_MENU(2516,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_POI(1802.66, -4560.66, 6, 6, 0, "Magar's Cloth Goods"); - player->SEND_GOSSIP_MENU(2518,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_orgrimmar(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_orgrimmar(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_orgrimmar(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_orgrimmar(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_orgrimmar(player, _Creature, action); break; - } - return true; -} - -bool ReceiveEmote_guard_orgrimmar(Player *player, Creature *_Creature, uint32 emote) -{ - if( player->GetTeam() == HORDE ) - DoReplyToTextEmote(_Creature,emote); - return true; -} - -/******************************************************* - * guard_orgrimmar end - *******************************************************/ - -CreatureAI* GetAI_guard_orgrimmar(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_shattrath start - *******************************************************/ - -bool GossipHello_guard_shattrath(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAVERN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FLIGHTMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MANALOOM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMYLAB , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMMERCHANT , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(10321, _Creature->GetGUID()); - - return true; -} - -void SendDefaultMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Tavern - player->SEND_POI(-1759.5, 5165, 6, 6, 0, "Worlds End Tavern"); - player->SEND_GOSSIP_MENU(10394, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bank - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANKALDOR , GOSSIP_SENDER_SEC_BANK, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANKSCYERS , GOSSIP_SENDER_SEC_BANK, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(10379, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Inn - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INNALDOR , GOSSIP_SENDER_SEC_INN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INNSCYERS , GOSSIP_SENDER_SEC_INN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(10382, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Flight master - player->SEND_POI(-1832, 5299, 6, 6, 0, "Flight Master"); - player->SEND_GOSSIP_MENU(10385, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANKALDOR , GOSSIP_SENDER_SEC_MAILBOX, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INNALDOR , GOSSIP_SENDER_SEC_MAILBOX, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANKSCYERS , GOSSIP_SENDER_SEC_MAILBOX, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INNSCYERS , GOSSIP_SENDER_SEC_MAILBOX, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(10386, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Stable master - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEALDOR , GOSSIP_SENDER_SEC_STABLEMASTER, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLESCYERS , GOSSIP_SENDER_SEC_STABLEMASTER, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(10387, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERALLIANCE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERHORDE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(10388, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Profession master - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(10391, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Mana Loom - player->SEND_POI(-2070, 5265.5, 6, 6, 0, "Mana Loom"); - player->SEND_GOSSIP_MENU(10503, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Alchemy Lab - player->SEND_POI(-1648.5, 5540, 6, 6, 0, "Alchemy Lab"); - player->SEND_GOSSIP_MENU(10321, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Gem Merchant - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMALDOR , GOSSIP_SENDER_SEC_GEMMERCHANT, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMSCYERS , GOSSIP_SENDER_SEC_GEMMERCHANT, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(10697, _Creature->GetGUID()); - break; - } -} - -void SendBankMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->SEND_POI(-1730.5, 5496, 6, 6, 0, "Aldor Bank"); - player->SEND_GOSSIP_MENU(10380, _Creature->GetGUID()); - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->SEND_POI(-1997.7, 5363, 6, 6, 0, "Scyers Bank"); - player->SEND_GOSSIP_MENU(10381, _Creature->GetGUID()); - } -} - -void SendInnMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->SEND_POI(-1895, 5767, 6, 6, 0, "Aldor Inn"); - player->SEND_GOSSIP_MENU(10383, _Creature->GetGUID()); - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->SEND_POI(-2178, 5405, 6, 6, 0, "Scyers Inn"); - player->SEND_GOSSIP_MENU(10384, _Creature->GetGUID()); - } -} - -void SendMailboxMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: - player->SEND_POI(-1730.5, 5496, 6, 6, 0, "Aldor Bank"); - player->SEND_GOSSIP_MENU(10380, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - player->SEND_POI(-1895, 5767, 6, 6, 0, "Aldor Inn"); - player->SEND_GOSSIP_MENU(10383, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->SEND_POI(-1997.7, 5363, 6, 6, 0, "Scyers Bank"); - player->SEND_GOSSIP_MENU(10381, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: - player->SEND_POI(-2178, 5405, 6, 6, 0, "Scyers Inn"); - player->SEND_GOSSIP_MENU(10384, _Creature->GetGUID()); - break; - } -} - -void SendStableMasterMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->SEND_POI(-1888.5, 5761, 6, 6, 0, "Aldor Stable"); - player->SEND_GOSSIP_MENU(10321, _Creature->GetGUID()); - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->SEND_POI(-2170, 5404, 6, 6, 0, "Scyers Stable"); - player->SEND_GOSSIP_MENU(10321, _Creature->GetGUID()); - } -} - -void SendBattleMasterMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: - player->SEND_POI(-1774, 5251, 6, 6, 0, "Alliance Battlemasters"); - player->SEND_GOSSIP_MENU(10389, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - player->SEND_POI(-1963, 5263, 6, 6, 0, "Horde Battlemasters"); - player->SEND_GOSSIP_MENU(10390, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->SEND_POI(-1960, 5175, 6, 6, 0, "Arena Battlemasters"); - player->SEND_GOSSIP_MENU(12510, _Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-1648.5, 5534, 6, 6, 0, "Lorokeem"); - player->SEND_GOSSIP_MENU(10392, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-1847, 5222, 6, 6, 0, "Kradu Grimblade and Zula Slagfury"); - player->SEND_GOSSIP_MENU(10400, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-2067.4, 5316.5, 6, 6, 0, "Jack Trapper"); - player->SEND_GOSSIP_MENU(10393, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(-2263.5, 5563.5, 6, 6, 0, "High Enchanter Bardolan"); - player->SEND_GOSSIP_MENU(10395, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //First Aid - player->SEND_POI(-1591, 5265.5, 6, 6, 0, "Mildred Fletcher"); - player->SEND_GOSSIP_MENU(10396, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Jewelcrafting - player->SEND_POI(-1654, 5667.5, 6, 6, 0, "Hamanar"); - player->SEND_GOSSIP_MENU(10397, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking - player->SEND_POI(-2060.5, 5256.5, 6, 6, 0, "Darmari"); - player->SEND_GOSSIP_MENU(10399, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Skinning - player->SEND_POI(-2048, 5300, 6, 6, 0, "Seymour"); - player->SEND_GOSSIP_MENU(10398, _Creature->GetGUID()); - break; - } -} - -void SendGemMerchantMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->SEND_POI(-1645, 5669.5, 6, 6, 0, "Aldor Gem Merchant"); - player->SEND_GOSSIP_MENU(10698, _Creature->GetGUID()); - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->SEND_POI(-2193, 5424.5, 6, 6, 0, "Scyers Gem Merchant"); - player->SEND_GOSSIP_MENU(10699, _Creature->GetGUID()); - } -} - -bool GossipSelect_guard_shattrath(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_shattrath(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BANK: SendBankMenu_guard_shattrath(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_INN: SendInnMenu_guard_shattrath(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_STABLEMASTER: SendStableMasterMenu_guard_shattrath(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_GEMMERCHANT: SendGemMerchantMenu_guard_shattrath(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_MAILBOX: SendMailboxMenu_guard_shattrath(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_shattrath(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_shattrath(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_shattrath end - *******************************************************/ - -CreatureAI* GetAI_guard_shattrath(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_shattrath_aldor - *******************************************************/ - -#define SPELL_BANISHED_SHATTRATH_A 36642 -#define SPELL_BANISHED_SHATTRATH_S 36671 -#define SPELL_BANISH_TELEPORT 36643 -#define SPELL_EXILE 39533 - -struct MANGOS_DLL_DECL guard_shattrath_aldorAI : public guardAI -{ - guard_shattrath_aldorAI(Creature *c) : guardAI(c) { Reset(); } - - uint32 Exile_Timer; - uint32 Banish_Timer; - uint64 playerGUID; - bool CanTeleport; - - void Reset() - { - Banish_Timer = 5000; - Exile_Timer = 8500; - playerGUID = 0; - CanTeleport = false; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( CanTeleport ) - { - if( Exile_Timer < diff ) - { - if( Unit* temp = Unit::GetUnit(*m_creature,playerGUID) ) - { - temp->CastSpell(temp,SPELL_EXILE,true); - temp->CastSpell(temp,SPELL_BANISH_TELEPORT,true); - } - playerGUID = 0; - Exile_Timer = 8500; - CanTeleport = false; - }else Exile_Timer -= diff; - } - else if( Banish_Timer < diff ) - { - Unit* temp = m_creature->getVictim(); - if( temp && temp->GetTypeId() == TYPEID_PLAYER ) - { - DoCast(temp,SPELL_BANISHED_SHATTRATH_A); - Banish_Timer = 9000; - playerGUID = temp->GetGUID(); - if( playerGUID ) - CanTeleport = true; - } - }else Banish_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -bool GossipHello_guard_shattrath_aldor(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAVERN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FLIGHTMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MANALOOM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMYLAB , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMMERCHANT , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(10524, _Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_shattrath_aldor(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Tavern - player->SEND_POI(-1759.5, 5165, 6, 6, 0, "Worlds End Tavern"); - player->SEND_GOSSIP_MENU(10394, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bank - player->SEND_POI(-1730.5, 5496, 6, 6, 0, "Aldor Bank"); - player->SEND_GOSSIP_MENU(10380, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Inn - player->SEND_POI(-1895, 5767, 6, 6, 0, "Aldor Inn"); - player->SEND_GOSSIP_MENU(10525, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Flight master - player->SEND_POI(-1832, 5299, 6, 6, 0, "Shattrath Flight Master"); - player->SEND_GOSSIP_MENU(10402, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox - player->SEND_POI(0, 0, 6, 6, 0, "Aldor Mailbox"); - //unknown - player->SEND_GOSSIP_MENU(10524, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Stable master - player->SEND_POI(-1888.5, 5761, 6, 6, 0, "Aldor Stable Master"); - player->SEND_GOSSIP_MENU(10527, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERALLIANCE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERHORDE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(10388, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Profession master - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(10391, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Mana Loom - player->SEND_POI(-2070, 5265.5, 6, 6, 0, "Mana Loom"); - player->SEND_GOSSIP_MENU(10522, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Alchemy Lab - player->SEND_POI(-1648.5, 5540, 6, 6, 0, "Alchemy Lab"); - player->SEND_GOSSIP_MENU(10696, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Gem Merchant - player->SEND_POI(-1645, 5669.5, 6, 6, 0, "Aldor Gem Merchant"); - player->SEND_GOSSIP_MENU(10411, _Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_shattrath_aldor(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-1648.5, 5534, 6, 6, 0, "Lorokeem"); - player->SEND_GOSSIP_MENU(10392, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-1847, 5222, 6, 6, 0, "Kradu Grimblade and Zula Slagfury"); - player->SEND_GOSSIP_MENU(10400, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-2067.4, 5316.5, 6, 6, 0, "Jack Trapper"); - player->SEND_GOSSIP_MENU(10393, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(-2263.5, 5563.5, 6, 6, 0, "High Enchanter Bardolan"); - player->SEND_GOSSIP_MENU(10528, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //First Aid - player->SEND_POI(-1591, 5265.5, 6, 6, 0, "Mildred Fletcher"); - player->SEND_GOSSIP_MENU(10396, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Jewelcrafting - player->SEND_POI(-1654, 5667.5, 6, 6, 0, "Hamanar"); - player->SEND_GOSSIP_MENU(10529, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking - player->SEND_POI(-2060.5, 5256.5, 6, 6, 0, "Darmari"); - player->SEND_GOSSIP_MENU(10399, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Skinning - player->SEND_POI(-2048, 5300, 6, 6, 0, "Seymour"); - player->SEND_GOSSIP_MENU(10419, _Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_shattrath_aldor(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_shattrath_aldor(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_shattrath_aldor(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_shattrath(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_shattrath_aldor end - *******************************************************/ - -CreatureAI* GetAI_guard_shattrath_aldor(Creature *_Creature) -{ - return new guard_shattrath_aldorAI (_Creature); -} - -/******************************************************* - * guard_shattrath_scryer - *******************************************************/ - -struct MANGOS_DLL_DECL guard_shattrath_scryerAI : public guardAI -{ - guard_shattrath_scryerAI(Creature *c) : guardAI(c) { Reset(); } - - uint32 Exile_Timer; - uint32 Banish_Timer; - uint64 playerGUID; - bool CanTeleport; - - void Reset() - { - Banish_Timer = 5000; - Exile_Timer = 8500; - playerGUID = 0; - CanTeleport = false; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( CanTeleport ) - { - if( Exile_Timer < diff ) - { - if( Unit* temp = Unit::GetUnit(*m_creature,playerGUID) ) - { - temp->CastSpell(temp,SPELL_EXILE,true); - temp->CastSpell(temp,SPELL_BANISH_TELEPORT,true); - } - playerGUID = 0; - Exile_Timer = 8500; - CanTeleport = false; - }else Exile_Timer -= diff; - } - else if( Banish_Timer < diff ) - { - Unit* temp = m_creature->getVictim(); - if( temp && temp->GetTypeId() == TYPEID_PLAYER ) - { - DoCast(temp,SPELL_BANISHED_SHATTRATH_S); - Banish_Timer = 9000; - playerGUID = temp->GetGUID(); - if( playerGUID ) - CanTeleport = true; - } - }else Banish_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -bool GossipHello_guard_shattrath_scryer(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAVERN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FLIGHTMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MANALOOM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMYLAB , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMMERCHANT , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(10430, _Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_shattrath_scryer(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Tavern - player->SEND_POI(-1759.5, 5165, 6, 6, 0, "Worlds End Tavern"); - player->SEND_GOSSIP_MENU(10431, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bank - player->SEND_POI(-1996.6, 5363.7, 6, 6, 0, "Scryer Bank"); - player->SEND_GOSSIP_MENU(10432, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Inn - player->SEND_POI(-2176.6, 5405.8, 6, 6, 0, "Scryer Inn"); - player->SEND_GOSSIP_MENU(10433, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Flight master - player->SEND_POI(-1832, 5299, 6, 6, 0, "Shattrath Flight Master"); - player->SEND_GOSSIP_MENU(10435, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox - player->SEND_POI(-2174.3, 5411.4, 6, 6, 0, "Scryer Mailbox"); - player->SEND_GOSSIP_MENU(10436, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Stable master - player->SEND_POI(-2169.9, 5405.1, 6, 6, 0, "Scryer Stable Master"); - player->SEND_GOSSIP_MENU(10437, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERALLIANCE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERHORDE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(10438, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Profession master - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(10504, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Mana Loom - player->SEND_POI(-2070, 5265.5, 6, 6, 0, "Mana Loom"); - player->SEND_GOSSIP_MENU(10522, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Alchemy Lab - player->SEND_POI(-1648.5, 5540, 6, 6, 0, "Alchemy Lab"); - player->SEND_GOSSIP_MENU(10701, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Gem Merchant - player->SEND_POI(-1645, 5669.5, 6, 6, 0, "Scryer Gem Merchant"); - player->SEND_GOSSIP_MENU(10702, _Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_shattrath_scryer(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-1648.5, 5534, 6, 6, 0, "Lorokeem"); - player->SEND_GOSSIP_MENU(10516, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-1847, 5222, 6, 6, 0, "Kradu Grimblade and Zula Slagfury"); - player->SEND_GOSSIP_MENU(10517, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-2067.4, 5316.5, 6, 6, 0, "Jack Trapper"); - player->SEND_GOSSIP_MENU(10518, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(-2263.5, 5563.5, 6, 6, 0, "High Enchanter Bardolan"); - player->SEND_GOSSIP_MENU(10519, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //First Aid - player->SEND_POI(-1591, 5265.5, 6, 6, 0, "Mildred Fletcher"); - player->SEND_GOSSIP_MENU(10520, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Jewelcrafting - player->SEND_POI(-1654, 5667.5, 6, 6, 0, "Hamanar"); - player->SEND_GOSSIP_MENU(10521, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking - player->SEND_POI(-2060.5, 5256.5, 6, 6, 0, "Darmari"); - player->SEND_GOSSIP_MENU(10523, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Skinning - player->SEND_POI(-2048, 5300, 6, 6, 0, "Seymour"); - player->SEND_GOSSIP_MENU(10523, _Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_shattrath_scryer(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_shattrath_scryer(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_shattrath_scryer(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_shattrath(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_shattrath_scryer end - *******************************************************/ - -CreatureAI* GetAI_guard_shattrath_scryer(Creature *_Creature) -{ - return new guard_shattrath_scryerAI (_Creature); -} - -/******************************************************* - * guard_silvermoon start - *******************************************************/ - -bool GossipHello_guard_silvermoon(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Auction house - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AH_SILVERMOON_1 , GOSSIP_SENDER_SEC_AUCTIONHOUSE, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AH_SILVERMOON_2 , GOSSIP_SENDER_SEC_AUCTIONHOUSE, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(9317, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bank - player->SEND_POI(9808.4, -7488.16, 6, 6, 0, "Silvermoon Bank"); - player->SEND_GOSSIP_MENU(9322, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Guild master - player->SEND_POI(9474.97, -7345.21, 6, 6, 0, "Tandrine"); - player->SEND_GOSSIP_MENU(9324, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN_SILVERMOON_1 , GOSSIP_SENDER_SEC_INN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN_SILVERMOON_2 , GOSSIP_SENDER_SEC_INN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(9602, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox - player->SEND_POI(9658.33, -7492.17, 6, 6, 0, "Silvermoon Mailbox"); - player->SEND_GOSSIP_MENU(9326, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Stable master - player->SEND_POI(9904.95, -7404.31, 6, 6, 0, "Shalenn"); - player->SEND_GOSSIP_MENU(9327, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Weapon trainer - player->SEND_POI(9841.17, -7505.13, 6, 6, 0, "Ileda"); - player->SEND_GOSSIP_MENU(9328, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Wind master - player->SEND_POI(9378.45, -7163.94, 6, 6, 0, "Silvermoon Wind Master"); - player->SEND_GOSSIP_MENU(10181, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_EYEOFTHESTORM , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(9331, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 13); - player->SEND_GOSSIP_MENU(9338, _Creature->GetGUID()); - break; - } -} - -void SendAuctionhouseMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->SEND_POI(9644.47, -7140.22, 6, 6, 0, "Western Auction House"); - player->SEND_GOSSIP_MENU(9318, _Creature->GetGUID()); - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->SEND_POI(9683.27, -7521.22, 6, 6, 0, "Royal Exchange Auction House"); - player->SEND_GOSSIP_MENU(9319, _Creature->GetGUID()); - } -} - -void SendInnMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->SEND_POI(9677.7, -7368, 6, 6, 0, "Silvermoon City Inn"); - player->SEND_GOSSIP_MENU(9325, _Creature->GetGUID()); - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->SEND_POI(9561.1, -7517.5, 6, 6, 0, "Wayfarer's Rest tavern"); - player->SEND_GOSSIP_MENU(9603, _Creature->GetGUID()); - } -} - -void SendBattleMasterMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //AV - player->SEND_POI(9850.49, -7572.26, 6, 6, 0, "Gurak"); - player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //AB - player->SEND_POI(9857.18, -7564.36, 6, 6, 0, "Karen Wentworth"); - player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //A - player->SEND_POI(9850.6, -7559.25, 6, 6, 0, "Bipp Glizzitor"); - player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //EOS - player->SEND_POI(9857.18, -7564.36, 6, 6, 0, "Karen Wentworth"); - player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //WSG - player->SEND_POI(9845.45, -7562.58, 6, 6, 0, "Krukk"); - player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_POI(9700.55, -7262.57, 6, 6, 0, "Harene Plainwalker"); - player->SEND_GOSSIP_MENU(9330, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_POI(9927.48, -7426.14, 6, 6, 0, "Zandine"); - player->SEND_GOSSIP_MENU(9332, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Mage - player->SEND_POI(9995.07, -7118.17, 6, 6, 0, "Quithas"); - player->SEND_GOSSIP_MENU(9333, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Paladin - player->SEND_POI(9850.22, -7516.93, 6, 6, 0, "Champion Bachi"); - player->SEND_GOSSIP_MENU(9334, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Priest - player->SEND_POI(9926.79, -7066.66, 6, 6, 0, "Belestra"); - player->SEND_GOSSIP_MENU(9335, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Rogue - player->SEND_POI(9739.88, -7374.33, 6, 6, 0, "Zelanis"); - player->SEND_GOSSIP_MENU(9336, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Warlock - player->SEND_POI(9787.57, -7284.63, 6, 6, 0, "Alamma"); - player->SEND_GOSSIP_MENU(9337, _Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(9998.09, -7214.36, 6, 6, 0, "Silvermoon Alchemy Trainer"); - player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(9841.43, -7361.53, 6, 6, 0, "Silvermoon Blacksmithing Trainer"); - player->SEND_GOSSIP_MENU(9340, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(9577.26, -7243.6, 6, 6, 0, "Silvermoon Cooking Trainer"); - player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(9962.57, -7246.18, 6, 6, 0, "Silvermoon Enchanting Trainer"); - player->SEND_GOSSIP_MENU(9341, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(9820.18, -7329.56, 6, 6, 0, "Silvermoon Engineering Trainer"); - player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(9579.8, -7343.71, 6, 6, 0, "Silvermoon First Aid Trainer"); - player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(9602.73, -7328.3, 6, 6, 0, "Silvermoon Fishing Trainer"); - player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Jewelcrafting - player->SEND_POI(9553.54, -7506.43, 6, 6, 0, "Silvermoon Jewelcrafting Trainer"); - player->SEND_GOSSIP_MENU(9346, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Herbalism - player->SEND_POI(10004.4, -7216.86, 6, 6, 0, "Silvermoon Herbalism Trainer"); - player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Leatherworking - player->SEND_POI(9503.72, -7430.16, 6, 6, 0, "Silvermoon Leatherworking Trainer"); - player->SEND_GOSSIP_MENU(9347, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Mining - player->SEND_POI(9805.1, -7355.56, 6, 6, 0, "Silvermoon Mining Trainer"); - player->SEND_GOSSIP_MENU(9348, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Skinning - player->SEND_POI(9513.37, -7429.4, 6, 6, 0, "Silvermoon Skinning Trainer"); - player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: //Tailoring - player->SEND_POI(9750.55, -7095.28, 6, 6, 0, "Silvermoon Tailor"); - player->SEND_GOSSIP_MENU(9350, _Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_silvermoon(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_silvermoon(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_AUCTIONHOUSE: SendAuctionhouseMenu_guard_silvermoon(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_INN: SendInnMenu_guard_silvermoon(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_silvermoon(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_silvermoon(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_silvermoon(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_silvermoon end - *******************************************************/ - -CreatureAI* GetAI_guard_silvermoon(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_stormwind start - *******************************************************/ - -bool GossipHello_guard_stormwind(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STORMWIND_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DEEPRUNTRAM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GRYPHON , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_OFFICERS , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); - player->SEND_GOSSIP_MENU(933,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_stormwind(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Auction House - player->SEND_POI(-8811.46, 667.46, 6, 6, 0, "Stormwind Auction House"); - player->SEND_GOSSIP_MENU(3834,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bank - player->SEND_POI(-8916.87, 622.87, 6, 6, 0, "Stormwind Bank"); - player->SEND_GOSSIP_MENU(764,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Deeprun tram - player->SEND_POI(-8378.88, 554.23, 6, 6, 0, "The Deeprun Tram"); - player->SEND_GOSSIP_MENU(3813,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->SEND_POI(-8869.0, 675.4, 6, 6, 0, "The Gilded Rose"); - player->SEND_GOSSIP_MENU(3860,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Gryphon Master - player->SEND_POI(-8837.0, 493.5, 6, 6, 0, "Stormwind Gryphon Master"); - player->SEND_GOSSIP_MENU(879,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Guild Master - player->SEND_POI(-8894.0, 611.2, 6, 6, 0, "Stormwind Vistor`s Center"); - player->SEND_GOSSIP_MENU(882,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Mailbox - player->SEND_POI(-8876.48, 649.18, 6, 6, 0, "Stormwind Mailbox"); - player->SEND_GOSSIP_MENU(3861,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Stable Master - player->SEND_POI(-8433.0, 554.7, 6, 6, 0, "Jenova Stoneshield"); - player->SEND_GOSSIP_MENU(5984,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Weapon Trainer - player->SEND_POI(-8797.0, 612.8, 6, 6, 0, "Woo Ping"); - player->SEND_GOSSIP_MENU(4516,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Officers Lounge - player->SEND_POI(-8759.92, 399.69, 6, 6, 0, "Champions` Hall"); - player->SEND_GOSSIP_MENU(7047,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Battlemasters - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(7499,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Class trainers - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->SEND_GOSSIP_MENU(898,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: //Profession trainers - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(918,_Creature->GetGUID()); - break; - } -} - -void SendBattleMasterMenu_guard_stormwind(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //AV - player->SEND_POI(-8443.88, 335.99, 6, 6, 0, "Thelman Slatefist"); - player->SEND_GOSSIP_MENU(7500, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //AB - player->SEND_POI(-8443.88, 335.99, 6, 6, 0, "Lady Hoteshem"); - player->SEND_GOSSIP_MENU(7650, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //WSG - player->SEND_POI(-8443.88, 335.99, 6, 6, 0, "Elfarran"); - player->SEND_GOSSIP_MENU(7501, _Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_stormwind(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Mage - player->SEND_POI(-9012.0, 867.6, 6, 6, 0, "Wizard`s Sanctum"); - player->SEND_GOSSIP_MENU(899,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Rogue - player->SEND_POI(-8753.0, 367.8, 6, 6, 0, "Stormwind - Rogue House"); - player->SEND_GOSSIP_MENU(900,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Warrior - player->SEND_POI(-8624.54, 402.61, 6, 6, 0, "Pig and Whistle Tavern"); - player->SEND_GOSSIP_MENU(901,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Druid - player->SEND_POI(-8751.0, 1124.5, 6, 6, 0, "The Park"); - player->SEND_GOSSIP_MENU(902,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Priest - player->SEND_POI(-8512.0, 862.4, 6, 6, 0, "Catedral Of Light"); - player->SEND_GOSSIP_MENU(903,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Paladin - player->SEND_POI(-8577.0, 881.7, 6, 6, 0, "Catedral Of Light"); - player->SEND_GOSSIP_MENU(904,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Hunter - player->SEND_POI(-8413.0, 541.5, 6, 6, 0, "Hunter Lodge"); - player->SEND_GOSSIP_MENU(905,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Warlock - player->SEND_POI(-8948.91, 998.35, 6, 6, 0, "The Slaughtered Lamb"); - player->SEND_GOSSIP_MENU(906,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Shaman - player->SEND_POI(-9033, 550, 6, 6, 0, "Valley Of Heroes"); - //incorrect id - player->SEND_GOSSIP_MENU(2593,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_stormwind(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(-8988.0, 759.60, 6, 6, 0, "Alchemy Needs"); - player->SEND_GOSSIP_MENU(919,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(-8424.0, 616.9, 6, 6, 0, "Therum Deepforge"); - player->SEND_GOSSIP_MENU(920,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(-8611.0, 364.6, 6, 6, 0, "Pig and Whistle Tavern"); - player->SEND_GOSSIP_MENU(921,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(-8858.0, 803.7, 6, 6, 0, "Lucan Cordell"); - player->SEND_GOSSIP_MENU(941,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(-8347.0, 644.1, 6, 6, 0, "Lilliam Sparkspindle"); - player->SEND_GOSSIP_MENU(922,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(-8513.0, 801.8, 6, 6, 0, "Shaina Fuller"); - player->SEND_GOSSIP_MENU(923,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(-8803.0, 767.5, 6, 6, 0, "Arnold Leland"); - player->SEND_GOSSIP_MENU(940,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_POI(-8967.0, 779.5, 6, 6, 0, "Alchemy Needs"); - player->SEND_GOSSIP_MENU(924,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_POI(-8726.0, 477.4, 6, 6, 0, "The Protective Hide"); - player->SEND_GOSSIP_MENU(925,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Mining - player->SEND_POI(-8434.0, 692.8, 6, 6, 0, "Gelman Stonehand"); - player->SEND_GOSSIP_MENU(927,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_POI(-8716.0, 469.4, 6, 6, 0, "The Protective Hide"); - player->SEND_GOSSIP_MENU(928,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_POI(-8938.0, 800.7, 6, 6, 0, "Duncan`s Textiles"); - player->SEND_GOSSIP_MENU(929,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_stormwind(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_stormwind(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_stormwind(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_stormwind(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_stormwind(player, _Creature, action); break; - } - return true; -} - -bool ReceiveEmote_guard_stormwind(Player *player, Creature *_Creature, uint32 emote) -{ - if( player->GetTeam() == ALLIANCE ) - DoReplyToTextEmote(_Creature,emote); - return true; -} - -/******************************************************* - * guard_stormwind end - *******************************************************/ - -CreatureAI* GetAI_guard_stormwind(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_teldrassil start - *******************************************************/ - -bool GossipHello_guard_teldrassil(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FERRY , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(4316,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_teldrassil(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_GOSSIP_MENU(4317,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Rut`theran - player->SEND_GOSSIP_MENU(4318,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Guild master - player->SEND_GOSSIP_MENU(4319,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->SEND_POI(9821.49, 960.13, 6, 6, 0, "Dolanaar Inn"); - player->SEND_GOSSIP_MENU(4320,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //stable master - player->SEND_POI(9808.37, 931.1, 6, 6, 0, "Seriadne"); - player->SEND_GOSSIP_MENU(5982,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(4264,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->SEND_GOSSIP_MENU(4273,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_teldrassil(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Druid - player->SEND_POI(9741.58, 963.7, 6, 6, 0, "Kal"); - player->SEND_GOSSIP_MENU(4323,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Hunter - player->SEND_POI(9815.12, 926.28, 6, 6, 0, "Dazalar"); - player->SEND_GOSSIP_MENU(4324,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Priest - player->SEND_POI(9906.16, 986.63, 6, 6, 0, "Laurna Morninglight"); - player->SEND_GOSSIP_MENU(4325,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Rogue - player->SEND_POI(9789, 942.86, 6, 6, 0, "Jannok Breezesong"); - player->SEND_GOSSIP_MENU(4326,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Warrior - player->SEND_POI(9821.96, 950.61, 6, 6, 0, "Kyra Windblade"); - player->SEND_GOSSIP_MENU(4327,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_teldrassil(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(9767.59, 878.81, 6, 6, 0, "Cyndra Kindwhisper"); - player->SEND_GOSSIP_MENU(4329,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Cooking - player->SEND_POI(9751.19, 906.13, 6, 6, 0, "Zarrin"); - player->SEND_GOSSIP_MENU(4330,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Enchanting - player->SEND_POI(10677.59, 1946.56, 6, 6, 0, "Alanna Raveneye"); - player->SEND_GOSSIP_MENU(4331,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //First Aid - player->SEND_POI(9903.12, 999, 6, 6, 0, "Byancie"); - player->SEND_GOSSIP_MENU(4332,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Fishing - player->SEND_GOSSIP_MENU(4333,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Herbalism - player->SEND_POI(9773.78, 875.88, 6, 6, 0, "Malorne Bladeleaf"); - player->SEND_GOSSIP_MENU(4334,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking - player->SEND_POI(10152.59, 1681.46, 6, 6, 0, "Nadyia Maneweaver"); - player->SEND_GOSSIP_MENU(4335,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Skinning - player->SEND_POI(10135.59, 1673.18, 6, 6, 0, "Radnaal Maneweaver"); - player->SEND_GOSSIP_MENU(4336,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Tailoring - player->SEND_GOSSIP_MENU(4337,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_teldrassil(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_teldrassil(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_teldrassil(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_teldrassil(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_teldrassil end - *******************************************************/ - -CreatureAI* GetAI_guard_teldrassil(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_tirisfal start - *******************************************************/ - -bool GossipHello_guard_tirisfal(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATHANDLER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(4097,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_tirisfal(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_GOSSIP_MENU(4074,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //bat handler - player->SEND_GOSSIP_MENU(4075,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Inn - player->SEND_POI(2246.68, 241.89, 6, 6, 0, "Gallows` End Tavern"); - player->SEND_GOSSIP_MENU(4076,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Stable Master - player->SEND_POI(2267.66, 319.32, 6, 6, 0, "Morganus"); - player->SEND_GOSSIP_MENU(5978,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(4292,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(4096,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_tirisfal(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Mage - player->SEND_POI(2259.18, 240.93, 6, 6, 0, "Cain Firesong"); - player->SEND_GOSSIP_MENU(4077,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Priest - player->SEND_POI(2259.18, 240.93, 6, 6, 0, "Dark Cleric Beryl"); - player->SEND_GOSSIP_MENU(4078,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Rogue - player->SEND_POI(2259.18, 240.93, 6, 6, 0, "Marion Call"); - player->SEND_GOSSIP_MENU(4079,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Warlock - player->SEND_POI(2259.18, 240.93, 6, 6, 0, "Rupert Boch"); - player->SEND_GOSSIP_MENU(4080,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Warrior - player->SEND_POI(2256.48, 240.32, 6, 6, 0, "Austil de Mon"); - player->SEND_GOSSIP_MENU(4081,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_tirisfal(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(2263.25, 344.23, 6, 6, 0, "Carolai Anise"); - player->SEND_GOSSIP_MENU(4082,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_GOSSIP_MENU(4083,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_GOSSIP_MENU(4084,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(2250.35, 249.12, 6, 6, 0, "Vance Undergloom"); - player->SEND_GOSSIP_MENU(4085,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_GOSSIP_MENU(4086,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(2246.68, 241.89, 6, 6, 0, "Nurse Neela"); - player->SEND_GOSSIP_MENU(4087,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(2292.37, -10.72, 6, 6, 0, "Clyde Kellen"); - player->SEND_GOSSIP_MENU(4088,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_POI(2268.21, 331.69, 6, 6, 0, "Faruza"); - player->SEND_GOSSIP_MENU(4089,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_POI(2027, 78.72, 6, 6, 0, "Shelene Rhobart"); - player->SEND_GOSSIP_MENU(4090,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Mining - player->SEND_GOSSIP_MENU(4091,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_POI(2027, 78.72, 6, 6, 0, "Rand Rhobart"); - player->SEND_GOSSIP_MENU(4092,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_POI(2160.45, 659.93, 6, 6, 0, "Bowen Brisboise"); - player->SEND_GOSSIP_MENU(4093,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_tirisfal(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_tirisfal(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_tirisfal(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_tirisfal(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_tirisfal end - *******************************************************/ - -CreatureAI* GetAI_guard_tirisfal(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * guard_undercity start - *******************************************************/ - -bool GossipHello_guard_undercity(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATHANDLER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ZEPPLINMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(3543,_Creature->GetGUID()); - return true; -} - -void SendDefaultMenu_guard_undercity(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Bank - player->SEND_POI(1595.64, 232.45, 6, 6, 0, "Undercity Bank"); - player->SEND_GOSSIP_MENU(3514,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Bat handler - player->SEND_POI(1565.9, 271.43, 6, 6, 0, "Undercity Bat Handler"); - player->SEND_GOSSIP_MENU(3515,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Guild master - player->SEND_POI(1594.17, 205.57, 6, 6, 0, "Undercity Guild Master"); - player->SEND_GOSSIP_MENU(3516,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Inn - player->SEND_POI(1639.43, 220.99, 6, 6, 0, "Undercity Inn"); - player->SEND_GOSSIP_MENU(3517,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox - player->SEND_POI(1632.68, 219.4, 6, 6, 0, "Undercity Mailbox"); - player->SEND_GOSSIP_MENU(3518,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //Auction House - player->SEND_POI(1647.9, 258.49, 6, 6, 0, "Undercity Auction House"); - player->SEND_GOSSIP_MENU(3519,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Zeppelin - player->SEND_POI(2059, 274.86, 6, 6, 0, "Undercity Zeppelin"); - player->SEND_GOSSIP_MENU(3520,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Weapon Master - player->SEND_POI(1670.31, 324.66, 6, 6, 0, "Archibald"); - player->SEND_GOSSIP_MENU(4521,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Stable master - player->SEND_POI(1634.18, 226.76, 6, 6, 0, "Anya Maulray"); - player->SEND_GOSSIP_MENU(5979,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Battlemaster - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(7527,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Class trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(3542,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Profession trainer - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(3541,_Creature->GetGUID()); - break; - } -} - -void SendBattleMasterMenu_guard_undercity(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //AV - player->SEND_POI(1329, 333.92, 6, 6, 0, "Grizzle Halfmane"); - player->SEND_GOSSIP_MENU(7525,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //AB - player->SEND_POI(1283.3, 287.16, 6, 6, 0, "Sir Malory Wheeler"); - player->SEND_GOSSIP_MENU(7646,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //WSG - player->SEND_POI(1265, 351.18, 6, 6, 0, "Kurden Bloodclaw"); - player->SEND_GOSSIP_MENU(7526,_Creature->GetGUID()); - break; - } -} - -void SendClassTrainerMenu_guard_undercity(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Mage - player->SEND_POI(1781, 53, 6, 6, 0, "Undercity Mage Trainers"); - player->SEND_GOSSIP_MENU(3513,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Priest - player->SEND_POI(1758.33, 401.5, 6, 6, 0, "Undercity Priest Trainers"); - player->SEND_GOSSIP_MENU(3521,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Rogue - player->SEND_POI(1418.56, 65, 6, 6, 0, "Undercity Rogue Trainers"); - player->SEND_GOSSIP_MENU(3524,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Warlock - player->SEND_POI(1780.92, 53.16, 6, 6, 0, "Undercity Warlock Trainers"); - player->SEND_GOSSIP_MENU(3526,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Warrior - player->SEND_POI(1775.59, 418.19, 6, 6, 0, "Undercity Warrior Trainers"); - player->SEND_GOSSIP_MENU(3527,_Creature->GetGUID()); - break; - } -} - -void SendProfTrainerMenu_guard_undercity(Player *player, Creature *_Creature, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy - player->SEND_POI(1419.82, 417.19, 6, 6, 0, "The Apothecarium"); - player->SEND_GOSSIP_MENU(3528,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing - player->SEND_POI(1696, 285, 6, 6, 0, "Undercity Blacksmithing Trainer"); - player->SEND_GOSSIP_MENU(3529,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: //Cooking - player->SEND_POI(1596.34, 274.68, 6, 6, 0, "Undercity Cooking Trainer"); - player->SEND_GOSSIP_MENU(3530,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting - player->SEND_POI(1488.54, 280.19, 6, 6, 0, "Undercity Enchanting Trainer"); - player->SEND_GOSSIP_MENU(3531,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: //Engineering - player->SEND_POI(1408.58, 143.43, 6, 6, 0, "Undercity Engineering Trainer"); - player->SEND_GOSSIP_MENU(3532,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: //First Aid - player->SEND_POI(1519.65, 167.19, 6, 6, 0, "Undercity First Aid Trainer"); - player->SEND_GOSSIP_MENU(3533,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: //Fishing - player->SEND_POI(1679.9, 89, 6, 6, 0, "Undercity Fishing Trainer"); - player->SEND_GOSSIP_MENU(3534,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism - player->SEND_POI(1558, 349.36, 6, 6, 0, "Undercity Herbalism Trainer"); - player->SEND_GOSSIP_MENU(3535,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking - player->SEND_POI(1498.76, 196.43, 6, 6, 0, "Undercity Leatherworking Trainer"); - player->SEND_GOSSIP_MENU(3536,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: //Mining - player->SEND_POI(1642.88, 335.58, 6, 6, 0, "Undercity Mining Trainer"); - player->SEND_GOSSIP_MENU(3537,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: //Skinning - player->SEND_POI(1498.6, 196.46, 6, 6, 0, "Undercity Skinning Trainer"); - player->SEND_GOSSIP_MENU(3538,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring - player->SEND_POI(1689.55, 193, 6, 6, 0, "Undercity Tailoring Trainer"); - player->SEND_GOSSIP_MENU(3539,_Creature->GetGUID()); - break; - } -} - -bool GossipSelect_guard_undercity(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (sender) - { - case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_undercity(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_undercity(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_undercity(player, _Creature, action); break; - case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_undercity(player, _Creature, action); break; - } - return true; -} - -/******************************************************* - * guard_undercity end - *******************************************************/ - -CreatureAI* GetAI_guard_undercity(Creature *_Creature) -{ - return new guardAI (_Creature); -} - -/******************************************************* - * AddSC - *******************************************************/ - -void AddSC_guards() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="guard_azuremyst"; - newscript->pGossipHello = &GossipHello_guard_azuremyst; - newscript->pGossipSelect = &GossipSelect_guard_azuremyst; - newscript->GetAI = GetAI_guard_azuremyst; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_bluffwatcher"; - newscript->pGossipHello = &GossipHello_guard_bluffwatcher; - newscript->pGossipSelect = &GossipSelect_guard_bluffwatcher; - newscript->GetAI = GetAI_guard_bluffwatcher; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_contested"; - newscript->GetAI = GetAI_guard_contested; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_darnassus"; - newscript->pGossipHello = &GossipHello_guard_darnassus; - newscript->pGossipSelect = &GossipSelect_guard_darnassus; - newscript->GetAI = GetAI_guard_darnassus; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_dunmorogh"; - newscript->pGossipHello = &GossipHello_guard_dunmorogh; - newscript->pGossipSelect = &GossipSelect_guard_dunmorogh; - newscript->GetAI = GetAI_guard_dunmorogh; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_durotar"; - newscript->pGossipHello = &GossipHello_guard_durotar; - newscript->pGossipSelect = &GossipSelect_guard_durotar; - newscript->GetAI = GetAI_guard_durotar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_elwynnforest"; - newscript->pGossipHello = &GossipHello_guard_elwynnforest; - newscript->pGossipSelect = &GossipSelect_guard_elwynnforest; - newscript->GetAI = GetAI_guard_elwynnforest; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_eversong"; - newscript->pGossipHello = &GossipHello_guard_eversong; - newscript->pGossipSelect = &GossipSelect_guard_eversong; - newscript->GetAI = GetAI_guard_eversong; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_exodar"; - newscript->pGossipHello = &GossipHello_guard_exodar; - newscript->pGossipSelect = &GossipSelect_guard_exodar; - newscript->GetAI = GetAI_guard_exodar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_ironforge"; - newscript->pGossipHello = &GossipHello_guard_ironforge; - newscript->pGossipSelect = &GossipSelect_guard_ironforge; - newscript->GetAI = GetAI_guard_ironforge; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_mulgore"; - newscript->pGossipHello = &GossipHello_guard_mulgore; - newscript->pGossipSelect = &GossipSelect_guard_mulgore; - newscript->GetAI = GetAI_guard_mulgore; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_orgrimmar"; - newscript->pGossipHello = &GossipHello_guard_orgrimmar; - newscript->pGossipSelect = &GossipSelect_guard_orgrimmar; - newscript->pReceiveEmote = &ReceiveEmote_guard_orgrimmar; - newscript->GetAI = GetAI_guard_orgrimmar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_shattrath"; - newscript->pGossipHello = &GossipHello_guard_shattrath; - newscript->pGossipSelect = &GossipSelect_guard_shattrath; - newscript->GetAI = GetAI_guard_shattrath; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_shattrath_aldor"; - newscript->GetAI = GetAI_guard_shattrath_aldor; - newscript->pGossipHello = &GossipHello_guard_shattrath_aldor; - newscript->pGossipSelect = &GossipSelect_guard_shattrath_aldor; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_shattrath_scryer"; - newscript->GetAI = GetAI_guard_shattrath_scryer; - newscript->pGossipHello = &GossipHello_guard_shattrath_scryer; - newscript->pGossipSelect = &GossipSelect_guard_shattrath_scryer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_silvermoon"; - newscript->pGossipHello = &GossipHello_guard_silvermoon; - newscript->pGossipSelect = &GossipSelect_guard_silvermoon; - newscript->GetAI = GetAI_guard_silvermoon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_stormwind"; - newscript->pGossipHello = &GossipHello_guard_stormwind; - newscript->pGossipSelect = &GossipSelect_guard_stormwind; - newscript->pReceiveEmote = &ReceiveEmote_guard_stormwind; - newscript->GetAI = GetAI_guard_stormwind; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_teldrassil"; - newscript->pGossipHello = &GossipHello_guard_teldrassil; - newscript->pGossipSelect = &GossipSelect_guard_teldrassil; - newscript->GetAI = GetAI_guard_teldrassil; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_tirisfal"; - newscript->pGossipHello = &GossipHello_guard_tirisfal; - newscript->pGossipSelect = &GossipSelect_guard_tirisfal; - newscript->GetAI = GetAI_guard_tirisfal; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="guard_undercity"; - newscript->pGossipHello = &GossipHello_guard_undercity; - newscript->pGossipSelect = &GossipSelect_guard_undercity; - newscript->GetAI = GetAI_guard_undercity; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Guards +SD%Complete: 100 +SDComment: All Guard gossip data, quite some npc_text-id's still missing, adding constantly as new id's are known. CombatAI should be organized better for future. +SDCategory: Guards +EndScriptData */ + +/* ContentData +guard_azuremyst +guard_bluffwatcher +guard_contested +guard_darnassus +guard_dunmorogh +guard_durotar +guard_elwynnforest +guard_eversong +guard_exodar +guard_ironforge +guard_mulgore +guard_orgrimmar +guard_shattrath +guard_shattrath_aldor +guard_shattrath_scryer +guard_silvermoon +guard_stormwind +guard_teldrassil +guard_tirisfal +guard_undercity +EndContentData */ + +#include "precompiled.h" +#include "guard_ai.h" + +//script spesific action +#define GOSSIP_ACTION_TAVERN 101 +#define GOSSIP_ACTION_GEMMERCHANT 102 +#define GOSSIP_ACTION_MANALOOM 103 + +//script spesific sender +#define GOSSIP_SENDER_SEC_GEMMERCHANT 101 +#define GOSSIP_SENDER_SEC_AUCTIONHOUSE 102 + +//script spesific gossip text +#define GOSSIP_TEXT_TAVERN "Worlds End Tavern" +#define GOSSIP_TEXT_BANKSCYERS "Scyers bank" +#define GOSSIP_TEXT_BANKALDOR "Aldor Bank" +#define GOSSIP_TEXT_INNSCYERS "Scyers Inn" +#define GOSSIP_TEXT_INNALDOR "Aldor Inn" +#define GOSSIP_TEXT_STABLESCYERS "Scyers Stable" +#define GOSSIP_TEXT_STABLEALDOR "Aldor Stable" +#define GOSSIP_TEXT_BATTLEMASTERALLIANCE "Alliance Battlemasters" +#define GOSSIP_TEXT_BATTLEMASTERHORDE "Horde Battlemasters" +#define GOSSIP_TEXT_BATTLEMASTERARENA "Arena Battlemasters" +#define GOSSIP_TEXT_MANALOOM "Mana Loom" +#define GOSSIP_TEXT_ALCHEMYLAB "Alchemy Lab" +#define GOSSIP_TEXT_GEMMERCHANT "Gem Merchant" +#define GOSSIP_TEXT_GEMSCYERS "Scyers Gem Merchant" +#define GOSSIP_TEXT_GEMALDOR "Aldor Gem Merchant" + +#define GOSSIP_TEXT_AH_SILVERMOON_1 "Western Auction House" +#define GOSSIP_TEXT_AH_SILVERMOON_2 "Royal Exchange Auction House" + +#define GOSSIP_TEXT_INN_SILVERMOON_1 "Silvermoon City Inn" +#define GOSSIP_TEXT_INN_SILVERMOON_2 "Wayfarer's Rest tavern" + +//common used for guards in main cities +void DoReplyToTextEmote(Creature *_Creature,uint32 em) +{ + switch(em) + { + case TEXTEMOTE_KISS: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_BOW); break; + case TEXTEMOTE_WAVE: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); break; + case TEXTEMOTE_SALUTE: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); break; + case TEXTEMOTE_SHY: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_FLEX); break; + case TEXTEMOTE_RUDE: + case TEXTEMOTE_CHICKEN: _Creature->HandleEmoteCommand(EMOTE_ONESHOT_POINT); break; + } +} + +/******************************************************* + * guard_azuremyst start + *******************************************************/ + +bool GossipHello_guard_azuremyst(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HIPPOGRYPH , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(10066,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_azuremyst(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_POI(-3918.95, -11544.7, 6, 6, 0, "Bank"); + player->SEND_GOSSIP_MENU(10067,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hippogryph Master + player->SEND_POI(-4057.15, -11788.6, 6, 6, 0, "Stephanos"); + player->SEND_GOSSIP_MENU(10071,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Guild master + player->SEND_POI(-4092.43, -11626.6, 6, 6, 0, "Funaam"); + player->SEND_GOSSIP_MENU(10073,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->SEND_POI(-4129.43, -12469, 6, 6, 0, "Caregiver Chellan"); + player->SEND_GOSSIP_MENU(10074,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Stable Master + player->SEND_POI(-4146.42, -12492.7, 6, 6, 0, "Esbina"); + player->SEND_GOSSIP_MENU(10075,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(10076,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 13); + player->SEND_GOSSIP_MENU(10087,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_azuremyst(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_POI(-4274.81, -11495.3, 6, 6, 0, "Shalannius"); + player->SEND_GOSSIP_MENU(10077,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_POI(-4203.65, -12526.5, 6, 6, 0, "Acteon"); + player->SEND_GOSSIP_MENU(10078,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Mage + player->SEND_POI(-4149.62, -12530.1, 6, 6, 0, "Semid"); + player->SEND_GOSSIP_MENU(10081,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Paladin + player->SEND_POI(-4138.98, -12468.5, 6, 6, 0, "Tullas"); + player->SEND_GOSSIP_MENU(10083,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Priest + player->SEND_POI(-4131.66, -12478.6, 6, 6, 0, "Guvan"); + player->SEND_GOSSIP_MENU(10084,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Shaman + player->SEND_POI(-4162.33, -12456.1, 6, 6, 0, "Tuluun"); + player->SEND_GOSSIP_MENU(10085,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warrior + player->SEND_POI(-4165.05, -12536.4, 6, 6, 0, "Ruada"); + player->SEND_GOSSIP_MENU(10086,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_azuremyst(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-4191.15, -12470, 6, 6, 0, "Daedal"); + player->SEND_GOSSIP_MENU(10088,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-4726.29, -12387, 6, 6, 0, "Blacksmith Calypso"); + player->SEND_GOSSIP_MENU(10089,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-4710.87, -12400.6, 6, 6, 0, "'Cookie' McWeaksauce"); + player->SEND_GOSSIP_MENU(10090,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(-3882.85, -11496.7, 6, 6, 0, "Nahogg"); + player->SEND_GOSSIP_MENU(10091,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(-4157.57, -12470.2, 6, 6, 0, "Artificer Daelo"); + player->SEND_GOSSIP_MENU(10092,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(-4199.11, -12469.9, 6, 6, 0, "Anchorite Fateema"); + player->SEND_GOSSIP_MENU(10093,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(-4266.38, -12985.1, 6, 6, 0, "Diktynna"); + player->SEND_GOSSIP_MENU(10094,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_GOSSIP_MENU(10095,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Jewelcrafting + player->SEND_POI(-3781.55, -11541.8, 6, 6, 0, "Farii"); + player->SEND_GOSSIP_MENU(10097,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Leatherworking + player->SEND_POI(-3442.68, -12322.2, 6, 6, 0, "Moordo"); + player->SEND_GOSSIP_MENU(10098,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Mining + player->SEND_POI(-4179.89, -12493.1, 6, 6, 0, "Dulvi"); + player->SEND_GOSSIP_MENU(10097,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Skinning + player->SEND_POI(-3431.17, -12316.5, 6, 6, 0, "Gurf"); + player->SEND_GOSSIP_MENU(10098,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 13: //Tailoring + player->SEND_POI(-4711.54, -12386.7, 6, 6, 0, "Erin Kelly"); + player->SEND_GOSSIP_MENU(10099,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_azuremyst(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_azuremyst(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_azuremyst(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_azuremyst(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_azuremyst end + *******************************************************/ + +CreatureAI* GetAI_guard_azuremyst(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_bluffwatcher start + *******************************************************/ + +bool GossipHello_guard_bluffwatcher(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(3543,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_POI(-1257.8, 24.14, 6, 6, 0, "Thunder Bluff Bank"); + player->SEND_GOSSIP_MENU(1292,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Wind master + player->SEND_POI(-1196.43, 28.26, 6, 6, 0, "Wind Rider Roost"); + player->SEND_GOSSIP_MENU(1293,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Guild master + player->SEND_POI(-1296.5, 127.57, 6, 6, 0, "Thunder Bluff Civic Information"); + player->SEND_GOSSIP_MENU(1291,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->SEND_POI(-1296, 39.7, 6, 6, 0, "Thunder Bluff Inn"); + player->SEND_GOSSIP_MENU(3153,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox + player->SEND_POI(-1263.59, 44.36, 6, 6, 0, "Thunder Bluff Mailbox"); + player->SEND_GOSSIP_MENU(3154,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Auction House + player->SEND_POI(1381.77, -4371.16, 6, 6, 0, GOSSIP_TEXT_AUCTIONHOUSE); + player->SEND_GOSSIP_MENU(3155,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Weapon master + player->SEND_POI(-1282.31, 89.56, 6, 6, 0, "Ansekhwa"); + player->SEND_GOSSIP_MENU(4520,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Stable master + player->SEND_POI(-1270.19, 48.84, 6, 6, 0, "Bulrug"); + player->SEND_GOSSIP_MENU(5977,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(7527,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(3542,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(3541,_Creature->GetGUID()); + break; + } +} + +void SendBattleMasterMenu_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //AV + player->SEND_POI(-1387.82, -97.55, 6, 6, 0, "Taim Ragetotem"); + player->SEND_GOSSIP_MENU(7522,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //AB + player->SEND_POI(-997, 214.12, 6, 6, 0, "Martin Lindsey"); + player->SEND_GOSSIP_MENU(7648,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //WSG + player->SEND_POI(-1384.94, -75.91, 6, 6, 0, "Kergul Bloodaxe"); + player->SEND_GOSSIP_MENU(7523,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_POI(-1054.47, -285, 6, 6, 0, "Hall of Elders"); + player->SEND_GOSSIP_MENU(1294,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_POI(-1416.32, -114.28, 6, 6, 0, "Hunter's Hall"); + player->SEND_GOSSIP_MENU(1295,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Mage + player->SEND_POI(-1061.2, 195.5, 6, 6, 0, "Pools of Vision"); + player->SEND_GOSSIP_MENU(1296,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Priest + player->SEND_POI(-1061.2, 195.5, 6, 6, 0, "Pools of Vision"); + player->SEND_GOSSIP_MENU(1297,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Shaman + player->SEND_POI(-989.54, 278.25, 6, 6, 0, "Hall of Spirits"); + player->SEND_GOSSIP_MENU(1298,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Warrior + player->SEND_POI(-1416.32, -114.28, 6, 6, 0, "Hunter's Hall"); + player->SEND_GOSSIP_MENU(1299,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-1085.56, 27.29, 6, 6, 0, "Bena's Alchemy"); + player->SEND_GOSSIP_MENU(1332,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-1239.75, 104.88, 6, 6, 0, "Karn's Smithy"); + player->SEND_GOSSIP_MENU(1333,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-1214.5, -21.23, 6, 6, 0, "Aska's Kitchen"); + player->SEND_GOSSIP_MENU(1334,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(-1112.65, 48.26, 6, 6, 0, "Dawnstrider Enchanters"); + player->SEND_GOSSIP_MENU(1335,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //First Aid + player->SEND_POI(-996.58, 200.5, 6, 6, 0, "Spiritual Healing"); + player->SEND_GOSSIP_MENU(1336,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Fishing + player->SEND_POI(-1169.35, -68.87, 6, 6, 0, "Mountaintop Bait & Tackle"); + player->SEND_GOSSIP_MENU(1337,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Herbalism + player->SEND_POI(-1137.7, -1.51, 6, 6, 0, "Holistic Herbalism"); + player->SEND_GOSSIP_MENU(1338,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Leatherworking + player->SEND_POI(-1156.22, 66.86, 6, 6, 0, "Thunder Bluff Armorers"); + player->SEND_GOSSIP_MENU(1339,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Mining + player->SEND_POI(-1249.17, 155, 6, 6, 0, "Stonehoof Geology"); + player->SEND_GOSSIP_MENU(1340,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Skinning + player->SEND_POI(-1148.56, 51.18, 6, 6, 0, "Mooranta"); + player->SEND_GOSSIP_MENU(1343,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Tailoring + player->SEND_POI(-1156.22, 66.86, 6, 6, 0, "Thunder Bluff Armorers"); + player->SEND_GOSSIP_MENU(1341,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_bluffwatcher(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_bluffwatcher(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_bluffwatcher(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_bluffwatcher(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_bluffwatcher(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_bluffwatcher end + *******************************************************/ + +CreatureAI* GetAI_guard_bluffwatcher(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_contested start + *******************************************************/ + +struct MANGOS_DLL_DECL guard_contested : public guardAI +{ + guard_contested(Creature *c) : guardAI(c) {} + + void MoveInLineOfSight(Unit *who) + { + if ( who->isAttackingPlayer() ) + { + if(who->GetTypeId() == TYPEID_PLAYER || who->GetOwnerGUID() && GUID_HIPART(who->GetOwnerGUID())==HIGHGUID_PLAYER) + { + m_creature->AddThreat(who, 0.0f); + if(Unit* owner = who->GetOwner()) + m_creature->AddThreat(owner, 0.0f); + + if(!m_creature->isInCombat()) + { + if (m_creature->GetEntry() == 15184) //Cenarion Hold Infantry + { + srand (time(NULL)); + if (rand()%100 <= 30) + { + DoSay("Taste blade, mongrel!", LANG_UNIVERSAL,NULL); + } + else if (rand()%100 > 30 && rand()%100 < 50) + { + DoSay("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...", LANG_UNIVERSAL,NULL); + } + else if (rand()%100 >= 50) + { + DoSay("As if we don`t have enough problems, you go and create more!", LANG_UNIVERSAL,NULL); + } + } + else + { + SpellEntry const *spell = m_creature->reachWithSpellAttack(who); + DoCastSpell(who, spell); + } + } + DoStartAttackAndMovement(who); + } + } + } +}; +/******************************************************* + * guard_contested end + *******************************************************/ + +CreatureAI* GetAI_guard_contested(Creature *_Creature) +{ + return new guard_contested (_Creature); +} + +/******************************************************* + * guard_darnassus start + *******************************************************/ + +bool GossipHello_guard_darnassus(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HIPPOGRYPH , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(3016, _Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_darnassus(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Auction house + player->SEND_POI(9861.23, 2334.55, 6, 6, 0, "Darnassus Auction House"); + player->SEND_GOSSIP_MENU(3833, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bank + player->SEND_POI(9938.45, 2512.35, 6, 6, 0, "Darnassus Bank"); + player->SEND_GOSSIP_MENU(3017, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Wind master + player->SEND_POI(9945.65, 2618.94, 6, 6, 0, "Rut'theran Village"); + player->SEND_GOSSIP_MENU(3018, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Guild master + player->SEND_POI(10076.40, 2199.59, 6, 6, 0, "Darnassus Guild Master"); + player->SEND_GOSSIP_MENU(3019, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Inn + player->SEND_POI(10133.29, 2222.52, 6, 6, 0, "Darnassus Inn"); + player->SEND_GOSSIP_MENU(3020, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Mailbox + player->SEND_POI(9942.17, 2495.48, 6, 6, 0, "Darnassus Mailbox"); + player->SEND_GOSSIP_MENU(3021, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Stable master + player->SEND_POI(10167.20, 2522.66, 6, 6, 0, "Alassin"); + player->SEND_GOSSIP_MENU(5980, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Weapon trainer + player->SEND_POI(9907.11, 2329.70, 6, 6, 0, "Ilyenia Moonfire"); + player->SEND_GOSSIP_MENU(4517, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(7519, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(4264, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->SEND_GOSSIP_MENU(4273, _Creature->GetGUID()); + break; + } +} + +void SendBattleMasterMenu_guard_darnassus(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //AV + player->SEND_POI(9923.61, 2327.43, 6, 6, 0, "Brogun Stoneshield"); + player->SEND_GOSSIP_MENU(7518, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //AB + player->SEND_POI(9977.37, 2324.39, 6, 6, 0, "Keras Wolfheart"); + player->SEND_GOSSIP_MENU(7651, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //WSG + player->SEND_POI(9979.84, 2315.79, 6, 6, 0, "Aethalas"); + player->SEND_GOSSIP_MENU(7482, _Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_darnassus(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_POI(10186, 2570.46, 6, 6, 0, "Darnassus Druid Trainer"); + player->SEND_GOSSIP_MENU(3024, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_POI(10177.29, 2511.10, 6, 6, 0, "Darnassus Hunter Trainer"); + player->SEND_GOSSIP_MENU(3023, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Priest + player->SEND_POI(9659.12, 2524.88, 6, 6, 0, "Temple of the Moon"); + player->SEND_GOSSIP_MENU(3025, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Rogue + player->SEND_POI(10122, 2599.12, 6, 6, 0, "Darnassus Rogue Trainer"); + player->SEND_GOSSIP_MENU(3026, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Warrior + player->SEND_POI(9951.91, 2280.38, 6, 6, 0, "Warrior's Terrace"); + player->SEND_GOSSIP_MENU(3033, _Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_darnassus(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(10075.90, 2356.76, 6, 6, 0, "Darnassus Alchemy Trainer"); + player->SEND_GOSSIP_MENU(3035, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Cooking + player->SEND_POI(10088.59, 2419.21, 6, 6, 0, "Darnassus Cooking Trainer"); + player->SEND_GOSSIP_MENU(3036, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Enchanting + player->SEND_POI(10146.09, 2313.42, 6, 6, 0, "Darnassus Enchanting Trainer"); + player->SEND_GOSSIP_MENU(3337, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //First Aid + player->SEND_POI(10150.09, 2390.43, 6, 6, 0, "Darnassus First Aid Trainer"); + player->SEND_GOSSIP_MENU(3037, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Fishing + player->SEND_POI(9836.20, 2432.17, 6, 6, 0, "Darnassus Fishing Trainer"); + player->SEND_GOSSIP_MENU(3038, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Herbalism + player->SEND_POI(9757.17, 2430.16, 6, 6, 0, "Darnassus Herbalism Trainer"); + player->SEND_GOSSIP_MENU(3039, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking + player->SEND_POI(10086.59, 2255.77, 6, 6, 0, "Darnassus Leatherworking Trainer"); + player->SEND_GOSSIP_MENU(3040, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Skinning + player->SEND_POI(10081.40, 2257.18, 6, 6, 0, "Darnassus Skinning Trainer"); + player->SEND_GOSSIP_MENU(3042, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Tailoring + player->SEND_POI(10079.70, 2268.19, 6, 6, 0, "Darnassus Tailor"); + player->SEND_GOSSIP_MENU(3044, _Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_darnassus(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_darnassus(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_darnassus(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_darnassus(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_darnassus(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_darnassus end + *******************************************************/ + +CreatureAI* GetAI_guard_darnassus(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_dunmorogh start + *******************************************************/ + +bool GossipHello_guard_dunmorogh(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HIPPOGRYPH , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(4287,_Creature->GetGUID()); + + return true; +} + +void SendDefaultMenu_guard_dunmorogh(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_GOSSIP_MENU(4288,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Gryphon master + player->SEND_GOSSIP_MENU(4289,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Guild master + player->SEND_GOSSIP_MENU(4290,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->SEND_POI(-5582.66, -525.89, 6, 6, 0, "Thunderbrew Distillery"); + player->SEND_GOSSIP_MENU(4291,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Stable Master + player->SEND_POI(-5604, -509.58, 6, 6, 0, "Shelby Stoneflint"); + player->SEND_GOSSIP_MENU(5985,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(4292,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(4300,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_dunmorogh(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Hunter + player->SEND_POI(-5618.29, -454.25, 6, 6, 0, "Grif Wildheart"); + player->SEND_GOSSIP_MENU(4293,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Mage + player->SEND_POI(-5585.6, -539.99, 6, 6, 0, "Magis Sparkmantle"); + player->SEND_GOSSIP_MENU(4294,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Paladin + player->SEND_POI(-5585.6, -539.99, 6, 6, 0, "Azar Stronghammer"); + player->SEND_GOSSIP_MENU(4295,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Priest + player->SEND_POI(-5591.74, -525.61, 6, 6, 0, "Maxan Anvol"); + player->SEND_GOSSIP_MENU(4296,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Rogue + player->SEND_POI(-5602.75, -542.4, 6, 6, 0, "Hogral Bakkan"); + player->SEND_GOSSIP_MENU(4297,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Warlock + player->SEND_POI(-5641.97, -523.76, 6, 6, 0, "Gimrizz Shadowcog"); + player->SEND_GOSSIP_MENU(4298,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warrior + player->SEND_POI(-5604.79, -529.38, 6, 6, 0, "Granis Swiftaxe"); + player->SEND_GOSSIP_MENU(4299,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_dunmorogh(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_GOSSIP_MENU(4301,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-5584.72, -428.41, 6, 6, 0, "Tognus Flintfire"); + player->SEND_GOSSIP_MENU(4302,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-5596.85, -541.43, 6, 6, 0, "Gremlock Pilsnor"); + player->SEND_GOSSIP_MENU(4303,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_GOSSIP_MENU(4304,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(-5531, -666.53, 6, 6, 0, "Bronk Guzzlegear"); + player->SEND_GOSSIP_MENU(4305,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(-5603.67, -523.57, 6, 6, 0, "Thamner Pol"); + player->SEND_GOSSIP_MENU(4306,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(-5199.9, 58.58, 6, 6, 0, "Paxton Ganter"); + player->SEND_GOSSIP_MENU(4307,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_GOSSIP_MENU(4308,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_GOSSIP_MENU(4310,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Mining + player->SEND_POI(-5531, -666.53, 6, 6, 0, "Yarr Hamerstone"); + player->SEND_GOSSIP_MENU(4311,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_GOSSIP_MENU(4312,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_GOSSIP_MENU(4313,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_dunmorogh(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_dunmorogh(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_dunmorogh(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_dunmorogh(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_dunmorogh end + *******************************************************/ + +CreatureAI* GetAI_guard_dunmorogh(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_durotar start + *******************************************************/ + +bool GossipHello_guard_durotar(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(4037,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_durotar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_GOSSIP_MENU(4032,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Wind rider + player->SEND_GOSSIP_MENU(4033,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Inn + player->SEND_POI(338.7, -4688.87, 6, 6, 0, "Razor Hill Inn"); + player->SEND_GOSSIP_MENU(4034,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Stable master + player->SEND_POI(330.31, -4710.66, 6, 6, 0, "Shoja'my"); + player->SEND_GOSSIP_MENU(5973,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(4035,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(4036,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_durotar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Hunter + player->SEND_POI(276, -4706.72, 6, 6, 0, "Thotar"); + player->SEND_GOSSIP_MENU(4013,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Mage + player->SEND_POI(-839.33, -4935.6, 6, 6, 0, "Un'Thuwa"); + player->SEND_GOSSIP_MENU(4014,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Priest + player->SEND_POI(296.22, -4828.1, 6, 6, 0, "Tai'jin"); + player->SEND_GOSSIP_MENU(4015,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Rogue + player->SEND_POI(265.76, -4709, 6, 6, 0, "Kaplak"); + player->SEND_GOSSIP_MENU(4016,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Shaman + player->SEND_POI(307.79, -4836.97, 6, 6, 0, "Swart"); + player->SEND_GOSSIP_MENU(4017,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Warlock + player->SEND_POI(355.88, -4836.45, 6, 6, 0, "Dhugru Gorelust"); + player->SEND_GOSSIP_MENU(4018,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warrior + player->SEND_POI(312.3, -4824.66, 6, 6, 0, "Tarshaw Jaggedscar"); + player->SEND_GOSSIP_MENU(4019,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_durotar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-800.25, -4894.33, 6, 6, 0, "Miao'zan"); + player->SEND_GOSSIP_MENU(4020,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(373.24, -4716.45, 6, 6, 0, "Dwukk"); + player->SEND_GOSSIP_MENU(4021,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_GOSSIP_MENU(4022,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_GOSSIP_MENU(4023,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(368.95, -4723.95, 6, 6, 0, "Mukdrak"); + player->SEND_GOSSIP_MENU(4024,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(327.17, -4825.62, 6, 6, 0, "Rawrk"); + player->SEND_GOSSIP_MENU(4025,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(-1065.48, -4777.43, 6, 6, 0, "Lau'Tiki"); + player->SEND_GOSSIP_MENU(4026,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_POI(-836.25, -4896.89, 6, 6, 0, "Mishiki"); + player->SEND_GOSSIP_MENU(4027,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_GOSSIP_MENU(4028,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Mining + player->SEND_POI(366.94, -4705, 6, 6, 0, "Krunn"); + player->SEND_GOSSIP_MENU(4029,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_GOSSIP_MENU(4030,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_GOSSIP_MENU(4031,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_durotar(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_durotar(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_durotar(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_durotar(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_durotar end + *******************************************************/ + +CreatureAI* GetAI_guard_durotar(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_elwynnforest start + *******************************************************/ + +bool GossipHello_guard_elwynnforest(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GRYPHON , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(933,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_elwynnforest(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_GOSSIP_MENU(4260,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Gryphon master + player->SEND_GOSSIP_MENU(4261,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Guild master + player->SEND_GOSSIP_MENU(4262,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->SEND_POI(-9459.34, 42.08, 6, 6, 0, "Lion's Pride Inn"); + player->SEND_GOSSIP_MENU(4263,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Stable Master + player->SEND_POI(-9466.62, 45.87, 6, 6, 0, "Erma"); + player->SEND_GOSSIP_MENU(5983,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->SEND_GOSSIP_MENU(4264,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(4273,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_elwynnforest(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_GOSSIP_MENU(4265,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_GOSSIP_MENU(4266,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Mage + player->SEND_POI(-9471.12, 33.44, 6, 6, 0, "Zaldimar Wefhellt"); + player->SEND_GOSSIP_MENU(4268,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Paladin + player->SEND_POI(-9469, 108.05, 6, 6, 0, "Brother Wilhelm"); + player->SEND_GOSSIP_MENU(4269,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Priest + player->SEND_POI(-9461.07, 32.6, 6, 6, 0, "Priestess Josetta"); + player->SEND_GOSSIP_MENU(4267,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Rogue + player->SEND_POI(-9465.13, 13.29, 6, 6, 0, "Keryn Sylvius"); + player->SEND_GOSSIP_MENU(4270,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warlock + player->SEND_POI(-9473.21, -4.08, 6, 6, 0, "Maximillian Crowe"); + player->SEND_GOSSIP_MENU(4272,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Warrior + player->SEND_POI(-9461.82, 109.50, 6, 6, 0, "Lyria Du Lac"); + player->SEND_GOSSIP_MENU(4271,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_elwynnforest(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-9057.04, 153.63, 6, 6, 0, "Alchemist Mallory"); + player->SEND_GOSSIP_MENU(4274,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-9456.58, 87.90, 6, 6, 0, "Smith Argus"); + player->SEND_GOSSIP_MENU(4275,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-9467.54, -3.16, 6, 6, 0, "Tomas"); + player->SEND_GOSSIP_MENU(4276,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_GOSSIP_MENU(4277,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_GOSSIP_MENU(4278,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(-9456.82, 30.49, 6, 6, 0, "Michelle Belle"); + player->SEND_GOSSIP_MENU(4279,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(-9386.54, -118.73, 6, 6, 0, "Lee Brown"); + player->SEND_GOSSIP_MENU(4280,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_POI(-9060.70, 149.23, 6, 6, 0, "Herbalist Pomeroy"); + player->SEND_GOSSIP_MENU(4281,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_POI(-9376.12, -75.23, 6, 6, 0, "Adele Fielder"); + player->SEND_GOSSIP_MENU(4282,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Mining + player->SEND_GOSSIP_MENU(4283,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_POI(-9536.91, -1212.76, 6, 6, 0, "Helene Peltskinner"); + player->SEND_GOSSIP_MENU(4284,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_POI(-9376.12, -75.23, 6, 6, 0, "Eldrin"); + player->SEND_GOSSIP_MENU(4285,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_elwynnforest(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_elwynnforest(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_elwynnforest(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_elwynnforest(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_elwynnforest end + *******************************************************/ + +CreatureAI* GetAI_guard_elwynnforest(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_eversong start + *******************************************************/ + +bool GossipHello_guard_eversong(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATHANDLER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(10180,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_eversong(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bat Handler + player->SEND_POI(9371.93, -7164.80, 6, 6, 0, "Skymistress Gloaming"); + player->SEND_GOSSIP_MENU(10181,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Guild master + player->SEND_GOSSIP_MENU(10182,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Inn + player->SEND_POI(9483.74, -6844.58, 6, 6, 0, "Delaniel's inn"); + player->SEND_GOSSIP_MENU(10183,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Stable Master + player->SEND_POI(9489.62, -6829.93, 6, 6, 0, "Anathos"); + player->SEND_GOSSIP_MENU(10184,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(10180,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(10180,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_eversong(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_GOSSIP_MENU(10185,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_POI(9527.44, -6865.25, 6, 6, 0, "Hannovia"); + player->SEND_GOSSIP_MENU(10186,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Mage + player->SEND_POI(9464.24, -6855.52, 6, 6, 0, "Garridel"); + player->SEND_GOSSIP_MENU(10187,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Paladin + player->SEND_POI(9517.61, -6871.04, 6, 6, 0, "Noellene"); + player->SEND_GOSSIP_MENU(10189,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Priest + player->SEND_POI(9467.39, -6845.72, 6, 6, 0, "Ponaris"); + player->SEND_GOSSIP_MENU(10190,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Rogue + player->SEND_POI(9533.67, -6877.39, 6, 6, 0, "Tannaria"); + player->SEND_GOSSIP_MENU(10191,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warlock + player->SEND_POI(9468.99, -6865.60, 6, 6, 0, "Celoenus"); + player->SEND_GOSSIP_MENU(10192,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_eversong(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(8659.90, -6368.12, 6, 6, 0, "Arcanist Sheynathren"); + player->SEND_GOSSIP_MENU(10193,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(8984.21, -7419.21, 6, 6, 0, "Arathel Sunforge"); + player->SEND_GOSSIP_MENU(10194,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(9494.04, -6881.51, 6, 6, 0, "Quarelestra"); + player->SEND_GOSSIP_MENU(10195,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Engineering + player->SEND_GOSSIP_MENU(10197,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //First Aid + player->SEND_POI(9479.46, -6879.16, 6, 6, 0, "Kanaria"); + player->SEND_GOSSIP_MENU(10198,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Fishing + player->SEND_GOSSIP_MENU(10199,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Herbalism + player->SEND_POI(8678.92, -6329.09, 6, 6, 0, "Botanist Tyniarrel"); + player->SEND_GOSSIP_MENU(10200,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Jewelcrafting + player->SEND_POI(9484.32, -6874.98, 6, 6, 0, "Aleinia"); + player->SEND_GOSSIP_MENU(10203,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_POI(9362.04, -7130.33, 6, 6, 0, "Sathein"); + player->SEND_GOSSIP_MENU(10204,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Mining + player->SEND_GOSSIP_MENU(10205,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_POI(9362.04, -7130.33, 6, 6, 0, "Mathreyn"); + player->SEND_GOSSIP_MENU(10206,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_POI(8680.36, -6327.51, 6, 6, 0, "Sempstress Ambershine"); + player->SEND_GOSSIP_MENU(10207,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_eversong(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_eversong(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_eversong(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_eversong(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_eversong end + *******************************************************/ + +CreatureAI* GetAI_guard_eversong(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_exodar start + *******************************************************/ + +bool GossipHello_guard_exodar(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HIPPOGRYPH , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(9551, _Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_exodar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Auction house + player->SEND_POI(-4023.6, -11739.3, 6, 6, 0, "Exodar Auction House"); + player->SEND_GOSSIP_MENU(9528, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bank + player->SEND_POI(-3923.89, -11544.5, 6, 6, 0, "Exodar Bank"); + player->SEND_GOSSIP_MENU(9529, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Guild master + player->SEND_POI(-4092.57, -11626.5, 6, 6, 0, "Exodar Guild Master"); + player->SEND_GOSSIP_MENU(9539, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Hippogryph master + player->SEND_POI(-4060.46, -11787.1, 6, 6, 0, "Exodar Hippogryph Master"); + player->SEND_GOSSIP_MENU(9530, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Inn + player->SEND_POI(-3741.87, -11695.1, 6, 6, 0, "Exodar Inn"); + player->SEND_GOSSIP_MENU(9545, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Mailbox + player->SEND_POI(-3972.5, -11696.0, 6, 6, 0, "Mailbox"); + player->SEND_GOSSIP_MENU(10254, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Stable master + player->SEND_POI(-3786.5, -11702.5, 6, 6, 0, "Stable Master Arthaid"); + player->SEND_GOSSIP_MENU(9558, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Weapon trainer + player->SEND_POI(-4215.68, -11628.9, 6, 6, 0, "Weapon Master Handiir"); + player->SEND_GOSSIP_MENU(9565, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_EYEOFTHESTORM , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(9533, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 13); + player->SEND_GOSSIP_MENU(9555, _Creature->GetGUID()); + break; + } +} + +void SendBattleMasterMenu_guard_exodar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //AV + player->SEND_POI(-3978.1, -11357, 6, 6, 0, "Alterac Valley Battlemaster"); + player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //AB + player->SEND_POI(-3998.9, -11345.2, 6, 6, 0, "Arathi Basin Battlemaster"); + player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //A + player->SEND_POI(-3759.27, -11695.63, 6, 6, 0, "Miglik Blotstrom"); + player->SEND_GOSSIP_MENU(10223, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //EOS + player->SEND_POI(-3978.1, -11357, 6, 6, 0, "Eye Of The Storm Battlemaster"); + player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //WSG + player->SEND_POI(-3977.5, -11381.2, 6, 6, 0, "Warsong Gulch Battlemaster"); + player->SEND_GOSSIP_MENU(9531, _Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_exodar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_POI(-4276.0, -11495, 6, 6, 0, "Exodar Druid Trainer"); + player->SEND_GOSSIP_MENU(9534, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_POI(-4210.6, -11575.2, 6, 6, 0, "Exodar Hunter Trainer"); + player->SEND_GOSSIP_MENU(9544, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Mage + player->SEND_POI(-4057.32, -11556.5, 6, 6, 0, "Exodar Mage Trainer"); + player->SEND_GOSSIP_MENU(9550, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Paladin + player->SEND_POI(-4191.2, -11470.4, 6, 6, 0, "Exodar Paladin Trainer"); + player->SEND_GOSSIP_MENU(9553, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Priest + player->SEND_POI(-3969.63, -11482.8, 6, 6, 0, "Exodar Priest Trainer"); + player->SEND_GOSSIP_MENU(9554, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Shaman + player->SEND_POI(-3805.5, -11380.7, 6, 6, 0, "Exodar Shaman Trainer"); + player->SEND_GOSSIP_MENU(9556, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warrior + player->SEND_POI(-4189.43, -11653.7, 6, 6, 0, "Exodar Warrior Trainer"); + player->SEND_GOSSIP_MENU(9562, _Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_exodar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-4040.6, -11364.5, 6, 6, 0, "Exodar Alchemy Trainer"); + player->SEND_GOSSIP_MENU(9527, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-4229.5, -11706, 6, 6, 0, "Exodar Blacksmithing Trainer"); + player->SEND_GOSSIP_MENU(9532, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-3798.3, -11651.7, 6, 6, 0, "Exodar Cooking Trainer"); + player->SEND_GOSSIP_MENU(9551, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(-3889.3, -11495, 6, 6, 0, "Exodar Enchanting Trainer"); + player->SEND_GOSSIP_MENU(9535, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(-4257.68, -11640.3, 6, 6, 0, "Exodar Engineering Trainer"); + player->SEND_GOSSIP_MENU(9536, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(-3769.5, -11479.6, 6, 6, 0, "Exodar First Aid Trainer"); + player->SEND_GOSSIP_MENU(9537, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(-3725.5, -11385.2, 6, 6, 0, "Exodar Fishing Trainer"); + player->SEND_GOSSIP_MENU(9538, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Jewelcrafting + player->SEND_POI(-3783, -11546, 6, 6, 0, "Exodar Jewelcrafting Trainer"); + player->SEND_GOSSIP_MENU(9547, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Herbalism + player->SEND_POI(-4040.6, -11364.5, 6, 6, 0, "Exodar Herbalist Trainer"); + player->SEND_GOSSIP_MENU(9543, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Leatherworking + player->SEND_POI(-4140.6, -11776.7, 6, 6, 0, "Exodar Leatherworking Trainer"); + player->SEND_GOSSIP_MENU(9549, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Mining + player->SEND_POI(-4228, -11697, 6, 6, 0, "Exodar Mining Trainer"); + player->SEND_GOSSIP_MENU(9552, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Skinning + player->SEND_POI(-4134.97, -11760.5, 6, 6, 0, "Exodar Skinning Trainer"); + player->SEND_GOSSIP_MENU(9557, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 13: //Tailoring + player->SEND_POI(-4092.5, -11744.5, 6, 6, 0, "Exodar Tailor Trainer"); + player->SEND_GOSSIP_MENU(9559, _Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_exodar(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_exodar(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_exodar(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_exodar(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_exodar(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_exodar end + *******************************************************/ + +CreatureAI* GetAI_guard_exodar(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_ironforge start + *******************************************************/ + +bool GossipHello_guard_ironforge(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_IRONFORGE_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DEEPRUNTRAM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GRYPHON , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(2760, _Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_ironforge(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Auction House + player->SEND_POI(-4957.39, -911.6, 6, 6, 0, "Ironforge Auction House"); + player->SEND_GOSSIP_MENU(3014, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bank + player->SEND_POI(-4891.91, -991.47, 6, 6, 0, "The Vault"); + player->SEND_GOSSIP_MENU(2761, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Tram + player->SEND_POI(-4835.27, -1294.69, 6, 6, 0, "Deeprun Tram"); + player->SEND_GOSSIP_MENU(3814, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Gryphon Master + player->SEND_POI(-4821.52, -1152.3, 6, 6, 0, "Ironforge Gryphon Master"); + player->SEND_GOSSIP_MENU(2762, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Guild Master + player->SEND_POI(-5021, -996.45, 6, 6, 0, "Ironforge Visitor's Center"); + player->SEND_GOSSIP_MENU(2764, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Inn + player->SEND_POI(-4850.47, -872.57, 6, 6, 0, "Stonefire Tavern"); + player->SEND_GOSSIP_MENU(2768, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Mailbox + player->SEND_POI(-4845.7, -880.55, 6, 6, 0, "Ironforge Mailbox"); + player->SEND_GOSSIP_MENU(2769, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Stable Master + player->SEND_POI(-5010.2, -1262, 6, 6, 0, "Ulbrek Firehand"); + player->SEND_GOSSIP_MENU(5986, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Weapons Trainer + player->SEND_POI(-5040, -1201.88, 6, 6, 0, "Bixi and Buliwyf"); + player->SEND_GOSSIP_MENU(4518, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(7529, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Class Trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->SEND_GOSSIP_MENU(2766, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Profession Trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(2793, _Creature->GetGUID()); + break; + } +} + +void SendBattleMasterMenu_guard_ironforge(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //AV + player->SEND_POI(-5047.87, -1263.77, 6, 6, 0, "Glordrum Steelbeard"); + player->SEND_GOSSIP_MENU(7483, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //AB + player->SEND_POI(-5038.37, -1266.39, 6, 6, 0, "Donal Osgood"); + player->SEND_GOSSIP_MENU(7649, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //WSG + player->SEND_POI(-5037.24, -1274.82, 6, 6, 0, "Lylandris"); + player->SEND_GOSSIP_MENU(7528, _Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_ironforge(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Hunter + player->SEND_POI(-5023, -1253.68, 6, 6, 0, "Hall of Arms"); + player->SEND_GOSSIP_MENU(2770, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Mage + player->SEND_POI(-4627, -926.45, 6, 6, 0, "Hall of Mysteries"); + player->SEND_GOSSIP_MENU(2771, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Paladin + player->SEND_POI(-4627.02, -926.45, 6, 6, 0, "Hall of Mysteries"); + player->SEND_GOSSIP_MENU(2773, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Priest + player->SEND_POI(-4627, -926.45, 6, 6, 0, "Hall of Mysteries"); + player->SEND_GOSSIP_MENU(2772, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Rogue + player->SEND_POI(-4647.83, -1124, 6, 6, 0, "Ironforge Rogue Trainer"); + player->SEND_GOSSIP_MENU(2774, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Warlock + player->SEND_POI(-4605, -1110.45, 6, 6, 0, "Ironforge Warlock Trainer"); + player->SEND_GOSSIP_MENU(2775, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warrior + player->SEND_POI(-5023.08, -1253.68, 6, 6, 0, "Hall of Arms"); + player->SEND_GOSSIP_MENU(2776, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Shaman + player->SEND_POI(-4732, -1147, 6, 6, 0, "Ironforge Shaman Trainer"); + //incorrect id + player->SEND_GOSSIP_MENU(2766, _Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_ironforge(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-4858.5, -1241.83, 6, 6, 0, "Berryfizz's Potions and Mixed Drinks"); + player->SEND_GOSSIP_MENU(2794, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-4796.97, -1110.17, 6, 6, 0, "The Great Forge"); + player->SEND_GOSSIP_MENU(2795, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-4767.83, -1184.59, 6, 6, 0, "The Bronze Kettle"); + player->SEND_GOSSIP_MENU(2796, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(-4803.72, -1196.53, 6, 6, 0, "Thistlefuzz Arcanery"); + player->SEND_GOSSIP_MENU(2797, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(-4799.56, -1250.23, 6, 6, 0, "Springspindle's Gadgets"); + player->SEND_GOSSIP_MENU(2798, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(-4881.6, -1153.13, 6, 6, 0, "Ironforge Physician"); + player->SEND_GOSSIP_MENU(2799, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(-4597.91, -1091.93, 6, 6, 0, "Traveling Fisherman"); + player->SEND_GOSSIP_MENU(2800, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_POI(-4876.9, -1151.92, 6, 6, 0, "Ironforge Physician"); + player->SEND_GOSSIP_MENU(2801, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_POI(-4745, -1027.57, 6, 6, 0, "Finespindle's Leather Goods"); + player->SEND_GOSSIP_MENU(2802, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Minning + player->SEND_POI(-4705.06, -1116.43, 6, 6, 0, "Deepmountain Mining Guild"); + player->SEND_GOSSIP_MENU(2804, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_POI(-4745, -1027.57, 6, 6, 0, "Finespindle's Leather Goods"); + player->SEND_GOSSIP_MENU(2805, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_POI(-4719.60, -1056.96, 6, 6, 0, "Stonebrow's Clothier"); + player->SEND_GOSSIP_MENU(2807, _Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_ironforge(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_ironforge(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_ironforge(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_ironforge(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_ironforge(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_ironforge end + *******************************************************/ + +CreatureAI* GetAI_guard_ironforge(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_mulgore start + *******************************************************/ + +bool GossipHello_guard_mulgore(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(3543,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_mulgore(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_GOSSIP_MENU(4051,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Wind rider + player->SEND_GOSSIP_MENU(4052,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Inn + player->SEND_POI(-2361.38, -349.19, 6, 6, 0, "Bloodhoof Village Inn"); + player->SEND_GOSSIP_MENU(4053,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Stable master + player->SEND_POI(-2338.86, -357.56, 6, 6, 0, "Seikwa"); + player->SEND_GOSSIP_MENU(5976,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(4069,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(4070,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_mulgore(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_POI(-2312.15, -443.69, 6, 6, 0, "Gennia Runetotem"); + player->SEND_GOSSIP_MENU(4054,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_POI(-2178.14, -406.14, 6, 6, 0, "Yaw Sharpmane"); + player->SEND_GOSSIP_MENU(4055,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Shaman + player->SEND_POI(-2301.5, -439.87, 6, 6, 0, "Narm Skychaser"); + player->SEND_GOSSIP_MENU(4056,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Warrior + player->SEND_POI(-2345.43, -494.11, 6, 6, 0, "Krang Stonehoof"); + player->SEND_GOSSIP_MENU(4057,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_mulgore(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_GOSSIP_MENU(4058,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_GOSSIP_MENU(4059,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-2263.34, -287.91, 6, 6, 0, "Pyall Silentstride"); + player->SEND_GOSSIP_MENU(4060,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_GOSSIP_MENU(4061,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //First Aid + player->SEND_POI(-2353.52, -355.82, 6, 6, 0, "Vira Younghoof"); + player->SEND_GOSSIP_MENU(4062,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Fishing + player->SEND_POI(-2349.21, -241.37, 6, 6, 0, "Uthan Stillwater"); + player->SEND_GOSSIP_MENU(4063,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Herbalism + player->SEND_GOSSIP_MENU(4064,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Leatherworking + player->SEND_POI(-2257.12, -288.63, 6, 6, 0, "Chaw Stronghide"); + player->SEND_GOSSIP_MENU(4065,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Mining + player->SEND_GOSSIP_MENU(4066,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Skinning + player->SEND_POI(-2252.94, -291.32, 6, 6, 0, "Yonn Deepcut"); + player->SEND_GOSSIP_MENU(4067,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Tailoring + player->SEND_GOSSIP_MENU(4068,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_mulgore(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_mulgore(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_mulgore(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_mulgore(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_mulgore end + *******************************************************/ + +CreatureAI* GetAI_guard_mulgore(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_orgrimmar start + *******************************************************/ + +bool GossipHello_guard_orgrimmar(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ZEPPLINMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_OFFICERS , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); + player->SEND_GOSSIP_MENU(2593,_Creature->GetGUID()); + + return true; +} + +void SendDefaultMenu_guard_orgrimmar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_POI(1631.51, -4375.33, 6, 6, 0, "Bank of Orgrimmar"); + player->SEND_GOSSIP_MENU(2554,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //wind rider + player->SEND_POI(1676.6, -4332.72, 6, 6, 0, "The Sky Tower"); + player->SEND_GOSSIP_MENU(2555,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //guild master + player->SEND_POI(1576.93, -4294.75, 6, 6, 0, "Horde Embassy"); + player->SEND_GOSSIP_MENU(2556,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->SEND_POI(1644.51, -4447.27, 6, 6, 0, "Orgrimmar Inn"); + player->SEND_GOSSIP_MENU(2557,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //mailbox + player->SEND_POI(1622.53, -4388.79, 6, 6, 0, "Orgrimmar Mailbox"); + player->SEND_GOSSIP_MENU(2558,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //auction house + player->SEND_POI(1679.21, -4450.1, 6, 6, 0, "Orgrimmar Auction House"); + player->SEND_GOSSIP_MENU(3075,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //zeppelin + player->SEND_POI(1337.36, -4632.7, 6, 6, 0, "Orgrimmar Zeppelin Tower"); + player->SEND_GOSSIP_MENU(3173,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //weapon master + player->SEND_POI(2092.56, -4823.95, 6, 6, 0, "Sayoc & Hanashi"); + player->SEND_GOSSIP_MENU(4519,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //stable master + player->SEND_POI(2133.12, -4663.93, 6, 6, 0, "Xon'cha"); + player->SEND_GOSSIP_MENU(5974,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //officers lounge + player->SEND_POI(1633.56, -4249.37, 6, 6, 0, "Hall of Legends"); + player->SEND_GOSSIP_MENU(7046,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(7521,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->SEND_GOSSIP_MENU(2599,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 13: //profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(2594,_Creature->GetGUID()); + break; + } +} + +void SendBattleMasterMenu_guard_orgrimmar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //AV + player->SEND_POI(1983.92, -4794.2, 6, 6, 0, "Hall of the Brave"); + player->SEND_GOSSIP_MENU(7484,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //AB + player->SEND_POI(1983.92, -4794.2, 6, 6, 0, "Hall of the Brave"); + player->SEND_GOSSIP_MENU(7644,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //WSG + player->SEND_POI(1983.92, -4794.2, 6, 6, 0, "Hall of the Brave"); + player->SEND_GOSSIP_MENU(7520,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_orgrimmar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Hunter + player->SEND_POI(2114.84, -4625.31, 6, 6, 0, "Orgrimmar Hunter's Hall"); + player->SEND_GOSSIP_MENU(2559,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Mage + player->SEND_POI(1451.26, -4223.33, 6, 6, 0, "Darkbriar Lodge"); + player->SEND_GOSSIP_MENU(2560,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Priest + player->SEND_POI(1442.21, -4183.24, 6, 6, 0, "Spirit Lodge"); + player->SEND_GOSSIP_MENU(2561,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Shaman + player->SEND_POI(1925.34, -4181.89, 6, 6, 0, "Thrall's Fortress"); + player->SEND_GOSSIP_MENU(2562,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Rogue + player->SEND_POI(1773.39, -4278.97, 6, 6, 0, "Shadowswift Brotherhood"); + player->SEND_GOSSIP_MENU(2563,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Warlock + player->SEND_POI(1849.57, -4359.68, 6, 6, 0, "Darkfire Enclave"); + player->SEND_GOSSIP_MENU(2564,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warrior + player->SEND_POI(1983.92, -4794.2, 6, 6, 0, "Hall of the Brave"); + player->SEND_GOSSIP_MENU(2565,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Paladin + player->SEND_POI(1906.65, -4134.26, 6, 6, 0, "Valley of Wisdom"); + player->SEND_GOSSIP_MENU(10843,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_orgrimmar(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(1955.17, -4475.79, 6, 6, 0, "Yelmak's Alchemy and Potions"); + player->SEND_GOSSIP_MENU(2497,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(2054.34, -4831.85, 6, 6, 0, "The Burning Anvil"); + player->SEND_GOSSIP_MENU(2499,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(1780.96, -4481.31, 6, 6, 0, "Borstan's Firepit"); + player->SEND_GOSSIP_MENU(2500,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(1917.5, -4434.95, 6, 6, 0, "Godan's Runeworks"); + player->SEND_GOSSIP_MENU(2501,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(2038.45, -4744.75, 6, 6, 0, "Nogg's Machine Shop"); + player->SEND_GOSSIP_MENU(2653,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(1485.21, -4160.91, 6, 6, 0, "Survival of the Fittest"); + player->SEND_GOSSIP_MENU(2502,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(1994.15, -4655.7, 6, 6, 0, "Lumak's Fishing"); + player->SEND_GOSSIP_MENU(2503,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_POI(1898.61, -4454.93, 6, 6, 0, "Jandi's Arboretum"); + player->SEND_GOSSIP_MENU(2504,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_POI(1852.82, -4562.31, 6, 6, 0, "Kodohide Leatherworkers"); + player->SEND_GOSSIP_MENU(2513,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Mining + player->SEND_POI(2029.79, -4704, 6, 6, 0, "Red Canyon Mining"); + player->SEND_GOSSIP_MENU(2515,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_POI(1852.82, -4562.31, 6, 6, 0, "Kodohide Leatherworkers"); + player->SEND_GOSSIP_MENU(2516,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_POI(1802.66, -4560.66, 6, 6, 0, "Magar's Cloth Goods"); + player->SEND_GOSSIP_MENU(2518,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_orgrimmar(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_orgrimmar(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_orgrimmar(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_orgrimmar(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_orgrimmar(player, _Creature, action); break; + } + return true; +} + +bool ReceiveEmote_guard_orgrimmar(Player *player, Creature *_Creature, uint32 emote) +{ + if( player->GetTeam() == HORDE ) + DoReplyToTextEmote(_Creature,emote); + return true; +} + +/******************************************************* + * guard_orgrimmar end + *******************************************************/ + +CreatureAI* GetAI_guard_orgrimmar(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_shattrath start + *******************************************************/ + +bool GossipHello_guard_shattrath(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAVERN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FLIGHTMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MANALOOM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMYLAB , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMMERCHANT , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(10321, _Creature->GetGUID()); + + return true; +} + +void SendDefaultMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Tavern + player->SEND_POI(-1759.5, 5165, 6, 6, 0, "Worlds End Tavern"); + player->SEND_GOSSIP_MENU(10394, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bank + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANKALDOR , GOSSIP_SENDER_SEC_BANK, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANKSCYERS , GOSSIP_SENDER_SEC_BANK, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(10379, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Inn + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INNALDOR , GOSSIP_SENDER_SEC_INN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INNSCYERS , GOSSIP_SENDER_SEC_INN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(10382, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Flight master + player->SEND_POI(-1832, 5299, 6, 6, 0, "Flight Master"); + player->SEND_GOSSIP_MENU(10385, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANKALDOR , GOSSIP_SENDER_SEC_MAILBOX, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INNALDOR , GOSSIP_SENDER_SEC_MAILBOX, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANKSCYERS , GOSSIP_SENDER_SEC_MAILBOX, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INNSCYERS , GOSSIP_SENDER_SEC_MAILBOX, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(10386, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Stable master + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEALDOR , GOSSIP_SENDER_SEC_STABLEMASTER, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLESCYERS , GOSSIP_SENDER_SEC_STABLEMASTER, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(10387, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERALLIANCE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERHORDE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(10388, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Profession master + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->SEND_GOSSIP_MENU(10391, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Mana Loom + player->SEND_POI(-2070, 5265.5, 6, 6, 0, "Mana Loom"); + player->SEND_GOSSIP_MENU(10503, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Alchemy Lab + player->SEND_POI(-1648.5, 5540, 6, 6, 0, "Alchemy Lab"); + player->SEND_GOSSIP_MENU(10321, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Gem Merchant + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMALDOR , GOSSIP_SENDER_SEC_GEMMERCHANT, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMSCYERS , GOSSIP_SENDER_SEC_GEMMERCHANT, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(10697, _Creature->GetGUID()); + break; + } +} + +void SendBankMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->SEND_POI(-1730.5, 5496, 6, 6, 0, "Aldor Bank"); + player->SEND_GOSSIP_MENU(10380, _Creature->GetGUID()); + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->SEND_POI(-1997.7, 5363, 6, 6, 0, "Scyers Bank"); + player->SEND_GOSSIP_MENU(10381, _Creature->GetGUID()); + } +} + +void SendInnMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->SEND_POI(-1895, 5767, 6, 6, 0, "Aldor Inn"); + player->SEND_GOSSIP_MENU(10383, _Creature->GetGUID()); + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->SEND_POI(-2178, 5405, 6, 6, 0, "Scyers Inn"); + player->SEND_GOSSIP_MENU(10384, _Creature->GetGUID()); + } +} + +void SendMailboxMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: + player->SEND_POI(-1730.5, 5496, 6, 6, 0, "Aldor Bank"); + player->SEND_GOSSIP_MENU(10380, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + player->SEND_POI(-1895, 5767, 6, 6, 0, "Aldor Inn"); + player->SEND_GOSSIP_MENU(10383, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + player->SEND_POI(-1997.7, 5363, 6, 6, 0, "Scyers Bank"); + player->SEND_GOSSIP_MENU(10381, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: + player->SEND_POI(-2178, 5405, 6, 6, 0, "Scyers Inn"); + player->SEND_GOSSIP_MENU(10384, _Creature->GetGUID()); + break; + } +} + +void SendStableMasterMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->SEND_POI(-1888.5, 5761, 6, 6, 0, "Aldor Stable"); + player->SEND_GOSSIP_MENU(10321, _Creature->GetGUID()); + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->SEND_POI(-2170, 5404, 6, 6, 0, "Scyers Stable"); + player->SEND_GOSSIP_MENU(10321, _Creature->GetGUID()); + } +} + +void SendBattleMasterMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: + player->SEND_POI(-1774, 5251, 6, 6, 0, "Alliance Battlemasters"); + player->SEND_GOSSIP_MENU(10389, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + player->SEND_POI(-1963, 5263, 6, 6, 0, "Horde Battlemasters"); + player->SEND_GOSSIP_MENU(10390, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + player->SEND_POI(-1960, 5175, 6, 6, 0, "Arena Battlemasters"); + player->SEND_GOSSIP_MENU(12510, _Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-1648.5, 5534, 6, 6, 0, "Lorokeem"); + player->SEND_GOSSIP_MENU(10392, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-1847, 5222, 6, 6, 0, "Kradu Grimblade and Zula Slagfury"); + player->SEND_GOSSIP_MENU(10400, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-2067.4, 5316.5, 6, 6, 0, "Jack Trapper"); + player->SEND_GOSSIP_MENU(10393, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(-2263.5, 5563.5, 6, 6, 0, "High Enchanter Bardolan"); + player->SEND_GOSSIP_MENU(10395, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //First Aid + player->SEND_POI(-1591, 5265.5, 6, 6, 0, "Mildred Fletcher"); + player->SEND_GOSSIP_MENU(10396, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Jewelcrafting + player->SEND_POI(-1654, 5667.5, 6, 6, 0, "Hamanar"); + player->SEND_GOSSIP_MENU(10397, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking + player->SEND_POI(-2060.5, 5256.5, 6, 6, 0, "Darmari"); + player->SEND_GOSSIP_MENU(10399, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Skinning + player->SEND_POI(-2048, 5300, 6, 6, 0, "Seymour"); + player->SEND_GOSSIP_MENU(10398, _Creature->GetGUID()); + break; + } +} + +void SendGemMerchantMenu_guard_shattrath(Player *player, Creature *_Creature, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->SEND_POI(-1645, 5669.5, 6, 6, 0, "Aldor Gem Merchant"); + player->SEND_GOSSIP_MENU(10698, _Creature->GetGUID()); + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->SEND_POI(-2193, 5424.5, 6, 6, 0, "Scyers Gem Merchant"); + player->SEND_GOSSIP_MENU(10699, _Creature->GetGUID()); + } +} + +bool GossipSelect_guard_shattrath(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_shattrath(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BANK: SendBankMenu_guard_shattrath(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_INN: SendInnMenu_guard_shattrath(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_STABLEMASTER: SendStableMasterMenu_guard_shattrath(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_GEMMERCHANT: SendGemMerchantMenu_guard_shattrath(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_MAILBOX: SendMailboxMenu_guard_shattrath(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_shattrath(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_shattrath(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_shattrath end + *******************************************************/ + +CreatureAI* GetAI_guard_shattrath(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_shattrath_aldor + *******************************************************/ + +#define SPELL_BANISHED_SHATTRATH_A 36642 +#define SPELL_BANISHED_SHATTRATH_S 36671 +#define SPELL_BANISH_TELEPORT 36643 +#define SPELL_EXILE 39533 + +struct MANGOS_DLL_DECL guard_shattrath_aldorAI : public guardAI +{ + guard_shattrath_aldorAI(Creature *c) : guardAI(c) { Reset(); } + + uint32 Exile_Timer; + uint32 Banish_Timer; + uint64 playerGUID; + bool CanTeleport; + + void Reset() + { + Banish_Timer = 5000; + Exile_Timer = 8500; + playerGUID = 0; + CanTeleport = false; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( CanTeleport ) + { + if( Exile_Timer < diff ) + { + if( Unit* temp = Unit::GetUnit(*m_creature,playerGUID) ) + { + temp->CastSpell(temp,SPELL_EXILE,true); + temp->CastSpell(temp,SPELL_BANISH_TELEPORT,true); + } + playerGUID = 0; + Exile_Timer = 8500; + CanTeleport = false; + }else Exile_Timer -= diff; + } + else if( Banish_Timer < diff ) + { + Unit* temp = m_creature->getVictim(); + if( temp && temp->GetTypeId() == TYPEID_PLAYER ) + { + DoCast(temp,SPELL_BANISHED_SHATTRATH_A); + Banish_Timer = 9000; + playerGUID = temp->GetGUID(); + if( playerGUID ) + CanTeleport = true; + } + }else Banish_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +bool GossipHello_guard_shattrath_aldor(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAVERN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FLIGHTMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MANALOOM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMYLAB , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMMERCHANT , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(10524, _Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_shattrath_aldor(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Tavern + player->SEND_POI(-1759.5, 5165, 6, 6, 0, "Worlds End Tavern"); + player->SEND_GOSSIP_MENU(10394, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bank + player->SEND_POI(-1730.5, 5496, 6, 6, 0, "Aldor Bank"); + player->SEND_GOSSIP_MENU(10380, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Inn + player->SEND_POI(-1895, 5767, 6, 6, 0, "Aldor Inn"); + player->SEND_GOSSIP_MENU(10525, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Flight master + player->SEND_POI(-1832, 5299, 6, 6, 0, "Shattrath Flight Master"); + player->SEND_GOSSIP_MENU(10402, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox + player->SEND_POI(0, 0, 6, 6, 0, "Aldor Mailbox"); + //unknown + player->SEND_GOSSIP_MENU(10524, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Stable master + player->SEND_POI(-1888.5, 5761, 6, 6, 0, "Aldor Stable Master"); + player->SEND_GOSSIP_MENU(10527, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERALLIANCE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERHORDE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(10388, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Profession master + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->SEND_GOSSIP_MENU(10391, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Mana Loom + player->SEND_POI(-2070, 5265.5, 6, 6, 0, "Mana Loom"); + player->SEND_GOSSIP_MENU(10522, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Alchemy Lab + player->SEND_POI(-1648.5, 5540, 6, 6, 0, "Alchemy Lab"); + player->SEND_GOSSIP_MENU(10696, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Gem Merchant + player->SEND_POI(-1645, 5669.5, 6, 6, 0, "Aldor Gem Merchant"); + player->SEND_GOSSIP_MENU(10411, _Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_shattrath_aldor(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-1648.5, 5534, 6, 6, 0, "Lorokeem"); + player->SEND_GOSSIP_MENU(10392, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-1847, 5222, 6, 6, 0, "Kradu Grimblade and Zula Slagfury"); + player->SEND_GOSSIP_MENU(10400, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-2067.4, 5316.5, 6, 6, 0, "Jack Trapper"); + player->SEND_GOSSIP_MENU(10393, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(-2263.5, 5563.5, 6, 6, 0, "High Enchanter Bardolan"); + player->SEND_GOSSIP_MENU(10528, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //First Aid + player->SEND_POI(-1591, 5265.5, 6, 6, 0, "Mildred Fletcher"); + player->SEND_GOSSIP_MENU(10396, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Jewelcrafting + player->SEND_POI(-1654, 5667.5, 6, 6, 0, "Hamanar"); + player->SEND_GOSSIP_MENU(10529, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking + player->SEND_POI(-2060.5, 5256.5, 6, 6, 0, "Darmari"); + player->SEND_GOSSIP_MENU(10399, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Skinning + player->SEND_POI(-2048, 5300, 6, 6, 0, "Seymour"); + player->SEND_GOSSIP_MENU(10419, _Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_shattrath_aldor(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_shattrath_aldor(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_shattrath_aldor(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_shattrath(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_shattrath_aldor end + *******************************************************/ + +CreatureAI* GetAI_guard_shattrath_aldor(Creature *_Creature) +{ + return new guard_shattrath_aldorAI (_Creature); +} + +/******************************************************* + * guard_shattrath_scryer + *******************************************************/ + +struct MANGOS_DLL_DECL guard_shattrath_scryerAI : public guardAI +{ + guard_shattrath_scryerAI(Creature *c) : guardAI(c) { Reset(); } + + uint32 Exile_Timer; + uint32 Banish_Timer; + uint64 playerGUID; + bool CanTeleport; + + void Reset() + { + Banish_Timer = 5000; + Exile_Timer = 8500; + playerGUID = 0; + CanTeleport = false; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( CanTeleport ) + { + if( Exile_Timer < diff ) + { + if( Unit* temp = Unit::GetUnit(*m_creature,playerGUID) ) + { + temp->CastSpell(temp,SPELL_EXILE,true); + temp->CastSpell(temp,SPELL_BANISH_TELEPORT,true); + } + playerGUID = 0; + Exile_Timer = 8500; + CanTeleport = false; + }else Exile_Timer -= diff; + } + else if( Banish_Timer < diff ) + { + Unit* temp = m_creature->getVictim(); + if( temp && temp->GetTypeId() == TYPEID_PLAYER ) + { + DoCast(temp,SPELL_BANISHED_SHATTRATH_S); + Banish_Timer = 9000; + playerGUID = temp->GetGUID(); + if( playerGUID ) + CanTeleport = true; + } + }else Banish_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +bool GossipHello_guard_shattrath_scryer(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAVERN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FLIGHTMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MANALOOM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMYLAB , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GEMMERCHANT , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(10430, _Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_shattrath_scryer(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Tavern + player->SEND_POI(-1759.5, 5165, 6, 6, 0, "Worlds End Tavern"); + player->SEND_GOSSIP_MENU(10431, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bank + player->SEND_POI(-1996.6, 5363.7, 6, 6, 0, "Scryer Bank"); + player->SEND_GOSSIP_MENU(10432, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Inn + player->SEND_POI(-2176.6, 5405.8, 6, 6, 0, "Scryer Inn"); + player->SEND_GOSSIP_MENU(10433, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Flight master + player->SEND_POI(-1832, 5299, 6, 6, 0, "Shattrath Flight Master"); + player->SEND_GOSSIP_MENU(10435, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox + player->SEND_POI(-2174.3, 5411.4, 6, 6, 0, "Scryer Mailbox"); + player->SEND_GOSSIP_MENU(10436, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Stable master + player->SEND_POI(-2169.9, 5405.1, 6, 6, 0, "Scryer Stable Master"); + player->SEND_GOSSIP_MENU(10437, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERALLIANCE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERHORDE , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTERARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(10438, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Profession master + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->SEND_GOSSIP_MENU(10504, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Mana Loom + player->SEND_POI(-2070, 5265.5, 6, 6, 0, "Mana Loom"); + player->SEND_GOSSIP_MENU(10522, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Alchemy Lab + player->SEND_POI(-1648.5, 5540, 6, 6, 0, "Alchemy Lab"); + player->SEND_GOSSIP_MENU(10701, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Gem Merchant + player->SEND_POI(-1645, 5669.5, 6, 6, 0, "Scryer Gem Merchant"); + player->SEND_GOSSIP_MENU(10702, _Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_shattrath_scryer(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-1648.5, 5534, 6, 6, 0, "Lorokeem"); + player->SEND_GOSSIP_MENU(10516, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-1847, 5222, 6, 6, 0, "Kradu Grimblade and Zula Slagfury"); + player->SEND_GOSSIP_MENU(10517, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-2067.4, 5316.5, 6, 6, 0, "Jack Trapper"); + player->SEND_GOSSIP_MENU(10518, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(-2263.5, 5563.5, 6, 6, 0, "High Enchanter Bardolan"); + player->SEND_GOSSIP_MENU(10519, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //First Aid + player->SEND_POI(-1591, 5265.5, 6, 6, 0, "Mildred Fletcher"); + player->SEND_GOSSIP_MENU(10520, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Jewelcrafting + player->SEND_POI(-1654, 5667.5, 6, 6, 0, "Hamanar"); + player->SEND_GOSSIP_MENU(10521, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking + player->SEND_POI(-2060.5, 5256.5, 6, 6, 0, "Darmari"); + player->SEND_GOSSIP_MENU(10523, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Skinning + player->SEND_POI(-2048, 5300, 6, 6, 0, "Seymour"); + player->SEND_GOSSIP_MENU(10523, _Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_shattrath_scryer(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_shattrath_scryer(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_shattrath_scryer(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_shattrath(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_shattrath_scryer end + *******************************************************/ + +CreatureAI* GetAI_guard_shattrath_scryer(Creature *_Creature) +{ + return new guard_shattrath_scryerAI (_Creature); +} + +/******************************************************* + * guard_silvermoon start + *******************************************************/ + +bool GossipHello_guard_silvermoon(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WINDRIDER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Auction house + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AH_SILVERMOON_1 , GOSSIP_SENDER_SEC_AUCTIONHOUSE, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AH_SILVERMOON_2 , GOSSIP_SENDER_SEC_AUCTIONHOUSE, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(9317, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bank + player->SEND_POI(9808.4, -7488.16, 6, 6, 0, "Silvermoon Bank"); + player->SEND_GOSSIP_MENU(9322, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Guild master + player->SEND_POI(9474.97, -7345.21, 6, 6, 0, "Tandrine"); + player->SEND_GOSSIP_MENU(9324, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN_SILVERMOON_1 , GOSSIP_SENDER_SEC_INN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN_SILVERMOON_2 , GOSSIP_SENDER_SEC_INN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(9602, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox + player->SEND_POI(9658.33, -7492.17, 6, 6, 0, "Silvermoon Mailbox"); + player->SEND_GOSSIP_MENU(9326, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Stable master + player->SEND_POI(9904.95, -7404.31, 6, 6, 0, "Shalenn"); + player->SEND_GOSSIP_MENU(9327, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Weapon trainer + player->SEND_POI(9841.17, -7505.13, 6, 6, 0, "Ileda"); + player->SEND_GOSSIP_MENU(9328, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Wind master + player->SEND_POI(9378.45, -7163.94, 6, 6, 0, "Silvermoon Wind Master"); + player->SEND_GOSSIP_MENU(10181, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARENA , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_EYEOFTHESTORM , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(9331, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_JEWELCRAFTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 13); + player->SEND_GOSSIP_MENU(9338, _Creature->GetGUID()); + break; + } +} + +void SendAuctionhouseMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->SEND_POI(9644.47, -7140.22, 6, 6, 0, "Western Auction House"); + player->SEND_GOSSIP_MENU(9318, _Creature->GetGUID()); + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->SEND_POI(9683.27, -7521.22, 6, 6, 0, "Royal Exchange Auction House"); + player->SEND_GOSSIP_MENU(9319, _Creature->GetGUID()); + } +} + +void SendInnMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->SEND_POI(9677.7, -7368, 6, 6, 0, "Silvermoon City Inn"); + player->SEND_GOSSIP_MENU(9325, _Creature->GetGUID()); + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->SEND_POI(9561.1, -7517.5, 6, 6, 0, "Wayfarer's Rest tavern"); + player->SEND_GOSSIP_MENU(9603, _Creature->GetGUID()); + } +} + +void SendBattleMasterMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //AV + player->SEND_POI(9850.49, -7572.26, 6, 6, 0, "Gurak"); + player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //AB + player->SEND_POI(9857.18, -7564.36, 6, 6, 0, "Karen Wentworth"); + player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //A + player->SEND_POI(9850.6, -7559.25, 6, 6, 0, "Bipp Glizzitor"); + player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //EOS + player->SEND_POI(9857.18, -7564.36, 6, 6, 0, "Karen Wentworth"); + player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //WSG + player->SEND_POI(9845.45, -7562.58, 6, 6, 0, "Krukk"); + player->SEND_GOSSIP_MENU(9329, _Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_POI(9700.55, -7262.57, 6, 6, 0, "Harene Plainwalker"); + player->SEND_GOSSIP_MENU(9330, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_POI(9927.48, -7426.14, 6, 6, 0, "Zandine"); + player->SEND_GOSSIP_MENU(9332, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Mage + player->SEND_POI(9995.07, -7118.17, 6, 6, 0, "Quithas"); + player->SEND_GOSSIP_MENU(9333, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Paladin + player->SEND_POI(9850.22, -7516.93, 6, 6, 0, "Champion Bachi"); + player->SEND_GOSSIP_MENU(9334, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Priest + player->SEND_POI(9926.79, -7066.66, 6, 6, 0, "Belestra"); + player->SEND_GOSSIP_MENU(9335, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Rogue + player->SEND_POI(9739.88, -7374.33, 6, 6, 0, "Zelanis"); + player->SEND_GOSSIP_MENU(9336, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Warlock + player->SEND_POI(9787.57, -7284.63, 6, 6, 0, "Alamma"); + player->SEND_GOSSIP_MENU(9337, _Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_silvermoon(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(9998.09, -7214.36, 6, 6, 0, "Silvermoon Alchemy Trainer"); + player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(9841.43, -7361.53, 6, 6, 0, "Silvermoon Blacksmithing Trainer"); + player->SEND_GOSSIP_MENU(9340, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(9577.26, -7243.6, 6, 6, 0, "Silvermoon Cooking Trainer"); + player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(9962.57, -7246.18, 6, 6, 0, "Silvermoon Enchanting Trainer"); + player->SEND_GOSSIP_MENU(9341, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(9820.18, -7329.56, 6, 6, 0, "Silvermoon Engineering Trainer"); + player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(9579.8, -7343.71, 6, 6, 0, "Silvermoon First Aid Trainer"); + player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(9602.73, -7328.3, 6, 6, 0, "Silvermoon Fishing Trainer"); + player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Jewelcrafting + player->SEND_POI(9553.54, -7506.43, 6, 6, 0, "Silvermoon Jewelcrafting Trainer"); + player->SEND_GOSSIP_MENU(9346, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Herbalism + player->SEND_POI(10004.4, -7216.86, 6, 6, 0, "Silvermoon Herbalism Trainer"); + player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Leatherworking + player->SEND_POI(9503.72, -7430.16, 6, 6, 0, "Silvermoon Leatherworking Trainer"); + player->SEND_GOSSIP_MENU(9347, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Mining + player->SEND_POI(9805.1, -7355.56, 6, 6, 0, "Silvermoon Mining Trainer"); + player->SEND_GOSSIP_MENU(9348, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Skinning + player->SEND_POI(9513.37, -7429.4, 6, 6, 0, "Silvermoon Skinning Trainer"); + player->SEND_GOSSIP_MENU(9316, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 13: //Tailoring + player->SEND_POI(9750.55, -7095.28, 6, 6, 0, "Silvermoon Tailor"); + player->SEND_GOSSIP_MENU(9350, _Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_silvermoon(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_silvermoon(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_AUCTIONHOUSE: SendAuctionhouseMenu_guard_silvermoon(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_INN: SendInnMenu_guard_silvermoon(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_silvermoon(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_silvermoon(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_silvermoon(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_silvermoon end + *******************************************************/ + +CreatureAI* GetAI_guard_silvermoon(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_stormwind start + *******************************************************/ + +bool GossipHello_guard_stormwind(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STORMWIND_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DEEPRUNTRAM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GRYPHON , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_OFFICERS , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); + player->SEND_GOSSIP_MENU(933,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_stormwind(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Auction House + player->SEND_POI(-8811.46, 667.46, 6, 6, 0, "Stormwind Auction House"); + player->SEND_GOSSIP_MENU(3834,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bank + player->SEND_POI(-8916.87, 622.87, 6, 6, 0, "Stormwind Bank"); + player->SEND_GOSSIP_MENU(764,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Deeprun tram + player->SEND_POI(-8378.88, 554.23, 6, 6, 0, "The Deeprun Tram"); + player->SEND_GOSSIP_MENU(3813,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->SEND_POI(-8869.0, 675.4, 6, 6, 0, "The Gilded Rose"); + player->SEND_GOSSIP_MENU(3860,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Gryphon Master + player->SEND_POI(-8837.0, 493.5, 6, 6, 0, "Stormwind Gryphon Master"); + player->SEND_GOSSIP_MENU(879,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Guild Master + player->SEND_POI(-8894.0, 611.2, 6, 6, 0, "Stormwind Vistor`s Center"); + player->SEND_GOSSIP_MENU(882,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Mailbox + player->SEND_POI(-8876.48, 649.18, 6, 6, 0, "Stormwind Mailbox"); + player->SEND_GOSSIP_MENU(3861,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Stable Master + player->SEND_POI(-8433.0, 554.7, 6, 6, 0, "Jenova Stoneshield"); + player->SEND_GOSSIP_MENU(5984,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Weapon Trainer + player->SEND_POI(-8797.0, 612.8, 6, 6, 0, "Woo Ping"); + player->SEND_GOSSIP_MENU(4516,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Officers Lounge + player->SEND_POI(-8759.92, 399.69, 6, 6, 0, "Champions` Hall"); + player->SEND_GOSSIP_MENU(7047,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Battlemasters + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(7499,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Class trainers + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PALADIN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SHAMAN , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->SEND_GOSSIP_MENU(898,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 13: //Profession trainers + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(918,_Creature->GetGUID()); + break; + } +} + +void SendBattleMasterMenu_guard_stormwind(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //AV + player->SEND_POI(-8443.88, 335.99, 6, 6, 0, "Thelman Slatefist"); + player->SEND_GOSSIP_MENU(7500, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //AB + player->SEND_POI(-8443.88, 335.99, 6, 6, 0, "Lady Hoteshem"); + player->SEND_GOSSIP_MENU(7650, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //WSG + player->SEND_POI(-8443.88, 335.99, 6, 6, 0, "Elfarran"); + player->SEND_GOSSIP_MENU(7501, _Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_stormwind(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Mage + player->SEND_POI(-9012.0, 867.6, 6, 6, 0, "Wizard`s Sanctum"); + player->SEND_GOSSIP_MENU(899,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Rogue + player->SEND_POI(-8753.0, 367.8, 6, 6, 0, "Stormwind - Rogue House"); + player->SEND_GOSSIP_MENU(900,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Warrior + player->SEND_POI(-8624.54, 402.61, 6, 6, 0, "Pig and Whistle Tavern"); + player->SEND_GOSSIP_MENU(901,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Druid + player->SEND_POI(-8751.0, 1124.5, 6, 6, 0, "The Park"); + player->SEND_GOSSIP_MENU(902,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Priest + player->SEND_POI(-8512.0, 862.4, 6, 6, 0, "Catedral Of Light"); + player->SEND_GOSSIP_MENU(903,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Paladin + player->SEND_POI(-8577.0, 881.7, 6, 6, 0, "Catedral Of Light"); + player->SEND_GOSSIP_MENU(904,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Hunter + player->SEND_POI(-8413.0, 541.5, 6, 6, 0, "Hunter Lodge"); + player->SEND_GOSSIP_MENU(905,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Warlock + player->SEND_POI(-8948.91, 998.35, 6, 6, 0, "The Slaughtered Lamb"); + player->SEND_GOSSIP_MENU(906,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Shaman + player->SEND_POI(-9033, 550, 6, 6, 0, "Valley Of Heroes"); + //incorrect id + player->SEND_GOSSIP_MENU(2593,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_stormwind(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(-8988.0, 759.60, 6, 6, 0, "Alchemy Needs"); + player->SEND_GOSSIP_MENU(919,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(-8424.0, 616.9, 6, 6, 0, "Therum Deepforge"); + player->SEND_GOSSIP_MENU(920,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(-8611.0, 364.6, 6, 6, 0, "Pig and Whistle Tavern"); + player->SEND_GOSSIP_MENU(921,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(-8858.0, 803.7, 6, 6, 0, "Lucan Cordell"); + player->SEND_GOSSIP_MENU(941,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(-8347.0, 644.1, 6, 6, 0, "Lilliam Sparkspindle"); + player->SEND_GOSSIP_MENU(922,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(-8513.0, 801.8, 6, 6, 0, "Shaina Fuller"); + player->SEND_GOSSIP_MENU(923,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(-8803.0, 767.5, 6, 6, 0, "Arnold Leland"); + player->SEND_GOSSIP_MENU(940,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_POI(-8967.0, 779.5, 6, 6, 0, "Alchemy Needs"); + player->SEND_GOSSIP_MENU(924,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_POI(-8726.0, 477.4, 6, 6, 0, "The Protective Hide"); + player->SEND_GOSSIP_MENU(925,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Mining + player->SEND_POI(-8434.0, 692.8, 6, 6, 0, "Gelman Stonehand"); + player->SEND_GOSSIP_MENU(927,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_POI(-8716.0, 469.4, 6, 6, 0, "The Protective Hide"); + player->SEND_GOSSIP_MENU(928,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_POI(-8938.0, 800.7, 6, 6, 0, "Duncan`s Textiles"); + player->SEND_GOSSIP_MENU(929,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_stormwind(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_stormwind(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_stormwind(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_stormwind(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_stormwind(player, _Creature, action); break; + } + return true; +} + +bool ReceiveEmote_guard_stormwind(Player *player, Creature *_Creature, uint32 emote) +{ + if( player->GetTeam() == ALLIANCE ) + DoReplyToTextEmote(_Creature,emote); + return true; +} + +/******************************************************* + * guard_stormwind end + *******************************************************/ + +CreatureAI* GetAI_guard_stormwind(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_teldrassil start + *******************************************************/ + +bool GossipHello_guard_teldrassil(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FERRY , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(4316,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_teldrassil(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_GOSSIP_MENU(4317,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Rut`theran + player->SEND_GOSSIP_MENU(4318,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Guild master + player->SEND_GOSSIP_MENU(4319,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->SEND_POI(9821.49, 960.13, 6, 6, 0, "Dolanaar Inn"); + player->SEND_GOSSIP_MENU(4320,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //stable master + player->SEND_POI(9808.37, 931.1, 6, 6, 0, "Seriadne"); + player->SEND_GOSSIP_MENU(5982,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_DRUID , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HUNTER , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(4264,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->SEND_GOSSIP_MENU(4273,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_teldrassil(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Druid + player->SEND_POI(9741.58, 963.7, 6, 6, 0, "Kal"); + player->SEND_GOSSIP_MENU(4323,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Hunter + player->SEND_POI(9815.12, 926.28, 6, 6, 0, "Dazalar"); + player->SEND_GOSSIP_MENU(4324,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Priest + player->SEND_POI(9906.16, 986.63, 6, 6, 0, "Laurna Morninglight"); + player->SEND_GOSSIP_MENU(4325,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Rogue + player->SEND_POI(9789, 942.86, 6, 6, 0, "Jannok Breezesong"); + player->SEND_GOSSIP_MENU(4326,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Warrior + player->SEND_POI(9821.96, 950.61, 6, 6, 0, "Kyra Windblade"); + player->SEND_GOSSIP_MENU(4327,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_teldrassil(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(9767.59, 878.81, 6, 6, 0, "Cyndra Kindwhisper"); + player->SEND_GOSSIP_MENU(4329,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Cooking + player->SEND_POI(9751.19, 906.13, 6, 6, 0, "Zarrin"); + player->SEND_GOSSIP_MENU(4330,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Enchanting + player->SEND_POI(10677.59, 1946.56, 6, 6, 0, "Alanna Raveneye"); + player->SEND_GOSSIP_MENU(4331,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //First Aid + player->SEND_POI(9903.12, 999, 6, 6, 0, "Byancie"); + player->SEND_GOSSIP_MENU(4332,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Fishing + player->SEND_GOSSIP_MENU(4333,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Herbalism + player->SEND_POI(9773.78, 875.88, 6, 6, 0, "Malorne Bladeleaf"); + player->SEND_GOSSIP_MENU(4334,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Leatherworking + player->SEND_POI(10152.59, 1681.46, 6, 6, 0, "Nadyia Maneweaver"); + player->SEND_GOSSIP_MENU(4335,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Skinning + player->SEND_POI(10135.59, 1673.18, 6, 6, 0, "Radnaal Maneweaver"); + player->SEND_GOSSIP_MENU(4336,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Tailoring + player->SEND_GOSSIP_MENU(4337,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_teldrassil(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_teldrassil(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_teldrassil(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_teldrassil(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_teldrassil end + *******************************************************/ + +CreatureAI* GetAI_guard_teldrassil(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_tirisfal start + *******************************************************/ + +bool GossipHello_guard_tirisfal(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATHANDLER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(4097,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_tirisfal(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_GOSSIP_MENU(4074,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //bat handler + player->SEND_GOSSIP_MENU(4075,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Inn + player->SEND_POI(2246.68, 241.89, 6, 6, 0, "Gallows` End Tavern"); + player->SEND_GOSSIP_MENU(4076,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Stable Master + player->SEND_POI(2267.66, 319.32, 6, 6, 0, "Morganus"); + player->SEND_GOSSIP_MENU(5978,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(4292,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(4096,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_tirisfal(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Mage + player->SEND_POI(2259.18, 240.93, 6, 6, 0, "Cain Firesong"); + player->SEND_GOSSIP_MENU(4077,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Priest + player->SEND_POI(2259.18, 240.93, 6, 6, 0, "Dark Cleric Beryl"); + player->SEND_GOSSIP_MENU(4078,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Rogue + player->SEND_POI(2259.18, 240.93, 6, 6, 0, "Marion Call"); + player->SEND_GOSSIP_MENU(4079,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Warlock + player->SEND_POI(2259.18, 240.93, 6, 6, 0, "Rupert Boch"); + player->SEND_GOSSIP_MENU(4080,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Warrior + player->SEND_POI(2256.48, 240.32, 6, 6, 0, "Austil de Mon"); + player->SEND_GOSSIP_MENU(4081,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_tirisfal(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(2263.25, 344.23, 6, 6, 0, "Carolai Anise"); + player->SEND_GOSSIP_MENU(4082,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_GOSSIP_MENU(4083,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_GOSSIP_MENU(4084,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(2250.35, 249.12, 6, 6, 0, "Vance Undergloom"); + player->SEND_GOSSIP_MENU(4085,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_GOSSIP_MENU(4086,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(2246.68, 241.89, 6, 6, 0, "Nurse Neela"); + player->SEND_GOSSIP_MENU(4087,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(2292.37, -10.72, 6, 6, 0, "Clyde Kellen"); + player->SEND_GOSSIP_MENU(4088,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_POI(2268.21, 331.69, 6, 6, 0, "Faruza"); + player->SEND_GOSSIP_MENU(4089,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_POI(2027, 78.72, 6, 6, 0, "Shelene Rhobart"); + player->SEND_GOSSIP_MENU(4090,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Mining + player->SEND_GOSSIP_MENU(4091,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_POI(2027, 78.72, 6, 6, 0, "Rand Rhobart"); + player->SEND_GOSSIP_MENU(4092,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_POI(2160.45, 659.93, 6, 6, 0, "Bowen Brisboise"); + player->SEND_GOSSIP_MENU(4093,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_tirisfal(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_tirisfal(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_tirisfal(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_tirisfal(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_tirisfal end + *******************************************************/ + +CreatureAI* GetAI_guard_tirisfal(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * guard_undercity start + *******************************************************/ + +bool GossipHello_guard_undercity(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BANK , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATHANDLER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_GUILDMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_INN , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAILBOX , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_AUCTIONHOUSE , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ZEPPLINMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WEAPONMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_STABLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BATTLEMASTER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_CLASSTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PROFTRAINER , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(3543,_Creature->GetGUID()); + return true; +} + +void SendDefaultMenu_guard_undercity(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Bank + player->SEND_POI(1595.64, 232.45, 6, 6, 0, "Undercity Bank"); + player->SEND_GOSSIP_MENU(3514,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Bat handler + player->SEND_POI(1565.9, 271.43, 6, 6, 0, "Undercity Bat Handler"); + player->SEND_GOSSIP_MENU(3515,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Guild master + player->SEND_POI(1594.17, 205.57, 6, 6, 0, "Undercity Guild Master"); + player->SEND_GOSSIP_MENU(3516,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Inn + player->SEND_POI(1639.43, 220.99, 6, 6, 0, "Undercity Inn"); + player->SEND_GOSSIP_MENU(3517,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Mailbox + player->SEND_POI(1632.68, 219.4, 6, 6, 0, "Undercity Mailbox"); + player->SEND_GOSSIP_MENU(3518,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //Auction House + player->SEND_POI(1647.9, 258.49, 6, 6, 0, "Undercity Auction House"); + player->SEND_GOSSIP_MENU(3519,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Zeppelin + player->SEND_POI(2059, 274.86, 6, 6, 0, "Undercity Zeppelin"); + player->SEND_GOSSIP_MENU(3520,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Weapon Master + player->SEND_POI(1670.31, 324.66, 6, 6, 0, "Archibald"); + player->SEND_GOSSIP_MENU(4521,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Stable master + player->SEND_POI(1634.18, 226.76, 6, 6, 0, "Anya Maulray"); + player->SEND_GOSSIP_MENU(5979,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Battlemaster + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALTERACVALLEY , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ARATHIBASIN , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARSONGULCH , GOSSIP_SENDER_SEC_BATTLEINFO, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(7527,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Class trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MAGE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_PRIEST , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ROGUE , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARLOCK , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_WARRIOR , GOSSIP_SENDER_SEC_CLASSTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(3542,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Profession trainer + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ALCHEMY , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_BLACKSMITHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_COOKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENCHANTING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_ENGINEERING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FIRSTAID , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_FISHING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_HERBALISM , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_LEATHERWORKING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_MINING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_SKINNING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->ADD_GOSSIP_ITEM( 0, GOSSIP_TEXT_TAILORING , GOSSIP_SENDER_SEC_PROFTRAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(3541,_Creature->GetGUID()); + break; + } +} + +void SendBattleMasterMenu_guard_undercity(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //AV + player->SEND_POI(1329, 333.92, 6, 6, 0, "Grizzle Halfmane"); + player->SEND_GOSSIP_MENU(7525,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //AB + player->SEND_POI(1283.3, 287.16, 6, 6, 0, "Sir Malory Wheeler"); + player->SEND_GOSSIP_MENU(7646,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //WSG + player->SEND_POI(1265, 351.18, 6, 6, 0, "Kurden Bloodclaw"); + player->SEND_GOSSIP_MENU(7526,_Creature->GetGUID()); + break; + } +} + +void SendClassTrainerMenu_guard_undercity(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Mage + player->SEND_POI(1781, 53, 6, 6, 0, "Undercity Mage Trainers"); + player->SEND_GOSSIP_MENU(3513,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Priest + player->SEND_POI(1758.33, 401.5, 6, 6, 0, "Undercity Priest Trainers"); + player->SEND_GOSSIP_MENU(3521,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Rogue + player->SEND_POI(1418.56, 65, 6, 6, 0, "Undercity Rogue Trainers"); + player->SEND_GOSSIP_MENU(3524,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Warlock + player->SEND_POI(1780.92, 53.16, 6, 6, 0, "Undercity Warlock Trainers"); + player->SEND_GOSSIP_MENU(3526,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Warrior + player->SEND_POI(1775.59, 418.19, 6, 6, 0, "Undercity Warrior Trainers"); + player->SEND_GOSSIP_MENU(3527,_Creature->GetGUID()); + break; + } +} + +void SendProfTrainerMenu_guard_undercity(Player *player, Creature *_Creature, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: //Alchemy + player->SEND_POI(1419.82, 417.19, 6, 6, 0, "The Apothecarium"); + player->SEND_GOSSIP_MENU(3528,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: //Blacksmithing + player->SEND_POI(1696, 285, 6, 6, 0, "Undercity Blacksmithing Trainer"); + player->SEND_GOSSIP_MENU(3529,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: //Cooking + player->SEND_POI(1596.34, 274.68, 6, 6, 0, "Undercity Cooking Trainer"); + player->SEND_GOSSIP_MENU(3530,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: //Enchanting + player->SEND_POI(1488.54, 280.19, 6, 6, 0, "Undercity Enchanting Trainer"); + player->SEND_GOSSIP_MENU(3531,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: //Engineering + player->SEND_POI(1408.58, 143.43, 6, 6, 0, "Undercity Engineering Trainer"); + player->SEND_GOSSIP_MENU(3532,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: //First Aid + player->SEND_POI(1519.65, 167.19, 6, 6, 0, "Undercity First Aid Trainer"); + player->SEND_GOSSIP_MENU(3533,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: //Fishing + player->SEND_POI(1679.9, 89, 6, 6, 0, "Undercity Fishing Trainer"); + player->SEND_GOSSIP_MENU(3534,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 8: //Herbalism + player->SEND_POI(1558, 349.36, 6, 6, 0, "Undercity Herbalism Trainer"); + player->SEND_GOSSIP_MENU(3535,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 9: //Leatherworking + player->SEND_POI(1498.76, 196.43, 6, 6, 0, "Undercity Leatherworking Trainer"); + player->SEND_GOSSIP_MENU(3536,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: //Mining + player->SEND_POI(1642.88, 335.58, 6, 6, 0, "Undercity Mining Trainer"); + player->SEND_GOSSIP_MENU(3537,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: //Skinning + player->SEND_POI(1498.6, 196.46, 6, 6, 0, "Undercity Skinning Trainer"); + player->SEND_GOSSIP_MENU(3538,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: //Tailoring + player->SEND_POI(1689.55, 193, 6, 6, 0, "Undercity Tailoring Trainer"); + player->SEND_GOSSIP_MENU(3539,_Creature->GetGUID()); + break; + } +} + +bool GossipSelect_guard_undercity(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (sender) + { + case GOSSIP_SENDER_MAIN: SendDefaultMenu_guard_undercity(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_CLASSTRAIN: SendClassTrainerMenu_guard_undercity(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_PROFTRAIN: SendProfTrainerMenu_guard_undercity(player, _Creature, action); break; + case GOSSIP_SENDER_SEC_BATTLEINFO: SendBattleMasterMenu_guard_undercity(player, _Creature, action); break; + } + return true; +} + +/******************************************************* + * guard_undercity end + *******************************************************/ + +CreatureAI* GetAI_guard_undercity(Creature *_Creature) +{ + return new guardAI (_Creature); +} + +/******************************************************* + * AddSC + *******************************************************/ + +void AddSC_guards() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="guard_azuremyst"; + newscript->pGossipHello = &GossipHello_guard_azuremyst; + newscript->pGossipSelect = &GossipSelect_guard_azuremyst; + newscript->GetAI = GetAI_guard_azuremyst; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_bluffwatcher"; + newscript->pGossipHello = &GossipHello_guard_bluffwatcher; + newscript->pGossipSelect = &GossipSelect_guard_bluffwatcher; + newscript->GetAI = GetAI_guard_bluffwatcher; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_contested"; + newscript->GetAI = GetAI_guard_contested; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_darnassus"; + newscript->pGossipHello = &GossipHello_guard_darnassus; + newscript->pGossipSelect = &GossipSelect_guard_darnassus; + newscript->GetAI = GetAI_guard_darnassus; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_dunmorogh"; + newscript->pGossipHello = &GossipHello_guard_dunmorogh; + newscript->pGossipSelect = &GossipSelect_guard_dunmorogh; + newscript->GetAI = GetAI_guard_dunmorogh; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_durotar"; + newscript->pGossipHello = &GossipHello_guard_durotar; + newscript->pGossipSelect = &GossipSelect_guard_durotar; + newscript->GetAI = GetAI_guard_durotar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_elwynnforest"; + newscript->pGossipHello = &GossipHello_guard_elwynnforest; + newscript->pGossipSelect = &GossipSelect_guard_elwynnforest; + newscript->GetAI = GetAI_guard_elwynnforest; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_eversong"; + newscript->pGossipHello = &GossipHello_guard_eversong; + newscript->pGossipSelect = &GossipSelect_guard_eversong; + newscript->GetAI = GetAI_guard_eversong; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_exodar"; + newscript->pGossipHello = &GossipHello_guard_exodar; + newscript->pGossipSelect = &GossipSelect_guard_exodar; + newscript->GetAI = GetAI_guard_exodar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_ironforge"; + newscript->pGossipHello = &GossipHello_guard_ironforge; + newscript->pGossipSelect = &GossipSelect_guard_ironforge; + newscript->GetAI = GetAI_guard_ironforge; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_mulgore"; + newscript->pGossipHello = &GossipHello_guard_mulgore; + newscript->pGossipSelect = &GossipSelect_guard_mulgore; + newscript->GetAI = GetAI_guard_mulgore; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_orgrimmar"; + newscript->pGossipHello = &GossipHello_guard_orgrimmar; + newscript->pGossipSelect = &GossipSelect_guard_orgrimmar; + newscript->pReceiveEmote = &ReceiveEmote_guard_orgrimmar; + newscript->GetAI = GetAI_guard_orgrimmar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_shattrath"; + newscript->pGossipHello = &GossipHello_guard_shattrath; + newscript->pGossipSelect = &GossipSelect_guard_shattrath; + newscript->GetAI = GetAI_guard_shattrath; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_shattrath_aldor"; + newscript->GetAI = GetAI_guard_shattrath_aldor; + newscript->pGossipHello = &GossipHello_guard_shattrath_aldor; + newscript->pGossipSelect = &GossipSelect_guard_shattrath_aldor; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_shattrath_scryer"; + newscript->GetAI = GetAI_guard_shattrath_scryer; + newscript->pGossipHello = &GossipHello_guard_shattrath_scryer; + newscript->pGossipSelect = &GossipSelect_guard_shattrath_scryer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_silvermoon"; + newscript->pGossipHello = &GossipHello_guard_silvermoon; + newscript->pGossipSelect = &GossipSelect_guard_silvermoon; + newscript->GetAI = GetAI_guard_silvermoon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_stormwind"; + newscript->pGossipHello = &GossipHello_guard_stormwind; + newscript->pGossipSelect = &GossipSelect_guard_stormwind; + newscript->pReceiveEmote = &ReceiveEmote_guard_stormwind; + newscript->GetAI = GetAI_guard_stormwind; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_teldrassil"; + newscript->pGossipHello = &GossipHello_guard_teldrassil; + newscript->pGossipSelect = &GossipSelect_guard_teldrassil; + newscript->GetAI = GetAI_guard_teldrassil; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_tirisfal"; + newscript->pGossipHello = &GossipHello_guard_tirisfal; + newscript->pGossipSelect = &GossipSelect_guard_tirisfal; + newscript->GetAI = GetAI_guard_tirisfal; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="guard_undercity"; + newscript->pGossipHello = &GossipHello_guard_undercity; + newscript->pGossipSelect = &GossipSelect_guard_undercity; + newscript->GetAI = GetAI_guard_undercity; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/item/item_scripts.cpp b/src/bindings/scripts/scripts/item/item_scripts.cpp index 6d2bfe8d852..1b0ecfba27f 100644 --- a/src/bindings/scripts/scripts/item/item_scripts.cpp +++ b/src/bindings/scripts/scripts/item/item_scripts.cpp @@ -1,529 +1,529 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Item_Scripts -SD%Complete: 100 -SDComment: Items for a range of different items. See content below (in script) -SDCategory: Items -EndScriptData */ - -/* ContentData -item_area_52_special(i28132) Prevents abuse of this item -item_attuned_crystal_cores(i34368) Prevent abuse(quest 11524 & 11525) -item_blackwhelp_net(i31129) Quest Whelps of the Wyrmcult (q10747). Prevents abuse -item_draenei_fishing_net(i23654) Hacklike implements chance to spawn item or creature -item_disciplinary_rod Prevents abuse -item_nether_wraith_beacon(i31742) Summons creatures for quest Becoming a Spellfire Tailor (q10832) -item_flying_machine(i34060,i34061) Engineering crafted flying machines -item_gor_dreks_ointment(i30175) Protecting Our Own(q10488) -item_muiseks_vessel Cast on creature, they must be dead(q 3123,3124,3125,3126,3127) -item_protovoltaic_magneto_collector Prevents abuse -item_razorthorn_flayer_gland Quest Discovering Your Roots (q11520) and Rediscovering Your Roots (q11521). Prevents abuse -item_tame_beast_rods(many) Prevent cast on any other creature than the intended (for all tame beast quests) -item_soul_cannon(i32825) Prevents abuse of this item -item_sparrowhawk_net(i32321) Quest To Catch A Sparrowhawk (q10987). Prevents abuse -item_voodoo_charm Provide proper error message and target(q2561) -item_vorenthals_presence(i30259) Prevents abuse of this item -item_yehkinyas_bramble(i10699) Allow cast spell on vale screecher only and remove corpse if cast sucessful (q3520) -item_zezzak_shard(i31463) Quest The eyes of Grillok (q10813). Prevents abuse -EndContentData */ - -#include "precompiled.h" -#include "SpellMgr.h" -#include "Spell.h" -#include "WorldPacket.h" - -/*##### -# item_area_52_special -#####*/ - -bool ItemUse_item_area_52_special(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if ( player->GetAreaId() == 3803 ) - { - return false; - } - else - { - player->SendEquipError(EQUIP_ERR_OUT_OF_RANGE,_Item,NULL); - return true; - } -} - -/*##### -# item_attuned_crystal_cores -#####*/ - -bool ItemUse_item_attuned_crystal_cores(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 24972 && targets.getUnitTarget()->isDead() ) - return false; - - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); - return true; -} - -/*##### -# item_blackwhelp_net -#####*/ - -bool ItemUse_item_blackwhelp_net(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 21387 ) - return false; - - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### -# item_draenei_fishing_net -#####*/ - -//This is just a hack and should be removed from here. -//Creature/Item are in fact created before spell are sucessfully casted, without any checks at all to ensure proper/expected behavior. -bool ItemUse_item_draenei_fishing_net(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - //if( targets.getGOTarget() && targets.getGOTarget()->GetTypeId() == TYPEID_GAMEOBJECT && - //targets.getGOTarget()->GetGOInfo()->type == GAMEOBJECT_TYPE_SPELL_FOCUS && targets.getGOTarget()->GetEntry() == 181616 ) - //{ - if( player->GetQuestStatus(9452) == QUEST_STATUS_INCOMPLETE ) - { - if( rand()%100 < 35 ) - { - Creature *Murloc = player->SummonCreature(17102,player->GetPositionX() ,player->GetPositionY()+20, player->GetPositionZ(), 0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if( Murloc ) - Murloc->AI()->AttackStart(player); - } - else - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 23614, 1); - if( msg == EQUIP_ERR_OK ) - { - Item* item = player->StoreNewItem(dest,23614,true); - if( item ) - player->SendNewItem(item,1,false,true); - }else - player->SendEquipError(msg,NULL,NULL); - } - } - //} - return false; -} - -/*##### -# item_disciplinary_rod -#####*/ - -bool ItemUse_item_disciplinary_rod(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - (targets.getUnitTarget()->GetEntry() == 15941 || targets.getUnitTarget()->GetEntry() == 15945) ) - return false; - - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); - return true; -} - -/*##### -# item_nether_wraith_beacon -#####*/ - -bool ItemUse_item_nether_wraith_beacon(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if (player->GetQuestStatus(10832) == QUEST_STATUS_INCOMPLETE) - { - Creature *Nether; - Nether = player->SummonCreature(22408,player->GetPositionX() ,player->GetPositionY()+20, player->GetPositionZ(), 0,TEMPSUMMON_TIMED_DESPAWN,180000); - Nether = player->SummonCreature(22408,player->GetPositionX() ,player->GetPositionY()-20, player->GetPositionZ(), 0,TEMPSUMMON_TIMED_DESPAWN,180000); - if (Nether) - ((CreatureAI*)Nether->AI())->AttackStart(player); - } - return false; -} - -/*##### -# item_flying_machine -#####*/ - -bool ItemUse_item_flying_machine(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - uint32 itemId = _Item->GetEntry(); - if( itemId == 34060 ) - if( player->GetBaseSkillValue(SKILL_RIDING) >= 225 ) - return false; - - if( itemId == 34061 ) - if( player->GetBaseSkillValue(SKILL_RIDING) == 300 ) - return false; - - debug_log("SD2: Player attempt to use item %u, but did not meet riding requirement",itemId); - player->SendEquipError(EQUIP_ERR_ERR_CANT_EQUIP_SKILL,_Item,NULL); - return true; -} - -/*##### -# item_gor_dreks_ointment -#####*/ - -bool ItemUse_item_gor_dreks_ointment(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 20748 && !targets.getUnitTarget()->HasAura(32578,0) ) - return false; - - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); - return true; -} - -/*##### -# item_muiseks_vessel -#####*/ - -bool ItemUse_item_muiseks_vessel(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - Unit* uTarget = targets.getUnitTarget(); - uint32 itemSpell = _Item->GetProto()->Spells[0].SpellId; - uint32 cEntry = 0; - uint32 cEntry2 = 0; - uint32 cEntry3 = 0; - uint32 cEntry4 = 0; - - if(itemSpell) - { - switch(itemSpell) - { - case 11885: //Wandering Forest Walker - cEntry = 7584; - break; - case 11886: //Owlbeasts - cEntry = 2927; - cEntry2 = 2928; - cEntry3 = 2929; - cEntry4 = 7808; - break; - case 11887: //Freyfeather Hippogryphs - cEntry = 5300; - cEntry2 = 5304; - cEntry3 = 5305; - cEntry4 = 5306; - break; - case 11888: //Sprite Dragon Sprite Darters - cEntry = 5276; - cEntry2 = 5278; - break; - case 11889: //Zapped Land Walker Land Walker Zapped Cliff Giant Cliff Giant - cEntry = 5357; - cEntry2 = 5358; - cEntry3 = 14640; - cEntry4 = 14604; - break; - } - if( uTarget && uTarget->GetTypeId()==TYPEID_UNIT && uTarget->isDead() && - (uTarget->GetEntry()==cEntry || uTarget->GetEntry()==cEntry2 || uTarget->GetEntry()==cEntry3 || uTarget->GetEntry()==cEntry4) ) - { - ((Creature*)uTarget)->RemoveCorpse(); - return false; - } - } - - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(_Item->GetEntry()); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Invalid target - - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell - return true; -} - -/*##### -# item_razorthorn_flayer_gland -#####*/ - -bool ItemUse_item_razorthorn_flayer_gland(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 24922 ) - return false; - - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### -# item_tame_beast_rods -#####*/ - -bool ItemUse_item_tame_beast_rods(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - uint32 itemSpell = _Item->GetProto()->Spells[0].SpellId; - uint32 cEntry = 0; - - if(itemSpell) - { - switch(itemSpell) - { - case 19548: cEntry = 1196; break; //Ice Claw Bear - case 19674: cEntry = 1126; break; //Large Crag Boar - case 19687: cEntry = 1201; break; //Snow Leopard - case 19688: cEntry = 2956; break; //Adult Plainstrider - case 19689: cEntry = 2959; break; //Prairie Stalker - case 19692: cEntry = 2970; break; //Swoop - case 19693: cEntry = 1998; break; //Webwood Lurker - case 19694: cEntry = 3099; break; //Dire Mottled Boar - case 19696: cEntry = 3107; break; //Surf Crawler - case 19697: cEntry = 3126; break; //Armored Scorpid - case 19699: cEntry = 2043; break; //Nightsaber Stalker - case 19700: cEntry = 1996; break; //Strigid Screecher - case 30646: cEntry = 17217; break; //Barbed Crawler - case 30653: cEntry = 17374; break; //Greater Timberstrider - case 30654: cEntry = 17203; break; //Nightstalker - case 30099: cEntry = 15650; break; //Crazed Dragonhawk - case 30102: cEntry = 15652; break; //Elder Springpaw - case 30105: cEntry = 16353; break; //Mistbat - } - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == cEntry ) - return false; - } - - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(_Item->GetEntry()); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Invalid target - - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell - return true; -} - -/*##### -# item_protovoltaic_magneto_collector -#####*/ - -bool ItemUse_item_protovoltaic_magneto_collector(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 21729 ) - return false; - - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); - return true; -} - -/*##### -# item_soul_cannon -#####*/ - -bool ItemUse_item_soul_cannon(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - // allow use - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 22357 ) - return false; - - // error - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### -# item_sparrowhawk_net -#####*/ - -bool ItemUse_item_sparrowhawk_net(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 22979 ) - return false; - - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### -# item_voodoo_charm -#####*/ - -bool ItemUse_item_voodoo_charm(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && targets.getUnitTarget()->isDead() && - targets.getUnitTarget()->GetEntry()==7318 ) - return false; - - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(_Item->GetEntry()); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Invalid target - - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell - return true; -} - -/*##### -# item_vorenthals_presence -#####*/ - -bool ItemUse_item_vorenthals_presence(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - // allow use - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 20132 ) - return false; - - // error - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### -# item_yehkinyas_bramble -#####*/ - -bool ItemUse_item_yehkinyas_bramble(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if (player->GetQuestStatus(3520) == QUEST_STATUS_INCOMPLETE) - { - Unit * unit_target = targets.getUnitTarget(); - if( unit_target && - unit_target->GetTypeId()==TYPEID_UNIT && - unit_target->isDead() && - // cast only on corpse 5307 or 5308 - (unit_target->GetEntry()==5307 || unit_target->GetEntry()==5308) ) - { - ((Creature*)unit_target)->RemoveCorpse(); // remove corpse for cancelling second use - return false; // all ok - } - } - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(10699); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Bad target - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell - return true; -} - -/*##### -# item_zezzak_shard -#####*/ - -bool ItemUse_item_zezzak_shard(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 19440 ) - return false; - - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -void AddSC_item_scripts() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="item_area_52_special"; - newscript->pItemUse = ItemUse_item_area_52_special; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_attuned_crystal_cores"; - newscript->pItemUse = ItemUse_item_attuned_crystal_cores; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_blackwhelp_net"; - newscript->pItemUse = ItemUse_item_blackwhelp_net; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_disciplinary_rod"; - newscript->pItemUse = ItemUse_item_disciplinary_rod; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_draenei_fishing_net"; - newscript->pItemUse = ItemUse_item_draenei_fishing_net; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_nether_wraith_beacon"; - newscript->pItemUse = ItemUse_item_nether_wraith_beacon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_flying_machine"; - newscript->pItemUse = ItemUse_item_flying_machine; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_gor_dreks_ointment"; - newscript->pItemUse = ItemUse_item_gor_dreks_ointment; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_muiseks_vessel"; - newscript->pItemUse = ItemUse_item_muiseks_vessel; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_razorthorn_flayer_gland"; - newscript->pItemUse = ItemUse_item_razorthorn_flayer_gland; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_tame_beast_rods"; - newscript->pItemUse = ItemUse_item_tame_beast_rods; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_protovoltaic_magneto_collector"; - newscript->pItemUse = ItemUse_item_protovoltaic_magneto_collector; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_soul_cannon"; - newscript->pItemUse = ItemUse_item_soul_cannon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_sparrowhawk_net"; - newscript->pItemUse = ItemUse_item_sparrowhawk_net; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_voodoo_charm"; - newscript->pItemUse = ItemUse_item_voodoo_charm; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_vorenthals_presence"; - newscript->pItemUse = ItemUse_item_vorenthals_presence; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_yehkinyas_bramble"; - newscript->pItemUse = ItemUse_item_yehkinyas_bramble; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_zezzaks_shard"; - newscript->pItemUse = ItemUse_item_zezzak_shard; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Item_Scripts +SD%Complete: 100 +SDComment: Items for a range of different items. See content below (in script) +SDCategory: Items +EndScriptData */ + +/* ContentData +item_area_52_special(i28132) Prevents abuse of this item +item_attuned_crystal_cores(i34368) Prevent abuse(quest 11524 & 11525) +item_blackwhelp_net(i31129) Quest Whelps of the Wyrmcult (q10747). Prevents abuse +item_draenei_fishing_net(i23654) Hacklike implements chance to spawn item or creature +item_disciplinary_rod Prevents abuse +item_nether_wraith_beacon(i31742) Summons creatures for quest Becoming a Spellfire Tailor (q10832) +item_flying_machine(i34060,i34061) Engineering crafted flying machines +item_gor_dreks_ointment(i30175) Protecting Our Own(q10488) +item_muiseks_vessel Cast on creature, they must be dead(q 3123,3124,3125,3126,3127) +item_protovoltaic_magneto_collector Prevents abuse +item_razorthorn_flayer_gland Quest Discovering Your Roots (q11520) and Rediscovering Your Roots (q11521). Prevents abuse +item_tame_beast_rods(many) Prevent cast on any other creature than the intended (for all tame beast quests) +item_soul_cannon(i32825) Prevents abuse of this item +item_sparrowhawk_net(i32321) Quest To Catch A Sparrowhawk (q10987). Prevents abuse +item_voodoo_charm Provide proper error message and target(q2561) +item_vorenthals_presence(i30259) Prevents abuse of this item +item_yehkinyas_bramble(i10699) Allow cast spell on vale screecher only and remove corpse if cast sucessful (q3520) +item_zezzak_shard(i31463) Quest The eyes of Grillok (q10813). Prevents abuse +EndContentData */ + +#include "precompiled.h" +#include "SpellMgr.h" +#include "Spell.h" +#include "WorldPacket.h" + +/*##### +# item_area_52_special +#####*/ + +bool ItemUse_item_area_52_special(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if ( player->GetAreaId() == 3803 ) + { + return false; + } + else + { + player->SendEquipError(EQUIP_ERR_OUT_OF_RANGE,_Item,NULL); + return true; + } +} + +/*##### +# item_attuned_crystal_cores +#####*/ + +bool ItemUse_item_attuned_crystal_cores(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 24972 && targets.getUnitTarget()->isDead() ) + return false; + + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); + return true; +} + +/*##### +# item_blackwhelp_net +#####*/ + +bool ItemUse_item_blackwhelp_net(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 21387 ) + return false; + + player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); + return true; +} + +/*##### +# item_draenei_fishing_net +#####*/ + +//This is just a hack and should be removed from here. +//Creature/Item are in fact created before spell are sucessfully casted, without any checks at all to ensure proper/expected behavior. +bool ItemUse_item_draenei_fishing_net(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + //if( targets.getGOTarget() && targets.getGOTarget()->GetTypeId() == TYPEID_GAMEOBJECT && + //targets.getGOTarget()->GetGOInfo()->type == GAMEOBJECT_TYPE_SPELL_FOCUS && targets.getGOTarget()->GetEntry() == 181616 ) + //{ + if( player->GetQuestStatus(9452) == QUEST_STATUS_INCOMPLETE ) + { + if( rand()%100 < 35 ) + { + Creature *Murloc = player->SummonCreature(17102,player->GetPositionX() ,player->GetPositionY()+20, player->GetPositionZ(), 0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + if( Murloc ) + Murloc->AI()->AttackStart(player); + } + else + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 23614, 1); + if( msg == EQUIP_ERR_OK ) + { + Item* item = player->StoreNewItem(dest,23614,true); + if( item ) + player->SendNewItem(item,1,false,true); + }else + player->SendEquipError(msg,NULL,NULL); + } + } + //} + return false; +} + +/*##### +# item_disciplinary_rod +#####*/ + +bool ItemUse_item_disciplinary_rod(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + (targets.getUnitTarget()->GetEntry() == 15941 || targets.getUnitTarget()->GetEntry() == 15945) ) + return false; + + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); + return true; +} + +/*##### +# item_nether_wraith_beacon +#####*/ + +bool ItemUse_item_nether_wraith_beacon(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if (player->GetQuestStatus(10832) == QUEST_STATUS_INCOMPLETE) + { + Creature *Nether; + Nether = player->SummonCreature(22408,player->GetPositionX() ,player->GetPositionY()+20, player->GetPositionZ(), 0,TEMPSUMMON_TIMED_DESPAWN,180000); + Nether = player->SummonCreature(22408,player->GetPositionX() ,player->GetPositionY()-20, player->GetPositionZ(), 0,TEMPSUMMON_TIMED_DESPAWN,180000); + if (Nether) + ((CreatureAI*)Nether->AI())->AttackStart(player); + } + return false; +} + +/*##### +# item_flying_machine +#####*/ + +bool ItemUse_item_flying_machine(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + uint32 itemId = _Item->GetEntry(); + if( itemId == 34060 ) + if( player->GetBaseSkillValue(SKILL_RIDING) >= 225 ) + return false; + + if( itemId == 34061 ) + if( player->GetBaseSkillValue(SKILL_RIDING) == 300 ) + return false; + + debug_log("SD2: Player attempt to use item %u, but did not meet riding requirement",itemId); + player->SendEquipError(EQUIP_ERR_ERR_CANT_EQUIP_SKILL,_Item,NULL); + return true; +} + +/*##### +# item_gor_dreks_ointment +#####*/ + +bool ItemUse_item_gor_dreks_ointment(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 20748 && !targets.getUnitTarget()->HasAura(32578,0) ) + return false; + + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); + return true; +} + +/*##### +# item_muiseks_vessel +#####*/ + +bool ItemUse_item_muiseks_vessel(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + Unit* uTarget = targets.getUnitTarget(); + uint32 itemSpell = _Item->GetProto()->Spells[0].SpellId; + uint32 cEntry = 0; + uint32 cEntry2 = 0; + uint32 cEntry3 = 0; + uint32 cEntry4 = 0; + + if(itemSpell) + { + switch(itemSpell) + { + case 11885: //Wandering Forest Walker + cEntry = 7584; + break; + case 11886: //Owlbeasts + cEntry = 2927; + cEntry2 = 2928; + cEntry3 = 2929; + cEntry4 = 7808; + break; + case 11887: //Freyfeather Hippogryphs + cEntry = 5300; + cEntry2 = 5304; + cEntry3 = 5305; + cEntry4 = 5306; + break; + case 11888: //Sprite Dragon Sprite Darters + cEntry = 5276; + cEntry2 = 5278; + break; + case 11889: //Zapped Land Walker Land Walker Zapped Cliff Giant Cliff Giant + cEntry = 5357; + cEntry2 = 5358; + cEntry3 = 14640; + cEntry4 = 14604; + break; + } + if( uTarget && uTarget->GetTypeId()==TYPEID_UNIT && uTarget->isDead() && + (uTarget->GetEntry()==cEntry || uTarget->GetEntry()==cEntry2 || uTarget->GetEntry()==cEntry3 || uTarget->GetEntry()==cEntry4) ) + { + ((Creature*)uTarget)->RemoveCorpse(); + return false; + } + } + + WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message + data << uint32(_Item->GetEntry()); // itemId + data << uint8(SPELL_FAILED_BAD_TARGETS); // reason + player->GetSession()->SendPacket(&data); // send message: Invalid target + + player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell + return true; +} + +/*##### +# item_razorthorn_flayer_gland +#####*/ + +bool ItemUse_item_razorthorn_flayer_gland(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 24922 ) + return false; + + player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); + return true; +} + +/*##### +# item_tame_beast_rods +#####*/ + +bool ItemUse_item_tame_beast_rods(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + uint32 itemSpell = _Item->GetProto()->Spells[0].SpellId; + uint32 cEntry = 0; + + if(itemSpell) + { + switch(itemSpell) + { + case 19548: cEntry = 1196; break; //Ice Claw Bear + case 19674: cEntry = 1126; break; //Large Crag Boar + case 19687: cEntry = 1201; break; //Snow Leopard + case 19688: cEntry = 2956; break; //Adult Plainstrider + case 19689: cEntry = 2959; break; //Prairie Stalker + case 19692: cEntry = 2970; break; //Swoop + case 19693: cEntry = 1998; break; //Webwood Lurker + case 19694: cEntry = 3099; break; //Dire Mottled Boar + case 19696: cEntry = 3107; break; //Surf Crawler + case 19697: cEntry = 3126; break; //Armored Scorpid + case 19699: cEntry = 2043; break; //Nightsaber Stalker + case 19700: cEntry = 1996; break; //Strigid Screecher + case 30646: cEntry = 17217; break; //Barbed Crawler + case 30653: cEntry = 17374; break; //Greater Timberstrider + case 30654: cEntry = 17203; break; //Nightstalker + case 30099: cEntry = 15650; break; //Crazed Dragonhawk + case 30102: cEntry = 15652; break; //Elder Springpaw + case 30105: cEntry = 16353; break; //Mistbat + } + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == cEntry ) + return false; + } + + WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message + data << uint32(_Item->GetEntry()); // itemId + data << uint8(SPELL_FAILED_BAD_TARGETS); // reason + player->GetSession()->SendPacket(&data); // send message: Invalid target + + player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell + return true; +} + +/*##### +# item_protovoltaic_magneto_collector +#####*/ + +bool ItemUse_item_protovoltaic_magneto_collector(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 21729 ) + return false; + + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); + return true; +} + +/*##### +# item_soul_cannon +#####*/ + +bool ItemUse_item_soul_cannon(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + // allow use + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 22357 ) + return false; + + // error + player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); + return true; +} + +/*##### +# item_sparrowhawk_net +#####*/ + +bool ItemUse_item_sparrowhawk_net(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 22979 ) + return false; + + player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); + return true; +} + +/*##### +# item_voodoo_charm +#####*/ + +bool ItemUse_item_voodoo_charm(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && targets.getUnitTarget()->isDead() && + targets.getUnitTarget()->GetEntry()==7318 ) + return false; + + WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message + data << uint32(_Item->GetEntry()); // itemId + data << uint8(SPELL_FAILED_BAD_TARGETS); // reason + player->GetSession()->SendPacket(&data); // send message: Invalid target + + player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell + return true; +} + +/*##### +# item_vorenthals_presence +#####*/ + +bool ItemUse_item_vorenthals_presence(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + // allow use + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 20132 ) + return false; + + // error + player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); + return true; +} + +/*##### +# item_yehkinyas_bramble +#####*/ + +bool ItemUse_item_yehkinyas_bramble(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if (player->GetQuestStatus(3520) == QUEST_STATUS_INCOMPLETE) + { + Unit * unit_target = targets.getUnitTarget(); + if( unit_target && + unit_target->GetTypeId()==TYPEID_UNIT && + unit_target->isDead() && + // cast only on corpse 5307 or 5308 + (unit_target->GetEntry()==5307 || unit_target->GetEntry()==5308) ) + { + ((Creature*)unit_target)->RemoveCorpse(); // remove corpse for cancelling second use + return false; // all ok + } + } + WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message + data << uint32(10699); // itemId + data << uint8(SPELL_FAILED_BAD_TARGETS); // reason + player->GetSession()->SendPacket(&data); // send message: Bad target + player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell + return true; +} + +/*##### +# item_zezzak_shard +#####*/ + +bool ItemUse_item_zezzak_shard(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && + targets.getUnitTarget()->GetEntry() == 19440 ) + return false; + + player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); + return true; +} + +void AddSC_item_scripts() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="item_area_52_special"; + newscript->pItemUse = ItemUse_item_area_52_special; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_attuned_crystal_cores"; + newscript->pItemUse = ItemUse_item_attuned_crystal_cores; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_blackwhelp_net"; + newscript->pItemUse = ItemUse_item_blackwhelp_net; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_disciplinary_rod"; + newscript->pItemUse = ItemUse_item_disciplinary_rod; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_draenei_fishing_net"; + newscript->pItemUse = ItemUse_item_draenei_fishing_net; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_nether_wraith_beacon"; + newscript->pItemUse = ItemUse_item_nether_wraith_beacon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_flying_machine"; + newscript->pItemUse = ItemUse_item_flying_machine; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_gor_dreks_ointment"; + newscript->pItemUse = ItemUse_item_gor_dreks_ointment; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_muiseks_vessel"; + newscript->pItemUse = ItemUse_item_muiseks_vessel; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_razorthorn_flayer_gland"; + newscript->pItemUse = ItemUse_item_razorthorn_flayer_gland; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_tame_beast_rods"; + newscript->pItemUse = ItemUse_item_tame_beast_rods; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_protovoltaic_magneto_collector"; + newscript->pItemUse = ItemUse_item_protovoltaic_magneto_collector; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_soul_cannon"; + newscript->pItemUse = ItemUse_item_soul_cannon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_sparrowhawk_net"; + newscript->pItemUse = ItemUse_item_sparrowhawk_net; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_voodoo_charm"; + newscript->pItemUse = ItemUse_item_voodoo_charm; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_vorenthals_presence"; + newscript->pItemUse = ItemUse_item_vorenthals_presence; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_yehkinyas_bramble"; + newscript->pItemUse = ItemUse_item_yehkinyas_bramble; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_zezzaks_shard"; + newscript->pItemUse = ItemUse_item_zezzak_shard; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/item/item_test.cpp b/src/bindings/scripts/scripts/item/item_test.cpp index e4f7285e52a..d54a42d217a 100644 --- a/src/bindings/scripts/scripts/item/item_test.cpp +++ b/src/bindings/scripts/scripts/item/item_test.cpp @@ -1,42 +1,42 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Item_Test -SD%Complete: 100 -SDComment: Used for Testing Item Scripts -SDCategory: Items -EndScriptData */ - -#include "precompiled.h" - -extern void LoadDatabase(); - -bool ItemUse_item_test(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - LoadDatabase(); - return true; -} - -void AddSC_item_test() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="item_test"; - newscript->pItemUse = ItemUse_item_test; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Item_Test +SD%Complete: 100 +SDComment: Used for Testing Item Scripts +SDCategory: Items +EndScriptData */ + +#include "precompiled.h" + +extern void LoadDatabase(); + +bool ItemUse_item_test(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + LoadDatabase(); + return true; +} + +void AddSC_item_test() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="item_test"; + newscript->pItemUse = ItemUse_item_test; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/npc/npc_escortAI.cpp b/src/bindings/scripts/scripts/npc/npc_escortAI.cpp index d846727ac0a..9be59296dbb 100644 --- a/src/bindings/scripts/scripts/npc/npc_escortAI.cpp +++ b/src/bindings/scripts/scripts/npc/npc_escortAI.cpp @@ -1,304 +1,304 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -/* ScriptData -SDName: Npc_EscortAI -SD%Complete: 100 -SDComment: -SDCategory: Npc -EndScriptData */ - -#include "precompiled.h" -#include "npc_escortAI.h" - -#define WP_LAST_POINT -1 -#define MAX_PLAYER_DISTANCE 50 - -bool npc_escortAI::IsVisible(Unit* who) const -{ - if (!who) - return false; - - return (m_creature->GetDistance(who) < VISIBLE_RANGE) && who->isVisibleForOrDetect(m_creature,true); -} - -void npc_escortAI::AttackStart(Unit *who) -{ - if (!who) - return; - - if (IsBeingEscorted && !Defend) - return; - - if (who->isTargetableForAttack()) - { - //Begin attack - if ( m_creature->Attack(who, true) ) - { - m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MoveChase(who); - m_creature->AddThreat(who, 0.0f); - } - - if (!InCombat) - { - InCombat = true; - - //Store last position - m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z); - - debug_log("SD2: EscortAI has entered combat via Attack and stored last location"); - - Aggro(who); - } - } -} - -void npc_escortAI::MoveInLineOfSight(Unit *who) -{ - if (IsBeingEscorted && !Attack) - return; - - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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); - - //Begin attack - if ( m_creature->Attack(who, true) ) - { - m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MoveChase(who); - m_creature->AddThreat(who, 0.0f); - } - - if (!InCombat) - { - InCombat = true; - - //Store last position - m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z); - debug_log("SD2: EscortAI has entered combat via LOS and stored last location"); - - Aggro(who); - } - } - } -} - -void npc_escortAI::JustRespawned() -{ - InCombat = false; - IsBeingEscorted = false; - IsOnHold = false; - - //Re-Enable gossip - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - Reset(); -} - -void npc_escortAI::EnterEvadeMode() -{ - InCombat = false; - - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - m_creature->SetLootRecipient(NULL); - - if (IsBeingEscorted) - { - debug_log("SD2: EscortAI has left combat and is now returning to last point"); - Returning = true; - m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MovePoint(WP_LAST_POINT, LastPos.x, LastPos.y, LastPos.z); - - }else - { - m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MoveTargetedHome(); - } - - Reset(); -} - -void npc_escortAI::UpdateAI(const uint32 diff) -{ - //Waypoint Updating - if (IsBeingEscorted && !InCombat && WaitTimer && !Returning) - if (WaitTimer <= diff) - { - if (ReconnectWP) - { - //Correct movement speed - if (Run) - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - else m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - - //Continue with waypoints - if( !IsOnHold ) - { - m_creature->GetMotionMaster()->MovePoint(CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z ); - debug_log("SD2: EscortAI Reconnect WP is: %d, %f, %f, %f", CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z); - WaitTimer = 0; - ReconnectWP = false; - return; - } - } - - //End of the line, Despawn self then immediatly respawn - if (CurrentWP == WaypointList.end()) - { - debug_log("SD2: EscortAI reached end of waypoints"); - - m_creature->setDeathState(JUST_DIED); - m_creature->SetHealth(0); - m_creature->CombatStop(); - m_creature->DeleteThreatList(); - m_creature->Respawn(); - m_creature->GetMotionMaster()->Clear(true); - - //Re-Enable gossip - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - IsBeingEscorted = false; - WaitTimer = 0; - return; - } - - if( !IsOnHold ) - { - m_creature->GetMotionMaster()->MovePoint(CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z ); - debug_log("SD2: EscortAI Next WP is: %d, %f, %f, %f", CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z); - WaitTimer = 0; - } - }else WaitTimer -= diff; - - //Check if player is within range - if (IsBeingEscorted && !InCombat && PlayerGUID) - if (PlayerTimer < diff) - { - Unit* p = Unit::GetUnit(*m_creature, PlayerGUID); - - if (!p || m_creature->GetDistance(p) > MAX_PLAYER_DISTANCE) - { - JustDied(m_creature); - IsBeingEscorted = false; - - debug_log("SD2: EscortAI Evaded back to spawn point because player was to far away or not found"); - - m_creature->setDeathState(JUST_DIED); - m_creature->SetHealth(0); - m_creature->CombatStop(); - m_creature->DeleteThreatList(); - m_creature->Respawn(); - m_creature->GetMotionMaster()->Clear(true); - - //Re-Enable gossip - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - } - - PlayerTimer = 1000; - }else PlayerTimer -= diff; - - //Check if we have a current target - if( m_creature->isAlive() && m_creature->SelectHostilTarget() && m_creature->getVictim()) - { - //If we are within range melee the target - if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - if( m_creature->isAttackReady() ) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - } - } -} - -void npc_escortAI::MovementInform(uint32 type, uint32 id) -{ - if (type != POINT_MOTION_TYPE || !IsBeingEscorted) - return; - - //Original position reached, continue waypoint movement - if (id == WP_LAST_POINT) - { - debug_log("SD2: EscortAI has returned to original position before combat"); - ReconnectWP = true; - Returning = false; - WaitTimer = 1; - - }else - { - //Make sure that we are still on the right waypoint - if (CurrentWP->id != id) - { - debug_log("SD2 ERROR: EscortAI reached waypoint out of order %d, expected %d", id, CurrentWP->id); - return; - } - - debug_log("SD2: EscortAI Waypoint %d reached", CurrentWP->id); - - //Call WP function - WaypointReached(CurrentWP->id); - - WaitTimer = CurrentWP->WaitTimeMs + 1; - - ++CurrentWP; - } -} - -void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs) -{ - Escort_Waypoint t(id, x, y, z, WaitTimeMs); - - WaypointList.push_back(t); -} - -void npc_escortAI::Start(bool bAttack, bool bDefend, bool bRun, uint64 pGUID) -{ - if (InCombat) - { - debug_log("SD2 ERROR: EscortAI attempt to Start while in combat"); - return; - } - - if (WaypointList.empty()) - { - debug_log("SD2 ERROR: Call to escortAI::Start with 0 waypoints"); - return; - } - - Attack = bAttack; - Defend = bDefend; - Run = bRun; - PlayerGUID = pGUID; - - debug_log("SD2: EscortAI started with %d waypoints. Attack = %d, Defend = %d, Run = %d, PlayerGUID = %d", WaypointList.size(), Attack, Defend, Run, PlayerGUID); - - CurrentWP = WaypointList.begin(); - - //Set initial speed - if (Run) - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - else m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - - //Start WP - m_creature->GetMotionMaster()->MovePoint(CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z ); - debug_log("SD2: EscortAI Next WP is: %d, %f, %f, %f", CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z); - IsBeingEscorted = true; - ReconnectWP = false; - Returning = false; - IsOnHold = false; - - //Disable gossip - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +/* ScriptData +SDName: Npc_EscortAI +SD%Complete: 100 +SDComment: +SDCategory: Npc +EndScriptData */ + +#include "precompiled.h" +#include "npc_escortAI.h" + +#define WP_LAST_POINT -1 +#define MAX_PLAYER_DISTANCE 50 + +bool npc_escortAI::IsVisible(Unit* who) const +{ + if (!who) + return false; + + return (m_creature->GetDistance(who) < VISIBLE_RANGE) && who->isVisibleForOrDetect(m_creature,true); +} + +void npc_escortAI::AttackStart(Unit *who) +{ + if (!who) + return; + + if (IsBeingEscorted && !Defend) + return; + + if (who->isTargetableForAttack()) + { + //Begin attack + if ( m_creature->Attack(who, true) ) + { + m_creature->GetMotionMaster()->MovementExpired(); + m_creature->GetMotionMaster()->MoveChase(who); + m_creature->AddThreat(who, 0.0f); + } + + if (!InCombat) + { + InCombat = true; + + //Store last position + m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z); + + debug_log("SD2: EscortAI has entered combat via Attack and stored last location"); + + Aggro(who); + } + } +} + +void npc_escortAI::MoveInLineOfSight(Unit *who) +{ + if (IsBeingEscorted && !Attack) + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + { + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + //Begin attack + if ( m_creature->Attack(who, true) ) + { + m_creature->GetMotionMaster()->MovementExpired(); + m_creature->GetMotionMaster()->MoveChase(who); + m_creature->AddThreat(who, 0.0f); + } + + if (!InCombat) + { + InCombat = true; + + //Store last position + m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z); + debug_log("SD2: EscortAI has entered combat via LOS and stored last location"); + + Aggro(who); + } + } + } +} + +void npc_escortAI::JustRespawned() +{ + InCombat = false; + IsBeingEscorted = false; + IsOnHold = false; + + //Re-Enable gossip + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + Reset(); +} + +void npc_escortAI::EnterEvadeMode() +{ + InCombat = false; + + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + m_creature->SetLootRecipient(NULL); + + if (IsBeingEscorted) + { + debug_log("SD2: EscortAI has left combat and is now returning to last point"); + Returning = true; + m_creature->GetMotionMaster()->MovementExpired(); + m_creature->GetMotionMaster()->MovePoint(WP_LAST_POINT, LastPos.x, LastPos.y, LastPos.z); + + }else + { + m_creature->GetMotionMaster()->MovementExpired(); + m_creature->GetMotionMaster()->MoveTargetedHome(); + } + + Reset(); +} + +void npc_escortAI::UpdateAI(const uint32 diff) +{ + //Waypoint Updating + if (IsBeingEscorted && !InCombat && WaitTimer && !Returning) + if (WaitTimer <= diff) + { + if (ReconnectWP) + { + //Correct movement speed + if (Run) + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + else m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + + //Continue with waypoints + if( !IsOnHold ) + { + m_creature->GetMotionMaster()->MovePoint(CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z ); + debug_log("SD2: EscortAI Reconnect WP is: %d, %f, %f, %f", CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z); + WaitTimer = 0; + ReconnectWP = false; + return; + } + } + + //End of the line, Despawn self then immediatly respawn + if (CurrentWP == WaypointList.end()) + { + debug_log("SD2: EscortAI reached end of waypoints"); + + m_creature->setDeathState(JUST_DIED); + m_creature->SetHealth(0); + m_creature->CombatStop(); + m_creature->DeleteThreatList(); + m_creature->Respawn(); + m_creature->GetMotionMaster()->Clear(true); + + //Re-Enable gossip + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + IsBeingEscorted = false; + WaitTimer = 0; + return; + } + + if( !IsOnHold ) + { + m_creature->GetMotionMaster()->MovePoint(CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z ); + debug_log("SD2: EscortAI Next WP is: %d, %f, %f, %f", CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z); + WaitTimer = 0; + } + }else WaitTimer -= diff; + + //Check if player is within range + if (IsBeingEscorted && !InCombat && PlayerGUID) + if (PlayerTimer < diff) + { + Unit* p = Unit::GetUnit(*m_creature, PlayerGUID); + + if (!p || m_creature->GetDistance(p) > MAX_PLAYER_DISTANCE) + { + JustDied(m_creature); + IsBeingEscorted = false; + + debug_log("SD2: EscortAI Evaded back to spawn point because player was to far away or not found"); + + m_creature->setDeathState(JUST_DIED); + m_creature->SetHealth(0); + m_creature->CombatStop(); + m_creature->DeleteThreatList(); + m_creature->Respawn(); + m_creature->GetMotionMaster()->Clear(true); + + //Re-Enable gossip + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + PlayerTimer = 1000; + }else PlayerTimer -= diff; + + //Check if we have a current target + if( m_creature->isAlive() && m_creature->SelectHostilTarget() && m_creature->getVictim()) + { + //If we are within range melee the target + if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + { + if( m_creature->isAttackReady() ) + { + m_creature->AttackerStateUpdate(m_creature->getVictim()); + m_creature->resetAttackTimer(); + } + } + } +} + +void npc_escortAI::MovementInform(uint32 type, uint32 id) +{ + if (type != POINT_MOTION_TYPE || !IsBeingEscorted) + return; + + //Original position reached, continue waypoint movement + if (id == WP_LAST_POINT) + { + debug_log("SD2: EscortAI has returned to original position before combat"); + ReconnectWP = true; + Returning = false; + WaitTimer = 1; + + }else + { + //Make sure that we are still on the right waypoint + if (CurrentWP->id != id) + { + debug_log("SD2 ERROR: EscortAI reached waypoint out of order %d, expected %d", id, CurrentWP->id); + return; + } + + debug_log("SD2: EscortAI Waypoint %d reached", CurrentWP->id); + + //Call WP function + WaypointReached(CurrentWP->id); + + WaitTimer = CurrentWP->WaitTimeMs + 1; + + ++CurrentWP; + } +} + +void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs) +{ + Escort_Waypoint t(id, x, y, z, WaitTimeMs); + + WaypointList.push_back(t); +} + +void npc_escortAI::Start(bool bAttack, bool bDefend, bool bRun, uint64 pGUID) +{ + if (InCombat) + { + debug_log("SD2 ERROR: EscortAI attempt to Start while in combat"); + return; + } + + if (WaypointList.empty()) + { + debug_log("SD2 ERROR: Call to escortAI::Start with 0 waypoints"); + return; + } + + Attack = bAttack; + Defend = bDefend; + Run = bRun; + PlayerGUID = pGUID; + + debug_log("SD2: EscortAI started with %d waypoints. Attack = %d, Defend = %d, Run = %d, PlayerGUID = %d", WaypointList.size(), Attack, Defend, Run, PlayerGUID); + + CurrentWP = WaypointList.begin(); + + //Set initial speed + if (Run) + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + else m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + + //Start WP + m_creature->GetMotionMaster()->MovePoint(CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z ); + debug_log("SD2: EscortAI Next WP is: %d, %f, %f, %f", CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z); + IsBeingEscorted = true; + ReconnectWP = false; + Returning = false; + IsOnHold = false; + + //Disable gossip + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); +} diff --git a/src/bindings/scripts/scripts/npc/npc_escortAI.h b/src/bindings/scripts/scripts/npc/npc_escortAI.h index e1dbf186764..6f735316c6b 100644 --- a/src/bindings/scripts/scripts/npc/npc_escortAI.h +++ b/src/bindings/scripts/scripts/npc/npc_escortAI.h @@ -1,85 +1,85 @@ -/* Copyright (C) 2006 - 2008 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 - -struct Escort_Waypoint -{ - Escort_Waypoint(uint32 _id, float _x, float _y, float _z, uint32 _w) - { - id = _id; - x = _x; - y = _y; - z = _z; - WaitTimeMs = _w; - } - - uint32 id; - float x; - float y; - float z; - uint32 WaitTimeMs; -}; - -struct MANGOS_DLL_DECL npc_escortAI : public ScriptedAI -{ - public: - - // Pure Virtual Functions - virtual void WaypointReached(uint32) = 0; - - virtual void Aggro(Unit*) = 0; - - virtual void Reset() = 0; - - // CreatureAI functions - npc_escortAI(Creature *c) : ScriptedAI(c), IsBeingEscorted(false), PlayerTimer(1000) {m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z);} - - bool IsVisible(Unit*) const; - - void AttackStart(Unit*); - - void MoveInLineOfSight(Unit*); - - void JustRespawned(); - - void EnterEvadeMode(); - - void UpdateAI(const uint32); - - void MovementInform(uint32, uint32); - - // EscortAI functions - void AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs = 0); - - void Start(bool bAttack, bool bDefend, bool bRun, uint64 pGUID = 0); - - // EscortAI variables - protected: - uint64 PlayerGUID; - bool IsBeingEscorted; - bool IsOnHold; - - private: - uint32 WaitTimer; - uint32 PlayerTimer; - - struct - { - float x; - float y; - float z; - }LastPos; - - std::list WaypointList; - std::list::iterator CurrentWP; - - bool Attack; - bool Defend; - bool Returning; - bool ReconnectWP; - bool Run; -}; -#endif +/* Copyright (C) 2006 - 2008 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 + +struct Escort_Waypoint +{ + Escort_Waypoint(uint32 _id, float _x, float _y, float _z, uint32 _w) + { + id = _id; + x = _x; + y = _y; + z = _z; + WaitTimeMs = _w; + } + + uint32 id; + float x; + float y; + float z; + uint32 WaitTimeMs; +}; + +struct MANGOS_DLL_DECL npc_escortAI : public ScriptedAI +{ + public: + + // Pure Virtual Functions + virtual void WaypointReached(uint32) = 0; + + virtual void Aggro(Unit*) = 0; + + virtual void Reset() = 0; + + // CreatureAI functions + npc_escortAI(Creature *c) : ScriptedAI(c), IsBeingEscorted(false), PlayerTimer(1000) {m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z);} + + bool IsVisible(Unit*) const; + + void AttackStart(Unit*); + + void MoveInLineOfSight(Unit*); + + void JustRespawned(); + + void EnterEvadeMode(); + + void UpdateAI(const uint32); + + void MovementInform(uint32, uint32); + + // EscortAI functions + void AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs = 0); + + void Start(bool bAttack, bool bDefend, bool bRun, uint64 pGUID = 0); + + // EscortAI variables + protected: + uint64 PlayerGUID; + bool IsBeingEscorted; + bool IsOnHold; + + private: + uint32 WaitTimer; + uint32 PlayerTimer; + + struct + { + float x; + float y; + float z; + }LastPos; + + std::list WaypointList; + std::list::iterator CurrentWP; + + bool Attack; + bool Defend; + bool Returning; + bool ReconnectWP; + bool Run; +}; +#endif diff --git a/src/bindings/scripts/scripts/npc/npc_innkeeper.cpp b/src/bindings/scripts/scripts/npc/npc_innkeeper.cpp index 429d5b51115..9da0f267cb1 100644 --- a/src/bindings/scripts/scripts/npc/npc_innkeeper.cpp +++ b/src/bindings/scripts/scripts/npc/npc_innkeeper.cpp @@ -1,144 +1,144 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Innkeeper -SD%Complete: 50 -SDComment: This script are currently not in use. EventSystem cannot be used on Windows build of SD2 -SDCategory: NPCs -EndScriptData */ - -#include "precompiled.h" - -#define HALLOWEEN_EVENTID 12 -#define SPELL_TRICK_OR_TREATED 24755 -#define SPELL_TREAT 24715 - -#define LOCALE_TRICK_OR_TREAT_0 "Trick or Treat!" -#define LOCALE_TRICK_OR_TREAT_2 "Des bonbons ou des blagues!" -#define LOCALE_TRICK_OR_TREAT_3 "Süßes oder Saures!" -#define LOCALE_TRICK_OR_TREAT_6 "¡Truco o trato!" - -bool isEventActive() -{ - /* - const GameEvent::ActiveEvents *ActiveEventsList = gameeventmgr.GetActiveEventList(); - GameEvent::ActiveEvents::const_iterator itr; - for (itr = ActiveEventsList->begin(); itr != ActiveEventsList->end(); ++itr) - { - if (*itr==HALLOWEEN_EVENTID) - { - return true; - } - }*/ - return false; -} - -bool GossipHello_npc_innkeeper(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (isEventActive()&& !player->GetAura(SPELL_TRICK_OR_TREATED,0)) - { - char* localizedEntry; - switch (player->GetSession()->GetSessionDbLocaleIndex()) - { - case 0: - localizedEntry=LOCALE_TRICK_OR_TREAT_0; - break; - case 2: - localizedEntry=LOCALE_TRICK_OR_TREAT_2; - break; - case 3: - localizedEntry=LOCALE_TRICK_OR_TREAT_3; - break; - case 6: - localizedEntry=LOCALE_TRICK_OR_TREAT_6; - break; - default: - localizedEntry=LOCALE_TRICK_OR_TREAT_0; - } - - player->ADD_GOSSIP_ITEM(0, localizedEntry, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+HALLOWEEN_EVENTID); - } - - player->TalkedToCreature(_Creature->GetEntry(),_Creature->GetGUID()); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_innkeeper(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF+HALLOWEEN_EVENTID && isEventActive() && !player->GetAura(SPELL_TRICK_OR_TREATED,0)) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TRICK_OR_TREATED, true); - - // either trick or treat, 50% chance - if(rand()%2) - { - player->CastSpell(player, SPELL_TREAT, true); - } - else - { - int32 trickspell=0; - switch (rand()%9) // note that female characters can get male costumes and vice versa - { - case 0: - trickspell=24753; // cannot cast, random 30sec - break; - case 1: - trickspell=24713; // lepper gnome costume - break; - case 2: - trickspell=24735; // male ghost costume - break; - case 3: - trickspell=24736; // female ghostcostume - break; - case 4: - trickspell=24710; // male ninja costume - break; - case 5: - trickspell=24711; // female ninja costume - break; - case 6: - trickspell=24708; // male pirate costume - break; - case 7: - trickspell=24709; // female pirate costume - break; - case 8: - trickspell=24723; // skeleton costume - break; - } - player->CastSpell(player, trickspell, true); - } - return true; // prevent mangos core handling - } - return false; // the player didn't select "trick or treat" or cheated, normal core handling -} - -void AddSC_npc_innkeeper() -{ - Script *newscript; - newscript = new Script; - newscript->Name="npc_innkeeper"; - newscript->pGossipHello = &GossipHello_npc_innkeeper; - newscript->pGossipSelect = &GossipSelect_npc_innkeeper; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Innkeeper +SD%Complete: 50 +SDComment: This script are currently not in use. EventSystem cannot be used on Windows build of SD2 +SDCategory: NPCs +EndScriptData */ + +#include "precompiled.h" + +#define HALLOWEEN_EVENTID 12 +#define SPELL_TRICK_OR_TREATED 24755 +#define SPELL_TREAT 24715 + +#define LOCALE_TRICK_OR_TREAT_0 "Trick or Treat!" +#define LOCALE_TRICK_OR_TREAT_2 "Des bonbons ou des blagues!" +#define LOCALE_TRICK_OR_TREAT_3 "Süßes oder Saures!" +#define LOCALE_TRICK_OR_TREAT_6 "¡Truco o trato!" + +bool isEventActive() +{ + /* + const GameEvent::ActiveEvents *ActiveEventsList = gameeventmgr.GetActiveEventList(); + GameEvent::ActiveEvents::const_iterator itr; + for (itr = ActiveEventsList->begin(); itr != ActiveEventsList->end(); ++itr) + { + if (*itr==HALLOWEEN_EVENTID) + { + return true; + } + }*/ + return false; +} + +bool GossipHello_npc_innkeeper(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (isEventActive()&& !player->GetAura(SPELL_TRICK_OR_TREATED,0)) + { + char* localizedEntry; + switch (player->GetSession()->GetSessionDbLocaleIndex()) + { + case 0: + localizedEntry=LOCALE_TRICK_OR_TREAT_0; + break; + case 2: + localizedEntry=LOCALE_TRICK_OR_TREAT_2; + break; + case 3: + localizedEntry=LOCALE_TRICK_OR_TREAT_3; + break; + case 6: + localizedEntry=LOCALE_TRICK_OR_TREAT_6; + break; + default: + localizedEntry=LOCALE_TRICK_OR_TREAT_0; + } + + player->ADD_GOSSIP_ITEM(0, localizedEntry, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+HALLOWEEN_EVENTID); + } + + player->TalkedToCreature(_Creature->GetEntry(),_Creature->GetGUID()); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_innkeeper(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF+HALLOWEEN_EVENTID && isEventActive() && !player->GetAura(SPELL_TRICK_OR_TREATED,0)) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player, SPELL_TRICK_OR_TREATED, true); + + // either trick or treat, 50% chance + if(rand()%2) + { + player->CastSpell(player, SPELL_TREAT, true); + } + else + { + int32 trickspell=0; + switch (rand()%9) // note that female characters can get male costumes and vice versa + { + case 0: + trickspell=24753; // cannot cast, random 30sec + break; + case 1: + trickspell=24713; // lepper gnome costume + break; + case 2: + trickspell=24735; // male ghost costume + break; + case 3: + trickspell=24736; // female ghostcostume + break; + case 4: + trickspell=24710; // male ninja costume + break; + case 5: + trickspell=24711; // female ninja costume + break; + case 6: + trickspell=24708; // male pirate costume + break; + case 7: + trickspell=24709; // female pirate costume + break; + case 8: + trickspell=24723; // skeleton costume + break; + } + player->CastSpell(player, trickspell, true); + } + return true; // prevent mangos core handling + } + return false; // the player didn't select "trick or treat" or cheated, normal core handling +} + +void AddSC_npc_innkeeper() +{ + Script *newscript; + newscript = new Script; + newscript->Name="npc_innkeeper"; + newscript->pGossipHello = &GossipHello_npc_innkeeper; + newscript->pGossipSelect = &GossipSelect_npc_innkeeper; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/npc/npc_professions.cpp b/src/bindings/scripts/scripts/npc/npc_professions.cpp index 65487786058..1f5b3837572 100644 --- a/src/bindings/scripts/scripts/npc/npc_professions.cpp +++ b/src/bindings/scripts/scripts/npc/npc_professions.cpp @@ -1,1205 +1,1205 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Professions -SD%Complete: 80 -SDComment: Provides learn/unlearn/relearn-options for professions. Not supported: Unlearn engineering, re-learn engineering, re-learn leatherworking. -SDCategory: NPCs -EndScriptData */ - -#include "precompiled.h" - -/* -A few notes for future developement: -- A full implementation of gossip for GO's is required. They must have the same scripting capabilities as creatures. Basically, -there is no difference here (except that default text is chosen with `gameobject_template`.`data3` (for GO type2, different dataN for a few others) -- It's possible blacksmithing still require some tweaks and adjustments due to the way we _have_ to use reputation. -*/ - -/* --- UPDATE `gameobject_template` SET `ScriptName` = 'go_soothsaying_for_dummies' WHERE `entry` = 177226; -*/ - -/*### -# to be removed from here (->ncp_text). This is data for database projects. -###*/ -#define TALK_MUST_UNLEARN_WEAPON "You must forget your weapon type specialty before I can help you. Go to Everlook in Winterspring and seek help there." - -#define TALK_HAMMER_LEARN "Ah, a seasoned veteran you once were. I know you are capable, you merely need to ask and I shall teach you the way of the hammersmith." -#define TALK_AXE_LEARN "Ah, a seasoned veteran you once were. I know you are capable, you merely need to ask and I shall teach you the way of the axesmith." -#define TALK_SWORD_LEARN "Ah, a seasoned veteran you once were. I know you are capable, you merely need to ask and I shall teach you the way of the swordsmith." - -#define TALK_HAMMER_UNLEARN "Forgetting your Hammersmithing skill is not something to do lightly. If you choose to abandon it you will forget all recipes that require Hammersmithing to create!" -#define TALK_AXE_UNLEARN "Forgetting your Axesmithing skill is not something to do lightly. If you choose to abandon it you will forget all recipes that require Axesmithing to create!" -#define TALK_SWORD_UNLEARN "Forgetting your Swordsmithing skill is not something to do lightly. If you choose to abandon it you will forget all recipes that require Swordsmithing to create!" - -/*### -# generic defines -###*/ - -#define GOSSIP_SENDER_LEARN 50 -#define GOSSIP_SENDER_UNLEARN 51 -#define GOSSIP_SENDER_CHECK 52 - -/*### -# 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" -#define GOSSIP_ARMOR_UNLEARN "I wish to unlearn the art of Armorsmithing" - -#define GOSSIP_UNLEARN_SMITH_SPEC "I wish to unlearn my blacksmith specialty" -#define BOX_UNLEARN_ARMORORWEAPON "Do you really want to unlearn your blacksmith specialty and lose all associated recipes? \n Cost: " - -#define GOSSIP_LEARN_HAMMER "Please teach me how to become a Hammersmith, Lilith" -#define GOSSIP_UNLEARN_HAMMER "I wish to unlearn Hammersmithing" -#define GOSSIP_LEARN_AXE "Please teach me how to become a Axesmith, Kilram" -#define GOSSIP_UNLEARN_AXE "I wish to unlearn Axesmithing" -#define GOSSIP_LEARN_SWORD "Please teach me how to become a Swordsmith, Seril" -#define GOSSIP_UNLEARN_SWORD "I wish to unlearn Swordsmithing" - -#define BOX_UNLEARN_WEAPON_SPEC "Do you really want to unlearn your weaponsmith specialty and lose all associated recipes? \n Cost: " - -#define GOSSIP_LEARN_DRAGON "I am absolutely certain that i want to learn dragonscale leatherworking" -#define GOSSIP_UNLEARN_DRAGON "I wish to unlearn Dragonscale Leatherworking" -#define GOSSIP_LEARN_ELEMENTAL "I am absolutely certain that i want to learn elemental leatherworking" -#define GOSSIP_UNLEARN_ELEMENTAL "I wish to unlearn Elemental Leatherworking" -#define GOSSIP_LEARN_TRIBAL "I am absolutely certain that i want to learn tribal leatherworking" -#define GOSSIP_UNLEARN_TRIBAL "I wish to unlearn Tribal Leatherworking" - -#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" - -/*### -# spells defines -###*/ - -#define S_WEAPON 9787 -#define S_ARMOR 9788 -#define S_HAMMER 17040 -#define S_AXE 17041 -#define S_SWORD 17039 - -#define S_LEARN_WEAPON 9789 -#define S_LEARN_ARMOR 9790 -#define S_LEARN_HAMMER 39099 -#define S_LEARN_AXE 39098 -#define S_LEARN_SWORD 39097 - -#define S_UNLEARN_WEAPON 36436 -#define S_UNLEARN_ARMOR 36435 -#define S_UNLEARN_HAMMER 36441 -#define S_UNLEARN_AXE 36439 -#define S_UNLEARN_SWORD 36438 - -#define S_REP_ARMOR 17451 -#define S_REP_WEAPON 17452 - -#define REP_ARMOR 46 -#define REP_WEAPON 289 -#define REP_HAMMER 569 -#define REP_AXE 570 -#define REP_SWORD 571 - -#define S_DRAGON 10656 -#define S_ELEMENTAL 10658 -#define S_TRIBAL 10660 - -#define S_LEARN_DRAGON 10657 -#define S_LEARN_ELEMENTAL 10659 -#define S_LEARN_TRIBAL 10661 - -#define S_UNLEARN_DRAGON 36434 -#define S_UNLEARN_ELEMENTAL 36328 -#define S_UNLEARN_TRIBAL 36433 - -#define S_GOBLIN 20222 -#define S_GNOMISH 20219 - -#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 DoLearnCost(Player *player) //tailor, alchemy -{ - return 200000; -} - -int32 DoHighUnlearnCost(Player *player) //tailor, alchemy -{ - return 1500000; -} - -int32 DoMedUnlearnCost(Player *player) //blacksmith, leatherwork -{ - uint32 level = player->getLevel(); - if(level < 51) - return 250000; - else if (level < 66) - return 500000; - else - return 1000000; -} - -int32 DoLowUnlearnCost(Player *player) //blacksmith -{ - uint32 level = player->getLevel(); - if (level < 66) - return 50000; - else - return 100000; -} - -/*### -# unlearning related profession spells -###*/ - -bool EquippedOk(Player* player, uint32 spellId) -{ - SpellEntry const* spell = GetSpellStore()->LookupEntry(spellId); - - if( !spell ) - return false; - - for(int i=0; i<3; i++) - { - uint32 reqSpell = spell->EffectTriggerSpell[i]; - if( !reqSpell ) - continue; - - Item* pItem; - for(int j = EQUIPMENT_SLOT_START; j < EQUIPMENT_SLOT_END; j++) - { - pItem = player->GetItemByPos( INVENTORY_SLOT_BAG_0, j ); - if( pItem ) - if( pItem->GetProto()->RequiredSpell == reqSpell ) - { - //player 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; -} - -void ProfessionUnlearnSpells(Player *player, uint32 type) -{ - switch (type) - { - case 36436: // S_UNLEARN_WEAPON - player->removeSpell(36125); // Light Earthforged Blade - player->removeSpell(36128); // Light Emberforged Hammer - player->removeSpell(36126); // Light Skyforged Axe - break; - case 36435: // S_UNLEARN_ARMOR - player->removeSpell(36122); // Earthforged Leggings - player->removeSpell(36129); // Heavy Earthforged Breastplate - player->removeSpell(36130); // Stormforged Hauberk - player->removeSpell(34533); // Breastplate of Kings - player->removeSpell(34529); // Nether Chain Shirt - player->removeSpell(34534); // Bulwark of Kings - player->removeSpell(36257); // Bulwark of the Ancient Kings - player->removeSpell(36256); // Embrace of the Twisting Nether - player->removeSpell(34530); // Twisting Nether Chain Shirt - player->removeSpell(36124); // Windforged Leggings - break; - case 36441: // S_UNLEARN_HAMMER - player->removeSpell(36262); // Dragonstrike - player->removeSpell(34546); // Dragonmaw - player->removeSpell(34545); // Drakefist Hammer - player->removeSpell(36136); // Lavaforged Warhammer - player->removeSpell(34547); // Thunder - player->removeSpell(34567); // Deep Thunder - player->removeSpell(36263); // Stormherald - player->removeSpell(36137); // Great Earthforged Hammer - break; - case 36439: // S_UNLEARN_AXE - player->removeSpell(36260); // Wicked Edge of the Planes - player->removeSpell(34562); // Black Planar Edge - player->removeSpell(34541); // The Planar Edge - player->removeSpell(36134); // Stormforged Axe - player->removeSpell(36135); // Skyforged Great Axe - player->removeSpell(36261); // Bloodmoon - player->removeSpell(34543); // Lunar Crescent - player->removeSpell(34544); // Mooncleaver - break; - case 36438: // S_UNLEARN_SWORD - player->removeSpell(36258); // Blazefury - player->removeSpell(34537); // Blazeguard - player->removeSpell(34535); // Fireguard - player->removeSpell(36131); // Windforged Rapier - player->removeSpell(36133); // Stoneforged Claymore - player->removeSpell(34538); // Lionheart Blade - player->removeSpell(34540); // Lionheart Champion - player->removeSpell(36259); // Lionheart Executioner - break; - case 36434: // S_UNLEARN_DRAGON - player->removeSpell(36076); // Dragonstrike Leggings - player->removeSpell(36079); // Golden Dragonstrike Breastplate - player->removeSpell(35576); // Ebon Netherscale Belt - player->removeSpell(35577); // Ebon Netherscale Bracers - player->removeSpell(35575); // Ebon Netherscale Breastplate - player->removeSpell(35582); // Netherstrike Belt - player->removeSpell(35584); // Netherstrike Bracers - player->removeSpell(35580); // Netherstrike Breastplate - break; - case 36328: // S_UNLEARN_ELEMENTAL - player->removeSpell(36074); // Blackstorm Leggings - player->removeSpell(36077); // Primalstorm Breastplate - player->removeSpell(35590); // Primalstrike Belt - player->removeSpell(35591); // Primalstrike Bracers - player->removeSpell(35589); // Primalstrike Vest - break; - case 36433: // S_UNLEARN_TRIBAL - player->removeSpell(35585); // Windhawk Hauberk - player->removeSpell(35587); // Windhawk Belt - player->removeSpell(35588); // Windhawk Bracers - player->removeSpell(36075); // Wildfeather Leggings - player->removeSpell(36078); // Living Crystal Breastplate - break; - case 41299: // S_UNLEARN_SPELLFIRE - player->removeSpell(26752); // Spellfire Belt - player->removeSpell(26753); // Spellfire Gloves - player->removeSpell(26754); // Spellfire Robe - break; - case 41558: // S_UNLEARN_MOONCLOTH - player->removeSpell(26760); // Primal Mooncloth Belt - player->removeSpell(26761); // Primal Mooncloth Shoulders - player->removeSpell(26762); // Primal Mooncloth Robe - break; - case 41559: // S_UNLEARN_SHADOWEAVE - player->removeSpell(26756); // Frozen Shadoweave Shoulders - player->removeSpell(26757); // Frozen Shadoweave Boots - player->removeSpell(26758); // Frozen Shadoweave Robe - break; - } -} - -/*### -# start menues alchemy -###*/ - -bool HasAlchemySpell(Player *player) -{ - if(player->HasSpell(S_TRANSMUTE) || player->HasSpell(S_ELIXIR) || player->HasSpell(S_POTION)) - return true; - return false; -} - -bool GossipHello_npc_prof_alchemy(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - if (_Creature->isVendor()) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - if(_Creature->isTrainer()) - player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - uint32 eCreature = _Creature->GetEntry(); - - if (player->HasSkill(SKILL_ALCHEMY) && player->GetBaseSkillValue(SKILL_ALCHEMY)>=350 && player->getLevel() > 67) - { - if (player->GetQuestRewardStatus(10899) || player->GetQuestRewardStatus(10902) || player->GetQuestRewardStatus(10897)) - { - switch (eCreature) - { - case 22427: //Zarevhi - if (!HasAlchemySpell(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_TRANSMUTE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 1); - if (player->HasSpell(S_TRANSMUTE)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_TRANSMUTE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); - break; - case 19052: //Lorokeem - if (!HasAlchemySpell(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_ELIXIR, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 2); - if (player->HasSpell(S_ELIXIR)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_ELIXIR, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 5); - break; - case 17909: //Lauranna Thar'well - if (!HasAlchemySpell(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_POTION, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 3); - if (player->HasSpell(S_POTION)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_POTION, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 6); - break; - } - } - } - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -void SendActionMenu_npc_prof_alchemy(Player *player, Creature *_Creature, uint32 action) -{ - switch(action) - { - case GOSSIP_ACTION_TRADE: - player->SEND_VENDORLIST( _Creature->GetGUID() ); - break; - case GOSSIP_ACTION_TRAIN: - player->SEND_TRAINERLIST( _Creature->GetGUID() ); - break; - //Learn Alchemy - case GOSSIP_ACTION_INFO_DEF + 1: - if(!player->HasSpell(S_TRANSMUTE) && player->GetMoney() >= DoLearnCost(player)) - { - player->CastSpell(player, S_LEARN_TRANSMUTE, true); - player->ModifyMoney(-DoLearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - if(!player->HasSpell(S_ELIXIR) && player->GetMoney() >= DoLearnCost(player)) - { - player->CastSpell(player, S_LEARN_ELIXIR, true); - player->ModifyMoney(-DoLearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - if(!player->HasSpell(S_POTION) && player->GetMoney() >= DoLearnCost(player)) - { - player->CastSpell(player, S_LEARN_POTION, true); - player->ModifyMoney(-DoLearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - //Unlearn Alchemy - case GOSSIP_ACTION_INFO_DEF + 4: - if(player->GetMoney() >= DoHighUnlearnCost(player)) - { - _Creature->CastSpell(player, S_UNLEARN_TRANSMUTE, true); - player->ModifyMoney(-DoHighUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 5: - if(player->GetMoney() >= DoHighUnlearnCost(player)) - { - _Creature->CastSpell(player, S_UNLEARN_ELIXIR, true); - player->ModifyMoney(-DoHighUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - if(player->GetMoney() >= DoHighUnlearnCost(player)) - { - _Creature->CastSpell(player, S_UNLEARN_POTION, true); - player->ModifyMoney(-DoHighUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - } -} - -void SendConfirmLearn_npc_prof_alchemy(Player *player, Creature *_Creature, uint32 action) -{ - if(action) - { - uint32 eCreature = _Creature->GetEntry(); - switch(eCreature) - { - case 22427: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_TRANSMUTE, GOSSIP_SENDER_CHECK, action); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 19052: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_ELIXIR, GOSSIP_SENDER_CHECK, action); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 17909: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_POTION, GOSSIP_SENDER_CHECK, action); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - } - } -} - -void SendConfirmUnlearn_npc_prof_alchemy(Player *player, Creature *_Creature, uint32 action) -{ - if(action) - { - uint32 eCreature = _Creature->GetEntry(); - switch(eCreature) - { - case 22427: //Zarevhi - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_TRANSMUTE, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_ALCHEMY_SPEC, DoHighUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 19052: //Lorokeem - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_ELIXIR, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_ALCHEMY_SPEC, DoHighUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 17909: //Lauranna Thar'well - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_POTION, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_ALCHEMY_SPEC, DoHighUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - } - } -} - -bool GossipSelect_npc_prof_alchemy(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(sender) - { - case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_alchemy(player, _Creature, action); break; - case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_alchemy(player, _Creature, action); break; - case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_alchemy(player, _Creature, action); break; - case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_alchemy(player, _Creature, action); break; - } - return true; -} - -/*### -# start menues blacksmith -###*/ - -bool HasWeaponSub(Player *player) -{ - if (player->HasSpell(S_HAMMER) || player->HasSpell(S_AXE) || player->HasSpell(S_SWORD)) - return true; - return false; -} - -bool GossipHello_npc_prof_blacksmith(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - if (_Creature->isVendor()) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - if(_Creature->isTrainer()) - player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - uint32 eCreature = _Creature->GetEntry(); - //WEAPONSMITH & ARMORSMITH - if(player->GetBaseSkillValue(SKILL_BLACKSMITHING)>=225) - { - switch (eCreature) - { - case 11145: //Myolor Sunderfury - case 11176: //Krathok Moltenfist - if(!player->HasSpell(S_ARMOR) && !player->HasSpell(S_WEAPON) && player->GetReputationRank(REP_ARMOR) == REP_FRIENDLY) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ARMOR_LEARN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - if(!player->HasSpell(S_WEAPON) && !player->HasSpell(S_ARMOR) && player->GetReputationRank(REP_WEAPON) == REP_FRIENDLY) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_WEAPON_LEARN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - break; - case 11146: //Ironus Coldsteel - case 11178: //Borgosh Corebender - if(player->HasSpell(S_WEAPON)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_WEAPON_UNLEARN, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 3); - break; - case 5164: //Grumnus Steelshaper - case 11177: //Okothos Ironrager - if(player->HasSpell(S_ARMOR)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ARMOR_UNLEARN, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); - break; - } - } - //WEAPONSMITH SPEC - if(player->HasSpell(S_WEAPON) && player->getLevel() > 49 && player->GetBaseSkillValue(SKILL_BLACKSMITHING)>=250) - { - switch (eCreature) - { - case 11191: //Lilith the Lithe - if(!HasWeaponSub(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_HAMMER, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 5); - if(player->HasSpell(S_HAMMER)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_HAMMER, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 8); - break; - case 11192: //Kilram - if(!HasWeaponSub(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_AXE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 6); - if(player->HasSpell(S_AXE)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_AXE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 9); - break; - case 11193: //Seril Scourgebane - if(!HasWeaponSub(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SWORD, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 7); - if(player->HasSpell(S_SWORD)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_SWORD, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 10); - break; - } - } - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -void SendActionMenu_npc_prof_blacksmith(Player *player, Creature *_Creature, uint32 action) -{ - switch(action) - { - case GOSSIP_ACTION_TRADE: - player->SEND_VENDORLIST( _Creature->GetGUID() ); - break; - case GOSSIP_ACTION_TRAIN: - player->SEND_TRAINERLIST( _Creature->GetGUID() ); - break; - //Learn Armor/Weapon - case GOSSIP_ACTION_INFO_DEF + 1: - if(!player->HasSpell(S_ARMOR)) - { - player->CastSpell(player, S_LEARN_ARMOR, true); - //_Creature->CastSpell(player, S_REP_ARMOR, true); - } - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - if(!player->HasSpell(S_WEAPON)) - { - player->CastSpell(player, S_LEARN_WEAPON, true); - //_Creature->CastSpell(player, S_REP_WEAPON, true); - } - player->CLOSE_GOSSIP_MENU(); - break; - //Unlearn Armor/Weapon - case GOSSIP_ACTION_INFO_DEF + 3: - if(HasWeaponSub(player)) - { - //unknown textID (TALK_MUST_UNLEARN_WEAPON) - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - //Temporary, not offilike - _Creature->MonsterSay(TALK_MUST_UNLEARN_WEAPON,0,player->GetGUID()); - } - else if( EquippedOk(player,S_UNLEARN_WEAPON) ) - { - if( player->GetMoney() >= DoLowUnlearnCost(player) ) - { - player->CastSpell(player, S_UNLEARN_WEAPON, true); - ProfessionUnlearnSpells(player, S_UNLEARN_WEAPON); - player->ModifyMoney(-DoLowUnlearnCost(player)); - _Creature->CastSpell(player, S_REP_ARMOR, true); - player->CLOSE_GOSSIP_MENU(); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } - else - { - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - } - break; - case GOSSIP_ACTION_INFO_DEF + 4: - if( EquippedOk(player,S_UNLEARN_ARMOR) ) - { - if( player->GetMoney() >= DoLowUnlearnCost(player) ) - { - player->CastSpell(player, S_UNLEARN_ARMOR, true); - ProfessionUnlearnSpells(player, S_UNLEARN_ARMOR); - player->ModifyMoney(-DoLowUnlearnCost(player)); - _Creature->CastSpell(player, S_REP_WEAPON, true); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - //Learn Hammer/Axe/Sword - case GOSSIP_ACTION_INFO_DEF + 5: - player->CastSpell(player, S_LEARN_HAMMER, true); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - player->CastSpell(player, S_LEARN_AXE, true); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 7: - player->CastSpell(player, S_LEARN_SWORD, true); - player->CLOSE_GOSSIP_MENU(); - break; - //Unlearn Hammer/Axe/Sword - case GOSSIP_ACTION_INFO_DEF + 8: - if( EquippedOk(player,S_UNLEARN_HAMMER) ) - { - if( player->GetMoney() >= DoMedUnlearnCost(player)) - { - player->CastSpell(player, S_UNLEARN_HAMMER, true); - ProfessionUnlearnSpells(player, S_UNLEARN_HAMMER); - player->ModifyMoney(-DoMedUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 9: - if( EquippedOk(player,S_UNLEARN_AXE) ) - { - if( player->GetMoney() >= DoMedUnlearnCost(player)) - { - player->CastSpell(player, S_UNLEARN_AXE, true); - ProfessionUnlearnSpells(player, S_UNLEARN_AXE); - player->ModifyMoney(-DoMedUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 10: - if( EquippedOk(player,S_UNLEARN_SWORD) ) - { - if( player->GetMoney() >= DoMedUnlearnCost(player)) - { - player->CastSpell(player, S_UNLEARN_SWORD, true); - ProfessionUnlearnSpells(player, S_UNLEARN_SWORD); - player->ModifyMoney(-DoMedUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - } -} - -void SendConfirmLearn_npc_prof_blacksmith(Player *player, Creature *_Creature, uint32 action) -{ - if(action) - { - uint32 eCreature = _Creature->GetEntry(); - switch(eCreature) - { - case 11191: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_HAMMER, GOSSIP_SENDER_CHECK, action); - //unknown textID (TALK_HAMMER_LEARN) - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 11192: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_AXE, GOSSIP_SENDER_CHECK, action); - //unknown textID (TALK_AXE_LEARN) - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 11193: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SWORD, GOSSIP_SENDER_CHECK, action); - //unknown textID (TALK_SWORD_LEARN) - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - } - } -} - -void SendConfirmUnlearn_npc_prof_blacksmith(Player *player, Creature *_Creature, uint32 action) -{ - if(action) - { - uint32 eCreature = _Creature->GetEntry(); - switch(eCreature) - { - case 11146: //Ironus Coldsteel - case 11178: //Borgosh Corebender - case 5164: //Grumnus Steelshaper - case 11177: //Okothos Ironrager - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_SMITH_SPEC, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_ARMORORWEAPON, DoLowUnlearnCost(player)); - //unknown textID (TALK_UNLEARN_AXEORWEAPON) - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - - case 11191: - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_HAMMER, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_WEAPON_SPEC, DoMedUnlearnCost(player)); - //unknown textID (TALK_HAMMER_UNLEARN) - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 11192: - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_AXE, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_WEAPON_SPEC, DoMedUnlearnCost(player)); - //unknown textID (TALK_AXE_UNLEARN) - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 11193: - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_SWORD, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_WEAPON_SPEC, DoMedUnlearnCost(player)); - //unknown textID (TALK_SWORD_UNLEARN) - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - } - } -} - -bool GossipSelect_npc_prof_blacksmith(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(sender) - { - case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_blacksmith(player, _Creature, action); break; - case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_blacksmith(player, _Creature, action); break; - case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_blacksmith(player, _Creature, action); break; - case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_blacksmith(player, _Creature, action); break; - } - return true; -} - -/*bool QuestComplete_npc_prof_blacksmith( Player *player, Creature *_Creature, Quest const *_Quest ) -{ - if ( (_Quest->GetQuestId() == 5283) || (_Quest->GetQuestId() == 5301) ) //armorsmith - _Creature->CastSpell(player, 17451, true); - - if ( (_Quest->GetQuestId() == 5284) || (_Quest->GetQuestId() == 5302) ) //weaponsmith - _Creature->CastSpell(player, 17452, true); - - return true; -}*/ - -/*### -# start menues leatherworking -###*/ - -bool GossipHello_npc_prof_leather(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - if (_Creature->isVendor()) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - if(_Creature->isTrainer()) - player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - uint32 eCreature = _Creature->GetEntry(); - - if(player->HasSkill(SKILL_LEATHERWORKING) && player->GetBaseSkillValue(SKILL_LEATHERWORKING)>=250 && player->getLevel() > 49 ) - { - switch (eCreature) - { - case 7866: //Peter Galen - case 7867: //Thorkaf Dragoneye - if(player->HasSpell(S_DRAGON)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_DRAGON, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 1); - break; - case 7868: //Sarah Tanner - case 7869: //Brumn Winterhoof - if(player->HasSpell(S_ELEMENTAL)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_ELEMENTAL, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 2); - break; - case 7870: //Caryssia Moonhunter - case 7871: //Se'Jib - if(player->HasSpell(S_TRIBAL)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_TRIBAL, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 3); - break; - } - } - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -void SendActionMenu_npc_prof_leather(Player *player, Creature *_Creature, uint32 action) -{ - switch(action) - { - case GOSSIP_ACTION_TRADE: - player->SEND_VENDORLIST( _Creature->GetGUID() ); - break; - case GOSSIP_ACTION_TRAIN: - player->SEND_TRAINERLIST( _Creature->GetGUID() ); - break; - //Unlearn Leather - case GOSSIP_ACTION_INFO_DEF + 1: - if( EquippedOk(player,S_UNLEARN_DRAGON) ) - { - if( player->GetMoney() >= DoMedUnlearnCost(player) ) - { - player->CastSpell(player, S_UNLEARN_DRAGON, true); - ProfessionUnlearnSpells(player, S_UNLEARN_DRAGON); - player->ModifyMoney(-DoMedUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - if( EquippedOk(player,S_UNLEARN_ELEMENTAL) ) - { - if( player->GetMoney() >= DoMedUnlearnCost(player) ) - { - player->CastSpell(player, S_UNLEARN_ELEMENTAL, true); - ProfessionUnlearnSpells(player, S_UNLEARN_ELEMENTAL); - player->ModifyMoney(-DoMedUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - if( EquippedOk(player,S_UNLEARN_TRIBAL) ) - { - if(player->GetMoney() >= DoMedUnlearnCost(player)) - { - player->CastSpell(player, S_UNLEARN_TRIBAL, true); - ProfessionUnlearnSpells(player, S_UNLEARN_TRIBAL); - player->ModifyMoney(-DoMedUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - } -} - -void SendConfirmUnlearn_npc_prof_leather(Player *player, Creature *_Creature, uint32 action) -{ - if(action) - { - uint32 eCreature = _Creature->GetEntry(); - switch(eCreature) - { - case 7866: //Peter Galen - case 7867: //Thorkaf Dragoneye - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_DRAGON, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_LEATHER_SPEC, DoMedUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 7868: //Sarah Tanner - case 7869: //Brumn Winterhoof - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_ELEMENTAL, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_LEATHER_SPEC, DoMedUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 7870: //Caryssia Moonhunter - case 7871: //Se'Jib - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_TRIBAL, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_LEATHER_SPEC, DoMedUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - } - } -} - -bool GossipSelect_npc_prof_leather(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(sender) - { - case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_leather(player, _Creature, action); break; - case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_leather(player, _Creature, action); break; - case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_leather(player, _Creature, action); break; - } - return true; -} - -/*### -# start menues tailoring -###*/ - -bool HasTailorSpell(Player *player) -{ - if (player->HasSpell(S_MOONCLOTH) || player->HasSpell(S_SHADOWEAVE) || player->HasSpell(S_SPELLFIRE)) - return true; - return false; -} - -bool GossipHello_npc_prof_tailor(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - if (_Creature->isVendor()) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - if (_Creature->isTrainer()) - player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - uint32 eCreature = _Creature->GetEntry(); - //TAILORING SPEC - if (player->HasSkill(SKILL_TAILORING) && player->GetBaseSkillValue(SKILL_TAILORING)>=350 && player->getLevel() > 59) - { - if (player->GetQuestRewardStatus(10831) || player->GetQuestRewardStatus(10832) || player->GetQuestRewardStatus(10833)) - { - switch (eCreature) - { - case 22213: //Gidge Spellweaver - if (!HasTailorSpell(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SPELLFIRE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 1); - if (player->HasSpell(S_SPELLFIRE)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_SPELLFIRE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); - break; - case 22208: //Nasmara Moonsong - if (!HasTailorSpell(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_MOONCLOTH, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 2); - if (player->HasSpell(S_MOONCLOTH)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_MOONCLOTH, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 5); - break; - case 22212: //Andrion Darkspinner - if (!HasTailorSpell(player)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SHADOWEAVE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 3); - if (player->HasSpell(S_SHADOWEAVE)) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_SHADOWEAVE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 6); - break; - } - } - } - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -void SendActionMenu_npc_prof_tailor(Player *player, Creature *_Creature, uint32 action) -{ - switch(action) - { - case GOSSIP_ACTION_TRADE: - player->SEND_VENDORLIST( _Creature->GetGUID() ); - break; - case GOSSIP_ACTION_TRAIN: - player->SEND_TRAINERLIST( _Creature->GetGUID() ); - break; - //Learn Tailor - case GOSSIP_ACTION_INFO_DEF + 1: - if(!player->HasSpell(S_SPELLFIRE) && player->GetMoney() >= DoLearnCost(player)) - { - player->CastSpell(player, S_LEARN_SPELLFIRE, true); - player->ModifyMoney(-DoLearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - if(!player->HasSpell(S_MOONCLOTH) && player->GetMoney() >= DoLearnCost(player)) - { - player->CastSpell(player, S_LEARN_MOONCLOTH, true); - player->ModifyMoney(-DoLearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - if(!player->HasSpell(S_SHADOWEAVE) && player->GetMoney() >= DoLearnCost(player)) - { - player->CastSpell(player, S_LEARN_SHADOWEAVE, true); - player->ModifyMoney(-DoLearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - player->CLOSE_GOSSIP_MENU(); - break; - //Unlearn Tailor - case GOSSIP_ACTION_INFO_DEF + 4: - if( EquippedOk(player,S_UNLEARN_SPELLFIRE) ) - { - if( player->GetMoney() >= DoHighUnlearnCost(player) ) - { - player->CastSpell(player, S_UNLEARN_SPELLFIRE, true); - ProfessionUnlearnSpells(player, S_UNLEARN_SPELLFIRE); - player->ModifyMoney(-DoHighUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 5: - if( EquippedOk(player,S_UNLEARN_MOONCLOTH) ) - { - if( player->GetMoney() >= DoHighUnlearnCost(player) ) - { - player->CastSpell(player, S_UNLEARN_MOONCLOTH, true); - ProfessionUnlearnSpells(player, S_UNLEARN_MOONCLOTH); - player->ModifyMoney(-DoHighUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - if( EquippedOk(player,S_UNLEARN_SHADOWEAVE) ) - { - if( player->GetMoney() >= DoHighUnlearnCost(player) ) - { - player->CastSpell(player, S_UNLEARN_SHADOWEAVE, true); - ProfessionUnlearnSpells(player, S_UNLEARN_SHADOWEAVE); - player->ModifyMoney(-DoHighUnlearnCost(player)); - } else - player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); - } else - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - player->CLOSE_GOSSIP_MENU(); - break; - } -} - -void SendConfirmLearn_npc_prof_tailor(Player *player, Creature *_Creature, uint32 action) -{ - if(action) - { - uint32 eCreature = _Creature->GetEntry(); - switch(eCreature) - { - case 22213: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SPELLFIRE, GOSSIP_SENDER_CHECK, action); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 22208: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_MOONCLOTH, GOSSIP_SENDER_CHECK, action); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 22212: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SHADOWEAVE, GOSSIP_SENDER_CHECK, action); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - } - } -} - -void SendConfirmUnlearn_npc_prof_tailor(Player *player, Creature *_Creature, uint32 action) -{ - if(action) - { - uint32 eCreature = _Creature->GetEntry(); - switch(eCreature) - { - case 22213: //Gidge Spellweaver - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_SPELLFIRE, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_TAILOR_SPEC, DoHighUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 22208: //Nasmara Moonsong - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_MOONCLOTH, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_TAILOR_SPEC, DoHighUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case 22212: //Andrion Darkspinner - player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_SHADOWEAVE, GOSSIP_SENDER_CHECK, action,BOX_UNLEARN_TAILOR_SPEC, DoHighUnlearnCost(player)); - //unknown textID () - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - } - } -} - -bool GossipSelect_npc_prof_tailor(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(sender) - { - case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_tailor(player, _Creature, action); break; - case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_tailor(player, _Creature, action); break; - case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_tailor(player, _Creature, action); break; - case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_tailor(player, _Creature, action); break; - } - return true; -} - -/*### -# start menues for GO (engineering and leatherworking) -###*/ - -/*bool GOHello_go_soothsaying_for_dummies(Player *player, GameObject* _GO) -{ - player->PlayerTalkClass->GetGossipMenu()->AddMenuItem(0,GOSSIP_LEARN_DRAGON, GOSSIP_SENDER_INFO, GOSSIP_ACTION_INFO_DEF, "", 0); - - player->SEND_GOSSIP_MENU(5584, _GO->GetGUID()); - - return true; -}*/ - -/*### -# -###*/ - -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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_prof_blacksmith"; - newscript->pGossipHello = &GossipHello_npc_prof_blacksmith; - newscript->pGossipSelect = &GossipSelect_npc_prof_blacksmith; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_prof_leather"; - newscript->pGossipHello = &GossipHello_npc_prof_leather; - newscript->pGossipSelect = &GossipSelect_npc_prof_leather; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_prof_tailor"; - newscript->pGossipHello = &GossipHello_npc_prof_tailor; - newscript->pGossipSelect = &GossipSelect_npc_prof_tailor; - m_scripts[nrscripts++] = newscript; - - /*newscript = new Script; - newscript->Name="go_soothsaying_for_dummies"; - newscript->pGOHello = &GOHello_go_soothsaying_for_dummies; - //newscript->pGossipSelect = &GossipSelect_go_soothsaying_for_dummies; - m_scripts[nrscripts++] = newscript;*/ -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Professions +SD%Complete: 80 +SDComment: Provides learn/unlearn/relearn-options for professions. Not supported: Unlearn engineering, re-learn engineering, re-learn leatherworking. +SDCategory: NPCs +EndScriptData */ + +#include "precompiled.h" + +/* +A few notes for future developement: +- A full implementation of gossip for GO's is required. They must have the same scripting capabilities as creatures. Basically, +there is no difference here (except that default text is chosen with `gameobject_template`.`data3` (for GO type2, different dataN for a few others) +- It's possible blacksmithing still require some tweaks and adjustments due to the way we _have_ to use reputation. +*/ + +/* +-- UPDATE `gameobject_template` SET `ScriptName` = 'go_soothsaying_for_dummies' WHERE `entry` = 177226; +*/ + +/*### +# to be removed from here (->ncp_text). This is data for database projects. +###*/ +#define TALK_MUST_UNLEARN_WEAPON "You must forget your weapon type specialty before I can help you. Go to Everlook in Winterspring and seek help there." + +#define TALK_HAMMER_LEARN "Ah, a seasoned veteran you once were. I know you are capable, you merely need to ask and I shall teach you the way of the hammersmith." +#define TALK_AXE_LEARN "Ah, a seasoned veteran you once were. I know you are capable, you merely need to ask and I shall teach you the way of the axesmith." +#define TALK_SWORD_LEARN "Ah, a seasoned veteran you once were. I know you are capable, you merely need to ask and I shall teach you the way of the swordsmith." + +#define TALK_HAMMER_UNLEARN "Forgetting your Hammersmithing skill is not something to do lightly. If you choose to abandon it you will forget all recipes that require Hammersmithing to create!" +#define TALK_AXE_UNLEARN "Forgetting your Axesmithing skill is not something to do lightly. If you choose to abandon it you will forget all recipes that require Axesmithing to create!" +#define TALK_SWORD_UNLEARN "Forgetting your Swordsmithing skill is not something to do lightly. If you choose to abandon it you will forget all recipes that require Swordsmithing to create!" + +/*### +# generic defines +###*/ + +#define GOSSIP_SENDER_LEARN 50 +#define GOSSIP_SENDER_UNLEARN 51 +#define GOSSIP_SENDER_CHECK 52 + +/*### +# 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" +#define GOSSIP_ARMOR_UNLEARN "I wish to unlearn the art of Armorsmithing" + +#define GOSSIP_UNLEARN_SMITH_SPEC "I wish to unlearn my blacksmith specialty" +#define BOX_UNLEARN_ARMORORWEAPON "Do you really want to unlearn your blacksmith specialty and lose all associated recipes? \n Cost: " + +#define GOSSIP_LEARN_HAMMER "Please teach me how to become a Hammersmith, Lilith" +#define GOSSIP_UNLEARN_HAMMER "I wish to unlearn Hammersmithing" +#define GOSSIP_LEARN_AXE "Please teach me how to become a Axesmith, Kilram" +#define GOSSIP_UNLEARN_AXE "I wish to unlearn Axesmithing" +#define GOSSIP_LEARN_SWORD "Please teach me how to become a Swordsmith, Seril" +#define GOSSIP_UNLEARN_SWORD "I wish to unlearn Swordsmithing" + +#define BOX_UNLEARN_WEAPON_SPEC "Do you really want to unlearn your weaponsmith specialty and lose all associated recipes? \n Cost: " + +#define GOSSIP_LEARN_DRAGON "I am absolutely certain that i want to learn dragonscale leatherworking" +#define GOSSIP_UNLEARN_DRAGON "I wish to unlearn Dragonscale Leatherworking" +#define GOSSIP_LEARN_ELEMENTAL "I am absolutely certain that i want to learn elemental leatherworking" +#define GOSSIP_UNLEARN_ELEMENTAL "I wish to unlearn Elemental Leatherworking" +#define GOSSIP_LEARN_TRIBAL "I am absolutely certain that i want to learn tribal leatherworking" +#define GOSSIP_UNLEARN_TRIBAL "I wish to unlearn Tribal Leatherworking" + +#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" + +/*### +# spells defines +###*/ + +#define S_WEAPON 9787 +#define S_ARMOR 9788 +#define S_HAMMER 17040 +#define S_AXE 17041 +#define S_SWORD 17039 + +#define S_LEARN_WEAPON 9789 +#define S_LEARN_ARMOR 9790 +#define S_LEARN_HAMMER 39099 +#define S_LEARN_AXE 39098 +#define S_LEARN_SWORD 39097 + +#define S_UNLEARN_WEAPON 36436 +#define S_UNLEARN_ARMOR 36435 +#define S_UNLEARN_HAMMER 36441 +#define S_UNLEARN_AXE 36439 +#define S_UNLEARN_SWORD 36438 + +#define S_REP_ARMOR 17451 +#define S_REP_WEAPON 17452 + +#define REP_ARMOR 46 +#define REP_WEAPON 289 +#define REP_HAMMER 569 +#define REP_AXE 570 +#define REP_SWORD 571 + +#define S_DRAGON 10656 +#define S_ELEMENTAL 10658 +#define S_TRIBAL 10660 + +#define S_LEARN_DRAGON 10657 +#define S_LEARN_ELEMENTAL 10659 +#define S_LEARN_TRIBAL 10661 + +#define S_UNLEARN_DRAGON 36434 +#define S_UNLEARN_ELEMENTAL 36328 +#define S_UNLEARN_TRIBAL 36433 + +#define S_GOBLIN 20222 +#define S_GNOMISH 20219 + +#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 DoLearnCost(Player *player) //tailor, alchemy +{ + return 200000; +} + +int32 DoHighUnlearnCost(Player *player) //tailor, alchemy +{ + return 1500000; +} + +int32 DoMedUnlearnCost(Player *player) //blacksmith, leatherwork +{ + uint32 level = player->getLevel(); + if(level < 51) + return 250000; + else if (level < 66) + return 500000; + else + return 1000000; +} + +int32 DoLowUnlearnCost(Player *player) //blacksmith +{ + uint32 level = player->getLevel(); + if (level < 66) + return 50000; + else + return 100000; +} + +/*### +# unlearning related profession spells +###*/ + +bool EquippedOk(Player* player, uint32 spellId) +{ + SpellEntry const* spell = GetSpellStore()->LookupEntry(spellId); + + if( !spell ) + return false; + + for(int i=0; i<3; i++) + { + uint32 reqSpell = spell->EffectTriggerSpell[i]; + if( !reqSpell ) + continue; + + Item* pItem; + for(int j = EQUIPMENT_SLOT_START; j < EQUIPMENT_SLOT_END; j++) + { + pItem = player->GetItemByPos( INVENTORY_SLOT_BAG_0, j ); + if( pItem ) + if( pItem->GetProto()->RequiredSpell == reqSpell ) + { + //player 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; +} + +void ProfessionUnlearnSpells(Player *player, uint32 type) +{ + switch (type) + { + case 36436: // S_UNLEARN_WEAPON + player->removeSpell(36125); // Light Earthforged Blade + player->removeSpell(36128); // Light Emberforged Hammer + player->removeSpell(36126); // Light Skyforged Axe + break; + case 36435: // S_UNLEARN_ARMOR + player->removeSpell(36122); // Earthforged Leggings + player->removeSpell(36129); // Heavy Earthforged Breastplate + player->removeSpell(36130); // Stormforged Hauberk + player->removeSpell(34533); // Breastplate of Kings + player->removeSpell(34529); // Nether Chain Shirt + player->removeSpell(34534); // Bulwark of Kings + player->removeSpell(36257); // Bulwark of the Ancient Kings + player->removeSpell(36256); // Embrace of the Twisting Nether + player->removeSpell(34530); // Twisting Nether Chain Shirt + player->removeSpell(36124); // Windforged Leggings + break; + case 36441: // S_UNLEARN_HAMMER + player->removeSpell(36262); // Dragonstrike + player->removeSpell(34546); // Dragonmaw + player->removeSpell(34545); // Drakefist Hammer + player->removeSpell(36136); // Lavaforged Warhammer + player->removeSpell(34547); // Thunder + player->removeSpell(34567); // Deep Thunder + player->removeSpell(36263); // Stormherald + player->removeSpell(36137); // Great Earthforged Hammer + break; + case 36439: // S_UNLEARN_AXE + player->removeSpell(36260); // Wicked Edge of the Planes + player->removeSpell(34562); // Black Planar Edge + player->removeSpell(34541); // The Planar Edge + player->removeSpell(36134); // Stormforged Axe + player->removeSpell(36135); // Skyforged Great Axe + player->removeSpell(36261); // Bloodmoon + player->removeSpell(34543); // Lunar Crescent + player->removeSpell(34544); // Mooncleaver + break; + case 36438: // S_UNLEARN_SWORD + player->removeSpell(36258); // Blazefury + player->removeSpell(34537); // Blazeguard + player->removeSpell(34535); // Fireguard + player->removeSpell(36131); // Windforged Rapier + player->removeSpell(36133); // Stoneforged Claymore + player->removeSpell(34538); // Lionheart Blade + player->removeSpell(34540); // Lionheart Champion + player->removeSpell(36259); // Lionheart Executioner + break; + case 36434: // S_UNLEARN_DRAGON + player->removeSpell(36076); // Dragonstrike Leggings + player->removeSpell(36079); // Golden Dragonstrike Breastplate + player->removeSpell(35576); // Ebon Netherscale Belt + player->removeSpell(35577); // Ebon Netherscale Bracers + player->removeSpell(35575); // Ebon Netherscale Breastplate + player->removeSpell(35582); // Netherstrike Belt + player->removeSpell(35584); // Netherstrike Bracers + player->removeSpell(35580); // Netherstrike Breastplate + break; + case 36328: // S_UNLEARN_ELEMENTAL + player->removeSpell(36074); // Blackstorm Leggings + player->removeSpell(36077); // Primalstorm Breastplate + player->removeSpell(35590); // Primalstrike Belt + player->removeSpell(35591); // Primalstrike Bracers + player->removeSpell(35589); // Primalstrike Vest + break; + case 36433: // S_UNLEARN_TRIBAL + player->removeSpell(35585); // Windhawk Hauberk + player->removeSpell(35587); // Windhawk Belt + player->removeSpell(35588); // Windhawk Bracers + player->removeSpell(36075); // Wildfeather Leggings + player->removeSpell(36078); // Living Crystal Breastplate + break; + case 41299: // S_UNLEARN_SPELLFIRE + player->removeSpell(26752); // Spellfire Belt + player->removeSpell(26753); // Spellfire Gloves + player->removeSpell(26754); // Spellfire Robe + break; + case 41558: // S_UNLEARN_MOONCLOTH + player->removeSpell(26760); // Primal Mooncloth Belt + player->removeSpell(26761); // Primal Mooncloth Shoulders + player->removeSpell(26762); // Primal Mooncloth Robe + break; + case 41559: // S_UNLEARN_SHADOWEAVE + player->removeSpell(26756); // Frozen Shadoweave Shoulders + player->removeSpell(26757); // Frozen Shadoweave Boots + player->removeSpell(26758); // Frozen Shadoweave Robe + break; + } +} + +/*### +# start menues alchemy +###*/ + +bool HasAlchemySpell(Player *player) +{ + if(player->HasSpell(S_TRANSMUTE) || player->HasSpell(S_ELIXIR) || player->HasSpell(S_POTION)) + return true; + return false; +} + +bool GossipHello_npc_prof_alchemy(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + if (_Creature->isVendor()) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + if(_Creature->isTrainer()) + player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); + + uint32 eCreature = _Creature->GetEntry(); + + if (player->HasSkill(SKILL_ALCHEMY) && player->GetBaseSkillValue(SKILL_ALCHEMY)>=350 && player->getLevel() > 67) + { + if (player->GetQuestRewardStatus(10899) || player->GetQuestRewardStatus(10902) || player->GetQuestRewardStatus(10897)) + { + switch (eCreature) + { + case 22427: //Zarevhi + if (!HasAlchemySpell(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_TRANSMUTE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 1); + if (player->HasSpell(S_TRANSMUTE)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_TRANSMUTE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); + break; + case 19052: //Lorokeem + if (!HasAlchemySpell(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_ELIXIR, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 2); + if (player->HasSpell(S_ELIXIR)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_ELIXIR, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 5); + break; + case 17909: //Lauranna Thar'well + if (!HasAlchemySpell(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_POTION, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 3); + if (player->HasSpell(S_POTION)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_POTION, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 6); + break; + } + } + } + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +void SendActionMenu_npc_prof_alchemy(Player *player, Creature *_Creature, uint32 action) +{ + switch(action) + { + case GOSSIP_ACTION_TRADE: + player->SEND_VENDORLIST( _Creature->GetGUID() ); + break; + case GOSSIP_ACTION_TRAIN: + player->SEND_TRAINERLIST( _Creature->GetGUID() ); + break; + //Learn Alchemy + case GOSSIP_ACTION_INFO_DEF + 1: + if(!player->HasSpell(S_TRANSMUTE) && player->GetMoney() >= DoLearnCost(player)) + { + player->CastSpell(player, S_LEARN_TRANSMUTE, true); + player->ModifyMoney(-DoLearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + if(!player->HasSpell(S_ELIXIR) && player->GetMoney() >= DoLearnCost(player)) + { + player->CastSpell(player, S_LEARN_ELIXIR, true); + player->ModifyMoney(-DoLearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + if(!player->HasSpell(S_POTION) && player->GetMoney() >= DoLearnCost(player)) + { + player->CastSpell(player, S_LEARN_POTION, true); + player->ModifyMoney(-DoLearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + //Unlearn Alchemy + case GOSSIP_ACTION_INFO_DEF + 4: + if(player->GetMoney() >= DoHighUnlearnCost(player)) + { + _Creature->CastSpell(player, S_UNLEARN_TRANSMUTE, true); + player->ModifyMoney(-DoHighUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 5: + if(player->GetMoney() >= DoHighUnlearnCost(player)) + { + _Creature->CastSpell(player, S_UNLEARN_ELIXIR, true); + player->ModifyMoney(-DoHighUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 6: + if(player->GetMoney() >= DoHighUnlearnCost(player)) + { + _Creature->CastSpell(player, S_UNLEARN_POTION, true); + player->ModifyMoney(-DoHighUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + } +} + +void SendConfirmLearn_npc_prof_alchemy(Player *player, Creature *_Creature, uint32 action) +{ + if(action) + { + uint32 eCreature = _Creature->GetEntry(); + switch(eCreature) + { + case 22427: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_TRANSMUTE, GOSSIP_SENDER_CHECK, action); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 19052: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_ELIXIR, GOSSIP_SENDER_CHECK, action); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 17909: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_POTION, GOSSIP_SENDER_CHECK, action); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + } + } +} + +void SendConfirmUnlearn_npc_prof_alchemy(Player *player, Creature *_Creature, uint32 action) +{ + if(action) + { + uint32 eCreature = _Creature->GetEntry(); + switch(eCreature) + { + case 22427: //Zarevhi + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_TRANSMUTE, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_ALCHEMY_SPEC, DoHighUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 19052: //Lorokeem + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_ELIXIR, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_ALCHEMY_SPEC, DoHighUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 17909: //Lauranna Thar'well + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_POTION, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_ALCHEMY_SPEC, DoHighUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + } + } +} + +bool GossipSelect_npc_prof_alchemy(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(sender) + { + case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_alchemy(player, _Creature, action); break; + case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_alchemy(player, _Creature, action); break; + case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_alchemy(player, _Creature, action); break; + case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_alchemy(player, _Creature, action); break; + } + return true; +} + +/*### +# start menues blacksmith +###*/ + +bool HasWeaponSub(Player *player) +{ + if (player->HasSpell(S_HAMMER) || player->HasSpell(S_AXE) || player->HasSpell(S_SWORD)) + return true; + return false; +} + +bool GossipHello_npc_prof_blacksmith(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + if (_Creature->isVendor()) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + if(_Creature->isTrainer()) + player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); + + uint32 eCreature = _Creature->GetEntry(); + //WEAPONSMITH & ARMORSMITH + if(player->GetBaseSkillValue(SKILL_BLACKSMITHING)>=225) + { + switch (eCreature) + { + case 11145: //Myolor Sunderfury + case 11176: //Krathok Moltenfist + if(!player->HasSpell(S_ARMOR) && !player->HasSpell(S_WEAPON) && player->GetReputationRank(REP_ARMOR) == REP_FRIENDLY) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ARMOR_LEARN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + if(!player->HasSpell(S_WEAPON) && !player->HasSpell(S_ARMOR) && player->GetReputationRank(REP_WEAPON) == REP_FRIENDLY) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_WEAPON_LEARN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + break; + case 11146: //Ironus Coldsteel + case 11178: //Borgosh Corebender + if(player->HasSpell(S_WEAPON)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_WEAPON_UNLEARN, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 3); + break; + case 5164: //Grumnus Steelshaper + case 11177: //Okothos Ironrager + if(player->HasSpell(S_ARMOR)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ARMOR_UNLEARN, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); + break; + } + } + //WEAPONSMITH SPEC + if(player->HasSpell(S_WEAPON) && player->getLevel() > 49 && player->GetBaseSkillValue(SKILL_BLACKSMITHING)>=250) + { + switch (eCreature) + { + case 11191: //Lilith the Lithe + if(!HasWeaponSub(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_HAMMER, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 5); + if(player->HasSpell(S_HAMMER)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_HAMMER, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 8); + break; + case 11192: //Kilram + if(!HasWeaponSub(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_AXE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 6); + if(player->HasSpell(S_AXE)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_AXE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 9); + break; + case 11193: //Seril Scourgebane + if(!HasWeaponSub(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SWORD, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 7); + if(player->HasSpell(S_SWORD)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_SWORD, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 10); + break; + } + } + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +void SendActionMenu_npc_prof_blacksmith(Player *player, Creature *_Creature, uint32 action) +{ + switch(action) + { + case GOSSIP_ACTION_TRADE: + player->SEND_VENDORLIST( _Creature->GetGUID() ); + break; + case GOSSIP_ACTION_TRAIN: + player->SEND_TRAINERLIST( _Creature->GetGUID() ); + break; + //Learn Armor/Weapon + case GOSSIP_ACTION_INFO_DEF + 1: + if(!player->HasSpell(S_ARMOR)) + { + player->CastSpell(player, S_LEARN_ARMOR, true); + //_Creature->CastSpell(player, S_REP_ARMOR, true); + } + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + if(!player->HasSpell(S_WEAPON)) + { + player->CastSpell(player, S_LEARN_WEAPON, true); + //_Creature->CastSpell(player, S_REP_WEAPON, true); + } + player->CLOSE_GOSSIP_MENU(); + break; + //Unlearn Armor/Weapon + case GOSSIP_ACTION_INFO_DEF + 3: + if(HasWeaponSub(player)) + { + //unknown textID (TALK_MUST_UNLEARN_WEAPON) + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + //Temporary, not offilike + _Creature->MonsterSay(TALK_MUST_UNLEARN_WEAPON,0,player->GetGUID()); + } + else if( EquippedOk(player,S_UNLEARN_WEAPON) ) + { + if( player->GetMoney() >= DoLowUnlearnCost(player) ) + { + player->CastSpell(player, S_UNLEARN_WEAPON, true); + ProfessionUnlearnSpells(player, S_UNLEARN_WEAPON); + player->ModifyMoney(-DoLowUnlearnCost(player)); + _Creature->CastSpell(player, S_REP_ARMOR, true); + player->CLOSE_GOSSIP_MENU(); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } + else + { + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + } + break; + case GOSSIP_ACTION_INFO_DEF + 4: + if( EquippedOk(player,S_UNLEARN_ARMOR) ) + { + if( player->GetMoney() >= DoLowUnlearnCost(player) ) + { + player->CastSpell(player, S_UNLEARN_ARMOR, true); + ProfessionUnlearnSpells(player, S_UNLEARN_ARMOR); + player->ModifyMoney(-DoLowUnlearnCost(player)); + _Creature->CastSpell(player, S_REP_WEAPON, true); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + //Learn Hammer/Axe/Sword + case GOSSIP_ACTION_INFO_DEF + 5: + player->CastSpell(player, S_LEARN_HAMMER, true); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 6: + player->CastSpell(player, S_LEARN_AXE, true); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 7: + player->CastSpell(player, S_LEARN_SWORD, true); + player->CLOSE_GOSSIP_MENU(); + break; + //Unlearn Hammer/Axe/Sword + case GOSSIP_ACTION_INFO_DEF + 8: + if( EquippedOk(player,S_UNLEARN_HAMMER) ) + { + if( player->GetMoney() >= DoMedUnlearnCost(player)) + { + player->CastSpell(player, S_UNLEARN_HAMMER, true); + ProfessionUnlearnSpells(player, S_UNLEARN_HAMMER); + player->ModifyMoney(-DoMedUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 9: + if( EquippedOk(player,S_UNLEARN_AXE) ) + { + if( player->GetMoney() >= DoMedUnlearnCost(player)) + { + player->CastSpell(player, S_UNLEARN_AXE, true); + ProfessionUnlearnSpells(player, S_UNLEARN_AXE); + player->ModifyMoney(-DoMedUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 10: + if( EquippedOk(player,S_UNLEARN_SWORD) ) + { + if( player->GetMoney() >= DoMedUnlearnCost(player)) + { + player->CastSpell(player, S_UNLEARN_SWORD, true); + ProfessionUnlearnSpells(player, S_UNLEARN_SWORD); + player->ModifyMoney(-DoMedUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + } +} + +void SendConfirmLearn_npc_prof_blacksmith(Player *player, Creature *_Creature, uint32 action) +{ + if(action) + { + uint32 eCreature = _Creature->GetEntry(); + switch(eCreature) + { + case 11191: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_HAMMER, GOSSIP_SENDER_CHECK, action); + //unknown textID (TALK_HAMMER_LEARN) + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 11192: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_AXE, GOSSIP_SENDER_CHECK, action); + //unknown textID (TALK_AXE_LEARN) + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 11193: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SWORD, GOSSIP_SENDER_CHECK, action); + //unknown textID (TALK_SWORD_LEARN) + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + } + } +} + +void SendConfirmUnlearn_npc_prof_blacksmith(Player *player, Creature *_Creature, uint32 action) +{ + if(action) + { + uint32 eCreature = _Creature->GetEntry(); + switch(eCreature) + { + case 11146: //Ironus Coldsteel + case 11178: //Borgosh Corebender + case 5164: //Grumnus Steelshaper + case 11177: //Okothos Ironrager + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_SMITH_SPEC, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_ARMORORWEAPON, DoLowUnlearnCost(player),false); + //unknown textID (TALK_UNLEARN_AXEORWEAPON) + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + + case 11191: + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_HAMMER, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_WEAPON_SPEC, DoMedUnlearnCost(player),false); + //unknown textID (TALK_HAMMER_UNLEARN) + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 11192: + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_AXE, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_WEAPON_SPEC, DoMedUnlearnCost(player),false); + //unknown textID (TALK_AXE_UNLEARN) + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 11193: + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_SWORD, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_WEAPON_SPEC, DoMedUnlearnCost(player),false); + //unknown textID (TALK_SWORD_UNLEARN) + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + } + } +} + +bool GossipSelect_npc_prof_blacksmith(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(sender) + { + case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_blacksmith(player, _Creature, action); break; + case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_blacksmith(player, _Creature, action); break; + case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_blacksmith(player, _Creature, action); break; + case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_blacksmith(player, _Creature, action); break; + } + return true; +} + +/*bool QuestComplete_npc_prof_blacksmith( Player *player, Creature *_Creature, Quest const *_Quest ) +{ + if ( (_Quest->GetQuestId() == 5283) || (_Quest->GetQuestId() == 5301) ) //armorsmith + _Creature->CastSpell(player, 17451, true); + + if ( (_Quest->GetQuestId() == 5284) || (_Quest->GetQuestId() == 5302) ) //weaponsmith + _Creature->CastSpell(player, 17452, true); + + return true; +}*/ + +/*### +# start menues leatherworking +###*/ + +bool GossipHello_npc_prof_leather(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + if (_Creature->isVendor()) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + if(_Creature->isTrainer()) + player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); + + uint32 eCreature = _Creature->GetEntry(); + + if(player->HasSkill(SKILL_LEATHERWORKING) && player->GetBaseSkillValue(SKILL_LEATHERWORKING)>=250 && player->getLevel() > 49 ) + { + switch (eCreature) + { + case 7866: //Peter Galen + case 7867: //Thorkaf Dragoneye + if(player->HasSpell(S_DRAGON)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_DRAGON, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 1); + break; + case 7868: //Sarah Tanner + case 7869: //Brumn Winterhoof + if(player->HasSpell(S_ELEMENTAL)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_ELEMENTAL, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 2); + break; + case 7870: //Caryssia Moonhunter + case 7871: //Se'Jib + if(player->HasSpell(S_TRIBAL)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_TRIBAL, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 3); + break; + } + } + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +void SendActionMenu_npc_prof_leather(Player *player, Creature *_Creature, uint32 action) +{ + switch(action) + { + case GOSSIP_ACTION_TRADE: + player->SEND_VENDORLIST( _Creature->GetGUID() ); + break; + case GOSSIP_ACTION_TRAIN: + player->SEND_TRAINERLIST( _Creature->GetGUID() ); + break; + //Unlearn Leather + case GOSSIP_ACTION_INFO_DEF + 1: + if( EquippedOk(player,S_UNLEARN_DRAGON) ) + { + if( player->GetMoney() >= DoMedUnlearnCost(player) ) + { + player->CastSpell(player, S_UNLEARN_DRAGON, true); + ProfessionUnlearnSpells(player, S_UNLEARN_DRAGON); + player->ModifyMoney(-DoMedUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + if( EquippedOk(player,S_UNLEARN_ELEMENTAL) ) + { + if( player->GetMoney() >= DoMedUnlearnCost(player) ) + { + player->CastSpell(player, S_UNLEARN_ELEMENTAL, true); + ProfessionUnlearnSpells(player, S_UNLEARN_ELEMENTAL); + player->ModifyMoney(-DoMedUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + if( EquippedOk(player,S_UNLEARN_TRIBAL) ) + { + if(player->GetMoney() >= DoMedUnlearnCost(player)) + { + player->CastSpell(player, S_UNLEARN_TRIBAL, true); + ProfessionUnlearnSpells(player, S_UNLEARN_TRIBAL); + player->ModifyMoney(-DoMedUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + } +} + +void SendConfirmUnlearn_npc_prof_leather(Player *player, Creature *_Creature, uint32 action) +{ + if(action) + { + uint32 eCreature = _Creature->GetEntry(); + switch(eCreature) + { + case 7866: //Peter Galen + case 7867: //Thorkaf Dragoneye + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_DRAGON, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_LEATHER_SPEC, DoMedUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 7868: //Sarah Tanner + case 7869: //Brumn Winterhoof + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_ELEMENTAL, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_LEATHER_SPEC, DoMedUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 7870: //Caryssia Moonhunter + case 7871: //Se'Jib + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_TRIBAL, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_LEATHER_SPEC, DoMedUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + } + } +} + +bool GossipSelect_npc_prof_leather(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(sender) + { + case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_leather(player, _Creature, action); break; + case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_leather(player, _Creature, action); break; + case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_leather(player, _Creature, action); break; + } + return true; +} + +/*### +# start menues tailoring +###*/ + +bool HasTailorSpell(Player *player) +{ + if (player->HasSpell(S_MOONCLOTH) || player->HasSpell(S_SHADOWEAVE) || player->HasSpell(S_SPELLFIRE)) + return true; + return false; +} + +bool GossipHello_npc_prof_tailor(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + if (_Creature->isVendor()) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + if (_Creature->isTrainer()) + player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); + + uint32 eCreature = _Creature->GetEntry(); + //TAILORING SPEC + if (player->HasSkill(SKILL_TAILORING) && player->GetBaseSkillValue(SKILL_TAILORING)>=350 && player->getLevel() > 59) + { + if (player->GetQuestRewardStatus(10831) || player->GetQuestRewardStatus(10832) || player->GetQuestRewardStatus(10833)) + { + switch (eCreature) + { + case 22213: //Gidge Spellweaver + if (!HasTailorSpell(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SPELLFIRE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 1); + if (player->HasSpell(S_SPELLFIRE)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_SPELLFIRE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); + break; + case 22208: //Nasmara Moonsong + if (!HasTailorSpell(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_MOONCLOTH, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 2); + if (player->HasSpell(S_MOONCLOTH)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_MOONCLOTH, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 5); + break; + case 22212: //Andrion Darkspinner + if (!HasTailorSpell(player)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SHADOWEAVE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 3); + if (player->HasSpell(S_SHADOWEAVE)) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_UNLEARN_SHADOWEAVE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 6); + break; + } + } + } + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +void SendActionMenu_npc_prof_tailor(Player *player, Creature *_Creature, uint32 action) +{ + switch(action) + { + case GOSSIP_ACTION_TRADE: + player->SEND_VENDORLIST( _Creature->GetGUID() ); + break; + case GOSSIP_ACTION_TRAIN: + player->SEND_TRAINERLIST( _Creature->GetGUID() ); + break; + //Learn Tailor + case GOSSIP_ACTION_INFO_DEF + 1: + if(!player->HasSpell(S_SPELLFIRE) && player->GetMoney() >= DoLearnCost(player)) + { + player->CastSpell(player, S_LEARN_SPELLFIRE, true); + player->ModifyMoney(-DoLearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + if(!player->HasSpell(S_MOONCLOTH) && player->GetMoney() >= DoLearnCost(player)) + { + player->CastSpell(player, S_LEARN_MOONCLOTH, true); + player->ModifyMoney(-DoLearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + if(!player->HasSpell(S_SHADOWEAVE) && player->GetMoney() >= DoLearnCost(player)) + { + player->CastSpell(player, S_LEARN_SHADOWEAVE, true); + player->ModifyMoney(-DoLearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + player->CLOSE_GOSSIP_MENU(); + break; + //Unlearn Tailor + case GOSSIP_ACTION_INFO_DEF + 4: + if( EquippedOk(player,S_UNLEARN_SPELLFIRE) ) + { + if( player->GetMoney() >= DoHighUnlearnCost(player) ) + { + player->CastSpell(player, S_UNLEARN_SPELLFIRE, true); + ProfessionUnlearnSpells(player, S_UNLEARN_SPELLFIRE); + player->ModifyMoney(-DoHighUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 5: + if( EquippedOk(player,S_UNLEARN_MOONCLOTH) ) + { + if( player->GetMoney() >= DoHighUnlearnCost(player) ) + { + player->CastSpell(player, S_UNLEARN_MOONCLOTH, true); + ProfessionUnlearnSpells(player, S_UNLEARN_MOONCLOTH); + player->ModifyMoney(-DoHighUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 6: + if( EquippedOk(player,S_UNLEARN_SHADOWEAVE) ) + { + if( player->GetMoney() >= DoHighUnlearnCost(player) ) + { + player->CastSpell(player, S_UNLEARN_SHADOWEAVE, true); + ProfessionUnlearnSpells(player, S_UNLEARN_SHADOWEAVE); + player->ModifyMoney(-DoHighUnlearnCost(player)); + } else + player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, _Creature, 0, 0); + } else + player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + player->CLOSE_GOSSIP_MENU(); + break; + } +} + +void SendConfirmLearn_npc_prof_tailor(Player *player, Creature *_Creature, uint32 action) +{ + if(action) + { + uint32 eCreature = _Creature->GetEntry(); + switch(eCreature) + { + case 22213: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SPELLFIRE, GOSSIP_SENDER_CHECK, action); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 22208: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_MOONCLOTH, GOSSIP_SENDER_CHECK, action); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 22212: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_LEARN_SHADOWEAVE, GOSSIP_SENDER_CHECK, action); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + } + } +} + +void SendConfirmUnlearn_npc_prof_tailor(Player *player, Creature *_Creature, uint32 action) +{ + if(action) + { + uint32 eCreature = _Creature->GetEntry(); + switch(eCreature) + { + case 22213: //Gidge Spellweaver + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_SPELLFIRE, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_TAILOR_SPEC, DoHighUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 22208: //Nasmara Moonsong + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_MOONCLOTH, GOSSIP_SENDER_CHECK, action, BOX_UNLEARN_TAILOR_SPEC, DoHighUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case 22212: //Andrion Darkspinner + player->ADD_GOSSIP_ITEM_EXTENDED( 0, GOSSIP_UNLEARN_SHADOWEAVE, GOSSIP_SENDER_CHECK, action,BOX_UNLEARN_TAILOR_SPEC, DoHighUnlearnCost(player),false); + //unknown textID () + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + } + } +} + +bool GossipSelect_npc_prof_tailor(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(sender) + { + case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_tailor(player, _Creature, action); break; + case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_tailor(player, _Creature, action); break; + case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_tailor(player, _Creature, action); break; + case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_tailor(player, _Creature, action); break; + } + return true; +} + +/*### +# start menues for GO (engineering and leatherworking) +###*/ + +/*bool GOHello_go_soothsaying_for_dummies(Player *player, GameObject* _GO) +{ + player->PlayerTalkClass->GetGossipMenu()->AddMenuItem(0,GOSSIP_LEARN_DRAGON, GOSSIP_SENDER_INFO, GOSSIP_ACTION_INFO_DEF, "", 0); + + player->SEND_GOSSIP_MENU(5584, _GO->GetGUID()); + + return true; +}*/ + +/*### +# +###*/ + +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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_prof_blacksmith"; + newscript->pGossipHello = &GossipHello_npc_prof_blacksmith; + newscript->pGossipSelect = &GossipSelect_npc_prof_blacksmith; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_prof_leather"; + newscript->pGossipHello = &GossipHello_npc_prof_leather; + newscript->pGossipSelect = &GossipSelect_npc_prof_leather; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_prof_tailor"; + newscript->pGossipHello = &GossipHello_npc_prof_tailor; + newscript->pGossipSelect = &GossipSelect_npc_prof_tailor; + m_scripts[nrscripts++] = newscript; + + /*newscript = new Script; + newscript->Name="go_soothsaying_for_dummies"; + newscript->pGOHello = &GOHello_go_soothsaying_for_dummies; + //newscript->pGossipSelect = &GossipSelect_go_soothsaying_for_dummies; + m_scripts[nrscripts++] = newscript;*/ +} diff --git a/src/bindings/scripts/scripts/npc/npcs_special.cpp b/src/bindings/scripts/scripts/npc/npcs_special.cpp index a8ea8612c58..c7faf4032a6 100644 --- a/src/bindings/scripts/scripts/npc/npcs_special.cpp +++ b/src/bindings/scripts/scripts/npc/npcs_special.cpp @@ -1,878 +1,878 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Npcs_Special -SD%Complete: 100 -SDComment: To be used for special NPCs that are located globally. Support for quest 3861 (Cluck!), 6622 and 6624 (Triage) -SDCategory: NPCs -EndScriptData -*/ - -/* ContentData -npc_chicken_cluck 100% support for quest 3861 (Cluck!) -npc_dancing_flames 100% midsummer event NPC -npc_guardian 100% guardianAI used to prevent players from accessing off-limits areas. Not in use by SD2 -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_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 -EndContentData */ - -#include "precompiled.h" - -/*######## -# npc_chicken_cluck -#########*/ - -#define QUEST_CLUCK 3861 -#define EMOTE_A_HELLO "looks up at you quizzically. Maybe you should inspect it?" -#define EMOTE_H_HELLO "looks at you unexpectadly." -#define CLUCK_TEXT2 "starts pecking at the feed." -#define FACTION_FRIENDLY 84 -#define FACTION_CHICKEN 31 - -struct MANGOS_DLL_DECL npc_chicken_cluckAI : public ScriptedAI -{ - npc_chicken_cluckAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ResetFlagTimer; - - void Reset() - { - ResetFlagTimer = 120000; - - m_creature->setFaction(FACTION_CHICKEN); - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - // 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)) - { - if(ResetFlagTimer < diff) - EnterEvadeMode(); - else ResetFlagTimer -= diff; - } - - if(m_creature->SelectHostilTarget() && m_creature->getVictim()) - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_npc_chicken_cluck(Creature *_Creature) -{ - return new npc_chicken_cluckAI(_Creature); -} - -bool ReceiveEmote_npc_chicken_cluck( Player *player, Creature *_Creature, uint32 emote ) -{ - if( emote == TEXTEMOTE_CHICKEN ) - { - if( player->GetTeam() == ALLIANCE ) - { - if( rand()%30 == 1 ) - { - if( player->GetQuestStatus(QUEST_CLUCK) == QUEST_STATUS_NONE ) - { - _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - _Creature->setFaction(FACTION_FRIENDLY); - _Creature->MonsterTextEmote(EMOTE_A_HELLO, 0); - } - } - } else - _Creature->MonsterTextEmote(EMOTE_H_HELLO,0); - } - if( emote == TEXTEMOTE_CHEER && player->GetTeam() == ALLIANCE ) - if( player->GetQuestStatus(QUEST_CLUCK) == QUEST_STATUS_COMPLETE ) - { - _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - _Creature->setFaction(FACTION_FRIENDLY); - _Creature->MonsterTextEmote(CLUCK_TEXT2, 0); - } - - return true; -} - -bool QuestAccept_npc_chicken_cluck(Player *player, Creature *_Creature, const Quest *_Quest ) -{ - if(_Quest->GetQuestId() == QUEST_CLUCK) - ((npc_chicken_cluckAI*)_Creature->AI())->Reset(); - - return true; -} - -bool QuestComplete_npc_chicken_cluck(Player *player, Creature *_Creature, const Quest *_Quest) -{ - if(_Quest->GetQuestId() == QUEST_CLUCK) - ((npc_chicken_cluckAI*)_Creature->AI())->Reset(); - - return true; -} - -/*###### -## npc_dancing_flames -######*/ - -bool ReceiveEmote_npc_dancing_flames( Player *player, Creature *_Creature, uint32 emote ) -{ - if( emote == TEXTEMOTE_DANCE ) - _Creature->CastSpell(player,47057,false); - - return true; -} - -/*###### -## Triage quest -######*/ - -#define SAY_DOC1 "I'm saved! Thank you, doctor!" -#define SAY_DOC2 "HOORAY! I AM SAVED!" -#define SAY_DOC3 "Sweet, sweet embrace... take me..." - -struct Location -{ - float x, y, z, o; -}; - -#define DOCTOR_ALLIANCE 12939 - -static Location AllianceCoords[]= -{ - { // Top-far-right bunk as seen from entrance - -3757.38, -4533.05, 14.16, 3.62 - }, - { // Top-far-left bunk - -3754.36, -4539.13, 14.16, 5.13 - }, - { // Far-right bunk - -3749.54, -4540.25, 14.28, 3.34 - }, - { // Right bunk near entrance - -3742.10, -4536.85, 14.28, 3.64 - }, - { // Far-left bunk - -3755.89, -4529.07, 14.05, 0.57 - }, - { // Mid-left bunk - -3749.51, -4527.08, 14.07, 5.26 - }, - { // Left bunk near entrance - -3746.37, -4525.35, 14.16, 5.22 - }, -}; - -#define ALLIANCE_COORDS 7 - -//alliance run to where -#define A_RUNTOX -3742.96 -#define A_RUNTOY -4531.52 -#define A_RUNTOZ 11.91 - -#define DOCTOR_HORDE 12920 - -static Location HordeCoords[]= -{ - { // Left, Behind - -1013.75, -3492.59, 62.62, 4.34 - }, - { // Right, Behind - -1017.72, -3490.92, 62.62, 4.34 - }, - { // Left, Mid - -1015.77, -3497.15, 62.82, 4.34 - }, - { // Right, Mid - -1019.51, -3495.49, 62.82, 4.34 - }, - { // Left, front - -1017.25, -3500.85, 62.98, 4.34 - }, - { // Right, Front - -1020.95, -3499.21, 62.98, 4.34 - } -}; - -#define HORDE_COORDS 6 - -//horde run to where -#define H_RUNTOX -1016.44 -#define H_RUNTOY -3508.48 -#define H_RUNTOZ 62.96 - -const uint32 AllianceSoldierId[3] = -{ - 12938, // 12938 Injured Alliance Soldier - 12936, // 12936 Badly injured Alliance Soldier - 12937 // 12937 Critically injured Alliance Soldier -}; - -const uint32 HordeSoldierId[3] = -{ - 12923, //12923 Injured Soldier - 12924, //12924 Badly injured Soldier - 12925 //12925 Critically injured Soldier -}; - -/*###### -## npc_doctor (handles both Gustaf Vanhowzen and Gregory Victor) -######*/ - -struct MANGOS_DLL_DECL npc_doctorAI : public ScriptedAI -{ - uint64 Playerguid; - - uint32 SummonPatient_Timer; - uint32 SummonPatientCount; - uint32 PatientDiedCount; - uint32 PatientSavedCount; - - bool Event; - - std::list Patients; - std::vector Coordinates; - - npc_doctorAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset(){} - - void BeginEvent(Player* player); - void PatientDied(Location* Point); - void PatientSaved(Creature* soldier, Player* player, Location* Point); - void UpdateAI(const uint32 diff); - - void Aggro(Unit* who){} -}; - -/*##### -## npc_injured_patient (handles all the patients, no matter Horde or Alliance) -#####*/ - -struct MANGOS_DLL_DECL npc_injured_patientAI : public ScriptedAI -{ - npc_injured_patientAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 Doctorguid; - - Location* Coord; - - void Reset() - { - Doctorguid = 0; - - Coord = NULL; - //no select - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //no regen health - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - //to make them lay with face down - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_DEAD); - - uint32 mobId = m_creature->GetEntry(); - - switch (mobId) - { //lower max health - case 12923: - case 12938: //Injured Soldier - m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.75)); - break; - case 12924: - case 12936: //Badly injured Soldier - m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.50)); - break; - case 12925: - case 12937: //Critically injured Soldier - m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.25)); - break; - } - } - - void Aggro(Unit* who){} - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if (caster->GetTypeId() == TYPEID_PLAYER && m_creature->isAlive() && spell->Id == 20804) - { - if( (((Player*)caster)->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (((Player*)caster)->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) - { - if(Doctorguid) - { - Creature* Doctor = ((Creature*)Unit::GetUnit((*m_creature), Doctorguid)); - if(Doctor) - ((npc_doctorAI*)Doctor->AI())->PatientSaved(m_creature, ((Player*)caster), Coord); - } - } - //make not selectable - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //regen health - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - //stand up - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE); - DoSay(SAY_DOC1,LANG_UNIVERSAL,NULL); - - uint32 mobId = m_creature->GetEntry(); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - switch (mobId) - { - case 12923: - case 12924: - case 12925: - m_creature->GetMotionMaster()->MovePoint(0, H_RUNTOX, H_RUNTOY, H_RUNTOZ); - break; - case 12936: - case 12937: - case 12938: - m_creature->GetMotionMaster()->MovePoint(0, A_RUNTOX, A_RUNTOY, A_RUNTOZ); - break; - } - } - return; - } - - void UpdateAI(const uint32 diff) - { - if (m_creature->isAlive() && m_creature->GetHealth() > 6) - { //lower HP on every world tick makes it a useful counter, not officlone though - m_creature->SetHealth(uint32(m_creature->GetHealth()-5) ); - } - - if (m_creature->isAlive() && m_creature->GetHealth() <= 6) - { - 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, 32); - - if(Doctorguid) - { - Creature* Doctor = ((Creature*)Unit::GetUnit((*m_creature), Doctorguid)); - if(Doctor) - ((npc_doctorAI*)Doctor->AI())->PatientDied(Coord); - } - } - } -}; - -CreatureAI* GetAI_npc_injured_patient(Creature *_Creature) -{ - return new npc_injured_patientAI (_Creature); -} - -/* -npc_doctor (continue) -*/ - -void npc_doctorAI::BeginEvent(Player* player) -{ - Playerguid = player->GetGUID(); - - SummonPatient_Timer = 10000; - SummonPatientCount = 0; - PatientDiedCount = 0; - PatientSavedCount = 0; - - switch(m_creature->GetEntry()) - { - case DOCTOR_ALLIANCE: - for(uint8 i = 0; i < ALLIANCE_COORDS; ++i) - Coordinates.push_back(&AllianceCoords[i]); - break; - - case DOCTOR_HORDE: - for(uint8 i = 0; i < HORDE_COORDS; ++i) - Coordinates.push_back(&HordeCoords[i]); - break; - } - - Event = true; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -} - -void npc_doctorAI::PatientDied(Location* Point) -{ - Player* player = ((Player*)Unit::GetUnit((*m_creature), Playerguid)); - if(player && ((player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE))) - { - PatientDiedCount++; - if (PatientDiedCount > 5 && Event) - { - if(player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) - player->FailQuest(6624); - else if(player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) - player->FailQuest(6622); - - Event = false; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - Coordinates.push_back(Point); - } -} - -void npc_doctorAI::PatientSaved(Creature* soldier, Player* player, Location* Point) -{ - if(player && Playerguid == player->GetGUID()) - { - if((player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) - { - PatientSavedCount++; - if(PatientSavedCount == 15) - { - if(!Patients.empty()) - { - std::list::iterator itr; - for(itr = Patients.begin(); itr != Patients.end(); ++itr) - { - Creature* Patient = ((Creature*)Unit::GetUnit((*m_creature), *itr)); - if( Patient ) - Patient->setDeathState(JUST_DIED); - } - } - - if(player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(6624); - else if(player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(6622); - - Event = false; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - Coordinates.push_back(Point); - } - } -} - -void npc_doctorAI::UpdateAI(const uint32 diff) -{ - if(Event && SummonPatientCount >= 20) - { - Event = false; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - if(Event) - if(SummonPatient_Timer < diff) - { - Creature* Patient = NULL; - Location* Point = NULL; - - if(Coordinates.empty()) - return; - - std::vector::iterator itr = Coordinates.begin()+rand()%Coordinates.size(); - uint32 patientEntry = 0; - - switch(m_creature->GetEntry()) - { - case DOCTOR_ALLIANCE: patientEntry = AllianceSoldierId[rand()%3]; break; - case DOCTOR_HORDE: patientEntry = HordeSoldierId[rand()%3]; break; - default: - error_log("SD2: 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) - { - Patients.push_back(Patient->GetGUID()); - ((npc_injured_patientAI*)Patient->AI())->Doctorguid = m_creature->GetGUID(); - if(Point) - ((npc_injured_patientAI*)Patient->AI())->Coord = Point; - Coordinates.erase(itr); - } - SummonPatient_Timer = 10000; - SummonPatientCount++; - }else SummonPatient_Timer -= diff; -} - -bool QuestAccept_npc_doctor(Player *player, Creature *creature, Quest const *quest ) -{ - if((quest->GetQuestId() == 6624) || (quest->GetQuestId() == 6622)) - ((npc_doctorAI*)creature->AI())->BeginEvent(player); - - return true; -} - -CreatureAI* GetAI_npc_doctor(Creature *_Creature) -{ - return new npc_doctorAI (_Creature); -} - -/*###### -## npc_guardian -######*/ - -#define SPELL_DEATHTOUCH 5 -#define SAY_AGGRO "This area is closed!" - -struct MANGOS_DLL_DECL npc_guardianAI : public ScriptedAI -{ - npc_guardianAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (m_creature->isAttackReady()) - { - m_creature->CastSpell(m_creature->getVictim(),SPELL_DEATHTOUCH, true); - m_creature->resetAttackTimer(); - } - } -}; - -CreatureAI* GetAI_npc_guardian(Creature *_Creature) -{ - return new npc_guardianAI (_Creature); -} - -/*###### -## npc_mount_vendor -######*/ - -bool GossipHello_npc_mount_vendor(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - bool canBuy; - canBuy = false; - uint32 vendor = _Creature->GetEntry(); - uint8 race = player->getRace(); - - switch (vendor) - { - case 384: //Katie Hunter - case 1460: //Unger Statforth - case 2357: //Merideth Carlson - case 4885: //Gregor MacVince - if (player->GetReputationRank(72) != REP_EXALTED && race != RACE_HUMAN) - player->SEND_GOSSIP_MENU(5855, _Creature->GetGUID()); - else canBuy = true; - break; - case 1261: //Veron Amberstill - if (player->GetReputationRank(47) != REP_EXALTED && race != RACE_DWARF) - player->SEND_GOSSIP_MENU(5856, _Creature->GetGUID()); - else canBuy = true; - break; - case 3362: //Ogunaro Wolfrunner - if (player->GetReputationRank(76) != REP_EXALTED && race != RACE_ORC) - player->SEND_GOSSIP_MENU(5841, _Creature->GetGUID()); - else canBuy = true; - break; - case 3685: //Harb Clawhoof - if (player->GetReputationRank(81) != REP_EXALTED && race != RACE_TAUREN) - player->SEND_GOSSIP_MENU(5843, _Creature->GetGUID()); - else canBuy = true; - break; - case 4730: //Lelanai - if (player->GetReputationRank(69) != REP_EXALTED && race != RACE_NIGHTELF) - player->SEND_GOSSIP_MENU(5844, _Creature->GetGUID()); - else canBuy = true; - break; - case 4731: //Zachariah Post - if (player->GetReputationRank(68) != REP_EXALTED && race != RACE_UNDEAD_PLAYER) - player->SEND_GOSSIP_MENU(5840, _Creature->GetGUID()); - else canBuy = true; - break; - case 7952: //Zjolnir - if (player->GetReputationRank(530) != REP_EXALTED && race != RACE_TROLL) - player->SEND_GOSSIP_MENU(5842, _Creature->GetGUID()); - else canBuy = true; - break; - case 7955: //Milli Featherwhistle - if (player->GetReputationRank(54) != REP_EXALTED && race != RACE_GNOME) - player->SEND_GOSSIP_MENU(5857, _Creature->GetGUID()); - else canBuy = true; - break; - case 16264: //Winaestra - if (player->GetReputationRank(911) != REP_EXALTED && race != RACE_BLOODELF) - player->SEND_GOSSIP_MENU(10305, _Creature->GetGUID()); - else canBuy = true; - break; - case 17584: //Torallius the Pack Handler - if (player->GetReputationRank(930) != REP_EXALTED && race != RACE_DRAENEI) - player->SEND_GOSSIP_MENU(10239, _Creature->GetGUID()); - else canBuy = true; - break; - } - - if (canBuy) - { - if (_Creature->isVendor()) - player->ADD_GOSSIP_ITEM( 1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - } - return true; -} - -bool GossipSelect_npc_mount_vendor(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_TRADE) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - - return true; -} - -/*###### -## npc_rogue_trainer -######*/ - -bool GossipHello_npc_rogue_trainer(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( _Creature->isTrainer() ) - player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - if( _Creature->isCanTrainingAndResetTalentsOf(player) ) - player->ADD_GOSSIP_ITEM(2, "I wish to unlearn my talents", GOSSIP_SENDER_MAIN, GOSSIP_OPTION_UNLEARNTALENTS); - - if( player->getClass() == CLASS_ROGUE && player->getLevel() >= 24 && !player->HasItemCount(17126,1) && !player->GetQuestRewardStatus(6681) ) - { - player->ADD_GOSSIP_ITEM(0, "", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(5996, _Creature->GetGUID()); - } else - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_rogue_trainer(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch( action ) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,21100,false); - break; - case GOSSIP_ACTION_TRAIN: - player->SEND_TRAINERLIST( _Creature->GetGUID() ); - break; - case GOSSIP_OPTION_UNLEARNTALENTS: - player->CLOSE_GOSSIP_MENU(); - player->SendTalentWipeConfirm( _Creature->GetGUID() ); - break; - } - return true; -} - -/*###### -## npc_sayge -######*/ - -#define SPELL_DMG 23768 //dmg -#define SPELL_RES 23769 //res -#define SPELL_ARM 23767 //arm -#define SPELL_SPI 23738 //spi -#define SPELL_INT 23766 //int -#define SPELL_STM 23737 //stm -#define SPELL_STR 23735 //str -#define SPELL_AGI 23736 //agi -#define SPELL_FORTUNE 23765 //faire fortune - -bool GossipHello_npc_sayge(Player *player, Creature *_Creature) -{ - if(_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->HasSpellCooldown(SPELL_INT) || - player->HasSpellCooldown(SPELL_ARM) || - player->HasSpellCooldown(SPELL_DMG) || - player->HasSpellCooldown(SPELL_RES) || - player->HasSpellCooldown(SPELL_STR) || - player->HasSpellCooldown(SPELL_AGI) || - player->HasSpellCooldown(SPELL_STM) || - player->HasSpellCooldown(SPELL_SPI) ) - player->SEND_GOSSIP_MENU(7393, _Creature->GetGUID()); - else - { - player->ADD_GOSSIP_ITEM(0, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(7339, _Creature->GetGUID()); - } - - return true; -} - -void SendAction_npc_sayge(Player *player, Creature *_Creature, uint32 action) -{ - switch(action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, "Slay the Man", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->ADD_GOSSIP_ITEM(0, "Turn him over to liege", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->ADD_GOSSIP_ITEM(0, "Confiscate the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->ADD_GOSSIP_ITEM(0, "Let him go and have the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(7340, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(0, "Execute your friend painfully", GOSSIP_SENDER_MAIN+1, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Execute your friend painlessly", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Let your friend go", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(7341, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(0, "Confront the diplomat", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Show not so quiet defiance", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Remain quiet", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(7361, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(0, "Speak against your brother openly", GOSSIP_SENDER_MAIN+6, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Help your brother in", GOSSIP_SENDER_MAIN+7, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Keep your brother out without letting him know", GOSSIP_SENDER_MAIN+8, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(7362, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM(0, "Take credit, keep gold", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Take credit, share the gold", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); - player->ADD_GOSSIP_ITEM(0, "Let the knight take credit", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(7363, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM(0, "Thanks", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - player->SEND_GOSSIP_MENU(7364, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - _Creature->CastSpell(player, SPELL_FORTUNE, false); - player->SEND_GOSSIP_MENU(7365, _Creature->GetGUID()); - break; - } -} - -bool GossipSelect_npc_sayge(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(sender) - { - case GOSSIP_SENDER_MAIN: - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+1: - _Creature->CastSpell(player, SPELL_DMG, false); - player->AddSpellCooldown(SPELL_DMG,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+2: - _Creature->CastSpell(player, SPELL_RES, false); - player->AddSpellCooldown(SPELL_RES,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+3: - _Creature->CastSpell(player, SPELL_ARM, false); - player->AddSpellCooldown(SPELL_ARM,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+4: - _Creature->CastSpell(player, SPELL_SPI, false); - player->AddSpellCooldown(SPELL_SPI,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+5: - _Creature->CastSpell(player, SPELL_INT, false); - player->AddSpellCooldown(SPELL_INT,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+6: - _Creature->CastSpell(player, SPELL_STM, false); - player->AddSpellCooldown(SPELL_STM,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+7: - _Creature->CastSpell(player, SPELL_STR, false); - player->AddSpellCooldown(SPELL_STR,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - case GOSSIP_SENDER_MAIN+8: - _Creature->CastSpell(player, SPELL_AGI, false); - player->AddSpellCooldown(SPELL_AGI,0,time(NULL) + 7200); - SendAction_npc_sayge(player, _Creature, action); - break; - } - return true; -} - -void AddSC_npcs_special() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_chicken_cluck"; - newscript->GetAI = GetAI_npc_chicken_cluck; - newscript->pReceiveEmote = &ReceiveEmote_npc_chicken_cluck; - newscript->pQuestAccept = &QuestAccept_npc_chicken_cluck; - newscript->pQuestComplete = &QuestComplete_npc_chicken_cluck; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_dancing_flames"; - newscript->pReceiveEmote = &ReceiveEmote_npc_dancing_flames; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_injured_patient"; - newscript->GetAI = GetAI_npc_injured_patient; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_doctor"; - newscript->GetAI = GetAI_npc_doctor; - newscript->pQuestAccept = &QuestAccept_npc_doctor; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_guardian"; - newscript->GetAI = GetAI_npc_guardian; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_mount_vendor"; - newscript->pGossipHello = &GossipHello_npc_mount_vendor; - newscript->pGossipSelect = &GossipSelect_npc_mount_vendor; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_rogue_trainer"; - newscript->pGossipHello = &GossipHello_npc_rogue_trainer; - newscript->pGossipSelect = &GossipSelect_npc_rogue_trainer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_sayge"; - newscript->pGossipHello = &GossipHello_npc_sayge; - newscript->pGossipSelect = &GossipSelect_npc_sayge; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Npcs_Special +SD%Complete: 100 +SDComment: To be used for special NPCs that are located globally. Support for quest 3861 (Cluck!), 6622 and 6624 (Triage) +SDCategory: NPCs +EndScriptData +*/ + +/* ContentData +npc_chicken_cluck 100% support for quest 3861 (Cluck!) +npc_dancing_flames 100% midsummer event NPC +npc_guardian 100% guardianAI used to prevent players from accessing off-limits areas. Not in use by SD2 +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_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 +EndContentData */ + +#include "precompiled.h" + +/*######## +# npc_chicken_cluck +#########*/ + +#define QUEST_CLUCK 3861 +#define EMOTE_A_HELLO "looks up at you quizzically. Maybe you should inspect it?" +#define EMOTE_H_HELLO "looks at you unexpectadly." +#define CLUCK_TEXT2 "starts pecking at the feed." +#define FACTION_FRIENDLY 84 +#define FACTION_CHICKEN 31 + +struct MANGOS_DLL_DECL npc_chicken_cluckAI : public ScriptedAI +{ + npc_chicken_cluckAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ResetFlagTimer; + + void Reset() + { + ResetFlagTimer = 120000; + + m_creature->setFaction(FACTION_CHICKEN); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + // 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)) + { + if(ResetFlagTimer < diff) + EnterEvadeMode(); + else ResetFlagTimer -= diff; + } + + if(m_creature->SelectHostilTarget() && m_creature->getVictim()) + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_chicken_cluck(Creature *_Creature) +{ + return new npc_chicken_cluckAI(_Creature); +} + +bool ReceiveEmote_npc_chicken_cluck( Player *player, Creature *_Creature, uint32 emote ) +{ + if( emote == TEXTEMOTE_CHICKEN ) + { + if( player->GetTeam() == ALLIANCE ) + { + if( rand()%30 == 1 ) + { + if( player->GetQuestStatus(QUEST_CLUCK) == QUEST_STATUS_NONE ) + { + _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + _Creature->setFaction(FACTION_FRIENDLY); + _Creature->MonsterTextEmote(EMOTE_A_HELLO, 0); + } + } + } else + _Creature->MonsterTextEmote(EMOTE_H_HELLO,0); + } + if( emote == TEXTEMOTE_CHEER && player->GetTeam() == ALLIANCE ) + if( player->GetQuestStatus(QUEST_CLUCK) == QUEST_STATUS_COMPLETE ) + { + _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + _Creature->setFaction(FACTION_FRIENDLY); + _Creature->MonsterTextEmote(CLUCK_TEXT2, 0); + } + + return true; +} + +bool QuestAccept_npc_chicken_cluck(Player *player, Creature *_Creature, const Quest *_Quest ) +{ + if(_Quest->GetQuestId() == QUEST_CLUCK) + ((npc_chicken_cluckAI*)_Creature->AI())->Reset(); + + return true; +} + +bool QuestComplete_npc_chicken_cluck(Player *player, Creature *_Creature, const Quest *_Quest) +{ + if(_Quest->GetQuestId() == QUEST_CLUCK) + ((npc_chicken_cluckAI*)_Creature->AI())->Reset(); + + return true; +} + +/*###### +## npc_dancing_flames +######*/ + +bool ReceiveEmote_npc_dancing_flames( Player *player, Creature *_Creature, uint32 emote ) +{ + if( emote == TEXTEMOTE_DANCE ) + _Creature->CastSpell(player,47057,false); + + return true; +} + +/*###### +## Triage quest +######*/ + +#define SAY_DOC1 "I'm saved! Thank you, doctor!" +#define SAY_DOC2 "HOORAY! I AM SAVED!" +#define SAY_DOC3 "Sweet, sweet embrace... take me..." + +struct Location +{ + float x, y, z, o; +}; + +#define DOCTOR_ALLIANCE 12939 + +static Location AllianceCoords[]= +{ + { // Top-far-right bunk as seen from entrance + -3757.38, -4533.05, 14.16, 3.62 + }, + { // Top-far-left bunk + -3754.36, -4539.13, 14.16, 5.13 + }, + { // Far-right bunk + -3749.54, -4540.25, 14.28, 3.34 + }, + { // Right bunk near entrance + -3742.10, -4536.85, 14.28, 3.64 + }, + { // Far-left bunk + -3755.89, -4529.07, 14.05, 0.57 + }, + { // Mid-left bunk + -3749.51, -4527.08, 14.07, 5.26 + }, + { // Left bunk near entrance + -3746.37, -4525.35, 14.16, 5.22 + }, +}; + +#define ALLIANCE_COORDS 7 + +//alliance run to where +#define A_RUNTOX -3742.96 +#define A_RUNTOY -4531.52 +#define A_RUNTOZ 11.91 + +#define DOCTOR_HORDE 12920 + +static Location HordeCoords[]= +{ + { // Left, Behind + -1013.75, -3492.59, 62.62, 4.34 + }, + { // Right, Behind + -1017.72, -3490.92, 62.62, 4.34 + }, + { // Left, Mid + -1015.77, -3497.15, 62.82, 4.34 + }, + { // Right, Mid + -1019.51, -3495.49, 62.82, 4.34 + }, + { // Left, front + -1017.25, -3500.85, 62.98, 4.34 + }, + { // Right, Front + -1020.95, -3499.21, 62.98, 4.34 + } +}; + +#define HORDE_COORDS 6 + +//horde run to where +#define H_RUNTOX -1016.44 +#define H_RUNTOY -3508.48 +#define H_RUNTOZ 62.96 + +const uint32 AllianceSoldierId[3] = +{ + 12938, // 12938 Injured Alliance Soldier + 12936, // 12936 Badly injured Alliance Soldier + 12937 // 12937 Critically injured Alliance Soldier +}; + +const uint32 HordeSoldierId[3] = +{ + 12923, //12923 Injured Soldier + 12924, //12924 Badly injured Soldier + 12925 //12925 Critically injured Soldier +}; + +/*###### +## npc_doctor (handles both Gustaf Vanhowzen and Gregory Victor) +######*/ + +struct MANGOS_DLL_DECL npc_doctorAI : public ScriptedAI +{ + uint64 Playerguid; + + uint32 SummonPatient_Timer; + uint32 SummonPatientCount; + uint32 PatientDiedCount; + uint32 PatientSavedCount; + + bool Event; + + std::list Patients; + std::vector Coordinates; + + npc_doctorAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset(){} + + void BeginEvent(Player* player); + void PatientDied(Location* Point); + void PatientSaved(Creature* soldier, Player* player, Location* Point); + void UpdateAI(const uint32 diff); + + void Aggro(Unit* who){} +}; + +/*##### +## npc_injured_patient (handles all the patients, no matter Horde or Alliance) +#####*/ + +struct MANGOS_DLL_DECL npc_injured_patientAI : public ScriptedAI +{ + npc_injured_patientAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 Doctorguid; + + Location* Coord; + + void Reset() + { + Doctorguid = 0; + + Coord = NULL; + //no select + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //no regen health + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + //to make them lay with face down + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_DEAD); + + uint32 mobId = m_creature->GetEntry(); + + switch (mobId) + { //lower max health + case 12923: + case 12938: //Injured Soldier + m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.75)); + break; + case 12924: + case 12936: //Badly injured Soldier + m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.50)); + break; + case 12925: + case 12937: //Critically injured Soldier + m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.25)); + break; + } + } + + void Aggro(Unit* who){} + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (caster->GetTypeId() == TYPEID_PLAYER && m_creature->isAlive() && spell->Id == 20804) + { + if( (((Player*)caster)->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (((Player*)caster)->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) + { + if(Doctorguid) + { + Creature* Doctor = ((Creature*)Unit::GetUnit((*m_creature), Doctorguid)); + if(Doctor) + ((npc_doctorAI*)Doctor->AI())->PatientSaved(m_creature, ((Player*)caster), Coord); + } + } + //make not selectable + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //regen health + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + //stand up + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE); + DoSay(SAY_DOC1,LANG_UNIVERSAL,NULL); + + uint32 mobId = m_creature->GetEntry(); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + switch (mobId) + { + case 12923: + case 12924: + case 12925: + m_creature->GetMotionMaster()->MovePoint(0, H_RUNTOX, H_RUNTOY, H_RUNTOZ); + break; + case 12936: + case 12937: + case 12938: + m_creature->GetMotionMaster()->MovePoint(0, A_RUNTOX, A_RUNTOY, A_RUNTOZ); + break; + } + } + return; + } + + void UpdateAI(const uint32 diff) + { + if (m_creature->isAlive() && m_creature->GetHealth() > 6) + { //lower HP on every world tick makes it a useful counter, not officlone though + m_creature->SetHealth(uint32(m_creature->GetHealth()-5) ); + } + + if (m_creature->isAlive() && m_creature->GetHealth() <= 6) + { + 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, 32); + + if(Doctorguid) + { + Creature* Doctor = ((Creature*)Unit::GetUnit((*m_creature), Doctorguid)); + if(Doctor) + ((npc_doctorAI*)Doctor->AI())->PatientDied(Coord); + } + } + } +}; + +CreatureAI* GetAI_npc_injured_patient(Creature *_Creature) +{ + return new npc_injured_patientAI (_Creature); +} + +/* +npc_doctor (continue) +*/ + +void npc_doctorAI::BeginEvent(Player* player) +{ + Playerguid = player->GetGUID(); + + SummonPatient_Timer = 10000; + SummonPatientCount = 0; + PatientDiedCount = 0; + PatientSavedCount = 0; + + switch(m_creature->GetEntry()) + { + case DOCTOR_ALLIANCE: + for(uint8 i = 0; i < ALLIANCE_COORDS; ++i) + Coordinates.push_back(&AllianceCoords[i]); + break; + + case DOCTOR_HORDE: + for(uint8 i = 0; i < HORDE_COORDS; ++i) + Coordinates.push_back(&HordeCoords[i]); + break; + } + + Event = true; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +} + +void npc_doctorAI::PatientDied(Location* Point) +{ + Player* player = ((Player*)Unit::GetUnit((*m_creature), Playerguid)); + if(player && ((player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE))) + { + PatientDiedCount++; + if (PatientDiedCount > 5 && Event) + { + if(player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) + player->FailQuest(6624); + else if(player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) + player->FailQuest(6622); + + Event = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + Coordinates.push_back(Point); + } +} + +void npc_doctorAI::PatientSaved(Creature* soldier, Player* player, Location* Point) +{ + if(player && Playerguid == player->GetGUID()) + { + if((player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) + { + PatientSavedCount++; + if(PatientSavedCount == 15) + { + if(!Patients.empty()) + { + std::list::iterator itr; + for(itr = Patients.begin(); itr != Patients.end(); ++itr) + { + Creature* Patient = ((Creature*)Unit::GetUnit((*m_creature), *itr)); + if( Patient ) + Patient->setDeathState(JUST_DIED); + } + } + + if(player->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(6624); + else if(player->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(6622); + + Event = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + Coordinates.push_back(Point); + } + } +} + +void npc_doctorAI::UpdateAI(const uint32 diff) +{ + if(Event && SummonPatientCount >= 20) + { + Event = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + if(Event) + if(SummonPatient_Timer < diff) + { + Creature* Patient = NULL; + Location* Point = NULL; + + if(Coordinates.empty()) + return; + + std::vector::iterator itr = Coordinates.begin()+rand()%Coordinates.size(); + uint32 patientEntry = 0; + + switch(m_creature->GetEntry()) + { + case DOCTOR_ALLIANCE: patientEntry = AllianceSoldierId[rand()%3]; break; + case DOCTOR_HORDE: patientEntry = HordeSoldierId[rand()%3]; break; + default: + error_log("SD2: 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) + { + Patients.push_back(Patient->GetGUID()); + ((npc_injured_patientAI*)Patient->AI())->Doctorguid = m_creature->GetGUID(); + if(Point) + ((npc_injured_patientAI*)Patient->AI())->Coord = Point; + Coordinates.erase(itr); + } + SummonPatient_Timer = 10000; + SummonPatientCount++; + }else SummonPatient_Timer -= diff; +} + +bool QuestAccept_npc_doctor(Player *player, Creature *creature, Quest const *quest ) +{ + if((quest->GetQuestId() == 6624) || (quest->GetQuestId() == 6622)) + ((npc_doctorAI*)creature->AI())->BeginEvent(player); + + return true; +} + +CreatureAI* GetAI_npc_doctor(Creature *_Creature) +{ + return new npc_doctorAI (_Creature); +} + +/*###### +## npc_guardian +######*/ + +#define SPELL_DEATHTOUCH 5 +#define SAY_AGGRO "This area is closed!" + +struct MANGOS_DLL_DECL npc_guardianAI : public ScriptedAI +{ + npc_guardianAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (m_creature->isAttackReady()) + { + m_creature->CastSpell(m_creature->getVictim(),SPELL_DEATHTOUCH, true); + m_creature->resetAttackTimer(); + } + } +}; + +CreatureAI* GetAI_npc_guardian(Creature *_Creature) +{ + return new npc_guardianAI (_Creature); +} + +/*###### +## npc_mount_vendor +######*/ + +bool GossipHello_npc_mount_vendor(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + bool canBuy; + canBuy = false; + uint32 vendor = _Creature->GetEntry(); + uint8 race = player->getRace(); + + switch (vendor) + { + case 384: //Katie Hunter + case 1460: //Unger Statforth + case 2357: //Merideth Carlson + case 4885: //Gregor MacVince + if (player->GetReputationRank(72) != REP_EXALTED && race != RACE_HUMAN) + player->SEND_GOSSIP_MENU(5855, _Creature->GetGUID()); + else canBuy = true; + break; + case 1261: //Veron Amberstill + if (player->GetReputationRank(47) != REP_EXALTED && race != RACE_DWARF) + player->SEND_GOSSIP_MENU(5856, _Creature->GetGUID()); + else canBuy = true; + break; + case 3362: //Ogunaro Wolfrunner + if (player->GetReputationRank(76) != REP_EXALTED && race != RACE_ORC) + player->SEND_GOSSIP_MENU(5841, _Creature->GetGUID()); + else canBuy = true; + break; + case 3685: //Harb Clawhoof + if (player->GetReputationRank(81) != REP_EXALTED && race != RACE_TAUREN) + player->SEND_GOSSIP_MENU(5843, _Creature->GetGUID()); + else canBuy = true; + break; + case 4730: //Lelanai + if (player->GetReputationRank(69) != REP_EXALTED && race != RACE_NIGHTELF) + player->SEND_GOSSIP_MENU(5844, _Creature->GetGUID()); + else canBuy = true; + break; + case 4731: //Zachariah Post + if (player->GetReputationRank(68) != REP_EXALTED && race != RACE_UNDEAD_PLAYER) + player->SEND_GOSSIP_MENU(5840, _Creature->GetGUID()); + else canBuy = true; + break; + case 7952: //Zjolnir + if (player->GetReputationRank(530) != REP_EXALTED && race != RACE_TROLL) + player->SEND_GOSSIP_MENU(5842, _Creature->GetGUID()); + else canBuy = true; + break; + case 7955: //Milli Featherwhistle + if (player->GetReputationRank(54) != REP_EXALTED && race != RACE_GNOME) + player->SEND_GOSSIP_MENU(5857, _Creature->GetGUID()); + else canBuy = true; + break; + case 16264: //Winaestra + if (player->GetReputationRank(911) != REP_EXALTED && race != RACE_BLOODELF) + player->SEND_GOSSIP_MENU(10305, _Creature->GetGUID()); + else canBuy = true; + break; + case 17584: //Torallius the Pack Handler + if (player->GetReputationRank(930) != REP_EXALTED && race != RACE_DRAENEI) + player->SEND_GOSSIP_MENU(10239, _Creature->GetGUID()); + else canBuy = true; + break; + } + + if (canBuy) + { + if (_Creature->isVendor()) + player->ADD_GOSSIP_ITEM( 1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + } + return true; +} + +bool GossipSelect_npc_mount_vendor(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_TRADE) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + + return true; +} + +/*###### +## npc_rogue_trainer +######*/ + +bool GossipHello_npc_rogue_trainer(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( _Creature->isTrainer() ) + player->ADD_GOSSIP_ITEM(2, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); + + if( _Creature->isCanTrainingAndResetTalentsOf(player) ) + player->ADD_GOSSIP_ITEM(2, "I wish to unlearn my talents", GOSSIP_SENDER_MAIN, GOSSIP_OPTION_UNLEARNTALENTS); + + if( player->getClass() == CLASS_ROGUE && player->getLevel() >= 24 && !player->HasItemCount(17126,1) && !player->GetQuestRewardStatus(6681) ) + { + player->ADD_GOSSIP_ITEM(0, "", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(5996, _Creature->GetGUID()); + } else + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_rogue_trainer(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch( action ) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,21100,false); + break; + case GOSSIP_ACTION_TRAIN: + player->SEND_TRAINERLIST( _Creature->GetGUID() ); + break; + case GOSSIP_OPTION_UNLEARNTALENTS: + player->CLOSE_GOSSIP_MENU(); + player->SendTalentWipeConfirm( _Creature->GetGUID() ); + break; + } + return true; +} + +/*###### +## npc_sayge +######*/ + +#define SPELL_DMG 23768 //dmg +#define SPELL_RES 23769 //res +#define SPELL_ARM 23767 //arm +#define SPELL_SPI 23738 //spi +#define SPELL_INT 23766 //int +#define SPELL_STM 23737 //stm +#define SPELL_STR 23735 //str +#define SPELL_AGI 23736 //agi +#define SPELL_FORTUNE 23765 //faire fortune + +bool GossipHello_npc_sayge(Player *player, Creature *_Creature) +{ + if(_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->HasSpellCooldown(SPELL_INT) || + player->HasSpellCooldown(SPELL_ARM) || + player->HasSpellCooldown(SPELL_DMG) || + player->HasSpellCooldown(SPELL_RES) || + player->HasSpellCooldown(SPELL_STR) || + player->HasSpellCooldown(SPELL_AGI) || + player->HasSpellCooldown(SPELL_STM) || + player->HasSpellCooldown(SPELL_SPI) ) + player->SEND_GOSSIP_MENU(7393, _Creature->GetGUID()); + else + { + player->ADD_GOSSIP_ITEM(0, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(7339, _Creature->GetGUID()); + } + + return true; +} + +void SendAction_npc_sayge(Player *player, Creature *_Creature, uint32 action) +{ + switch(action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, "Slay the Man", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->ADD_GOSSIP_ITEM(0, "Turn him over to liege", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->ADD_GOSSIP_ITEM(0, "Confiscate the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->ADD_GOSSIP_ITEM(0, "Let him go and have the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(7340, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM(0, "Execute your friend painfully", GOSSIP_SENDER_MAIN+1, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Execute your friend painlessly", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Let your friend go", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(7341, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM(0, "Confront the diplomat", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Show not so quiet defiance", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Remain quiet", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(7361, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM(0, "Speak against your brother openly", GOSSIP_SENDER_MAIN+6, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Help your brother in", GOSSIP_SENDER_MAIN+7, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Keep your brother out without letting him know", GOSSIP_SENDER_MAIN+8, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(7362, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM(0, "Take credit, keep gold", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Take credit, share the gold", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); + player->ADD_GOSSIP_ITEM(0, "Let the knight take credit", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(7363, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM(0, "Thanks", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + player->SEND_GOSSIP_MENU(7364, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + _Creature->CastSpell(player, SPELL_FORTUNE, false); + player->SEND_GOSSIP_MENU(7365, _Creature->GetGUID()); + break; + } +} + +bool GossipSelect_npc_sayge(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(sender) + { + case GOSSIP_SENDER_MAIN: + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+1: + _Creature->CastSpell(player, SPELL_DMG, false); + player->AddSpellCooldown(SPELL_DMG,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+2: + _Creature->CastSpell(player, SPELL_RES, false); + player->AddSpellCooldown(SPELL_RES,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+3: + _Creature->CastSpell(player, SPELL_ARM, false); + player->AddSpellCooldown(SPELL_ARM,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+4: + _Creature->CastSpell(player, SPELL_SPI, false); + player->AddSpellCooldown(SPELL_SPI,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+5: + _Creature->CastSpell(player, SPELL_INT, false); + player->AddSpellCooldown(SPELL_INT,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+6: + _Creature->CastSpell(player, SPELL_STM, false); + player->AddSpellCooldown(SPELL_STM,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+7: + _Creature->CastSpell(player, SPELL_STR, false); + player->AddSpellCooldown(SPELL_STR,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + case GOSSIP_SENDER_MAIN+8: + _Creature->CastSpell(player, SPELL_AGI, false); + player->AddSpellCooldown(SPELL_AGI,0,time(NULL) + 7200); + SendAction_npc_sayge(player, _Creature, action); + break; + } + return true; +} + +void AddSC_npcs_special() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_chicken_cluck"; + newscript->GetAI = GetAI_npc_chicken_cluck; + newscript->pReceiveEmote = &ReceiveEmote_npc_chicken_cluck; + newscript->pQuestAccept = &QuestAccept_npc_chicken_cluck; + newscript->pQuestComplete = &QuestComplete_npc_chicken_cluck; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_dancing_flames"; + newscript->pReceiveEmote = &ReceiveEmote_npc_dancing_flames; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_injured_patient"; + newscript->GetAI = GetAI_npc_injured_patient; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_doctor"; + newscript->GetAI = GetAI_npc_doctor; + newscript->pQuestAccept = &QuestAccept_npc_doctor; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_guardian"; + newscript->GetAI = GetAI_npc_guardian; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_mount_vendor"; + newscript->pGossipHello = &GossipHello_npc_mount_vendor; + newscript->pGossipSelect = &GossipSelect_npc_mount_vendor; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_rogue_trainer"; + newscript->pGossipHello = &GossipHello_npc_rogue_trainer; + newscript->pGossipSelect = &GossipSelect_npc_rogue_trainer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_sayge"; + newscript->pGossipHello = &GossipHello_npc_sayge; + newscript->pGossipSelect = &GossipSelect_npc_sayge; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/alterac_mountains/alterac_mountains.cpp b/src/bindings/scripts/scripts/zone/alterac_mountains/alterac_mountains.cpp index 074bf2967b2..b306e38818e 100644 --- a/src/bindings/scripts/scripts/zone/alterac_mountains/alterac_mountains.cpp +++ b/src/bindings/scripts/scripts/zone/alterac_mountains/alterac_mountains.cpp @@ -1,62 +1,62 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Alterac_Mountains -SD%Complete: 100 -SDComment: Quest support: 6681 -SDCategory: Alterac Mountains -EndScriptData */ - -/* ContentData -npc_ravenholdt -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_ravenholdt -######*/ - -struct MANGOS_DLL_DECL npc_ravenholdtAI : public ScriptedAI -{ - npc_ravenholdtAI(Creature *c) : ScriptedAI(c) { Reset(); } - - void Reset() { } - - void MoveInLineOfSight(Unit *who) - { - if( who->GetTypeId() == TYPEID_PLAYER ) - if( ((Player*)who)->GetQuestStatus(6681) == QUEST_STATUS_INCOMPLETE ) - ((Player*)who)->KilledMonster(m_creature->GetEntry(),m_creature->GetGUID() ); - } - - void Aggro(Unit* who) { } -}; -CreatureAI* GetAI_npc_ravenholdt(Creature *_Creature) -{ - return new npc_ravenholdtAI (_Creature); -} - -void AddSC_alterac_mountains() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_ravenholdt"; - newscript->GetAI = GetAI_npc_ravenholdt; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Alterac_Mountains +SD%Complete: 100 +SDComment: Quest support: 6681 +SDCategory: Alterac Mountains +EndScriptData */ + +/* ContentData +npc_ravenholdt +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_ravenholdt +######*/ + +struct MANGOS_DLL_DECL npc_ravenholdtAI : public ScriptedAI +{ + npc_ravenholdtAI(Creature *c) : ScriptedAI(c) { Reset(); } + + void Reset() { } + + void MoveInLineOfSight(Unit *who) + { + if( who->GetTypeId() == TYPEID_PLAYER ) + if( ((Player*)who)->GetQuestStatus(6681) == QUEST_STATUS_INCOMPLETE ) + ((Player*)who)->KilledMonster(m_creature->GetEntry(),m_creature->GetGUID() ); + } + + void Aggro(Unit* who) { } +}; +CreatureAI* GetAI_npc_ravenholdt(Creature *_Creature) +{ + return new npc_ravenholdtAI (_Creature); +} + +void AddSC_alterac_mountains() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_ravenholdt"; + newscript->GetAI = GetAI_npc_ravenholdt; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp index 77b0d7eaedd..529d117aa40 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp @@ -1,405 +1,405 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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. -SDCategory: Auchindoun, Auchenai Crypts -EndScriptData */ - -/* ContentData -mob_stolen_soul -boss_exarch_maladaar -mob_avatar_of_martyred -EndContentData */ - -#include "precompiled.h" - -#define SPELL_MOONFIRE 37328 -#define SPELL_FIREBALL 37329 -#define SPELL_MIND_FLAY 37330 -#define SPELL_HEMORRHAGE 37331 -#define SPELL_FROSTSHOCK 37332 -#define SPELL_CURSE_OF_AGONY 37334 -#define SPELL_MORTAL_STRIKE 37335 -#define SPELL_FREEZING_TRAP 37368 -#define SPELL_HAMMER_OF_JUSTICE 37369 - -struct MANGOS_DLL_DECL mob_stolen_soulAI : public ScriptedAI -{ - mob_stolen_soulAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint8 myClass; - uint32 Class_Timer; - - void Reset() - { - Class_Timer = 1000; - } - - void Aggro(Unit *who) - { } - - void SetMyClass(uint8 myclass) - { - myClass = myclass; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( Class_Timer < diff ) - { - switch( myClass ) - { - case CLASS_WARRIOR: - DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); - Class_Timer = 6000; - break; - case CLASS_PALADIN: - DoCast(m_creature->getVictim(), SPELL_HAMMER_OF_JUSTICE); - Class_Timer = 6000; - break; - case CLASS_HUNTER: - DoCast(m_creature->getVictim(), SPELL_FREEZING_TRAP); - Class_Timer = 20000; - break; - case CLASS_ROGUE: - DoCast(m_creature->getVictim(), SPELL_HEMORRHAGE); - Class_Timer = 10000; - break; - case CLASS_PRIEST: - DoCast(m_creature->getVictim(), SPELL_MIND_FLAY); - Class_Timer = 5000; - break; - case CLASS_SHAMAN: - DoCast(m_creature->getVictim(), SPELL_FROSTSHOCK); - Class_Timer = 8000; - break; - case CLASS_MAGE: - DoCast(m_creature->getVictim(), SPELL_FIREBALL); - Class_Timer = 5000; - break; - case CLASS_WARLOCK: - DoCast(m_creature->getVictim(), SPELL_CURSE_OF_AGONY); - Class_Timer = 20000; - break; - case CLASS_DRUID: - DoCast(m_creature->getVictim(), SPELL_MOONFIRE); - Class_Timer = 10000; - break; - default: - break; - } - }else Class_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_stolen_soul(Creature *_Creature) -{ - return new mob_stolen_soulAI (_Creature); -} - -#define SAY_INTRO "You have defiled the resting place of our ancestors. For this offense, there can be but one punishment. It is fitting that you have come to a place of the dead... for you will soon be joining them." -#define SOUND_INTRO 10509 -#define SAY_SUMMON "Rise my fallen brothers. Take form and fight!" -#define SOUND_SUMMON 10512 - -#define SAY_AGGRO_1 "You will pay with your life!" -#define SOUND_AGGRO_1 10513 -#define SAY_AGGRO_2 "There's no turning back now!" -#define SOUND_AGGRO_2 10514 -#define SAY_AGGRO_3 "Serve your penitence!" -#define SOUND_AGGRO_3 10515 - -#define SAY_ROAR "Let your mind be clouded." -#define SOUND_ROAR 10510 -#define SAY_SOUL_CLEAVE "Stare into the darkness of your soul." -#define SOUND_SOUL_CLEAVE 10511 - -#define SAY_SLAY_1 "These walls will be your doom." -#define SOUND_SLAY_1 10516 -#define SAY_SLAY_2 " Now, you'll stay for eternity!" -#define SOUND_SLAY_2 10517 - -#define SAY_DEATH "This is... where.. I belong..." -#define SOUND_DEATH 10518 - -#define SPELL_RIBBON_OF_SOULS 32422 -#define SPELL_SOUL_SCREAM 32421 - -#define SPELL_STOLEN_SOUL 32346 -#define SPELL_STOLEN_SOUL_VISUAL 32395 - -#define SPELL_SUMMON_AVATAR 32424 - -#define ENTRY_STOLEN_SOUL 18441 - -struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI -{ - boss_exarch_maladaarAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 soulmodel; - uint64 soulholder; - uint8 soulclass; - - uint32 Fear_timer; - uint32 Ribbon_of_Souls_timer; - uint32 StolenSoul_Timer; - - bool HasTaunted; - bool Avatar_summoned; - - void Reset() - { - soulmodel = 0; - soulholder = 0; - soulclass = 0; - - Fear_timer = 20000; - Ribbon_of_Souls_timer = 5000; - StolenSoul_Timer = 30000; - - HasTaunted = false; - Avatar_summoned = false; - } - - void MoveInLineOfSight(Unit *who) - { - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if( !HasTaunted && m_creature->IsWithinDistInMap(who, 150.0) ) - { - DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_INTRO); - HasTaunted = true; - } - - if (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) ) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - } - - void JustSummoned(Creature *summoned) - { - if( summoned->GetEntry() == ENTRY_STOLEN_SOUL ) - { - //SPELL_STOLEN_SOUL_VISUAL has shapeshift effect, but not implemented feature in mangos for this spell. - summoned->SetDisplayId(soulmodel); - summoned->CastSpell(summoned,SPELL_STOLEN_SOUL_VISUAL,false); - - if( Unit *target = Unit::GetUnit(*m_creature,soulholder) ) - summoned->AI()->AttackStart(target); - - ((mob_stolen_soulAI*)summoned->AI())->SetMyClass(soulclass); - } - } - - void KilledUnit(Unit* victim) - { - if (rand()%2) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - - //When Exarch Maladar is defeated D'ore appear. - DoSpawnCreature(19412,0,0,0,0, TEMPSUMMON_TIMED_DESPAWN, 600000); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( !Avatar_summoned && ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 25) ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - DoYell(SAY_SUMMON, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SUMMON); - - DoCast(m_creature, SPELL_SUMMON_AVATAR); - Avatar_summoned = true; - StolenSoul_Timer = 45000; - } - - if( StolenSoul_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - { - if( target->GetTypeId() == TYPEID_PLAYER ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - uint32 i = urand(1,2); - if( i == 1 ) - { - DoYell(SAY_ROAR, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_ROAR); - } - else - { - DoYell(SAY_SOUL_CLEAVE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SOUL_CLEAVE); - } - - soulmodel = target->GetDisplayId(); - soulholder = target->GetGUID(); - soulclass = target->getClass(); - - DoCast(target,SPELL_STOLEN_SOUL); - DoSpawnCreature(ENTRY_STOLEN_SOUL,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - - StolenSoul_Timer = 45000; - } else StolenSoul_Timer = 1000; - } - }else StolenSoul_Timer -= diff; - - if( Ribbon_of_Souls_timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_RIBBON_OF_SOULS); - - Ribbon_of_Souls_timer = 5000 + (rand()%20 * 1000); - }else Ribbon_of_Souls_timer -= diff; - - if( Fear_timer < diff ) - { - DoCast(m_creature,SPELL_SOUL_SCREAM); - Fear_timer = 25000 + rand()% 10000; - }else Fear_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_exarch_maladaar(Creature *_Creature) -{ - return new boss_exarch_maladaarAI (_Creature); -} - -#define SPELL_MORTAL_STRIKE 16856 -#define SPELL_SUNDER_ARMOR 16145 - -struct MANGOS_DLL_DECL mob_avatar_of_martyredAI : public ScriptedAI -{ - mob_avatar_of_martyredAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Mortal_Strike_timer; - - void Reset() - { - Mortal_Strike_timer = 10000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(Mortal_Strike_timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); - Mortal_Strike_timer = 10000 + rand()%20 * 1000; - }else Mortal_Strike_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_avatar_of_martyred(Creature *_Creature) -{ - return new mob_avatar_of_martyredAI (_Creature); -} - -void AddSC_boss_exarch_maladaar() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_exarch_maladaar"; - newscript->GetAI = GetAI_boss_exarch_maladaar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_avatar_of_martyred"; - newscript->GetAI = GetAI_mob_avatar_of_martyred; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_stolen_soul"; - newscript->GetAI = GetAI_mob_stolen_soul; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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. +SDCategory: Auchindoun, Auchenai Crypts +EndScriptData */ + +/* ContentData +mob_stolen_soul +boss_exarch_maladaar +mob_avatar_of_martyred +EndContentData */ + +#include "precompiled.h" + +#define SPELL_MOONFIRE 37328 +#define SPELL_FIREBALL 37329 +#define SPELL_MIND_FLAY 37330 +#define SPELL_HEMORRHAGE 37331 +#define SPELL_FROSTSHOCK 37332 +#define SPELL_CURSE_OF_AGONY 37334 +#define SPELL_MORTAL_STRIKE 37335 +#define SPELL_FREEZING_TRAP 37368 +#define SPELL_HAMMER_OF_JUSTICE 37369 + +struct MANGOS_DLL_DECL mob_stolen_soulAI : public ScriptedAI +{ + mob_stolen_soulAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint8 myClass; + uint32 Class_Timer; + + void Reset() + { + Class_Timer = 1000; + } + + void Aggro(Unit *who) + { } + + void SetMyClass(uint8 myclass) + { + myClass = myclass; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( Class_Timer < diff ) + { + switch( myClass ) + { + case CLASS_WARRIOR: + DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); + Class_Timer = 6000; + break; + case CLASS_PALADIN: + DoCast(m_creature->getVictim(), SPELL_HAMMER_OF_JUSTICE); + Class_Timer = 6000; + break; + case CLASS_HUNTER: + DoCast(m_creature->getVictim(), SPELL_FREEZING_TRAP); + Class_Timer = 20000; + break; + case CLASS_ROGUE: + DoCast(m_creature->getVictim(), SPELL_HEMORRHAGE); + Class_Timer = 10000; + break; + case CLASS_PRIEST: + DoCast(m_creature->getVictim(), SPELL_MIND_FLAY); + Class_Timer = 5000; + break; + case CLASS_SHAMAN: + DoCast(m_creature->getVictim(), SPELL_FROSTSHOCK); + Class_Timer = 8000; + break; + case CLASS_MAGE: + DoCast(m_creature->getVictim(), SPELL_FIREBALL); + Class_Timer = 5000; + break; + case CLASS_WARLOCK: + DoCast(m_creature->getVictim(), SPELL_CURSE_OF_AGONY); + Class_Timer = 20000; + break; + case CLASS_DRUID: + DoCast(m_creature->getVictim(), SPELL_MOONFIRE); + Class_Timer = 10000; + break; + default: + break; + } + }else Class_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_stolen_soul(Creature *_Creature) +{ + return new mob_stolen_soulAI (_Creature); +} + +#define SAY_INTRO "You have defiled the resting place of our ancestors. For this offense, there can be but one punishment. It is fitting that you have come to a place of the dead... for you will soon be joining them." +#define SOUND_INTRO 10509 +#define SAY_SUMMON "Rise my fallen brothers. Take form and fight!" +#define SOUND_SUMMON 10512 + +#define SAY_AGGRO_1 "You will pay with your life!" +#define SOUND_AGGRO_1 10513 +#define SAY_AGGRO_2 "There's no turning back now!" +#define SOUND_AGGRO_2 10514 +#define SAY_AGGRO_3 "Serve your penitence!" +#define SOUND_AGGRO_3 10515 + +#define SAY_ROAR "Let your mind be clouded." +#define SOUND_ROAR 10510 +#define SAY_SOUL_CLEAVE "Stare into the darkness of your soul." +#define SOUND_SOUL_CLEAVE 10511 + +#define SAY_SLAY_1 "These walls will be your doom." +#define SOUND_SLAY_1 10516 +#define SAY_SLAY_2 " Now, you'll stay for eternity!" +#define SOUND_SLAY_2 10517 + +#define SAY_DEATH "This is... where.. I belong..." +#define SOUND_DEATH 10518 + +#define SPELL_RIBBON_OF_SOULS 32422 +#define SPELL_SOUL_SCREAM 32421 + +#define SPELL_STOLEN_SOUL 32346 +#define SPELL_STOLEN_SOUL_VISUAL 32395 + +#define SPELL_SUMMON_AVATAR 32424 + +#define ENTRY_STOLEN_SOUL 18441 + +struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI +{ + boss_exarch_maladaarAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 soulmodel; + uint64 soulholder; + uint8 soulclass; + + uint32 Fear_timer; + uint32 Ribbon_of_Souls_timer; + uint32 StolenSoul_Timer; + + bool HasTaunted; + bool Avatar_summoned; + + void Reset() + { + soulmodel = 0; + soulholder = 0; + soulclass = 0; + + Fear_timer = 20000; + Ribbon_of_Souls_timer = 5000; + StolenSoul_Timer = 30000; + + HasTaunted = false; + Avatar_summoned = false; + } + + void MoveInLineOfSight(Unit *who) + { + if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) + { + if( !HasTaunted && m_creature->IsWithinDistInMap(who, 150.0) ) + { + DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_INTRO); + HasTaunted = true; + } + + 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) ) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + } + + void JustSummoned(Creature *summoned) + { + if( summoned->GetEntry() == ENTRY_STOLEN_SOUL ) + { + //SPELL_STOLEN_SOUL_VISUAL has shapeshift effect, but not implemented feature in mangos for this spell. + summoned->SetDisplayId(soulmodel); + summoned->CastSpell(summoned,SPELL_STOLEN_SOUL_VISUAL,false); + + if( Unit *target = Unit::GetUnit(*m_creature,soulholder) ) + summoned->AI()->AttackStart(target); + + ((mob_stolen_soulAI*)summoned->AI())->SetMyClass(soulclass); + } + } + + void KilledUnit(Unit* victim) + { + if (rand()%2) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + + //When Exarch Maladar is defeated D'ore appear. + DoSpawnCreature(19412,0,0,0,0, TEMPSUMMON_TIMED_DESPAWN, 600000); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( !Avatar_summoned && ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 25) ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + DoYell(SAY_SUMMON, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SUMMON); + + DoCast(m_creature, SPELL_SUMMON_AVATAR); + Avatar_summoned = true; + StolenSoul_Timer = 45000; + } + + if( StolenSoul_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + { + if( target->GetTypeId() == TYPEID_PLAYER ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + uint32 i = urand(1,2); + if( i == 1 ) + { + DoYell(SAY_ROAR, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_ROAR); + } + else + { + DoYell(SAY_SOUL_CLEAVE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SOUL_CLEAVE); + } + + soulmodel = target->GetDisplayId(); + soulholder = target->GetGUID(); + soulclass = target->getClass(); + + DoCast(target,SPELL_STOLEN_SOUL); + DoSpawnCreature(ENTRY_STOLEN_SOUL,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + + StolenSoul_Timer = 45000; + } else StolenSoul_Timer = 1000; + } + }else StolenSoul_Timer -= diff; + + if( Ribbon_of_Souls_timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_RIBBON_OF_SOULS); + + Ribbon_of_Souls_timer = 5000 + (rand()%20 * 1000); + }else Ribbon_of_Souls_timer -= diff; + + if( Fear_timer < diff ) + { + DoCast(m_creature,SPELL_SOUL_SCREAM); + Fear_timer = 25000 + rand()% 10000; + }else Fear_timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_exarch_maladaar(Creature *_Creature) +{ + return new boss_exarch_maladaarAI (_Creature); +} + +#define SPELL_MORTAL_STRIKE 16856 +#define SPELL_SUNDER_ARMOR 16145 + +struct MANGOS_DLL_DECL mob_avatar_of_martyredAI : public ScriptedAI +{ + mob_avatar_of_martyredAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Mortal_Strike_timer; + + void Reset() + { + Mortal_Strike_timer = 10000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(Mortal_Strike_timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); + Mortal_Strike_timer = 10000 + rand()%20 * 1000; + }else Mortal_Strike_timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_avatar_of_martyred(Creature *_Creature) +{ + return new mob_avatar_of_martyredAI (_Creature); +} + +void AddSC_boss_exarch_maladaar() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_exarch_maladaar"; + newscript->GetAI = GetAI_boss_exarch_maladaar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_avatar_of_martyred"; + newscript->GetAI = GetAI_mob_avatar_of_martyred; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_stolen_soul"; + newscript->GetAI = GetAI_mob_stolen_soul; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp index 7191ea7a663..0583638cfc2 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp @@ -1,313 +1,313 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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. -SDCategory: Auchindoun, Mana Tombs -EndScriptData */ - -/* ContentData -boss_nexusprince_shaffar -mob_ethereal_beacon -EndContentData */ - -#include "precompiled.h" - -#define SAY_INTRO "What is this? You must forgive me, but I was not expecting company. As you can see, we are somewhat preoccupied right now. But no matter. As I am a gracious host, I will tend to you... personally." -#define SOUND_INTRO 10539 - -#define SAY_AGGRO_1 "We have not yet been properly introduced." -#define SOUND_AGGRO_1 10541 -#define SAY_AGGRO_2 "An epic battle. How exciting!" -#define SOUND_AGGRO_2 10542 -#define SAY_AGGRO_3 "I have longed for a good adventure." -#define SOUND_AGGRO_3 10543 - -#define SAY_SLAY_1 "It has been... entertaining." -#define SOUND_SLAY_1 10544 -#define SAY_SLAY_2 "And now we part company." -#define SOUND_SLAY_2 10545 - -#define SAY_SUMMON "I have such fascinating things to show you." -#define SOUND_SUMMON 10540 - -#define SAY_DEAD "I must bid you... farewell." -#define SOUND_DEAD 10546 - -#define SPELL_BLINK 34605 -#define SPELL_FROSTBOLT 32364 -#define SPELL_FIREBALL 32363 -#define SPELL_FROSTNOVA 32365 - -#define SPELL_ETHEREAL_BEACON 32371 // Summon 18431 -#define SPELL_ETHEREAL_BEACON_VISUAL 32368 - -#define ENTRY_BEACON 18431 - -struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI -{ - boss_nexusprince_shaffarAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Blink_Timer; - uint32 Beacon_Timer; - uint32 FireBall_Timer; - uint32 Frostbolt_Timer; - uint32 FrostNova_Timer; - - bool HasTaunted; - bool CanBlink; - - void Reset() - { - Blink_Timer = 1500; - Beacon_Timer = 10000; - FireBall_Timer = 8000; - Frostbolt_Timer = 4000; - FrostNova_Timer = 15000; - - HasTaunted = false; - CanBlink = false; - } - - void MoveInLineOfSight(Unit *who) - { - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if( !HasTaunted && m_creature->IsWithinDistInMap(who, 100.0) ) - { - DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_INTRO); - HasTaunted = true; - } - - if (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) ) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - } - - void JustSummoned(Creature *summoned) - { - if( summoned->GetEntry() == ENTRY_BEACON ) - { - summoned->CastSpell(summoned,SPELL_ETHEREAL_BEACON_VISUAL,false); - - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - summoned->AI()->AttackStart(target); - } - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEAD, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEAD); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( FrostNova_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - DoCast(m_creature,SPELL_FROSTNOVA); - FrostNova_Timer = 17500 + rand()%7500; - CanBlink = true; - }else FrostNova_Timer -= diff; - - if( Frostbolt_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_FROSTBOLT); - Frostbolt_Timer = 4500 + rand()%1500; - }else Frostbolt_Timer -= diff; - - if( FireBall_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_FIREBALL); - FireBall_Timer = 4500 + rand()%1500; - }else FireBall_Timer -= diff; - - if( CanBlink ) - { - if( Blink_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - DoCast(m_creature,SPELL_BLINK); - Blink_Timer = 1000 + rand()%1500; - CanBlink = false; - }else Blink_Timer -= diff; - } - - if( Beacon_Timer < diff) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - if( !urand(0,3) ) - { - DoYell(SAY_SUMMON, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SUMMON); - } - DoCast(m_creature,SPELL_ETHEREAL_BEACON); - - Beacon_Timer = 10000; - }else Beacon_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_nexusprince_shaffar(Creature *_Creature) -{ - return new boss_nexusprince_shaffarAI (_Creature); -} - -#define SPELL_ARCANE_BOLT 15254 -#define SPELL_ETHEREAL_APPRENTICE 32372 // Summon 18430 - -struct MANGOS_DLL_DECL mob_ethereal_beaconAI : public ScriptedAI -{ - mob_ethereal_beaconAI(Creature *c) : ScriptedAI(c) - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - Reset(); - } - - bool HeroicMode; - bool CanEvade; - uint32 Apprentice_Timer; - uint32 ArcaneBolt_Timer; - - void Reset() - { - if( CanEvade ) - m_creature->SetVisibility(VISIBILITY_OFF); - - CanEvade = false; - Apprentice_Timer = (HeroicMode ? 10000 : 20000); - ArcaneBolt_Timer = 1000; - } - - void Aggro(Unit *who) - { - } - - void JustSummoned(Creature *summoned) - { - summoned->AI()->AttackStart(m_creature->getVictim()); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( ArcaneBolt_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_ARCANE_BOLT); - ArcaneBolt_Timer = 2000 + rand()%2500; - }else ArcaneBolt_Timer -= diff; - - if( Apprentice_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - m_creature->CastSpell(m_creature,SPELL_ETHEREAL_APPRENTICE,true); - if( m_creature->GetOwner() ) - ((Pet*)m_creature)->SetDuration(0); - CanEvade = true; - }else Apprentice_Timer -= diff; - - if( CanEvade ) - EnterEvadeMode(); - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_ethereal_beacon(Creature *_Creature) -{ - return new mob_ethereal_beaconAI (_Creature); -} - -void AddSC_boss_nexusprince_shaffar() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_nexusprince_shaffar"; - newscript->GetAI = GetAI_boss_nexusprince_shaffar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_ethereal_beacon"; - newscript->GetAI = GetAI_mob_ethereal_beacon; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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. +SDCategory: Auchindoun, Mana Tombs +EndScriptData */ + +/* ContentData +boss_nexusprince_shaffar +mob_ethereal_beacon +EndContentData */ + +#include "precompiled.h" + +#define SAY_INTRO "What is this? You must forgive me, but I was not expecting company. As you can see, we are somewhat preoccupied right now. But no matter. As I am a gracious host, I will tend to you... personally." +#define SOUND_INTRO 10539 + +#define SAY_AGGRO_1 "We have not yet been properly introduced." +#define SOUND_AGGRO_1 10541 +#define SAY_AGGRO_2 "An epic battle. How exciting!" +#define SOUND_AGGRO_2 10542 +#define SAY_AGGRO_3 "I have longed for a good adventure." +#define SOUND_AGGRO_3 10543 + +#define SAY_SLAY_1 "It has been... entertaining." +#define SOUND_SLAY_1 10544 +#define SAY_SLAY_2 "And now we part company." +#define SOUND_SLAY_2 10545 + +#define SAY_SUMMON "I have such fascinating things to show you." +#define SOUND_SUMMON 10540 + +#define SAY_DEAD "I must bid you... farewell." +#define SOUND_DEAD 10546 + +#define SPELL_BLINK 34605 +#define SPELL_FROSTBOLT 32364 +#define SPELL_FIREBALL 32363 +#define SPELL_FROSTNOVA 32365 + +#define SPELL_ETHEREAL_BEACON 32371 // Summon 18431 +#define SPELL_ETHEREAL_BEACON_VISUAL 32368 + +#define ENTRY_BEACON 18431 + +struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI +{ + boss_nexusprince_shaffarAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Blink_Timer; + uint32 Beacon_Timer; + uint32 FireBall_Timer; + uint32 Frostbolt_Timer; + uint32 FrostNova_Timer; + + bool HasTaunted; + bool CanBlink; + + void Reset() + { + Blink_Timer = 1500; + Beacon_Timer = 10000; + FireBall_Timer = 8000; + Frostbolt_Timer = 4000; + FrostNova_Timer = 15000; + + HasTaunted = false; + CanBlink = false; + } + + void MoveInLineOfSight(Unit *who) + { + if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) + { + if( !HasTaunted && m_creature->IsWithinDistInMap(who, 100.0) ) + { + DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_INTRO); + HasTaunted = true; + } + + 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) ) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + } + + void JustSummoned(Creature *summoned) + { + if( summoned->GetEntry() == ENTRY_BEACON ) + { + summoned->CastSpell(summoned,SPELL_ETHEREAL_BEACON_VISUAL,false); + + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + summoned->AI()->AttackStart(target); + } + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEAD, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEAD); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( FrostNova_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + DoCast(m_creature,SPELL_FROSTNOVA); + FrostNova_Timer = 17500 + rand()%7500; + CanBlink = true; + }else FrostNova_Timer -= diff; + + if( Frostbolt_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_FROSTBOLT); + Frostbolt_Timer = 4500 + rand()%1500; + }else Frostbolt_Timer -= diff; + + if( FireBall_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_FIREBALL); + FireBall_Timer = 4500 + rand()%1500; + }else FireBall_Timer -= diff; + + if( CanBlink ) + { + if( Blink_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + DoCast(m_creature,SPELL_BLINK); + Blink_Timer = 1000 + rand()%1500; + CanBlink = false; + }else Blink_Timer -= diff; + } + + if( Beacon_Timer < diff) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + if( !urand(0,3) ) + { + DoYell(SAY_SUMMON, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SUMMON); + } + DoCast(m_creature,SPELL_ETHEREAL_BEACON); + + Beacon_Timer = 10000; + }else Beacon_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_nexusprince_shaffar(Creature *_Creature) +{ + return new boss_nexusprince_shaffarAI (_Creature); +} + +#define SPELL_ARCANE_BOLT 15254 +#define SPELL_ETHEREAL_APPRENTICE 32372 // Summon 18430 + +struct MANGOS_DLL_DECL mob_ethereal_beaconAI : public ScriptedAI +{ + mob_ethereal_beaconAI(Creature *c) : ScriptedAI(c) + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + Reset(); + } + + bool HeroicMode; + bool CanEvade; + uint32 Apprentice_Timer; + uint32 ArcaneBolt_Timer; + + void Reset() + { + if( CanEvade ) + m_creature->SetVisibility(VISIBILITY_OFF); + + CanEvade = false; + Apprentice_Timer = (HeroicMode ? 10000 : 20000); + ArcaneBolt_Timer = 1000; + } + + void Aggro(Unit *who) + { + } + + void JustSummoned(Creature *summoned) + { + summoned->AI()->AttackStart(m_creature->getVictim()); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( ArcaneBolt_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_ARCANE_BOLT); + ArcaneBolt_Timer = 2000 + rand()%2500; + }else ArcaneBolt_Timer -= diff; + + if( Apprentice_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + m_creature->CastSpell(m_creature,SPELL_ETHEREAL_APPRENTICE,true); + if( m_creature->GetOwner() ) + ((Pet*)m_creature)->SetDuration(0); + CanEvade = true; + }else Apprentice_Timer -= diff; + + if( CanEvade ) + EnterEvadeMode(); + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_ethereal_beacon(Creature *_Creature) +{ + return new mob_ethereal_beaconAI (_Creature); +} + +void AddSC_boss_nexusprince_shaffar() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_nexusprince_shaffar"; + newscript->GetAI = GetAI_boss_nexusprince_shaffar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_ethereal_beacon"; + newscript->GetAI = GetAI_mob_ethereal_beacon; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_pandemonius.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_pandemonius.cpp index 25f26289e53..4b7d8907acb 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_pandemonius.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_pandemonius.cpp @@ -1,159 +1,159 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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. -SDCategory: Auchindoun, Mana Tombs -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO_1 "I will feed on your soul." -#define SOUND_AGGRO_1 10561 -#define SAY_AGGRO_2 "So... full of life!" -#define SOUND_AGGRO_2 10562 -#define SAY_AGGRO_3 "Do not... resist." -#define SOUND_AGGRO_3 10563 - -#define SAY_KILL_1 "Yes! I am... empowered!" -#define SOUND_KILL_1 10564 -#define SAY_KILL_2 "More... I must have more!" -#define SOUND_KILL_2 10565 - -#define SAY_DEATH "To the void... once... more.." -#define SOUND_DEATH 10566 - -#define EMOTE_DARK_SHELL "shifts into the void..." - -#define SPELL_VOID_BLAST 32325 -#define H_SPELL_VOID_BLAST 38760 -#define SPELL_DARK_SHELL 32358 -#define H_SPELL_DARK_SHELL 38759 - -struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI -{ - boss_pandemoniusAI(Creature *c) : ScriptedAI(c) - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - Reset(); - } - - bool HeroicMode; - uint32 VoidBlast_Timer; - uint32 DarkShell_Timer; - uint32 VoidBlast_Counter; - - void Reset() - { - VoidBlast_Timer = 30000; - DarkShell_Timer = 20000; - VoidBlast_Counter = 0; - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_2); - break; - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( VoidBlast_Timer < diff ) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0) ) - { - DoCast(target,HeroicMode ? H_SPELL_VOID_BLAST : SPELL_VOID_BLAST); - VoidBlast_Timer = 500; - ++VoidBlast_Counter; - } - - if( VoidBlast_Counter == 5 ) - { - VoidBlast_Timer = 25000+rand()%10000; - VoidBlast_Counter = 0; - } - }else VoidBlast_Timer -= diff; - - if( !VoidBlast_Counter ) - { - if( DarkShell_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - DoTextEmote(EMOTE_DARK_SHELL,NULL,true); - DoCast(m_creature,HeroicMode ? H_SPELL_DARK_SHELL : SPELL_DARK_SHELL); - DarkShell_Timer = 20000; - }else DarkShell_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_pandemonius(Creature *_Creature) -{ - return new boss_pandemoniusAI (_Creature); -} - -void AddSC_boss_pandemonius() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_pandemonius"; - newscript->GetAI = GetAI_boss_pandemonius; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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. +SDCategory: Auchindoun, Mana Tombs +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO_1 "I will feed on your soul." +#define SOUND_AGGRO_1 10561 +#define SAY_AGGRO_2 "So... full of life!" +#define SOUND_AGGRO_2 10562 +#define SAY_AGGRO_3 "Do not... resist." +#define SOUND_AGGRO_3 10563 + +#define SAY_KILL_1 "Yes! I am... empowered!" +#define SOUND_KILL_1 10564 +#define SAY_KILL_2 "More... I must have more!" +#define SOUND_KILL_2 10565 + +#define SAY_DEATH "To the void... once... more.." +#define SOUND_DEATH 10566 + +#define EMOTE_DARK_SHELL "shifts into the void..." + +#define SPELL_VOID_BLAST 32325 +#define H_SPELL_VOID_BLAST 38760 +#define SPELL_DARK_SHELL 32358 +#define H_SPELL_DARK_SHELL 38759 + +struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI +{ + boss_pandemoniusAI(Creature *c) : ScriptedAI(c) + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + Reset(); + } + + bool HeroicMode; + uint32 VoidBlast_Timer; + uint32 DarkShell_Timer; + uint32 VoidBlast_Counter; + + void Reset() + { + VoidBlast_Timer = 30000; + DarkShell_Timer = 20000; + VoidBlast_Counter = 0; + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_2); + break; + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( VoidBlast_Timer < diff ) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0) ) + { + DoCast(target,HeroicMode ? H_SPELL_VOID_BLAST : SPELL_VOID_BLAST); + VoidBlast_Timer = 500; + ++VoidBlast_Counter; + } + + if( VoidBlast_Counter == 5 ) + { + VoidBlast_Timer = 25000+rand()%10000; + VoidBlast_Counter = 0; + } + }else VoidBlast_Timer -= diff; + + if( !VoidBlast_Counter ) + { + if( DarkShell_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + DoTextEmote(EMOTE_DARK_SHELL,NULL,true); + DoCast(m_creature,HeroicMode ? H_SPELL_DARK_SHELL : SPELL_DARK_SHELL); + DarkShell_Timer = 20000; + }else DarkShell_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_pandemonius(Creature *_Creature) +{ + return new boss_pandemoniusAI (_Creature); +} + +void AddSC_boss_pandemonius() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_pandemonius"; + newscript->GetAI = GetAI_boss_pandemonius; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_darkweaver_syth.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_darkweaver_syth.cpp index 2be88f661af..c08f3cc66fd 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_darkweaver_syth.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_darkweaver_syth.cpp @@ -1,441 +1,441 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Darkweaver_Syth -SD%Complete: 85 -SDComment: Shock spells/times need more work. Heroic not implemented. -SDCategory: Auchindoun, Sethekk Halls -EndScriptData */ - -#include "precompiled.h" - -#define SAY_SUMMON "I have pets....of my own!" -#define SOUND_SUMMON 10502 - -#define SAY_AGGRO_1 "Hrrmm.. Time to.. hrrm.. make my move." -#define SOUND_AGGRO_1 10503 -#define SAY_AGGRO_2 "Nice pets..hrm.. Yes! " -#define SOUND_AGGRO_2 10504 -#define SAY_AGGRO_3 "Nice pets have.. weapons. No so....nice." -#define SOUND_AGGRO_3 10505 - -#define SAY_SLAY_1 "Death.. meeting life is.. " -#define SOUND_SLAY_1 10506 -#define SAY_SLAY_2 "Uhn.. Be free.." -#define SOUND_SLAY_2 10507 - -#define SAY_DEATH "No more life..hrm. No more pain. " -#define SOUND_DEATH 10508 - -#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 - -struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI -{ - boss_darkweaver_sythAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 flameshock_timer; - uint32 arcaneshock_timer; - uint32 frostshock_timer; - uint32 shadowshock_timer; - uint32 chainlightning_timer; - - bool summon90; - bool summon50; - bool summon10; - - void Reset() - { - flameshock_timer = 2000; - arcaneshock_timer = 4000; - frostshock_timer = 6000; - shadowshock_timer = 8000; - chainlightning_timer = 15000; - - summon90 = false; - summon50 = false; - summon10 = false; - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void KilledUnit(Unit* victim) - { - if (rand()%2) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_2); - break; - } - } - - void JustSummoned(Creature *summoned) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - summoned->AI()->AttackStart(target); - - } - - void SythSummoning() - { - DoYell(SAY_SUMMON, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SUMMON); - - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(false); - - DoCast(m_creature,SPELL_SUMMON_SYTH_ARCANE,true); //front - DoCast(m_creature,SPELL_SUMMON_SYTH_FIRE,true); //back - DoCast(m_creature,SPELL_SUMMON_SYTH_FROST,true); //left - DoCast(m_creature,SPELL_SUMMON_SYTH_SHADOW,true); //right - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 90) && !summon90) - { - SythSummoning(); - summon90 = true; - } - - if( ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 50) && !summon50) - { - SythSummoning(); - summon50 = true; - } - - if( ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 10) && !summon10) - { - SythSummoning(); - summon10 = true; - } - - if( flameshock_timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_FLAME_SHOCK); - - flameshock_timer = 10000 + rand()%5000; - }else flameshock_timer -= diff; - - if( arcaneshock_timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_ARCANE_SHOCK); - - arcaneshock_timer = 10000 + rand()%5000; - }else arcaneshock_timer -= diff; - - if( frostshock_timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_FROST_SHOCK); - - frostshock_timer = 10000 + rand()%5000; - }else frostshock_timer -= diff; - - if( shadowshock_timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_SHADOW_SHOCK); - - shadowshock_timer = 10000 + rand()%5000; - }else shadowshock_timer -= diff; - - if( chainlightning_timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_CHAIN_LIGHTNING); - - chainlightning_timer = 25000; - }else chainlightning_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_darkweaver_syth(Creature *_Creature) -{ - return new boss_darkweaver_sythAI (_Creature); -} - -/* ELEMENTALS */ - -struct MANGOS_DLL_DECL mob_syth_fireAI : public ScriptedAI -{ - mob_syth_fireAI(Creature *c) : ScriptedAI(c) {Reset();} - - 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 Aggro(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(flameshock_timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_FLAME_SHOCK); - - flameshock_timer = 5000; - }else flameshock_timer -= diff; - - if(flamebuffet_timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_FLAME_BUFFET); - - flamebuffet_timer = 5000; - }else flamebuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_fire(Creature *_Creature) -{ - return new mob_syth_fireAI (_Creature); -} - -struct MANGOS_DLL_DECL mob_syth_arcaneAI : public ScriptedAI -{ - mob_syth_arcaneAI(Creature *c) : ScriptedAI(c) {Reset();} - - 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 Aggro(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(arcaneshock_timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_ARCANE_SHOCK); - - arcaneshock_timer = 5000; - }else arcaneshock_timer -= diff; - - if(arcanebuffet_timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_ARCANE_BUFFET); - - arcanebuffet_timer = 5000; - }else arcanebuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_arcane(Creature *_Creature) -{ - return new mob_syth_arcaneAI (_Creature); -} - -struct MANGOS_DLL_DECL mob_syth_frostAI : public ScriptedAI -{ - mob_syth_frostAI(Creature *c) : ScriptedAI(c) {Reset();} - - 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 Aggro(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(frostshock_timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_FROST_SHOCK); - - frostshock_timer = 5000; - }else frostshock_timer -= diff; - - if(frostbuffet_timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_FROST_BUFFET); - - frostbuffet_timer = 5000; - }else frostbuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_frost(Creature *_Creature) -{ - return new mob_syth_frostAI (_Creature); -} - -struct MANGOS_DLL_DECL mob_syth_shadowAI : public ScriptedAI -{ - mob_syth_shadowAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 shadowshock_timer; - uint32 shadowbuffet_timer; - - void Reset() - { - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, true); - shadowshock_timer = 2500; - shadowbuffet_timer = 5000; - } - - void Aggro(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(shadowshock_timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_SHADOW_SHOCK); - - shadowshock_timer = 5000; - }else shadowshock_timer -= diff; - - if(shadowbuffet_timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_SHADOW_BUFFET); - - shadowbuffet_timer = 5000; - }else shadowbuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_shadow(Creature *_Creature) -{ - return new mob_syth_shadowAI (_Creature); -} - -void AddSC_boss_darkweaver_syth() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_darkweaver_syth"; - newscript->GetAI = GetAI_boss_darkweaver_syth; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_syth_fire"; - newscript->GetAI = GetAI_mob_syth_arcane; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_syth_arcane"; - newscript->GetAI = GetAI_mob_syth_arcane; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_syth_frost"; - newscript->GetAI = GetAI_mob_syth_frost; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_syth_shadow"; - newscript->GetAI = GetAI_mob_syth_shadow; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Darkweaver_Syth +SD%Complete: 85 +SDComment: Shock spells/times need more work. Heroic not implemented. +SDCategory: Auchindoun, Sethekk Halls +EndScriptData */ + +#include "precompiled.h" + +#define SAY_SUMMON "I have pets....of my own!" +#define SOUND_SUMMON 10502 + +#define SAY_AGGRO_1 "Hrrmm.. Time to.. hrrm.. make my move." +#define SOUND_AGGRO_1 10503 +#define SAY_AGGRO_2 "Nice pets..hrm.. Yes! " +#define SOUND_AGGRO_2 10504 +#define SAY_AGGRO_3 "Nice pets have.. weapons. No so....nice." +#define SOUND_AGGRO_3 10505 + +#define SAY_SLAY_1 "Death.. meeting life is.. " +#define SOUND_SLAY_1 10506 +#define SAY_SLAY_2 "Uhn.. Be free.." +#define SOUND_SLAY_2 10507 + +#define SAY_DEATH "No more life..hrm. No more pain. " +#define SOUND_DEATH 10508 + +#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 + +struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI +{ + boss_darkweaver_sythAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 flameshock_timer; + uint32 arcaneshock_timer; + uint32 frostshock_timer; + uint32 shadowshock_timer; + uint32 chainlightning_timer; + + bool summon90; + bool summon50; + bool summon10; + + void Reset() + { + flameshock_timer = 2000; + arcaneshock_timer = 4000; + frostshock_timer = 6000; + shadowshock_timer = 8000; + chainlightning_timer = 15000; + + summon90 = false; + summon50 = false; + summon10 = false; + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void KilledUnit(Unit* victim) + { + if (rand()%2) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_2); + break; + } + } + + void JustSummoned(Creature *summoned) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + summoned->AI()->AttackStart(target); + + } + + void SythSummoning() + { + DoYell(SAY_SUMMON, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SUMMON); + + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(false); + + DoCast(m_creature,SPELL_SUMMON_SYTH_ARCANE,true); //front + DoCast(m_creature,SPELL_SUMMON_SYTH_FIRE,true); //back + DoCast(m_creature,SPELL_SUMMON_SYTH_FROST,true); //left + DoCast(m_creature,SPELL_SUMMON_SYTH_SHADOW,true); //right + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 90) && !summon90) + { + SythSummoning(); + summon90 = true; + } + + if( ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 50) && !summon50) + { + SythSummoning(); + summon50 = true; + } + + if( ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 10) && !summon10) + { + SythSummoning(); + summon10 = true; + } + + if( flameshock_timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_FLAME_SHOCK); + + flameshock_timer = 10000 + rand()%5000; + }else flameshock_timer -= diff; + + if( arcaneshock_timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_ARCANE_SHOCK); + + arcaneshock_timer = 10000 + rand()%5000; + }else arcaneshock_timer -= diff; + + if( frostshock_timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_FROST_SHOCK); + + frostshock_timer = 10000 + rand()%5000; + }else frostshock_timer -= diff; + + if( shadowshock_timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_SHADOW_SHOCK); + + shadowshock_timer = 10000 + rand()%5000; + }else shadowshock_timer -= diff; + + if( chainlightning_timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_CHAIN_LIGHTNING); + + chainlightning_timer = 25000; + }else chainlightning_timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_darkweaver_syth(Creature *_Creature) +{ + return new boss_darkweaver_sythAI (_Creature); +} + +/* ELEMENTALS */ + +struct MANGOS_DLL_DECL mob_syth_fireAI : public ScriptedAI +{ + mob_syth_fireAI(Creature *c) : ScriptedAI(c) {Reset();} + + 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 Aggro(Unit *who) { } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(flameshock_timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_FLAME_SHOCK); + + flameshock_timer = 5000; + }else flameshock_timer -= diff; + + if(flamebuffet_timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_FLAME_BUFFET); + + flamebuffet_timer = 5000; + }else flamebuffet_timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_syth_fire(Creature *_Creature) +{ + return new mob_syth_fireAI (_Creature); +} + +struct MANGOS_DLL_DECL mob_syth_arcaneAI : public ScriptedAI +{ + mob_syth_arcaneAI(Creature *c) : ScriptedAI(c) {Reset();} + + 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 Aggro(Unit *who) { } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(arcaneshock_timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_ARCANE_SHOCK); + + arcaneshock_timer = 5000; + }else arcaneshock_timer -= diff; + + if(arcanebuffet_timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_ARCANE_BUFFET); + + arcanebuffet_timer = 5000; + }else arcanebuffet_timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_syth_arcane(Creature *_Creature) +{ + return new mob_syth_arcaneAI (_Creature); +} + +struct MANGOS_DLL_DECL mob_syth_frostAI : public ScriptedAI +{ + mob_syth_frostAI(Creature *c) : ScriptedAI(c) {Reset();} + + 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 Aggro(Unit *who) { } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(frostshock_timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_FROST_SHOCK); + + frostshock_timer = 5000; + }else frostshock_timer -= diff; + + if(frostbuffet_timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_FROST_BUFFET); + + frostbuffet_timer = 5000; + }else frostbuffet_timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_syth_frost(Creature *_Creature) +{ + return new mob_syth_frostAI (_Creature); +} + +struct MANGOS_DLL_DECL mob_syth_shadowAI : public ScriptedAI +{ + mob_syth_shadowAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 shadowshock_timer; + uint32 shadowbuffet_timer; + + void Reset() + { + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, true); + shadowshock_timer = 2500; + shadowbuffet_timer = 5000; + } + + void Aggro(Unit *who) { } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(shadowshock_timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_SHADOW_SHOCK); + + shadowshock_timer = 5000; + }else shadowshock_timer -= diff; + + if(shadowbuffet_timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_SHADOW_BUFFET); + + shadowbuffet_timer = 5000; + }else shadowbuffet_timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_syth_shadow(Creature *_Creature) +{ + return new mob_syth_shadowAI (_Creature); +} + +void AddSC_boss_darkweaver_syth() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_darkweaver_syth"; + newscript->GetAI = GetAI_boss_darkweaver_syth; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_syth_fire"; + newscript->GetAI = GetAI_mob_syth_arcane; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_syth_arcane"; + newscript->GetAI = GetAI_mob_syth_arcane; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_syth_frost"; + newscript->GetAI = GetAI_mob_syth_frost; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_syth_shadow"; + newscript->GetAI = GetAI_mob_syth_shadow; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp index 4168458685d..0effeedb469 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp @@ -1,256 +1,256 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_sethekk_halls.h" - -#define SAY_INTRO "..Trinkets yes pretty Trinkets....power, great power...power in Trinkets.." -#define SOUND_INTRO 10557 - -#define SAY_AGGRO_1 "You make war on Ikiss?.." -#define SOUND_AGGRO_1 10554 -#define SAY_AGGRO_2 "Ikiss cut you pretty....slice you. Yes!" -#define SOUND_AGGRO_2 10555 -#define SAY_AGGRO_3 "No escape for....for you" -#define SOUND_AGGRO_3 10556 - -#define SAY_SLAY_1 "You die....stay away from Trinkets" -#define SOUND_SLAY_1 10558 -#define SAY_SLAY_2 "" -#define SOUND_SLAY_2 10559 - -#define SAY_DEATH "Ikiss will not....die" -#define SOUND_DEATH 10560 - -#define EMOTE_ARCANE_EXP "begins to channel arcane energy..." - -#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 *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - bool HeroicMode; - - uint32 ArcaneVolley_Timer; - uint32 Sheep_Timer; - uint32 Blink_Timer; - uint32 Slow_Timer; - - bool ManaShield; - bool Blink; - bool Intro; - - void Reset() - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - - ArcaneVolley_Timer = 5000; - Sheep_Timer = 8000; - Blink_Timer = 35000; - Slow_Timer = 15000+rand()%15000; - 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; - DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_INTRO); - } - - if (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) ) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - - if( pInstance ) - pInstance->SetData(DATA_IKISSDOOREVENT, DONE); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_2); - break; - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( Blink ) - { - DoCast(m_creature,HeroicMode ? H_SPELL_ARCANE_EXPLOSION : SPELL_ARCANE_EXPLOSION); - m_creature->CastSpell(m_creature,SPELL_ARCANE_BUBBLE,true); - Blink = false; - } - - if( ArcaneVolley_Timer < diff ) - { - DoCast(m_creature,HeroicMode ? H_SPELL_ARCANE_VOLLEY : SPELL_ARCANE_VOLLEY); - ArcaneVolley_Timer = 10000+rand()%5000; - }else ArcaneVolley_Timer -= diff; - - if( Sheep_Timer < diff ) - { - //second top aggro target in normal, random target in heroic correct? - Unit *target = NULL; - if( HeroicMode ? target = SelectUnit(SELECT_TARGET_RANDOM,0) : target = SelectUnit(SELECT_TARGET_TOPAGGRO,1) ) - DoCast(target,HeroicMode ? H_SPELL_POLYMORPH : SPELL_POLYMORPH); - Sheep_Timer = 15000+rand()%2500; - }else Sheep_Timer -= diff; - - //may not be correct time to cast - if( !ManaShield && ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 20) ) - { - DoCast(m_creature,SPELL_MANA_SHIELD); - ManaShield = true; - } - - if( HeroicMode ) - { - if( Slow_Timer < diff ) - { - DoCast(m_creature,H_SPELL_SLOW); - Slow_Timer = 15000+rand()%25000; - }else Slow_Timer -= diff; - } - - if( Blink_Timer < diff ) - { - DoTextEmote(EMOTE_ARCANE_EXP,NULL,true); - - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(false); - - //Spell doesn't work, but we use for visual effect at least - DoCast(target,SPELL_BLINK); - - float X = target->GetPositionX(); - float Y = target->GetPositionY(); - float Z = target->GetPositionZ(); - - m_creature->Relocate(X,Y,Z); - m_creature->SendMonsterMove(X, Y, Z, 0, 0, 0); - - DoCast(target,SPELL_BLINK_TELEPORT); - Blink = true; - } - Blink_Timer = 35000+rand()%5000; - }else Blink_Timer -= diff; - - if( !Blink ) - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_talon_king_ikiss(Creature *_Creature) -{ - return new boss_talon_king_ikissAI (_Creature); -} - -void AddSC_boss_talon_king_ikiss() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_talon_king_ikiss"; - newscript->GetAI = GetAI_boss_talon_king_ikiss; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_sethekk_halls.h" + +#define SAY_INTRO "..Trinkets yes pretty Trinkets....power, great power...power in Trinkets.." +#define SOUND_INTRO 10557 + +#define SAY_AGGRO_1 "You make war on Ikiss?.." +#define SOUND_AGGRO_1 10554 +#define SAY_AGGRO_2 "Ikiss cut you pretty....slice you. Yes!" +#define SOUND_AGGRO_2 10555 +#define SAY_AGGRO_3 "No escape for....for you" +#define SOUND_AGGRO_3 10556 + +#define SAY_SLAY_1 "You die....stay away from Trinkets" +#define SOUND_SLAY_1 10558 +#define SAY_SLAY_2 "" +#define SOUND_SLAY_2 10559 + +#define SAY_DEATH "Ikiss will not....die" +#define SOUND_DEATH 10560 + +#define EMOTE_ARCANE_EXP "begins to channel arcane energy..." + +#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 *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + bool HeroicMode; + + uint32 ArcaneVolley_Timer; + uint32 Sheep_Timer; + uint32 Blink_Timer; + uint32 Slow_Timer; + + bool ManaShield; + bool Blink; + bool Intro; + + void Reset() + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + + ArcaneVolley_Timer = 5000; + Sheep_Timer = 8000; + Blink_Timer = 35000; + Slow_Timer = 15000+rand()%15000; + 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; + DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_INTRO); + } + + 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) ) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + + if( pInstance ) + pInstance->SetData(DATA_IKISSDOOREVENT, DONE); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_2); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( Blink ) + { + DoCast(m_creature,HeroicMode ? H_SPELL_ARCANE_EXPLOSION : SPELL_ARCANE_EXPLOSION); + m_creature->CastSpell(m_creature,SPELL_ARCANE_BUBBLE,true); + Blink = false; + } + + if( ArcaneVolley_Timer < diff ) + { + DoCast(m_creature,HeroicMode ? H_SPELL_ARCANE_VOLLEY : SPELL_ARCANE_VOLLEY); + ArcaneVolley_Timer = 10000+rand()%5000; + }else ArcaneVolley_Timer -= diff; + + if( Sheep_Timer < diff ) + { + //second top aggro target in normal, random target in heroic correct? + Unit *target = NULL; + if( HeroicMode ? target = SelectUnit(SELECT_TARGET_RANDOM,0) : target = SelectUnit(SELECT_TARGET_TOPAGGRO,1) ) + DoCast(target,HeroicMode ? H_SPELL_POLYMORPH : SPELL_POLYMORPH); + Sheep_Timer = 15000+rand()%2500; + }else Sheep_Timer -= diff; + + //may not be correct time to cast + if( !ManaShield && ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 20) ) + { + DoCast(m_creature,SPELL_MANA_SHIELD); + ManaShield = true; + } + + if( HeroicMode ) + { + if( Slow_Timer < diff ) + { + DoCast(m_creature,H_SPELL_SLOW); + Slow_Timer = 15000+rand()%25000; + }else Slow_Timer -= diff; + } + + if( Blink_Timer < diff ) + { + DoTextEmote(EMOTE_ARCANE_EXP,NULL,true); + + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(false); + + //Spell doesn't work, but we use for visual effect at least + DoCast(target,SPELL_BLINK); + + float X = target->GetPositionX(); + float Y = target->GetPositionY(); + float Z = target->GetPositionZ(); + + m_creature->Relocate(X,Y,Z); + m_creature->SendMonsterMove(X, Y, Z, 0, 0, 0); + + DoCast(target,SPELL_BLINK_TELEPORT); + Blink = true; + } + Blink_Timer = 35000+rand()%5000; + }else Blink_Timer -= diff; + + if( !Blink ) + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_talon_king_ikiss(Creature *_Creature) +{ + return new boss_talon_king_ikissAI (_Creature); +} + +void AddSC_boss_talon_king_ikiss() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_talon_king_ikiss"; + newscript->GetAI = GetAI_boss_talon_king_ikiss; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/def_sethekk_halls.h b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/def_sethekk_halls.h index f609ecac1f2..73aafca29f7 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/def_sethekk_halls.h +++ b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/def_sethekk_halls.h @@ -1,9 +1,9 @@ -/* Copyright (C) 2006 - 2008 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 -#endif +/* Copyright (C) 2006 - 2008 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 +#endif diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/instance_sethekk_halls.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/instance_sethekk_halls.cpp index 980717653c6..244fada32f7 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/instance_sethekk_halls.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/instance_sethekk_halls.cpp @@ -1,74 +1,74 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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 - Sethekk Halls -SD%Complete: 50 -SDComment: Instance Data for Sethekk Halls instance -SDCategory: Auchindoun, Sethekk Halls -EndScriptData */ - -#include "precompiled.h" -#include "def_sethekk_halls.h" - -#define IKISS_DOOR 177203 - -struct MANGOS_DLL_DECL instance_sethekk_halls : public ScriptedInstance -{ - instance_sethekk_halls(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - GameObject *IkissDoor; - - void Initialize() - { - IkissDoor = NULL; - } - - void OnObjectCreate(GameObject *go) - { - switch(go->GetEntry()) - { - case IKISS_DOOR: - IkissDoor = go; - break; - } - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_IKISSDOOREVENT: - if( IkissDoor ) - IkissDoor->SetGoState(0); - break; - } - } -}; - -InstanceData* GetInstanceData_instance_sethekk_halls(Map* map) -{ - return new instance_sethekk_halls(map); -} - -void AddSC_instance_sethekk_halls() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_sethekk_halls"; - newscript->GetInstanceData = GetInstanceData_instance_sethekk_halls; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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 - Sethekk Halls +SD%Complete: 50 +SDComment: Instance Data for Sethekk Halls instance +SDCategory: Auchindoun, Sethekk Halls +EndScriptData */ + +#include "precompiled.h" +#include "def_sethekk_halls.h" + +#define IKISS_DOOR 177203 + +struct MANGOS_DLL_DECL instance_sethekk_halls : public ScriptedInstance +{ + instance_sethekk_halls(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + GameObject *IkissDoor; + + void Initialize() + { + IkissDoor = NULL; + } + + void OnObjectCreate(GameObject *go) + { + switch(go->GetEntry()) + { + case IKISS_DOOR: + IkissDoor = go; + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_IKISSDOOREVENT: + if( IkissDoor ) + IkissDoor->SetGoState(0); + break; + } + } +}; + +InstanceData* GetInstanceData_instance_sethekk_halls(Map* map) +{ + return new instance_sethekk_halls(map); +} + +void AddSC_instance_sethekk_halls() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_sethekk_halls"; + newscript->GetInstanceData = GetInstanceData_instance_sethekk_halls; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp index b575461dfaa..69d26ac8a75 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp @@ -1,223 +1,223 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Hellmaw -SD%Complete: 75 -SDComment: Waypoints after Intro not implemented. Enrage spell missing/not known -SDCategory: Auchindoun, Shadow Labyrinth -EndScriptData */ - -#include "precompiled.h" -#include "def_shadow_labyrinth.h" - -#define SAY_INTRO "Infidels have invaded the sanctuary! Sniveling pests...You have yet to learn the true meaning of agony!" -#define SOUND_INTRO 10473 - -#define SAY_AGGRO1 "Pathetic mortals! You will pay dearly!" -#define SOUND_AGGRO1 10475 -#define SAY_AGGRO2 "I will break you!" -#define SOUND_AGGRO2 10476 -#define SAY_AGGRO3 "Finally! Something to relieve the tedium!" -#define SOUND_AGGRO3 10477 - -#define SAY_HELP "Aid me, you fools, before it's too late!" -#define SOUND_HELP 10474 - -#define SAY_SLAY1 "Do you fear death?" -#define SOUND_SLAY1 10478 -#define SAY_SLAY2 "This is the part I enjoy most." -#define SOUND_SLAY2 10479 - -#define SAY_DEATH "Do not...grow...overconfident, mortal." -#define SOUND_DEATH 10480 - -#define SPELL_BANISH 30231 -#define SPELL_CORROSIVE_ACID 23313 -#define SPELL_FEAR 33547 -#define SPELL_ENRAGE 0 //need to find proper spell - -struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public ScriptedAI -{ - boss_ambassador_hellmawAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - bool HeroicMode; - - uint32 EventCheck_Timer; - uint32 CorrosiveAcid_Timer; - uint32 Fear_Timer; - uint32 Enrage_Timer; - bool Intro; - bool IsBanished; - - void Reset() - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - - EventCheck_Timer = 5000; - CorrosiveAcid_Timer = 25000; - Fear_Timer = 40000; - Enrage_Timer = 180000; - Intro = false; - IsBanished = false; - - if( pInstance ) - { - if( pInstance->GetData(TYPE_HELLMAW) == NOT_STARTED ) - { - DoCast(m_creature,SPELL_BANISH); - IsBanished = true; - } - else pInstance->SetData(TYPE_HELLMAW,FAIL); - - if( pInstance->GetData(TYPE_OVERSEER) == DONE ) - { - if( m_creature->HasAura(SPELL_BANISH,0) ) - m_creature->RemoveAurasDueToSpell(SPELL_BANISH); - Intro = true; - } - } - } - - void MovementInform(uint32 type, uint32 id) - { - if( type != POINT_MOTION_TYPE ) - return; - } - - void DoIntro() - { - DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_INTRO); - - if( m_creature->HasAura(SPELL_BANISH,0) ) - m_creature->RemoveAurasDueToSpell(SPELL_BANISH); - - IsBanished = false; - Intro = true; - - if( pInstance ) - pInstance->SetData(TYPE_HELLMAW, IN_PROGRESS); - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - break; - } - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if( pInstance ) - pInstance->SetData(TYPE_HELLMAW, DONE); - } - - void UpdateAI(const uint32 diff) - { - if( !Intro ) - { - if( EventCheck_Timer < diff ) - { - if( pInstance ) - { - if( pInstance->GetData(TYPE_OVERSEER) == DONE ) - DoIntro(); - } - EventCheck_Timer = 5000; - }else EventCheck_Timer -= diff; - } - - if( !InCombat && !IsBanished ) - { - //this is where we add MovePoint() - //DoWhine("I haz no mount!", LANG_UNIVERSAL, NULL); - } - - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( CorrosiveAcid_Timer < diff ) - { - DoCast(m_creature,SPELL_CORROSIVE_ACID); - CorrosiveAcid_Timer = 25000; - }else CorrosiveAcid_Timer -= diff; - - if( Fear_Timer < diff ) - { - DoCast(m_creature,SPELL_FEAR); - Fear_Timer = 35000; - }else Fear_Timer -= diff; - - /*if( HeroicMode ) - { - if( Enrage_Timer < diff ) - { - DoCast(m_creature,SPELL_ENRAGE); - }else Enrage_Timer -= diff; - }*/ - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ambassador_hellmaw(Creature *_Creature) -{ - return new boss_ambassador_hellmawAI (_Creature); -} - -void AddSC_boss_ambassador_hellmaw() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ambassador_hellmaw"; - newscript->GetAI = GetAI_boss_ambassador_hellmaw; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Hellmaw +SD%Complete: 75 +SDComment: Waypoints after Intro not implemented. Enrage spell missing/not known +SDCategory: Auchindoun, Shadow Labyrinth +EndScriptData */ + +#include "precompiled.h" +#include "def_shadow_labyrinth.h" + +#define SAY_INTRO "Infidels have invaded the sanctuary! Sniveling pests...You have yet to learn the true meaning of agony!" +#define SOUND_INTRO 10473 + +#define SAY_AGGRO1 "Pathetic mortals! You will pay dearly!" +#define SOUND_AGGRO1 10475 +#define SAY_AGGRO2 "I will break you!" +#define SOUND_AGGRO2 10476 +#define SAY_AGGRO3 "Finally! Something to relieve the tedium!" +#define SOUND_AGGRO3 10477 + +#define SAY_HELP "Aid me, you fools, before it's too late!" +#define SOUND_HELP 10474 + +#define SAY_SLAY1 "Do you fear death?" +#define SOUND_SLAY1 10478 +#define SAY_SLAY2 "This is the part I enjoy most." +#define SOUND_SLAY2 10479 + +#define SAY_DEATH "Do not...grow...overconfident, mortal." +#define SOUND_DEATH 10480 + +#define SPELL_BANISH 30231 +#define SPELL_CORROSIVE_ACID 23313 +#define SPELL_FEAR 33547 +#define SPELL_ENRAGE 0 //need to find proper spell + +struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public ScriptedAI +{ + boss_ambassador_hellmawAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + bool HeroicMode; + + uint32 EventCheck_Timer; + uint32 CorrosiveAcid_Timer; + uint32 Fear_Timer; + uint32 Enrage_Timer; + bool Intro; + bool IsBanished; + + void Reset() + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + + EventCheck_Timer = 5000; + CorrosiveAcid_Timer = 25000; + Fear_Timer = 40000; + Enrage_Timer = 180000; + Intro = false; + IsBanished = false; + + if( pInstance ) + { + if( pInstance->GetData(TYPE_HELLMAW) == NOT_STARTED ) + { + DoCast(m_creature,SPELL_BANISH); + IsBanished = true; + } + else pInstance->SetData(TYPE_HELLMAW,FAIL); + + if( pInstance->GetData(TYPE_OVERSEER) == DONE ) + { + if( m_creature->HasAura(SPELL_BANISH,0) ) + m_creature->RemoveAurasDueToSpell(SPELL_BANISH); + Intro = true; + } + } + } + + void MovementInform(uint32 type, uint32 id) + { + if( type != POINT_MOTION_TYPE ) + return; + } + + void DoIntro() + { + DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_INTRO); + + if( m_creature->HasAura(SPELL_BANISH,0) ) + m_creature->RemoveAurasDueToSpell(SPELL_BANISH); + + IsBanished = false; + Intro = true; + + if( pInstance ) + pInstance->SetData(TYPE_HELLMAW, IN_PROGRESS); + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO3); + break; + } + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if( pInstance ) + pInstance->SetData(TYPE_HELLMAW, DONE); + } + + void UpdateAI(const uint32 diff) + { + if( !Intro ) + { + if( EventCheck_Timer < diff ) + { + if( pInstance ) + { + if( pInstance->GetData(TYPE_OVERSEER) == DONE ) + DoIntro(); + } + EventCheck_Timer = 5000; + }else EventCheck_Timer -= diff; + } + + if( !InCombat && !IsBanished ) + { + //this is where we add MovePoint() + //DoWhine("I haz no mount!", LANG_UNIVERSAL, NULL); + } + + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( CorrosiveAcid_Timer < diff ) + { + DoCast(m_creature,SPELL_CORROSIVE_ACID); + CorrosiveAcid_Timer = 25000; + }else CorrosiveAcid_Timer -= diff; + + if( Fear_Timer < diff ) + { + DoCast(m_creature,SPELL_FEAR); + Fear_Timer = 35000; + }else Fear_Timer -= diff; + + /*if( HeroicMode ) + { + if( Enrage_Timer < diff ) + { + DoCast(m_creature,SPELL_ENRAGE); + }else Enrage_Timer -= diff; + }*/ + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_ambassador_hellmaw(Creature *_Creature) +{ + return new boss_ambassador_hellmawAI (_Creature); +} + +void AddSC_boss_ambassador_hellmaw() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ambassador_hellmaw"; + newscript->GetAI = GetAI_boss_ambassador_hellmaw; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp index 0a8c446b15c..dab0343cad8 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp @@ -1,191 +1,191 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Blackheart_the_Inciter -SD%Complete: 75 -SDComment: Incite Chaos not functional since core lacks Mind Control support -SDCategory: Auchindoun, Shadow Labyrinth -EndScriptData */ - -#include "precompiled.h" -#include "def_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_AGGRO1 "You be dead people!" -#define SAY_AGGRO2 "Time to kill!" -#define SAY_AGGRO3 "I see dead people!" -#define SAY_SLAY1 "No coming back for you!" -#define SAY_SLAY2 "Nice try!" -#define SAY_SLAY3 "Now you gone for good!" -#define SAY_DEATH "This...no...good.." - -#define SOUND_AGGRO1 10498 -#define SOUND_AGGRO2 10497 -#define SOUND_AGGRO3 10488 -#define SOUND_SLAY1 10489 -#define SOUND_SLAY2 10490 -#define SOUND_SLAY3 10499 -#define SOUND_DEATH 10491 - -struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI -{ - boss_blackheart_the_inciterAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - bool InciteChaos; - uint32 InciteChaos_Timer; - uint32 InciteChaosWait_Timer; - uint32 Charge_Timer; - uint32 Knockback_Timer; - - void Reset() - { - InciteChaos = false; - InciteChaos_Timer = 20000; - InciteChaosWait_Timer = 15000; - Charge_Timer = 5000; - Knockback_Timer = 15000; - - if( pInstance ) - pInstance->SetData(DATA_BLACKHEARTTHEINCITEREVENT, NOT_STARTED); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - case 2: - DoYell(SAY_SLAY3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY3); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if( pInstance ) - pInstance->SetData(DATA_BLACKHEARTTHEINCITEREVENT, DONE); - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - break; - } - - if( pInstance ) - pInstance->SetData(DATA_BLACKHEARTTHEINCITEREVENT, IN_PROGRESS); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( InciteChaos ) - { - if( InciteChaosWait_Timer < diff ) - { - InciteChaos = false; - InciteChaosWait_Timer = 15000; - }else InciteChaosWait_Timer -= diff; - - return; - } - - if( InciteChaos_Timer < diff ) - { - DoCast(m_creature, SPELL_INCITE_CHAOS); - - std::list t_list = m_creature->getThreatManager().getThreatList(); - for( std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr ) - { - Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - if( target && target->GetTypeId() == TYPEID_PLAYER ) - target->CastSpell(target,SPELL_INCITE_CHAOS_B,true); - } - - DoResetThreat(); - InciteChaos = true; - InciteChaos_Timer = 40000; - return; - }else InciteChaos_Timer -= diff; - - //Charge_Timer - if( Charge_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0) ) - DoCast(target, SPELL_CHARGE); - Charge_Timer = 25000; - }else Charge_Timer -= diff; - - //Knockback_Timer - if( Knockback_Timer < diff ) - { - DoCast(m_creature, SPELL_WAR_STOMP); - Knockback_Timer = 20000; - }else Knockback_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_blackheart_the_inciter(Creature *_Creature) -{ - return new boss_blackheart_the_inciterAI (_Creature); -} - -void AddSC_boss_blackheart_the_inciter() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_blackheart_the_inciter"; - newscript->GetAI = GetAI_boss_blackheart_the_inciter; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Blackheart_the_Inciter +SD%Complete: 75 +SDComment: Incite Chaos not functional since core lacks Mind Control support +SDCategory: Auchindoun, Shadow Labyrinth +EndScriptData */ + +#include "precompiled.h" +#include "def_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_AGGRO1 "You be dead people!" +#define SAY_AGGRO2 "Time to kill!" +#define SAY_AGGRO3 "I see dead people!" +#define SAY_SLAY1 "No coming back for you!" +#define SAY_SLAY2 "Nice try!" +#define SAY_SLAY3 "Now you gone for good!" +#define SAY_DEATH "This...no...good.." + +#define SOUND_AGGRO1 10498 +#define SOUND_AGGRO2 10497 +#define SOUND_AGGRO3 10488 +#define SOUND_SLAY1 10489 +#define SOUND_SLAY2 10490 +#define SOUND_SLAY3 10499 +#define SOUND_DEATH 10491 + +struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI +{ + boss_blackheart_the_inciterAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + bool InciteChaos; + uint32 InciteChaos_Timer; + uint32 InciteChaosWait_Timer; + uint32 Charge_Timer; + uint32 Knockback_Timer; + + void Reset() + { + InciteChaos = false; + InciteChaos_Timer = 20000; + InciteChaosWait_Timer = 15000; + Charge_Timer = 5000; + Knockback_Timer = 15000; + + if( pInstance ) + pInstance->SetData(DATA_BLACKHEARTTHEINCITEREVENT, NOT_STARTED); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + case 2: + DoYell(SAY_SLAY3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY3); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if( pInstance ) + pInstance->SetData(DATA_BLACKHEARTTHEINCITEREVENT, DONE); + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO3); + break; + } + + if( pInstance ) + pInstance->SetData(DATA_BLACKHEARTTHEINCITEREVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( InciteChaos ) + { + if( InciteChaosWait_Timer < diff ) + { + InciteChaos = false; + InciteChaosWait_Timer = 15000; + }else InciteChaosWait_Timer -= diff; + + return; + } + + if( InciteChaos_Timer < diff ) + { + DoCast(m_creature, SPELL_INCITE_CHAOS); + + std::list t_list = m_creature->getThreatManager().getThreatList(); + for( std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr ) + { + Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + if( target && target->GetTypeId() == TYPEID_PLAYER ) + target->CastSpell(target,SPELL_INCITE_CHAOS_B,true); + } + + DoResetThreat(); + InciteChaos = true; + InciteChaos_Timer = 40000; + return; + }else InciteChaos_Timer -= diff; + + //Charge_Timer + if( Charge_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0) ) + DoCast(target, SPELL_CHARGE); + Charge_Timer = 25000; + }else Charge_Timer -= diff; + + //Knockback_Timer + if( Knockback_Timer < diff ) + { + DoCast(m_creature, SPELL_WAR_STOMP); + Knockback_Timer = 20000; + }else Knockback_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_blackheart_the_inciter(Creature *_Creature) +{ + return new boss_blackheart_the_inciterAI (_Creature); +} + +void AddSC_boss_blackheart_the_inciter() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_blackheart_the_inciter"; + newscript->GetAI = GetAI_boss_blackheart_the_inciter; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp index 5e278c91fc5..4e1b791b9b6 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp @@ -1,294 +1,294 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Grandmaster_Vorpil -SD%Complete: 75 -SDComment: Despawn all summoned on death not implemented. Void Traveler effects not implemented. -SDCategory: Auchindoun, Shadow Labyrinth -EndScriptData */ - -#include "precompiled.h" -#include "def_shadow_labyrinth.h" - -#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 SAY_INTRO "Keep your minds focused for the days of reckoning are close at hand. Soon, the destroyer of worlds will return to make good on his promise. Soon the destruction of all that is will begin!" -#define SAY_AGGRO1 "I'll make an offering of your blood!" -#define SAY_AGGRO2 "You'll be a fine example, for the others." -#define SAY_AGGRO3 "Good, a worthy sacrifice." -#define SAY_HELP "Come to my aid, heed your master now!" -#define SAY_SLAY1 "I serve with pride." -#define SAY_SLAY2 "Your death is for the greater cause!" -#define SAY_DEATH "I give my life... Gladly." - -#define SOUND_INTRO 10522 -#define SOUND_AGGRO1 10524 -#define SOUND_AGGRO2 10525 -#define SOUND_AGGRO3 10526 -#define SOUND_HELP 10523 -#define SOUND_SLAY1 10527 -#define SOUND_SLAY2 10528 -#define SOUND_DEATH 10529 - -#define ENTRY_VOID_PORTAL 19224 -#define ENTRY_VOID_TRAVELER 19226 - -#define LOCX -253.06f -#define LOCY -264.02f -#define LOCZ 17.08 - -struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI -{ - boss_grandmaster_vorpilAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - bool HeroicMode; - - uint32 ShadowBoltVolley_Timer; - uint32 DrawShadows_Timer; - uint32 Teleport_Timer; - uint32 VoidTraveler_Timer; - uint32 Banish_Timer; - bool Intro; - bool Teleport; - - void Reset() - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - - ShadowBoltVolley_Timer = 15000; - DrawShadows_Timer = 40000; - Teleport_Timer = 1000; - VoidTraveler_Timer = 20000; - Banish_Timer = 25000; - Intro = false; - Teleport = false; - - if( pInstance ) - pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, NOT_STARTED); - } - - void MoveInLineOfSight(Unit *who) - { - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - //not sure about right radius - if(!Intro && m_creature->IsWithinDistInMap(who, 50)) - { - DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_INTRO); - DoCast(m_creature, SPELL_VOID_PORTAL_A,true); - m_creature->SummonCreature(ENTRY_VOID_PORTAL,-262.40,-229.57,17.08,0,TEMPSUMMON_CORPSE_DESPAWN,0); - m_creature->SummonCreature(ENTRY_VOID_PORTAL,-260.35,-297.56,17.08,0,TEMPSUMMON_CORPSE_DESPAWN,0); - m_creature->SummonCreature(ENTRY_VOID_PORTAL,-292.05,-270.37,12.68,0,TEMPSUMMON_CORPSE_DESPAWN,0); - m_creature->SummonCreature(ENTRY_VOID_PORTAL,-301.64,-255.97,12.68,0,TEMPSUMMON_CORPSE_DESPAWN,0); - Intro = true; - } - - if (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) ) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - break; - } - - if( pInstance ) - pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, IN_PROGRESS); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustSummoned(Creature *summoned) - { - if( summoned->GetEntry() == ENTRY_VOID_TRAVELER ) - { - summoned->GetMotionMaster()->MoveChase(m_creature); - summoned->SetSpeed(MOVE_WALK,0.8,true); - } - - if( summoned->GetEntry() == ENTRY_VOID_PORTAL ) - summoned->CastSpell(summoned,SPELL_VOID_PORTAL_VISUAL,true); - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if( pInstance ) - pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, DONE); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( Teleport ) - { - if( Teleport_Timer <= diff ) - { - m_creature->Relocate(LOCX,LOCY,LOCZ); - m_creature->SendMonsterMove(LOCX,LOCY,LOCZ,0,true,0); - - float ranX = LOCX; - float ranY = LOCY; - float ranZ = LOCZ; - - std::list t_list = m_creature->getThreatManager().getThreatList(); - for( std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr ) - { - Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - if( target && target->GetTypeId() == TYPEID_PLAYER ) - { - target->GetRandomPoint(LOCX,LOCY,LOCZ,3.0,ranX,ranY,ranZ); - DoTeleportPlayer(target,ranX,ranY,ranZ,m_creature->GetAngle(m_creature->GetPositionX(),m_creature->GetPositionY())); - } - } - Teleport = false; - - if( HeroicMode ) DoCast(m_creature->getVictim(), H_SPELL_RAIN_OF_FIRE); - else DoCast(m_creature->getVictim(), SPELL_RAIN_OF_FIRE); - - Teleport_Timer = 1000; - }else Teleport_Timer -= diff; - } - - if( ShadowBoltVolley_Timer < diff ) - { - DoCast(m_creature->getVictim(), SPELL_SHADOW_BOLT_VOLLEY); - ShadowBoltVolley_Timer = 30000; - }else ShadowBoltVolley_Timer -= diff; - - if( DrawShadows_Timer < diff ) - { - DoCast(m_creature,SPELL_DRAW_SHADOWS); - DrawShadows_Timer = 35000; - Teleport = true; - }else DrawShadows_Timer -= diff; - - if( VoidTraveler_Timer < diff ) - { - DoYell(SAY_HELP, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_HELP); - - switch(rand()%5) - { - case 0: - DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_A,true); - break; - case 1: - DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_B,true); - break; - case 2: - DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_C,true); - break; - case 3: - DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_D,true); - break; - case 4: - DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_E,true); - break; - } - //faster rate when below (X) health? - VoidTraveler_Timer = 35000; - }else VoidTraveler_Timer -= diff; - - if( HeroicMode ) - { - if( Banish_Timer < diff ) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1) ) - DoCast(target,H_SPELL_BANISH); - Banish_Timer = 35000; - }else Banish_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_grandmaster_vorpil(Creature *_Creature) -{ - return new boss_grandmaster_vorpilAI (_Creature); -} - -void AddSC_boss_grandmaster_vorpil() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_grandmaster_vorpil"; - newscript->GetAI = GetAI_boss_grandmaster_vorpil; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Grandmaster_Vorpil +SD%Complete: 75 +SDComment: Despawn all summoned on death not implemented. Void Traveler effects not implemented. +SDCategory: Auchindoun, Shadow Labyrinth +EndScriptData */ + +#include "precompiled.h" +#include "def_shadow_labyrinth.h" + +#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 SAY_INTRO "Keep your minds focused for the days of reckoning are close at hand. Soon, the destroyer of worlds will return to make good on his promise. Soon the destruction of all that is will begin!" +#define SAY_AGGRO1 "I'll make an offering of your blood!" +#define SAY_AGGRO2 "You'll be a fine example, for the others." +#define SAY_AGGRO3 "Good, a worthy sacrifice." +#define SAY_HELP "Come to my aid, heed your master now!" +#define SAY_SLAY1 "I serve with pride." +#define SAY_SLAY2 "Your death is for the greater cause!" +#define SAY_DEATH "I give my life... Gladly." + +#define SOUND_INTRO 10522 +#define SOUND_AGGRO1 10524 +#define SOUND_AGGRO2 10525 +#define SOUND_AGGRO3 10526 +#define SOUND_HELP 10523 +#define SOUND_SLAY1 10527 +#define SOUND_SLAY2 10528 +#define SOUND_DEATH 10529 + +#define ENTRY_VOID_PORTAL 19224 +#define ENTRY_VOID_TRAVELER 19226 + +#define LOCX -253.06f +#define LOCY -264.02f +#define LOCZ 17.08 + +struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI +{ + boss_grandmaster_vorpilAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + bool HeroicMode; + + uint32 ShadowBoltVolley_Timer; + uint32 DrawShadows_Timer; + uint32 Teleport_Timer; + uint32 VoidTraveler_Timer; + uint32 Banish_Timer; + bool Intro; + bool Teleport; + + void Reset() + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + + ShadowBoltVolley_Timer = 15000; + DrawShadows_Timer = 40000; + Teleport_Timer = 1000; + VoidTraveler_Timer = 20000; + Banish_Timer = 25000; + Intro = false; + Teleport = false; + + if( pInstance ) + pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, NOT_STARTED); + } + + void MoveInLineOfSight(Unit *who) + { + if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) + { + //not sure about right radius + if(!Intro && m_creature->IsWithinDistInMap(who, 50)) + { + DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_INTRO); + DoCast(m_creature, SPELL_VOID_PORTAL_A,true); + m_creature->SummonCreature(ENTRY_VOID_PORTAL,-262.40,-229.57,17.08,0,TEMPSUMMON_CORPSE_DESPAWN,0); + m_creature->SummonCreature(ENTRY_VOID_PORTAL,-260.35,-297.56,17.08,0,TEMPSUMMON_CORPSE_DESPAWN,0); + m_creature->SummonCreature(ENTRY_VOID_PORTAL,-292.05,-270.37,12.68,0,TEMPSUMMON_CORPSE_DESPAWN,0); + m_creature->SummonCreature(ENTRY_VOID_PORTAL,-301.64,-255.97,12.68,0,TEMPSUMMON_CORPSE_DESPAWN,0); + Intro = true; + } + + 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) ) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO3); + break; + } + + if( pInstance ) + pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustSummoned(Creature *summoned) + { + if( summoned->GetEntry() == ENTRY_VOID_TRAVELER ) + { + summoned->GetMotionMaster()->MoveChase(m_creature); + summoned->SetSpeed(MOVE_WALK,0.8,true); + } + + if( summoned->GetEntry() == ENTRY_VOID_PORTAL ) + summoned->CastSpell(summoned,SPELL_VOID_PORTAL_VISUAL,true); + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if( pInstance ) + pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, DONE); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( Teleport ) + { + if( Teleport_Timer <= diff ) + { + m_creature->Relocate(LOCX,LOCY,LOCZ); + m_creature->SendMonsterMove(LOCX,LOCY,LOCZ,0,true,0); + + float ranX = LOCX; + float ranY = LOCY; + float ranZ = LOCZ; + + std::list t_list = m_creature->getThreatManager().getThreatList(); + for( std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr ) + { + Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + if( target && target->GetTypeId() == TYPEID_PLAYER ) + { + target->GetRandomPoint(LOCX,LOCY,LOCZ,3.0,ranX,ranY,ranZ); + DoTeleportPlayer(target,ranX,ranY,ranZ,m_creature->GetAngle(m_creature->GetPositionX(),m_creature->GetPositionY())); + } + } + Teleport = false; + + if( HeroicMode ) DoCast(m_creature->getVictim(), H_SPELL_RAIN_OF_FIRE); + else DoCast(m_creature->getVictim(), SPELL_RAIN_OF_FIRE); + + Teleport_Timer = 1000; + }else Teleport_Timer -= diff; + } + + if( ShadowBoltVolley_Timer < diff ) + { + DoCast(m_creature->getVictim(), SPELL_SHADOW_BOLT_VOLLEY); + ShadowBoltVolley_Timer = 30000; + }else ShadowBoltVolley_Timer -= diff; + + if( DrawShadows_Timer < diff ) + { + DoCast(m_creature,SPELL_DRAW_SHADOWS); + DrawShadows_Timer = 35000; + Teleport = true; + }else DrawShadows_Timer -= diff; + + if( VoidTraveler_Timer < diff ) + { + DoYell(SAY_HELP, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_HELP); + + switch(rand()%5) + { + case 0: + DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_A,true); + break; + case 1: + DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_B,true); + break; + case 2: + DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_C,true); + break; + case 3: + DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_D,true); + break; + case 4: + DoCast(m_creature,SPELL_SUMMON_VOIDWALKER_E,true); + break; + } + //faster rate when below (X) health? + VoidTraveler_Timer = 35000; + }else VoidTraveler_Timer -= diff; + + if( HeroicMode ) + { + if( Banish_Timer < diff ) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1) ) + DoCast(target,H_SPELL_BANISH); + Banish_Timer = 35000; + }else Banish_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_grandmaster_vorpil(Creature *_Creature) +{ + return new boss_grandmaster_vorpilAI (_Creature); +} + +void AddSC_boss_grandmaster_vorpil() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_grandmaster_vorpil"; + newscript->GetAI = GetAI_boss_grandmaster_vorpil; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp index 81aa6ee170d..9be5fbfdc99 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp @@ -1,192 +1,192 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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. -SDCategory: Auchindoun, Shadow Labyrinth -EndScriptData */ - -#include "precompiled.h" - -#define EMOTE_SONIC_BOOM "draws energy from the air." - -#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 - -struct MANGOS_DLL_DECL boss_murmurAI : public ScriptedAI -{ - boss_murmurAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 SonicBoom_Timer; - uint32 MurmursTouch_Timer; - uint32 Resonance_Timer; - uint32 MagneticPull_Timer; - bool CanSonicBoom; - bool CanShockWave; - uint64 pTarget; - - void Reset() - { - SonicBoom_Timer = 30000; - MurmursTouch_Timer = 20000; - Resonance_Timer = 10000; - MagneticPull_Timer = 45000; - CanSonicBoom = false; - CanShockWave = false; - pTarget = 0; - - //database should have `RegenHealth`=0 to prevent regen - uint32 hp = m_creature->GetMaxHealth()*0.4; - if( hp ) - m_creature->SetHealth(hp); - } - - void Aggro(Unit *who) { } - - void AttackStart(Unit* who) - { - if (!who) - return; - - if (who->isTargetableForAttack()) - { - //Begin attack - DoStartAttackNoMovement(who); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - - void MoveInLineOfSight(Unit* who) - { - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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)) - { - DoStartAttackNoMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //SonicBoom_Timer - if(SonicBoom_Timer < diff) - { - if(CanSonicBoom) - { - DoCast(m_creature, SPELL_SONIC_BOOM_CAST,true); - CanSonicBoom = false; - SonicBoom_Timer = 30000; - } - else - { - DoTextEmote(EMOTE_SONIC_BOOM,NULL); - DoCast(m_creature,SPELL_SONIC_BOOM_PRE); - CanSonicBoom = true; - SonicBoom_Timer = 5000; - } - }else SonicBoom_Timer -= diff; - - //MurmursTouch_Timer - if(MurmursTouch_Timer < diff) - { - /*Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if(target) - DoCast(target, SPELL_MURMURS_TOUCH);*/ - DoCast(m_creature, SPELL_MURMURS_TOUCH); - MurmursTouch_Timer = 30000; - }else MurmursTouch_Timer -= diff; - - //Resonance_Timer - if(Resonance_Timer < diff) - { - if( !m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE) ) - DoCast(m_creature->getVictim(), SPELL_RESONANCE); - Resonance_Timer = 5000; - }else Resonance_Timer -= diff; - - //MagneticPull_Timer - if(MagneticPull_Timer < diff) - { - if( !CanShockWave ) - { - if( Unit* temp = SelectUnit(SELECT_TARGET_RANDOM,0) ) - { - if( temp->GetTypeId() == TYPEID_PLAYER ) - { - DoCast(temp, SPELL_MAGNETIC_PULL); - pTarget = temp->GetGUID(); - CanShockWave = true; - } - MagneticPull_Timer = 2500; - } - } - else - { - if( Unit* target = Unit::GetUnit(*m_creature,pTarget) ) - target->CastSpell(target,SPELL_SHOCKWAVE,true); - - MagneticPull_Timer = 35000; - CanShockWave = false; - pTarget = 0; - } - }else MagneticPull_Timer -= diff; - - //no meele if preparing for sonic boom - if(!CanSonicBoom) - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_murmur(Creature *_Creature) -{ - return new boss_murmurAI (_Creature); -} - -void AddSC_boss_murmur() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_murmur"; - newscript->GetAI = GetAI_boss_murmur; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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. +SDCategory: Auchindoun, Shadow Labyrinth +EndScriptData */ + +#include "precompiled.h" + +#define EMOTE_SONIC_BOOM "draws energy from the air." + +#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 + +struct MANGOS_DLL_DECL boss_murmurAI : public ScriptedAI +{ + boss_murmurAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 SonicBoom_Timer; + uint32 MurmursTouch_Timer; + uint32 Resonance_Timer; + uint32 MagneticPull_Timer; + bool CanSonicBoom; + bool CanShockWave; + uint64 pTarget; + + void Reset() + { + SonicBoom_Timer = 30000; + MurmursTouch_Timer = 20000; + Resonance_Timer = 10000; + MagneticPull_Timer = 45000; + CanSonicBoom = false; + CanShockWave = false; + pTarget = 0; + + //database should have `RegenHealth`=0 to prevent regen + uint32 hp = m_creature->GetMaxHealth()*0.4; + if( hp ) + m_creature->SetHealth(hp); + } + + void Aggro(Unit *who) { } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (who->isTargetableForAttack()) + { + //Begin attack + DoStartAttackNoMovement(who); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + + void MoveInLineOfSight(Unit* who) + { + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if(m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) + { + DoStartAttackNoMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //SonicBoom_Timer + if(SonicBoom_Timer < diff) + { + if(CanSonicBoom) + { + DoCast(m_creature, SPELL_SONIC_BOOM_CAST,true); + CanSonicBoom = false; + SonicBoom_Timer = 30000; + } + else + { + DoTextEmote(EMOTE_SONIC_BOOM,NULL); + DoCast(m_creature,SPELL_SONIC_BOOM_PRE); + CanSonicBoom = true; + SonicBoom_Timer = 5000; + } + }else SonicBoom_Timer -= diff; + + //MurmursTouch_Timer + if(MurmursTouch_Timer < diff) + { + /*Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if(target) + DoCast(target, SPELL_MURMURS_TOUCH);*/ + DoCast(m_creature, SPELL_MURMURS_TOUCH); + MurmursTouch_Timer = 30000; + }else MurmursTouch_Timer -= diff; + + //Resonance_Timer + if(Resonance_Timer < diff) + { + if( !m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE) ) + DoCast(m_creature->getVictim(), SPELL_RESONANCE); + Resonance_Timer = 5000; + }else Resonance_Timer -= diff; + + //MagneticPull_Timer + if(MagneticPull_Timer < diff) + { + if( !CanShockWave ) + { + if( Unit* temp = SelectUnit(SELECT_TARGET_RANDOM,0) ) + { + if( temp->GetTypeId() == TYPEID_PLAYER ) + { + DoCast(temp, SPELL_MAGNETIC_PULL); + pTarget = temp->GetGUID(); + CanShockWave = true; + } + MagneticPull_Timer = 2500; + } + } + else + { + if( Unit* target = Unit::GetUnit(*m_creature,pTarget) ) + target->CastSpell(target,SPELL_SHOCKWAVE,true); + + MagneticPull_Timer = 35000; + CanShockWave = false; + pTarget = 0; + } + }else MagneticPull_Timer -= diff; + + //no meele if preparing for sonic boom + if(!CanSonicBoom) + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_murmur(Creature *_Creature) +{ + return new boss_murmurAI (_Creature); +} + +void AddSC_boss_murmur() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_murmur"; + newscript->GetAI = GetAI_boss_murmur; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/def_shadow_labyrinth.h b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/def_shadow_labyrinth.h index 77b0387af16..1300c926c7d 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/def_shadow_labyrinth.h +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/def_shadow_labyrinth.h @@ -1,13 +1,13 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_SHADOW_LABYRINTH_H -#define DEF_SHADOW_LABYRINTH_H - -#define TYPE_HELLMAW 1 -#define TYPE_OVERSEER 2 -#define DATA_BLACKHEARTTHEINCITEREVENT 3 -#define DATA_GRANDMASTERVORPILEVENT 4 -#define DATA_MURMUREVENT 5 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_SHADOW_LABYRINTH_H +#define DEF_SHADOW_LABYRINTH_H + +#define TYPE_HELLMAW 1 +#define TYPE_OVERSEER 2 +#define DATA_BLACKHEARTTHEINCITEREVENT 3 +#define DATA_GRANDMASTERVORPILEVENT 4 +#define DATA_MURMUREVENT 5 +#endif diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp index ea2c141b2e0..86a0ef45c88 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp @@ -1,168 +1,168 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Shadow_Labyrinth -SD%Complete: 85 -SDComment: Some cleanup left along with save -SDCategory: Auchindoun, Shadow Labyrinth -EndScriptData */ - -#include "precompiled.h" -#include "def_shadow_labyrinth.h" - -#define ENCOUNTERS 5 - -#define REFECTORY_DOOR 183296 //door opened when blackheart the inciter dies -#define SCREAMING_HALL_DOOR 183295 //door opened when grandmaster vorpil dies - -/* Shadow Labyrinth encounters: -1 - Ambassador Hellmaw event -2 - Blackheart the Inciter event -3 - Grandmaster Vorpil event -4 - Murmur event -*/ - -struct MANGOS_DLL_DECL instance_shadow_labyrinth : public ScriptedInstance -{ - instance_shadow_labyrinth(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint32 Encounter[ENCOUNTERS]; - - GameObject *RefectoryDoor; - GameObject *ScreamingHallDoor; - uint64 GrandmasterVorpil; - uint32 FelOverseerCount; - - void Initialize() - { - RefectoryDoor = NULL; - ScreamingHallDoor = NULL; - GrandmasterVorpil = 0; - FelOverseerCount = 0; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounter[i] = false; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; i++) - if(Encounter[i]) return true; - - return false; - } - - void OnObjectCreate(GameObject *go) - { - switch(go->GetEntry()) - { - case REFECTORY_DOOR: - RefectoryDoor = go; - break; - case SCREAMING_HALL_DOOR: - ScreamingHallDoor = go; - break; - } - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case 18732: - GrandmasterVorpil = creature->GetGUID(); - break; - case 18796: - ++FelOverseerCount; - debug_log("SD2: Shadow Labyrinth: counting %u Fel Overseers.",FelOverseerCount); - break; - } - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case TYPE_HELLMAW: - Encounter[0] = data; - break; - - case TYPE_OVERSEER: - if( data != DONE ) - error_log("SD2: Shadow Labyrinth: TYPE_OVERSEER did not expect other data than DONE"); - if( FelOverseerCount ) - { - --FelOverseerCount; - debug_log("SD2: Shadow Labyrinth: %u Fel Overseers left to kill.",FelOverseerCount); - } - if( FelOverseerCount == 0 ) - { - Encounter[1] = DONE; - debug_log("SD2: Shadow Labyrinth: TYPE_OVERSEER == DONE"); - } - break; - - case DATA_BLACKHEARTTHEINCITEREVENT: - if( data == DONE ) - { - if( RefectoryDoor ) - RefectoryDoor->UseDoorOrButton(); - } - Encounter[2] = data; - break; - - case DATA_GRANDMASTERVORPILEVENT: - if( data == DONE ) - { - if( ScreamingHallDoor ) - ScreamingHallDoor->UseDoorOrButton(); - } - Encounter[3] = data; - break; - - case DATA_MURMUREVENT: - Encounter[4] = data; - break; - } - } - - uint32 GetData(uint32 type) - { - switch( type ) - { - case TYPE_HELLMAW: - return Encounter[0]; - case TYPE_OVERSEER: - return Encounter[1]; - } - return false; - } -}; - -InstanceData* GetInstanceData_instance_shadow_labyrinth(Map* map) -{ - return new instance_shadow_labyrinth(map); -} - -void AddSC_instance_shadow_labyrinth() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_shadow_labyrinth"; - newscript->GetInstanceData = GetInstanceData_instance_shadow_labyrinth; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Shadow_Labyrinth +SD%Complete: 85 +SDComment: Some cleanup left along with save +SDCategory: Auchindoun, Shadow Labyrinth +EndScriptData */ + +#include "precompiled.h" +#include "def_shadow_labyrinth.h" + +#define ENCOUNTERS 5 + +#define REFECTORY_DOOR 183296 //door opened when blackheart the inciter dies +#define SCREAMING_HALL_DOOR 183295 //door opened when grandmaster vorpil dies + +/* Shadow Labyrinth encounters: +1 - Ambassador Hellmaw event +2 - Blackheart the Inciter event +3 - Grandmaster Vorpil event +4 - Murmur event +*/ + +struct MANGOS_DLL_DECL instance_shadow_labyrinth : public ScriptedInstance +{ + instance_shadow_labyrinth(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 Encounter[ENCOUNTERS]; + + GameObject *RefectoryDoor; + GameObject *ScreamingHallDoor; + uint64 GrandmasterVorpil; + uint32 FelOverseerCount; + + void Initialize() + { + RefectoryDoor = NULL; + ScreamingHallDoor = NULL; + GrandmasterVorpil = 0; + FelOverseerCount = 0; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounter[i] = false; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounter[i]) return true; + + return false; + } + + void OnObjectCreate(GameObject *go) + { + switch(go->GetEntry()) + { + case REFECTORY_DOOR: + RefectoryDoor = go; + break; + case SCREAMING_HALL_DOOR: + ScreamingHallDoor = go; + break; + } + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case 18732: + GrandmasterVorpil = creature->GetGUID(); + break; + case 18796: + ++FelOverseerCount; + debug_log("SD2: Shadow Labyrinth: counting %u Fel Overseers.",FelOverseerCount); + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case TYPE_HELLMAW: + Encounter[0] = data; + break; + + case TYPE_OVERSEER: + if( data != DONE ) + error_log("SD2: Shadow Labyrinth: TYPE_OVERSEER did not expect other data than DONE"); + if( FelOverseerCount ) + { + --FelOverseerCount; + debug_log("SD2: Shadow Labyrinth: %u Fel Overseers left to kill.",FelOverseerCount); + } + if( FelOverseerCount == 0 ) + { + Encounter[1] = DONE; + debug_log("SD2: Shadow Labyrinth: TYPE_OVERSEER == DONE"); + } + break; + + case DATA_BLACKHEARTTHEINCITEREVENT: + if( data == DONE ) + { + if( RefectoryDoor ) + RefectoryDoor->UseDoorOrButton(); + } + Encounter[2] = data; + break; + + case DATA_GRANDMASTERVORPILEVENT: + if( data == DONE ) + { + if( ScreamingHallDoor ) + ScreamingHallDoor->UseDoorOrButton(); + } + Encounter[3] = data; + break; + + case DATA_MURMUREVENT: + Encounter[4] = data; + break; + } + } + + uint32 GetData(uint32 type) + { + switch( type ) + { + case TYPE_HELLMAW: + return Encounter[0]; + case TYPE_OVERSEER: + return Encounter[1]; + } + return false; + } +}; + +InstanceData* GetInstanceData_instance_shadow_labyrinth(Map* map) +{ + return new instance_shadow_labyrinth(map); +} + +void AddSC_instance_shadow_labyrinth() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_shadow_labyrinth"; + newscript->GetInstanceData = GetInstanceData_instance_shadow_labyrinth; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/azshara/azshara.cpp b/src/bindings/scripts/scripts/zone/azshara/azshara.cpp index c892847bbc8..0f08d3d7592 100644 --- a/src/bindings/scripts/scripts/zone/azshara/azshara.cpp +++ b/src/bindings/scripts/scripts/zone/azshara/azshara.cpp @@ -1,164 +1,164 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Azshara -SD%Complete: 90 -SDComment: Quest support: 2744, 3141, 9364 -SDCategory: Azshara -EndScriptData */ - -/* ContentData -mobs_spitelashes -npc_loramus_thalipedes -EndContentData */ - -#include "precompiled.h" - -/*###### -## mobs_spitelashes -######*/ - -struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI -{ - mobs_spitelashesAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 morphtimer; - bool spellhit; - - void Reset() - { - morphtimer = 0; - spellhit = false; - } - - void Aggro(Unit *who) { } - - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) - { - 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) ) - { - spellhit=true; - DoCast(m_creature,29124); //become a sheep - } - } - - void UpdateAI(const uint32 diff) - { - // 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->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_creature->RemoveCorpse(); //you don't see any corpse on off. - EnterEvadeMode(); //spellhit will be set to false - } - // walk 5 seconds before summoning - if( spellhit && morphtimer<5000 ) - { - morphtimer+=diff; - if( morphtimer>=5000 ) - { - DoCast(m_creature,28406); //summon copies - DoCast(m_creature,6924); //visual explosion - } - } - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //TODO: add abilities for the different creatures - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_mobs_spitelashes(Creature *_Creature) -{ - return new mobs_spitelashesAI (_Creature); -} - -/*###### -## npc_loramus_thalipedes -######*/ - -bool GossipHello_npc_loramus_thalipedes(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(2744) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Can you help me?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - if (player->GetQuestStatus(3141) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Tell me your story", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_loramus_thalipedes(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(2744); - break; - - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "Please continue", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); - player->SEND_GOSSIP_MENU(1813, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+21: - player->ADD_GOSSIP_ITEM( 0, "I do not understand", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); - player->SEND_GOSSIP_MENU(1814, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+22: - player->ADD_GOSSIP_ITEM( 0, "Indeed", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 23); - player->SEND_GOSSIP_MENU(1815, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+23: - player->ADD_GOSSIP_ITEM( 0, "I will do this with or your help, Loramus", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 24); - player->SEND_GOSSIP_MENU(1816, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+24: - player->ADD_GOSSIP_ITEM( 0, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 25); - player->SEND_GOSSIP_MENU(1817, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+25: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(3141); - break; - } - return true; -} - -void AddSC_azshara() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mobs_spitelashes"; - newscript->GetAI = GetAI_mobs_spitelashes; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_loramus_thalipedes"; - newscript->pGossipHello = &GossipHello_npc_loramus_thalipedes; - newscript->pGossipSelect = &GossipSelect_npc_loramus_thalipedes; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Azshara +SD%Complete: 90 +SDComment: Quest support: 2744, 3141, 9364 +SDCategory: Azshara +EndScriptData */ + +/* ContentData +mobs_spitelashes +npc_loramus_thalipedes +EndContentData */ + +#include "precompiled.h" + +/*###### +## mobs_spitelashes +######*/ + +struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI +{ + mobs_spitelashesAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 morphtimer; + bool spellhit; + + void Reset() + { + morphtimer = 0; + spellhit = false; + } + + void Aggro(Unit *who) { } + + void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) + { + 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) ) + { + spellhit=true; + DoCast(m_creature,29124); //become a sheep + } + } + + void UpdateAI(const uint32 diff) + { + // 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->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_creature->RemoveCorpse(); //you don't see any corpse on off. + EnterEvadeMode(); //spellhit will be set to false + } + // walk 5 seconds before summoning + if( spellhit && morphtimer<5000 ) + { + morphtimer+=diff; + if( morphtimer>=5000 ) + { + DoCast(m_creature,28406); //summon copies + DoCast(m_creature,6924); //visual explosion + } + } + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //TODO: add abilities for the different creatures + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_mobs_spitelashes(Creature *_Creature) +{ + return new mobs_spitelashesAI (_Creature); +} + +/*###### +## npc_loramus_thalipedes +######*/ + +bool GossipHello_npc_loramus_thalipedes(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(2744) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Can you help me?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + if (player->GetQuestStatus(3141) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Tell me your story", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_loramus_thalipedes(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(2744); + break; + + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "Please continue", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); + player->SEND_GOSSIP_MENU(1813, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+21: + player->ADD_GOSSIP_ITEM( 0, "I do not understand", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); + player->SEND_GOSSIP_MENU(1814, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+22: + player->ADD_GOSSIP_ITEM( 0, "Indeed", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 23); + player->SEND_GOSSIP_MENU(1815, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+23: + player->ADD_GOSSIP_ITEM( 0, "I will do this with or your help, Loramus", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 24); + player->SEND_GOSSIP_MENU(1816, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+24: + player->ADD_GOSSIP_ITEM( 0, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 25); + player->SEND_GOSSIP_MENU(1817, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+25: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(3141); + break; + } + return true; +} + +void AddSC_azshara() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mobs_spitelashes"; + newscript->GetAI = GetAI_mobs_spitelashes; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_loramus_thalipedes"; + newscript->pGossipHello = &GossipHello_npc_loramus_thalipedes; + newscript->pGossipSelect = &GossipSelect_npc_loramus_thalipedes; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/azshara/boss_azuregos.cpp b/src/bindings/scripts/scripts/zone/azshara/boss_azuregos.cpp index 5193fd841a1..550a25a3f75 100644 --- a/src/bindings/scripts/scripts/zone/azshara/boss_azuregos.cpp +++ b/src/bindings/scripts/scripts/zone/azshara/boss_azuregos.cpp @@ -1,153 +1,153 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Azuregos -SD%Complete: 90 -SDComment: Teleport not included, spell reflect not effecting dots (Core problem) -SDCategory: Azshara -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_MARKOFFROST 23182 -#define SPELL_MANASTORM 21097 -#define SPELL_CHILL 21098 -#define SPELL_FROSTBREATH 21099 -#define SPELL_REFLECT 22067 //Old one was 30969 -#define SPELL_CLEAVE 8255 //Perhaps not right ID -#define SPELL_ENRAGE 23537 - -struct MANGOS_DLL_DECL boss_azuregosAI : public ScriptedAI -{ - boss_azuregosAI(Creature *c) : ScriptedAI(c) {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; - - void Reset() - { - MarkOfFrost_Timer = 35000; - ManaStorm_Timer = 5000 + rand()%12000; - Chill_Timer = 10000 + rand()%20000; - Breath_Timer = 2000 + rand()%6000; - Teleport_Timer = 30000; - Reflect_Timer = 15000 + rand()%15000; - Cleave_Timer = 7000; - Enrage_Timer = 0; - Enraged = false; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(Teleport_Timer < diff) - { - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list::iterator i = m_threatlist.begin(); - for (i = m_threatlist.begin(); i!= m_threatlist.end();++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) - { - DoTeleportPlayer(pUnit, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+3, pUnit->GetOrientation()); - } - } - - DoResetThreat(); - Teleport_Timer = 30000; - }else Teleport_Timer -= diff; - - // //MarkOfFrost_Timer - // if (MarkOfFrost_Timer < diff) - // { - // DoCast(m_creature->getVictim(),SPELL_MARKOFFROST); - // MarkOfFrost_Timer = 25000; - // }else MarkOfFrost_Timer -= diff; - - //Chill_Timer - if (Chill_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CHILL); - Chill_Timer = 13000 + rand()%12000; - }else Chill_Timer -= diff; - - //Breath_Timer - if (Breath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROSTBREATH); - Breath_Timer = 10000 + rand()%5000; - }else Breath_Timer -= diff; - - //ManaStorm_Timer - if (ManaStorm_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - DoCast(target,SPELL_MANASTORM); - ManaStorm_Timer = 7500 + rand()%5000; - }else ManaStorm_Timer -= diff; - - //Reflect_Timer - if (Reflect_Timer < diff) - { - DoCast(m_creature,SPELL_REFLECT); - Reflect_Timer = 20000 + rand()%15000; - }else Reflect_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - //Enrage_Timer - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 26 && !Enraged) - { - DoCast(m_creature, SPELL_ENRAGE); - Enraged = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_azuregos(Creature *_Creature) -{ - return new boss_azuregosAI (_Creature); -} - -void AddSC_boss_azuregos() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_azuregos"; - newscript->GetAI = GetAI_boss_azuregos; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Azuregos +SD%Complete: 90 +SDComment: Teleport not included, spell reflect not effecting dots (Core problem) +SDCategory: Azshara +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_MARKOFFROST 23182 +#define SPELL_MANASTORM 21097 +#define SPELL_CHILL 21098 +#define SPELL_FROSTBREATH 21099 +#define SPELL_REFLECT 22067 //Old one was 30969 +#define SPELL_CLEAVE 8255 //Perhaps not right ID +#define SPELL_ENRAGE 23537 + +struct MANGOS_DLL_DECL boss_azuregosAI : public ScriptedAI +{ + boss_azuregosAI(Creature *c) : ScriptedAI(c) {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; + + void Reset() + { + MarkOfFrost_Timer = 35000; + ManaStorm_Timer = 5000 + rand()%12000; + Chill_Timer = 10000 + rand()%20000; + Breath_Timer = 2000 + rand()%6000; + Teleport_Timer = 30000; + Reflect_Timer = 15000 + rand()%15000; + Cleave_Timer = 7000; + Enrage_Timer = 0; + Enraged = false; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(Teleport_Timer < diff) + { + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + std::list::iterator i = m_threatlist.begin(); + for (i = m_threatlist.begin(); i!= m_threatlist.end();++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) + { + DoTeleportPlayer(pUnit, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+3, pUnit->GetOrientation()); + } + } + + DoResetThreat(); + Teleport_Timer = 30000; + }else Teleport_Timer -= diff; + + // //MarkOfFrost_Timer + // if (MarkOfFrost_Timer < diff) + // { + // DoCast(m_creature->getVictim(),SPELL_MARKOFFROST); + // MarkOfFrost_Timer = 25000; + // }else MarkOfFrost_Timer -= diff; + + //Chill_Timer + if (Chill_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CHILL); + Chill_Timer = 13000 + rand()%12000; + }else Chill_Timer -= diff; + + //Breath_Timer + if (Breath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROSTBREATH); + Breath_Timer = 10000 + rand()%5000; + }else Breath_Timer -= diff; + + //ManaStorm_Timer + if (ManaStorm_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + DoCast(target,SPELL_MANASTORM); + ManaStorm_Timer = 7500 + rand()%5000; + }else ManaStorm_Timer -= diff; + + //Reflect_Timer + if (Reflect_Timer < diff) + { + DoCast(m_creature,SPELL_REFLECT); + Reflect_Timer = 20000 + rand()%15000; + }else Reflect_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 7000; + }else Cleave_Timer -= diff; + + //Enrage_Timer + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 26 && !Enraged) + { + DoCast(m_creature, SPELL_ENRAGE); + Enraged = true; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_azuregos(Creature *_Creature) +{ + return new boss_azuregosAI (_Creature); +} + +void AddSC_boss_azuregos() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_azuregos"; + newscript->GetAI = GetAI_boss_azuregos; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp b/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp index f1f68ff4ee3..3ec11ef1eb0 100644 --- a/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp +++ b/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp @@ -1,372 +1,372 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Azuremyst_Isle -SD%Complete: 75 -SDComment: Quest support: 9283, 9537, 9554(special flight path, proper model for mount missing). Injured Draenei cosmetic only -SDCategory: Azuremyst Isle -EndScriptData */ - -/* ContentData -npc_draenei_survivor -npc_engineer_spark_overgrind -npc_injured_draenei -npc_susurrus -EndContentData */ - -#include "precompiled.h" -#include - -/*###### -## npc_draenei_survivor -######*/ - -#define HEAL1 "The last thing I remember is the ship falling and us getting into the pods. I'll go see how I can help. Thank you!" -#define HEAL2 "$C, Where am I? Who are you? Oh no! What happened to the ship?." -#define HEAL3 "$C You saved me! I owe you a debt that I can never repay. I'll go see if I can help the others." -#define HEAL4 "Ugh... what is this place? Is that all that's left of the ship over there?" - -#define HELP1 "Oh, the pain..." -#define HELP2 "Everything hurts, Please make it stop..." -#define HELP3 "Ughhh... I hurt. Can you help me?" -#define HELP4 "I don't know if I can make it, please help me..." - -struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI -{ - npc_draenei_survivorAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 UnSpawnTimer; - uint32 ResetlifeTimer; - uint32 SayingTimer; - uint32 HealSayTimer; - bool UnSpawn; - bool say; - bool HealSay; - bool isRun; - bool isMove; - - void Reset() - { - UnSpawnTimer = 2500; - ResetlifeTimer= 60000; - SayingTimer = 5000; - HealSayTimer = 6000; - say = false; - isRun = false; - isMove = false; - UnSpawn = false; - HealSay = false; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - //cast red shining - m_creature->CastSpell(m_creature, 29152, false, NULL); - //set creature health - m_creature->SetHealth(int(m_creature->GetMaxHealth()*.1)); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); - } - - void Aggro(Unit *who) {} - - void MoveInLineOfSight(Unit *who) //MoveInLineOfSight is called if creature could see you, updated all 100 ms - { - if (!who) - return; - - if(who->GetTypeId() == TYPEID_PLAYER && m_creature->IsFriendlyTo(who) && m_creature->IsWithinDistInMap(who, 15) && say && !isRun) - { - switch (rand()%4) //Random switch between 4 texts - { - case 0: - DoSay(HELP1, LANG_UNIVERSAL, NULL); - SayingTimer = 15000; - say = false; - break; - case 1: - DoSay(HELP2, LANG_UNIVERSAL, NULL); - SayingTimer = 15000; - say = false; - break; - case 2: - DoSay(HELP3, LANG_UNIVERSAL, NULL); - SayingTimer = 15000; - say = false; - break; - case 3: - DoSay(HELP4, LANG_UNIVERSAL, NULL); - SayingTimer = 15000; - say = false; - break; - } - } - else - { - isRun = false; - } - } - - void UpdateAI(const uint32 diff) //Is also called each ms for Creature AI Updates... - { - if (m_creature->GetHealth() > 50) - { - if(ResetlifeTimer < diff) - { - ResetlifeTimer = 60000; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - //set creature health - m_creature->SetHealth(int(m_creature->GetMaxHealth()*.1)); - // ley down - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,3); - } - else ResetlifeTimer -= diff; - } - - if(HealSay) - { - if (HealSayTimer < diff) - { - UnSpawn = true; - isRun = true; - isMove = true; - }else HealSayTimer -= diff; - } - - if(UnSpawn) - { - if(isMove) - { - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MovePoint(0, -4115.053711f, -13754.831055f, 73.508949f); - isMove = false; - } - - if (UnSpawnTimer < diff) - { - m_creature->StopMoving(); - EnterEvadeMode(); - //set creature health - m_creature->SetHealth(int(m_creature->GetMaxHealth()*.1)); - - }else UnSpawnTimer -= diff; - } - - if(SayingTimer < diff) - { - say = true; - }else SayingTimer -= diff; - } - - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind)//Called if you cast a spell and do some things if Specified spell is true! - { - if (Hitter && Spellkind->Id == 28880) - { - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - m_creature->HandleEmoteCommand(ANIM_RISE); - switch (rand()%4) //This switch doesn't work at all, creature say nothing! - { - case 0: DoSay(HEAL1, LANG_UNIVERSAL, Hitter); break; - case 1: DoSay(HEAL2, LANG_UNIVERSAL, Hitter); break; - case 2: DoSay(HEAL3, LANG_UNIVERSAL, Hitter); break; - case 3: DoSay(HEAL4, LANG_UNIVERSAL, Hitter); break; - } - HealSay = true; - } - } -}; -CreatureAI* GetAI_npc_draenei_survivor(Creature *_Creature) -{ - return new npc_draenei_survivorAI (_Creature); -} - -/*###### -## npc_engineer_spark_overgrind -######*/ - -#define SAY_TEXT "Yes Master, all goes along as planned." -#define SAY_EMOTE "puts the shell to his ear." -#define GOSSIP_FIGHT "Traitor! You will be brought to justice!" -#define ATTACK_YELL "Now I cut you!" -#define SPELL_DYNAMITE 7978 - -struct MANGOS_DLL_DECL npc_engineer_spark_overgrindAI : public ScriptedAI -{ - npc_engineer_spark_overgrindAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Dynamite_Timer; - uint32 Emote_Timer; - - void Reset() - { - Dynamite_Timer = 8000; - Emote_Timer = 120000 + rand()%30000; - m_creature->setFaction(875); - } - - void Aggro(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if( !InCombat ) - { - if (Emote_Timer < diff) - { - DoSay(SAY_TEXT,LANG_UNIVERSAL,NULL); - DoTextEmote(SAY_EMOTE,NULL); - Emote_Timer = 120000 + rand()%30000; - }else Emote_Timer -= diff; - } - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (Dynamite_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_DYNAMITE); - Dynamite_Timer = 8000; - } else Dynamite_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_npc_engineer_spark_overgrind(Creature *_Creature) -{ - return new npc_engineer_spark_overgrindAI (_Creature); -} - -bool GossipHello_npc_engineer_spark_overgrind(Player *player, Creature *_Creature) -{ - if( player->GetQuestStatus(9537) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM(0, GOSSIP_FIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_engineer_spark_overgrind(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_INFO_DEF ) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->setFaction(14); - _Creature->Yell(ATTACK_YELL, LANG_UNIVERSAL, player->GetGUID()); - ((npc_engineer_spark_overgrindAI*)_Creature->AI())->AttackStart(player); - } - return true; -} - -/*###### -## npc_injured_draenei -######*/ - -struct MANGOS_DLL_DECL npc_injured_draeneiAI : public ScriptedAI -{ - npc_injured_draeneiAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - m_creature->SetHealth(int(m_creature->GetMaxHealth()*.15)); - switch (rand()%2) - { - case 0: m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 1); break; - case 1: m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); break; - } - } - - void Aggro(Unit *who) {} - - void MoveInLineOfSight(Unit *who) - { - return; //ignore everyone around them (won't aggro anything) - } - - void UpdateAI(const uint32 diff) - { - return; - } - -}; -CreatureAI* GetAI_npc_injured_draenei(Creature *_Creature) -{ - return new npc_injured_draeneiAI (_Creature); -} - -/*###### -## npc_susurrus -######*/ - -bool GossipHello_npc_susurrus(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->HasItemCount(23843,1,true)) - player->ADD_GOSSIP_ITEM(0, "I am ready.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_susurrus(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,32474,true); //apparently correct spell, possible not correct place to cast, or correct caster - - std::vector nodes; - - nodes.resize(2); - nodes[0] = 92; //from susurrus - nodes[1] = 91; //end at exodar - player->ActivateTaxiPathTo(nodes,11686); //TaxiPath 506. Using invisible model, possible mangos must allow 0(from dbc) for cases like this. - } - return true; -} - -/*###### -## -######*/ - -void AddSC_azuremyst_isle() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_draenei_survivor"; - newscript->GetAI = GetAI_npc_draenei_survivor; - m_scripts[nrscripts++] = newscript; - - 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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_injured_draenei"; - newscript->GetAI = GetAI_npc_injured_draenei; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_susurrus"; - newscript->pGossipHello = &GossipHello_npc_susurrus; - newscript->pGossipSelect = &GossipSelect_npc_susurrus; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Azuremyst_Isle +SD%Complete: 75 +SDComment: Quest support: 9283, 9537, 9554(special flight path, proper model for mount missing). Injured Draenei cosmetic only +SDCategory: Azuremyst Isle +EndScriptData */ + +/* ContentData +npc_draenei_survivor +npc_engineer_spark_overgrind +npc_injured_draenei +npc_susurrus +EndContentData */ + +#include "precompiled.h" +#include + +/*###### +## npc_draenei_survivor +######*/ + +#define HEAL1 "The last thing I remember is the ship falling and us getting into the pods. I'll go see how I can help. Thank you!" +#define HEAL2 "$C, Where am I? Who are you? Oh no! What happened to the ship?." +#define HEAL3 "$C You saved me! I owe you a debt that I can never repay. I'll go see if I can help the others." +#define HEAL4 "Ugh... what is this place? Is that all that's left of the ship over there?" + +#define HELP1 "Oh, the pain..." +#define HELP2 "Everything hurts, Please make it stop..." +#define HELP3 "Ughhh... I hurt. Can you help me?" +#define HELP4 "I don't know if I can make it, please help me..." + +struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI +{ + npc_draenei_survivorAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 UnSpawnTimer; + uint32 ResetlifeTimer; + uint32 SayingTimer; + uint32 HealSayTimer; + bool UnSpawn; + bool say; + bool HealSay; + bool isRun; + bool isMove; + + void Reset() + { + UnSpawnTimer = 2500; + ResetlifeTimer= 60000; + SayingTimer = 5000; + HealSayTimer = 6000; + say = false; + isRun = false; + isMove = false; + UnSpawn = false; + HealSay = false; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + //cast red shining + m_creature->CastSpell(m_creature, 29152, false, NULL); + //set creature health + m_creature->SetHealth(int(m_creature->GetMaxHealth()*.1)); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); + } + + void Aggro(Unit *who) {} + + void MoveInLineOfSight(Unit *who) //MoveInLineOfSight is called if creature could see you, updated all 100 ms + { + if (!who) + return; + + if(who->GetTypeId() == TYPEID_PLAYER && m_creature->IsFriendlyTo(who) && m_creature->IsWithinDistInMap(who, 15) && say && !isRun) + { + switch (rand()%4) //Random switch between 4 texts + { + case 0: + DoSay(HELP1, LANG_UNIVERSAL, NULL); + SayingTimer = 15000; + say = false; + break; + case 1: + DoSay(HELP2, LANG_UNIVERSAL, NULL); + SayingTimer = 15000; + say = false; + break; + case 2: + DoSay(HELP3, LANG_UNIVERSAL, NULL); + SayingTimer = 15000; + say = false; + break; + case 3: + DoSay(HELP4, LANG_UNIVERSAL, NULL); + SayingTimer = 15000; + say = false; + break; + } + } + else + { + isRun = false; + } + } + + void UpdateAI(const uint32 diff) //Is also called each ms for Creature AI Updates... + { + if (m_creature->GetHealth() > 50) + { + if(ResetlifeTimer < diff) + { + ResetlifeTimer = 60000; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + //set creature health + m_creature->SetHealth(int(m_creature->GetMaxHealth()*.1)); + // ley down + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,3); + } + else ResetlifeTimer -= diff; + } + + if(HealSay) + { + if (HealSayTimer < diff) + { + UnSpawn = true; + isRun = true; + isMove = true; + }else HealSayTimer -= diff; + } + + if(UnSpawn) + { + if(isMove) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(0, -4115.053711f, -13754.831055f, 73.508949f); + isMove = false; + } + + if (UnSpawnTimer < diff) + { + m_creature->StopMoving(); + EnterEvadeMode(); + //set creature health + m_creature->SetHealth(int(m_creature->GetMaxHealth()*.1)); + + }else UnSpawnTimer -= diff; + } + + if(SayingTimer < diff) + { + say = true; + }else SayingTimer -= diff; + } + + void SpellHit(Unit *Hitter, const SpellEntry *Spellkind)//Called if you cast a spell and do some things if Specified spell is true! + { + if (Hitter && Spellkind->Id == 28880) + { + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + m_creature->HandleEmoteCommand(ANIM_RISE); + switch (rand()%4) //This switch doesn't work at all, creature say nothing! + { + case 0: DoSay(HEAL1, LANG_UNIVERSAL, Hitter); break; + case 1: DoSay(HEAL2, LANG_UNIVERSAL, Hitter); break; + case 2: DoSay(HEAL3, LANG_UNIVERSAL, Hitter); break; + case 3: DoSay(HEAL4, LANG_UNIVERSAL, Hitter); break; + } + HealSay = true; + } + } +}; +CreatureAI* GetAI_npc_draenei_survivor(Creature *_Creature) +{ + return new npc_draenei_survivorAI (_Creature); +} + +/*###### +## npc_engineer_spark_overgrind +######*/ + +#define SAY_TEXT "Yes Master, all goes along as planned." +#define SAY_EMOTE "puts the shell to his ear." +#define GOSSIP_FIGHT "Traitor! You will be brought to justice!" +#define ATTACK_YELL "Now I cut you!" +#define SPELL_DYNAMITE 7978 + +struct MANGOS_DLL_DECL npc_engineer_spark_overgrindAI : public ScriptedAI +{ + npc_engineer_spark_overgrindAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Dynamite_Timer; + uint32 Emote_Timer; + + void Reset() + { + Dynamite_Timer = 8000; + Emote_Timer = 120000 + rand()%30000; + m_creature->setFaction(875); + } + + void Aggro(Unit *who) { } + + void UpdateAI(const uint32 diff) + { + if( !InCombat ) + { + if (Emote_Timer < diff) + { + DoSay(SAY_TEXT,LANG_UNIVERSAL,NULL); + DoTextEmote(SAY_EMOTE,NULL); + Emote_Timer = 120000 + rand()%30000; + }else Emote_Timer -= diff; + } + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (Dynamite_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_DYNAMITE); + Dynamite_Timer = 8000; + } else Dynamite_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_engineer_spark_overgrind(Creature *_Creature) +{ + return new npc_engineer_spark_overgrindAI (_Creature); +} + +bool GossipHello_npc_engineer_spark_overgrind(Player *player, Creature *_Creature) +{ + if( player->GetQuestStatus(9537) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM(0, GOSSIP_FIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_engineer_spark_overgrind(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF ) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->setFaction(14); + _Creature->Yell(ATTACK_YELL, LANG_UNIVERSAL, player->GetGUID()); + ((npc_engineer_spark_overgrindAI*)_Creature->AI())->AttackStart(player); + } + return true; +} + +/*###### +## npc_injured_draenei +######*/ + +struct MANGOS_DLL_DECL npc_injured_draeneiAI : public ScriptedAI +{ + npc_injured_draeneiAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + m_creature->SetHealth(int(m_creature->GetMaxHealth()*.15)); + switch (rand()%2) + { + case 0: m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 1); break; + case 1: m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); break; + } + } + + void Aggro(Unit *who) {} + + void MoveInLineOfSight(Unit *who) + { + return; //ignore everyone around them (won't aggro anything) + } + + void UpdateAI(const uint32 diff) + { + return; + } + +}; +CreatureAI* GetAI_npc_injured_draenei(Creature *_Creature) +{ + return new npc_injured_draeneiAI (_Creature); +} + +/*###### +## npc_susurrus +######*/ + +bool GossipHello_npc_susurrus(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->HasItemCount(23843,1,true)) + player->ADD_GOSSIP_ITEM(0, "I am ready.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_susurrus(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,32474,true); //apparently correct spell, possible not correct place to cast, or correct caster + + std::vector nodes; + + nodes.resize(2); + nodes[0] = 92; //from susurrus + nodes[1] = 91; //end at exodar + player->ActivateTaxiPathTo(nodes,11686); //TaxiPath 506. Using invisible model, possible mangos must allow 0(from dbc) for cases like this. + } + return true; +} + +/*###### +## +######*/ + +void AddSC_azuremyst_isle() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_draenei_survivor"; + newscript->GetAI = GetAI_npc_draenei_survivor; + m_scripts[nrscripts++] = newscript; + + 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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_injured_draenei"; + newscript->GetAI = GetAI_npc_injured_draenei; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_susurrus"; + newscript->pGossipHello = &GossipHello_npc_susurrus; + newscript->pGossipSelect = &GossipSelect_npc_susurrus; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/barrens/the_barrens.cpp b/src/bindings/scripts/scripts/zone/barrens/the_barrens.cpp index b09dd9222de..b235bde66f0 100644 --- a/src/bindings/scripts/scripts/zone/barrens/the_barrens.cpp +++ b/src/bindings/scripts/scripts/zone/barrens/the_barrens.cpp @@ -1,189 +1,189 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Barrens -SD%Complete: 90 -SDComment: Quest support: 2458, 4921, 6981 -SDCategory: Barrens -EndScriptData */ - -/* ContentData -npc_beaten_corpse -npc_sputtervalve -npc_taskmaster_fizzule remove hack when mangos implement feature/detect spell kind to not aggro -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_beaten_corpse -######*/ - -bool GossipHello_npc_beaten_corpse(Player *player, Creature *_Creature) -{ - if( player->GetQuestStatus(4921) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(4921) == QUEST_STATUS_COMPLETE) - player->ADD_GOSSIP_ITEM(0,"Examine corpse in detail...",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(3557,_Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_beaten_corpse(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if(action == GOSSIP_ACTION_INFO_DEF +1) - { - player->SEND_GOSSIP_MENU(3558,_Creature->GetGUID()); - player->KilledMonster( 10668,_Creature->GetGUID() ); - } - return true; -} - -/*###### -## npc_sputtervalve -######*/ - -bool GossipHello_npc_sputtervalve(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->GetQuestStatus(6981) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(0,"Can you tell me about this shard?",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_sputtervalve(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if(action == GOSSIP_ACTION_INFO_DEF) - { - player->SEND_GOSSIP_MENU(2013,_Creature->GetGUID()); - player->AreaExploredOrEventHappens(6981); - } - return true; -} - -/*###### -## npc_taskmaster_fizzule -######*/ - -//#define FACTION_HOSTILE_F 430 -#define FACTION_HOSTILE_F 16 -#define FACTION_FRIENDLY_F 35 - -#define SPELL_FLARE 10113 -#define SPELL_FOLLY 10137 - -struct MANGOS_DLL_DECL npc_taskmaster_fizzuleAI : public ScriptedAI -{ - npc_taskmaster_fizzuleAI(Creature* c) : ScriptedAI(c) { Reset(); } - - bool IsFriend; - uint32 Reset_Timer; - uint32 FlareCount; - - void Reset() - { - IsFriend = false; - Reset_Timer = 120000; - FlareCount = 0; - m_creature->setFaction(FACTION_HOSTILE_F); - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - } - - //This is a hack. Spellcast will make creature aggro but that is not - //supposed to happen (mangos not implemented/not found way to detect this spell kind) - void DoUglyHack() - { - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if( spell->Id == SPELL_FLARE || spell->Id == SPELL_FOLLY ) - { - DoUglyHack(); - ++FlareCount; - if( FlareCount >= 2 ) - { - m_creature->setFaction(FACTION_FRIENDLY_F); - IsFriend = true; - } - } - } - - void Aggro(Unit* who) { } - - void UpdateAI(const uint32 diff) - { - if( IsFriend ) - { - if( Reset_Timer < diff ) - { - EnterEvadeMode(); - } else Reset_Timer -= diff; - } - - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_taskmaster_fizzule(Creature *_Creature) -{ - return new npc_taskmaster_fizzuleAI (_Creature); -} - -bool ReciveEmote_npc_taskmaster_fizzule(Player *player, Creature *_Creature, uint32 emote) -{ - if( emote == TEXTEMOTE_SALUTE ) - { - if( ((npc_taskmaster_fizzuleAI*)_Creature->AI())->FlareCount >= 2 ) - { - _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - _Creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); - } - } - return true; -} - -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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_sputtervalve"; - newscript->pGossipHello = &GossipHello_npc_sputtervalve; - newscript->pGossipSelect = &GossipSelect_npc_sputtervalve; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_taskmaster_fizzule"; - newscript->GetAI = GetAI_npc_taskmaster_fizzule; - newscript->pReceiveEmote = &ReciveEmote_npc_taskmaster_fizzule; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Barrens +SD%Complete: 90 +SDComment: Quest support: 2458, 4921, 6981 +SDCategory: Barrens +EndScriptData */ + +/* ContentData +npc_beaten_corpse +npc_sputtervalve +npc_taskmaster_fizzule remove hack when mangos implement feature/detect spell kind to not aggro +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_beaten_corpse +######*/ + +bool GossipHello_npc_beaten_corpse(Player *player, Creature *_Creature) +{ + if( player->GetQuestStatus(4921) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(4921) == QUEST_STATUS_COMPLETE) + player->ADD_GOSSIP_ITEM(0,"Examine corpse in detail...",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(3557,_Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_beaten_corpse(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if(action == GOSSIP_ACTION_INFO_DEF +1) + { + player->SEND_GOSSIP_MENU(3558,_Creature->GetGUID()); + player->KilledMonster( 10668,_Creature->GetGUID() ); + } + return true; +} + +/*###### +## npc_sputtervalve +######*/ + +bool GossipHello_npc_sputtervalve(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->GetQuestStatus(6981) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(0,"Can you tell me about this shard?",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_sputtervalve(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if(action == GOSSIP_ACTION_INFO_DEF) + { + player->SEND_GOSSIP_MENU(2013,_Creature->GetGUID()); + player->AreaExploredOrEventHappens(6981); + } + return true; +} + +/*###### +## npc_taskmaster_fizzule +######*/ + +//#define FACTION_HOSTILE_F 430 +#define FACTION_HOSTILE_F 16 +#define FACTION_FRIENDLY_F 35 + +#define SPELL_FLARE 10113 +#define SPELL_FOLLY 10137 + +struct MANGOS_DLL_DECL npc_taskmaster_fizzuleAI : public ScriptedAI +{ + npc_taskmaster_fizzuleAI(Creature* c) : ScriptedAI(c) { Reset(); } + + bool IsFriend; + uint32 Reset_Timer; + uint32 FlareCount; + + void Reset() + { + IsFriend = false; + Reset_Timer = 120000; + FlareCount = 0; + m_creature->setFaction(FACTION_HOSTILE_F); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + } + + //This is a hack. Spellcast will make creature aggro but that is not + //supposed to happen (mangos not implemented/not found way to detect this spell kind) + void DoUglyHack() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if( spell->Id == SPELL_FLARE || spell->Id == SPELL_FOLLY ) + { + DoUglyHack(); + ++FlareCount; + if( FlareCount >= 2 ) + { + m_creature->setFaction(FACTION_FRIENDLY_F); + IsFriend = true; + } + } + } + + void Aggro(Unit* who) { } + + void UpdateAI(const uint32 diff) + { + if( IsFriend ) + { + if( Reset_Timer < diff ) + { + EnterEvadeMode(); + } else Reset_Timer -= diff; + } + + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_taskmaster_fizzule(Creature *_Creature) +{ + return new npc_taskmaster_fizzuleAI (_Creature); +} + +bool ReciveEmote_npc_taskmaster_fizzule(Player *player, Creature *_Creature, uint32 emote) +{ + if( emote == TEXTEMOTE_SALUTE ) + { + if( ((npc_taskmaster_fizzuleAI*)_Creature->AI())->FlareCount >= 2 ) + { + _Creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + _Creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + } + } + return true; +} + +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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_sputtervalve"; + newscript->pGossipHello = &GossipHello_npc_sputtervalve; + newscript->pGossipSelect = &GossipSelect_npc_sputtervalve; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_taskmaster_fizzule"; + newscript->GetAI = GetAI_npc_taskmaster_fizzule; + newscript->pReceiveEmote = &ReciveEmote_npc_taskmaster_fizzule; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/black_temple.cpp b/src/bindings/scripts/scripts/zone/black_temple/black_temple.cpp index 137d87ed8a6..9f6c4d2500b 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/black_temple.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/black_temple.cpp @@ -1,68 +1,68 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Black_Temple -SD%Complete: 95 -SDComment: Spirit of Olum: Player Teleporter to Seer Kanai Teleport after defeating Naj'entus and Supremus. TODO: Find proper gossip. -SDCategory: Black Temple -EndScriptData */ - -/* ContentData -npc_spirit_of_olum -EndContentData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -/*### -# npc_spirit_of_olum -####*/ - -#define SPELL_TELEPORT 41566 // s41566 - Teleport to Ashtongue NPC's -#define GOSSIP_OLUM1 "Teleport me to the other Ashtongue Deathsworn" - -bool GossipHello_npc_spirit_of_olum(Player* player, Creature* _Creature) -{ - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - - if(pInstance && (pInstance->GetData(DATA_SUPREMUSEVENT) >= DONE) && (pInstance->GetData(DATA_HIGHWARLORDNAJENTUSEVENT) >= DONE)) - player->ADD_GOSSIP_ITEM(0, GOSSIP_OLUM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_spirit_of_olum(Player* player, Creature* _Creature, uint32 sender, uint32 action) -{ - if(action == GOSSIP_ACTION_INFO_DEF + 1) - player->CLOSE_GOSSIP_MENU(); - - player->InterruptNonMeleeSpells(false); - player->CastSpell(player, SPELL_TELEPORT, false); - return true; -} - -void AddSC_black_temple() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_spirit_of_olum"; - newscript->pGossipHello = GossipHello_npc_spirit_of_olum; - newscript->pGossipSelect = GossipSelect_npc_spirit_of_olum; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Black_Temple +SD%Complete: 95 +SDComment: Spirit of Olum: Player Teleporter to Seer Kanai Teleport after defeating Naj'entus and Supremus. TODO: Find proper gossip. +SDCategory: Black Temple +EndScriptData */ + +/* ContentData +npc_spirit_of_olum +EndContentData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +/*### +# npc_spirit_of_olum +####*/ + +#define SPELL_TELEPORT 41566 // s41566 - Teleport to Ashtongue NPC's +#define GOSSIP_OLUM1 "Teleport me to the other Ashtongue Deathsworn" + +bool GossipHello_npc_spirit_of_olum(Player* player, Creature* _Creature) +{ + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + + if(pInstance && (pInstance->GetData(DATA_SUPREMUSEVENT) >= DONE) && (pInstance->GetData(DATA_HIGHWARLORDNAJENTUSEVENT) >= DONE)) + player->ADD_GOSSIP_ITEM(0, GOSSIP_OLUM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_spirit_of_olum(Player* player, Creature* _Creature, uint32 sender, uint32 action) +{ + if(action == GOSSIP_ACTION_INFO_DEF + 1) + player->CLOSE_GOSSIP_MENU(); + + player->InterruptNonMeleeSpells(false); + player->CastSpell(player, SPELL_TELEPORT, false); + return true; +} + +void AddSC_black_temple() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_spirit_of_olum"; + newscript->pGossipHello = GossipHello_npc_spirit_of_olum; + newscript->pGossipSelect = GossipSelect_npc_spirit_of_olum; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_bloodboil.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_bloodboil.cpp index fba3f7fc36d..40a97fbf6ee 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_bloodboil.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_bloodboil.cpp @@ -1,365 +1,365 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Bloodboil -SD%Complete: 80 -SDComment: Bloodboil not working correctly, missing enrage -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -//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 - -//Speech'n'Sound -#define SAY_AGGRO "Horde will crush you!" -#define SOUND_AGGRO 11432 - -#define SAY_SLAY1 "Time to feast!" -#define SOUND_SLAY1 11433 - -#define SAY_SLAY2 "More! I want more!" -#define SOUND_SLAY2 11434 - -#define SAY_SPECIAL1 "Drink your blood! Eat your flesh!" -#define SOUND_SPECIAL1 11435 - -#define SAY_SPECIAL2 "I hunger!" -#define SOUND_SPECIAL2 11436 - -#define SAY_ENRAGE "I'll rip the meat from your bones!" -#define SOUND_ENRAGE 11437 - -#define SOUND_DEATH 11439 - -//This is used to sort the players by distance in preparation for the Bloodboil cast. -struct TargetDistanceOrder : public std::binary_function -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator ">" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return (MainTarget->GetDistance(_Left) > MainTarget->GetDistance(_Right)); - } -}; - -struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI -{ - boss_gurtogg_bloodboilAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 TargetGUID; - - float TargetThreat; - - uint32 BloodboilTimer; - uint32 BloodboilCount; - uint32 AcidGeyserTimer; - uint32 AcidicWoundTimer; - uint32 ArcingSmashTimer; - uint32 EnrageTimer; - uint32 FelAcidTimer; - uint32 EjectTimer; - uint32 BewilderingStrikeTimer; - uint32 PhaseChangeTimer; - - bool Phase1; - - void Reset() - { - if(pInstance) - pInstance->SetData(DATA_GURTOGGBLOODBOILEVENT, NOT_STARTED); - - TargetGUID = 0; - - TargetThreat = 0; - - BloodboilTimer = 10000; - BloodboilCount = 0; - AcidGeyserTimer = 1000; - AcidicWoundTimer = 6000; - ArcingSmashTimer = 19000; - EnrageTimer = 600000; - FelAcidTimer = 25000; - EjectTimer = 10000; - BewilderingStrikeTimer = 15000; - PhaseChangeTimer = 60000; - - Phase1 = true; - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - if(pInstance) - pInstance->SetData(DATA_GURTOGGBLOODBOILEVENT, IN_PROGRESS); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - if(pInstance) - pInstance->SetData(DATA_GURTOGGBLOODBOILEVENT, DONE); - - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - // 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() - { - // Get the Threat List - std::list m_threatlist = m_creature->getThreatManager().getThreatList(); - - if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue - - std::list targets; - std::list::iterator itr = m_threatlist.begin(); - for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container - { - Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - //only on alive players - if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) - targets.push_back( target); - } - - //Sort the list of players - targets.sort(TargetDistanceOrder(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) - { - Unit* pUnit = NULL; - pUnit = Unit::GetUnit((*m_creature), guid); - if(pUnit) - { - if(m_creature->getThreatManager().getThreat(pUnit)) - m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); - if(TargetThreat) - m_creature->AddThreat(pUnit, TargetThreat); - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(ArcingSmashTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ARCING_SMASH); - ArcingSmashTimer = 10000; - }else ArcingSmashTimer -= diff; - - if(FelAcidTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FEL_ACID); - FelAcidTimer = 25000; - }else FelAcidTimer -= diff; - - if(!m_creature->HasAura(SPELL_BERSERK, 0)) - if(EnrageTimer < diff) - { - DoCast(m_creature, SPELL_BERSERK); - DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - }else EnrageTimer -= diff; - - if(Phase1) - { - if(BewilderingStrikeTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_BEWILDERING_STRIKE); - float mt_threat = m_creature->getThreatManager().getThreat(m_creature->getVictim()); - Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); - m_creature->AddThreat(target, mt_threat); - BewilderingStrikeTimer = 20000; - }else BewilderingStrikeTimer -= diff; - - if(EjectTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_EJECT1); - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -40); - EjectTimer = 15000; - }else EjectTimer -= diff; - - if(AcidicWoundTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ACIDIC_WOUND); - AcidicWoundTimer = 10000; - }else AcidicWoundTimer -= diff; - - if(BloodboilTimer < diff) - { - if(BloodboilCount < 5) // Only cast it five times. - { - //CastBloodboil(); // Causes issues on windows, so is commented out. - DoCast(m_creature->getVictim(), SPELL_BLOODBOIL); - ++BloodboilCount; - BloodboilTimer = 10000*BloodboilCount; - } - }else BloodboilTimer -= diff; - } - - if(!Phase1) - { - if(AcidGeyserTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ACID_GEYSER); - AcidGeyserTimer = 30000; - }else AcidGeyserTimer -= diff; - - if(EjectTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_EJECT2); - EjectTimer = 15000; - }else EjectTimer -= diff; - } - - if(PhaseChangeTimer < diff) - { - if(Phase1) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target && target->isAlive()) - { - 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 - DoCast(m_creature, SPELL_INSIGNIFIGANCE, true); - DoCast(target, SPELL_FEL_RAGE_TARGET, true); - DoCast(target,SPELL_FEL_RAGE_2, true); - /* These spells do not work, comment them out for now. - DoCast(target, SPELL_FEL_RAGE_2, true); - DoCast(target, SPELL_FEL_RAGE_3, true);*/ - - //Cast this without triggered so that it appears in combat logs and shows visual. - DoCast(m_creature, SPELL_FEL_RAGE_SELF); - - switch(rand()%2) - { - case 0: - DoYell(SAY_SPECIAL1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SPECIAL1); - break; - case 1: - DoYell(SAY_SPECIAL2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SPECIAL2); - break; - } - - AcidGeyserTimer = 1000; - PhaseChangeTimer = 30000; - } - }else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage - { - if(TargetGUID) - RevertThreatOnTarget(TargetGUID); - TargetGUID = 0; - Phase1 = true; - BloodboilTimer = 10000; - BloodboilCount = 0; - AcidicWoundTimer += 2000; - ArcingSmashTimer += 2000; - FelAcidTimer += 2000; - EjectTimer += 2000; - PhaseChangeTimer = 60000; - } - }else PhaseChangeTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_gurtogg_bloodboil(Creature *_Creature) -{ - return new boss_gurtogg_bloodboilAI (_Creature); -} - -void AddSC_boss_gurtogg_bloodboil() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gurtogg_bloodboil"; - newscript->GetAI = GetAI_boss_gurtogg_bloodboil; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Bloodboil +SD%Complete: 80 +SDComment: Bloodboil not working correctly, missing enrage +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +//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 + +//Speech'n'Sound +#define SAY_AGGRO "Horde will crush you!" +#define SOUND_AGGRO 11432 + +#define SAY_SLAY1 "Time to feast!" +#define SOUND_SLAY1 11433 + +#define SAY_SLAY2 "More! I want more!" +#define SOUND_SLAY2 11434 + +#define SAY_SPECIAL1 "Drink your blood! Eat your flesh!" +#define SOUND_SPECIAL1 11435 + +#define SAY_SPECIAL2 "I hunger!" +#define SOUND_SPECIAL2 11436 + +#define SAY_ENRAGE "I'll rip the meat from your bones!" +#define SOUND_ENRAGE 11437 + +#define SOUND_DEATH 11439 + +//This is used to sort the players by distance in preparation for the Bloodboil cast. +struct TargetDistanceOrder : public std::binary_function +{ + const Unit* MainTarget; + TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; + // functor for operator ">" + bool operator()(const Unit* _Left, const Unit* _Right) const + { + return (MainTarget->GetDistance(_Left) > MainTarget->GetDistance(_Right)); + } +}; + +struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI +{ + boss_gurtogg_bloodboilAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 TargetGUID; + + float TargetThreat; + + uint32 BloodboilTimer; + uint32 BloodboilCount; + uint32 AcidGeyserTimer; + uint32 AcidicWoundTimer; + uint32 ArcingSmashTimer; + uint32 EnrageTimer; + uint32 FelAcidTimer; + uint32 EjectTimer; + uint32 BewilderingStrikeTimer; + uint32 PhaseChangeTimer; + + bool Phase1; + + void Reset() + { + if(pInstance) + pInstance->SetData(DATA_GURTOGGBLOODBOILEVENT, NOT_STARTED); + + TargetGUID = 0; + + TargetThreat = 0; + + BloodboilTimer = 10000; + BloodboilCount = 0; + AcidGeyserTimer = 1000; + AcidicWoundTimer = 6000; + ArcingSmashTimer = 19000; + EnrageTimer = 600000; + FelAcidTimer = 25000; + EjectTimer = 10000; + BewilderingStrikeTimer = 15000; + PhaseChangeTimer = 60000; + + Phase1 = true; + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + if(pInstance) + pInstance->SetData(DATA_GURTOGGBLOODBOILEVENT, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + if(pInstance) + pInstance->SetData(DATA_GURTOGGBLOODBOILEVENT, DONE); + + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + // 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() + { + // Get the Threat List + std::list m_threatlist = m_creature->getThreatManager().getThreatList(); + + if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue + + std::list targets; + std::list::iterator itr = m_threatlist.begin(); + for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container + { + Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + //only on alive players + if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) + targets.push_back( target); + } + + //Sort the list of players + targets.sort(TargetDistanceOrder(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) + { + Unit* pUnit = NULL; + pUnit = Unit::GetUnit((*m_creature), guid); + if(pUnit) + { + if(m_creature->getThreatManager().getThreat(pUnit)) + m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); + if(TargetThreat) + m_creature->AddThreat(pUnit, TargetThreat); + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(ArcingSmashTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ARCING_SMASH); + ArcingSmashTimer = 10000; + }else ArcingSmashTimer -= diff; + + if(FelAcidTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FEL_ACID); + FelAcidTimer = 25000; + }else FelAcidTimer -= diff; + + if(!m_creature->HasAura(SPELL_BERSERK, 0)) + if(EnrageTimer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + }else EnrageTimer -= diff; + + if(Phase1) + { + if(BewilderingStrikeTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_BEWILDERING_STRIKE); + float mt_threat = m_creature->getThreatManager().getThreat(m_creature->getVictim()); + Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); + m_creature->AddThreat(target, mt_threat); + BewilderingStrikeTimer = 20000; + }else BewilderingStrikeTimer -= diff; + + if(EjectTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_EJECT1); + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -40); + EjectTimer = 15000; + }else EjectTimer -= diff; + + if(AcidicWoundTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ACIDIC_WOUND); + AcidicWoundTimer = 10000; + }else AcidicWoundTimer -= diff; + + if(BloodboilTimer < diff) + { + if(BloodboilCount < 5) // Only cast it five times. + { + //CastBloodboil(); // Causes issues on windows, so is commented out. + DoCast(m_creature->getVictim(), SPELL_BLOODBOIL); + ++BloodboilCount; + BloodboilTimer = 10000*BloodboilCount; + } + }else BloodboilTimer -= diff; + } + + if(!Phase1) + { + if(AcidGeyserTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ACID_GEYSER); + AcidGeyserTimer = 30000; + }else AcidGeyserTimer -= diff; + + if(EjectTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_EJECT2); + EjectTimer = 15000; + }else EjectTimer -= diff; + } + + if(PhaseChangeTimer < diff) + { + if(Phase1) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target && target->isAlive()) + { + 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 + DoCast(m_creature, SPELL_INSIGNIFIGANCE, true); + DoCast(target, SPELL_FEL_RAGE_TARGET, true); + DoCast(target,SPELL_FEL_RAGE_2, true); + /* These spells do not work, comment them out for now. + DoCast(target, SPELL_FEL_RAGE_2, true); + DoCast(target, SPELL_FEL_RAGE_3, true);*/ + + //Cast this without triggered so that it appears in combat logs and shows visual. + DoCast(m_creature, SPELL_FEL_RAGE_SELF); + + switch(rand()%2) + { + case 0: + DoYell(SAY_SPECIAL1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SPECIAL1); + break; + case 1: + DoYell(SAY_SPECIAL2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SPECIAL2); + break; + } + + AcidGeyserTimer = 1000; + PhaseChangeTimer = 30000; + } + }else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage + { + if(TargetGUID) + RevertThreatOnTarget(TargetGUID); + TargetGUID = 0; + Phase1 = true; + BloodboilTimer = 10000; + BloodboilCount = 0; + AcidicWoundTimer += 2000; + ArcingSmashTimer += 2000; + FelAcidTimer += 2000; + EjectTimer += 2000; + PhaseChangeTimer = 60000; + } + }else PhaseChangeTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_gurtogg_bloodboil(Creature *_Creature) +{ + return new boss_gurtogg_bloodboilAI (_Creature); +} + +void AddSC_boss_gurtogg_bloodboil() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gurtogg_bloodboil"; + newscript->GetAI = GetAI_boss_gurtogg_bloodboil; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp index ecf8ad427be..fdf69035bd4 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp @@ -1,2465 +1,2468 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: boss_illidan_stormrage -SD%Complete: 90 -SDComment: -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" -#include "WorldPacket.h" - -/************* Quotes and Sounds ***********************/ -// Gossip for when a player clicks Akama -#define GOSSIP_ITEM "We are ready to face Illidan" - -// Yells for/by Akama -#define SAY_AKAMA_BEWARE "Be wary friends, The Betrayer meditates in the court just beyond." -#define SOUND_AKAMA_BEWARE 11388 -#define SAY_AKAMA_MINION "Come, my minions. Deal with this traitor as he deserves!" -#define SOUND_AKAMA_MINION 11465 -#define SAY_AKAMA_LEAVE "I'll deal with these mongrels. Strike now, friends! Strike at the betrayer!" -#define SOUND_AKAMA_LEAVE 11390 - -// Self explanatory -#define SAY_KILL1 "Who shall be next to taste my blades?!" -#define SOUND_KILL1 11473 -#define SAY_KILL2 "This is too easy!" -#define SOUND_KILL2 11472 - -// I think I'll fly now and let my subordinates take you on -#define SAY_TAKEOFF "I will not be touched by rabble such as you!" -#define SOUND_TAKEOFF 11479 -#define SAY_SUMMONFLAMES "Behold the flames of Azzinoth!" -#define SOUND_SUMMONFLAMES 11480 - -// When casting Eye Blast. Demon Fire will be appear on places that he casts this -#define SAY_EYE_BLAST "Stare into the eyes of the Betrayer!" -#define SOUND_EYE_BLAST 11481 - -// kk, I go big, dark and demon on you. -#define SAY_MORPH "Behold the power... of the demon within!" -#define SOUND_MORPH 11475 - -// I KILL! -#define SAY_ENRAGE "You've wasted too much time mortals, now you shall fall!" -#define SOUND_ENRAGE 11474 - -/************** 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.740 -#define CENTER_Y 305.297 -#define CENTER_Z 353.192 - -/**** Creature Summon and Recognition IDs ****/ -enum CreatureEntry -{ - EMPTY = 0, - AKAMA = 22990, - ILLIDAN_STORMRAGE = 22917, - BLADE_OF_AZZINOTH = 22996, - FLAME_OF_AZZINOTH = 22997, - MAIEV_SHADOWSONG = 23197, - SHADOW_DEMON = 23375, - DEMON_FIRE = 23069, - FLAME_CRASH = 23336, - ILLIDAN_DOOR_TRIGGER = 23412, - SPIRIT_OF_OLUM = 23411, - SPIRIT_OF_UDALO = 23410, - ILLIDARI_ELITE = 23226, - PARASITIC_SHADOWFIEND = 23498, - CAGE_TRAP_TRIGGER = 23292, -}; - -/*** 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 Yells -{ - uint32 sound; - char* text; - uint32 creature, timer, emote; - bool Talk; -}; - -static Yells Conversation[]= -{ - {11463, "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.", ILLIDAN_STORMRAGE, 8000, 0, true}, - {0, NULL, ILLIDAN_STORMRAGE, 5000, 396, true}, - {11389, "We've come to end your reign, Illidan. My people and all of Outland shall be free!", AKAMA, 7000, 25, true}, - {0, NULL, AKAMA, 5000, 66, true}, - {11464, "Boldly said. But I remain unconvinced.", ILLIDAN_STORMRAGE, 8000, 396, true}, - {11380, "The time has come! The moment is at hand!", AKAMA, 3000, 22, true}, - {0, NULL, AKAMA, 2000, 15, true}, - {11466, "You are not prepared!", ILLIDAN_STORMRAGE, 3000, 406, true}, - {0, NULL, EMPTY, 1000, 0, true}, - {0, NULL, EMPTY, 0, 0, false}, - {11476, "Is this it, mortals? Is this all the fury you can muster?", ILLIDAN_STORMRAGE, 8000, 0, true}, - {11491, "Their fury pales before mine, Illidan. We have some unsettled business between us.", MAIEV_SHADOWSONG, 8000, 5, true}, - {11477, "Maiev... How is this even possible?", ILLIDAN_STORMRAGE, 7000, 1, true}, - {11492, "Ah... my long hunt is finally over. Today, Justice will be done!", MAIEV_SHADOWSONG, 8000, 15, true}, - {11470, "Feel the hatred of ten thousand years!", ILLIDAN_STORMRAGE, 1000, 0, false}, - {11496, "Ahh... It is finished. You are beaten.", MAIEV_SHADOWSONG, 6000, 0, true}, - { // Emote dead for now. Kill him later - 11478, "You have won... Maiev...but the huntress... is nothing...without the hunt... you... are nothing... without me..", ILLIDAN_STORMRAGE, 22000, 65, true - }, - {11497, "He is right. I feel nothing... I am nothing... Farewell, champions.", MAIEV_SHADOWSONG, 9000, 0, true}, - {11498, NULL, MAIEV_SHADOWSONG, 0, true}, - {11387, "The Light will fill these dismal halls once again. I swear it.", AKAMA, 8000, 0, true}, - {0, NULL, EMPTY, 1000, 0, false} -}; - -static Yells RandomTaunts[]= -{ - {11467, "I can feel your hatred.", ILLIDAN_STORMRAGE, 0, 0, false}, - {11468, "Give in to your fear!", ILLIDAN_STORMRAGE, 0, 0, false}, - {11469, "You know nothing of power!", ILLIDAN_STORMRAGE, 0, 0, false}, - {11471, "Such... arrogance!", ILLIDAN_STORMRAGE, 0, 0, false} -}; - -static Yells MaievTaunts[]= -{ - {11493, "That is for Naisha!", MAIEV_SHADOWSONG, 0, false}, - {11494, "Bleed as I have bled!", MAIEV_SHADOWSONG, 0, 0, false}, - {11495, "There shall be no prison for you this time!", MAIEV_SHADOWSONG, 0, 0, false}, - {11500, "Meet your end, demon!", MAIEV_SHADOWSONG, 0, 0, false} -}; - -struct Locations -{ - float x, y, z; - uint32 id; -}; - -static Locations GlaivePosition[]= -{ - {695.105, 305.303, 354.256}, - {659.338, 305.303, 354.256}, - {700.105, 305.303, 354.256}, - {664.338, 305.303, 354.256} -}; - -static Locations EyeBlast[]= -{ - {650.697, 320.128, 353.730}, - {652.799, 275.091, 353.367}, - {701.527, 273.815, 353.230}, - {709.865, 325.654, 353.322} -}; - -static Locations AkamaWP[]= -{ - { 770.01, 304.50, 312.29 }, // Bottom of the first stairs, at the doors - { 780.66, 304.50, 319.74 }, // Top of the first stairs - { 790.13, 319.68, 319.76 }, // Bottom of the second stairs (left from the entrance) - { 787.17, 347.38, 341.42 }, // Top of the second stairs - { 781.34, 350.31, 341.44 }, // Bottom of the third stairs - { 762.60, 361.06, 353.60 }, // Top of the third stairs - { 756.35, 360.52, 353.27 }, // Before the door-thingy - { 743.82, 342.21, 353.00 }, // Somewhere further - { 732.69, 305.13, 353.00 }, // In front of Illidan - { 738.11, 365.44, 353.00 }, // in front of the door-thingy (the other one!) - { 792.18, 366.62, 341.42 }, // Down the first flight of stairs - { 796.84, 304.89, 319.76 }, // Down the second flight of stairs - { 782.01, 304.55, 319.76 } // 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.5426, 309.9156, 312.2129, SPIRIT_OF_UDALO}, - {755.5426, 298.7923, 312.0834, SPIRIT_OF_OLUM} -}; - -struct WayPoints -{ - WayPoints(uint32 _id, float _x, float _y, float _z) - { - id = _id; - x = _x; - y = _y; - z = _z; - } - uint32 id; - float x, y, z; -}; - -struct Animation // For the demon transformation -{ - uint32 aura, unaura, timer, size, displayid, phase; - bool equip; -}; - -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} -}; - -/**** 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 -{ - demonfireAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 IllidanGUID; - - bool IsTrigger; - - uint32 CheckTimer; - uint32 DemonFireTimer; - uint32 DespawnTimer; - - void Reset() - { - IllidanGUID = 0; - - IsTrigger = false; - - CheckTimer = 2000; - DemonFireTimer = 0; - DespawnTimer = 45000; - } - - void Aggro(Unit *who) {} - void AttackStart(Unit* who) { } - void MoveInLineOfSight(Unit *who){ } - - void UpdateAI(const uint32 diff) - { - if(IsTrigger) - return; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - if(CheckTimer < diff) - { - if(!IllidanGUID && pInstance) - { - IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); - if(IllidanGUID) - { - Unit* Illidan = Unit::GetUnit((*m_creature), IllidanGUID); - if(Illidan && !Illidan->HasUnitMovementFlag(MOVEMENTFLAG_LEVITATING)) - m_creature->setDeathState(JUST_DIED); - } - } - CheckTimer = 2000; - }else CheckTimer -= diff; - - if(DemonFireTimer < diff) - { - DoCast(m_creature, SPELL_DEMON_FIRE); - DemonFireTimer = 30000; - }else DemonFireTimer -= diff; - - if(DespawnTimer < diff) - m_creature->setDeathState(JUST_DIED); - else DespawnTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -/******* Functions and vars for Akama's AI ******/ -struct MANGOS_DLL_SPEC npc_akama_illidanAI : public ScriptedAI -{ - npc_akama_illidanAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - WayPointList.clear(); - Reset(); - } - - /* Instance Data */ - ScriptedInstance* pInstance; - - /* 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 Aggro(Unit *who) {} - - void Reset() - { - if(pInstance) - { - pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED); - GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); - if( Gate && !Gate->GetGoState() ) - Gate->SetGoState(1); // close door if already open (when raid wipes or something) - - for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) - { - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); - if(Door) - Door->SetGoState(0); - } - } - - IllidanGUID = 0; - PlayerGUID = 0; - ChannelGUID = 0; - for(uint8 i = 0; i < 2; ++i) SpiritGUID[i] = 0; - - ChannelTimer = 0; - ChannelCount = 0; - SummonMinionTimer = 2000; - - WalkTimer = 0; - - TalkTimer = 0; - TalkCount = 0; - - KillAllElites(); - - IsReturningToIllidan = false; - FightMinions = false; - IsTalking = false; - StartChanneling = false; - DoorOpen = false; - - m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has strange values.. - 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); - } - - // 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() - { - InCombat = false; - - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - } - - void KillAllElites() - { - std::list::iterator itr; - for(itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); - if(pUnit && (pUnit->GetTypeId() == TYPEID_UNIT) && (pUnit->GetEntry() == ILLIDARI_ELITE)) - pUnit->setDeathState(JUST_DIED); - } - } - - void ReturnToIllidan() - { - KillAllElites(); - InCombat = false; - FightMinions = false; - IsReturningToIllidan = true; - WayPoint = WayPointList.begin(); - m_creature->SetSpeed(MOVE_RUN, 2.0f); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - IsWalking = true; - } - - void AddWaypoint(uint32 id, float x, float y, float z) - { - WayPoints AkamaWP(id, x, y, z); - WayPointList.push_back(AkamaWP); - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if(damage > m_creature->GetHealth() && (done_by->GetGUID() != m_creature->GetGUID())) - { - damage = 0; - DoCast(m_creature, SPELL_HEALING_POTION); - } - } - - void BeginDoorEvent(Player* player) - { - if(!pInstance) - return; - - outstring_log("SD2: Akama - Door event initiated by player %s", player->GetName()); - PlayerGUID = player->GetGUID(); - - GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); - if(Gate) - { - float x,y,z; - Gate->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(); - // Invisible but spell visuals can still be seen. - Channel->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); - Channel->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - 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(); - } - } - StartChanneling = true; - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoCast(Channel, SPELL_AKAMA_DOOR_FAIL); - } - } - } - - void MovementInform(uint32 type, uint32 id) - { - if(type != POINT_MOTION_TYPE || !IsWalking) - return; - - if(WayPoint->id != id) - return; - - switch(id) - { - case 6: - if(!IsReturningToIllidan) - { // open the doors that close the summit - for(uint32 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i) - { - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); - if(Door) - Door->SetGoState(0); - } - } - case 7: - if(IsReturningToIllidan) - { - IsWalking = false; - if(IllidanGUID) - { - Unit* Illidan = Unit::GetUnit((*m_creature), 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); - } - } - } - break; - case 8: - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if(!IsReturningToIllidan) - { - IsWalking = false; - BeginEvent(PlayerGUID); - } - break; - case 12: - IsWalking = false; - FightMinions = true; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - break; - } - - ++WayPoint; - WalkTimer = 200; - } - - void DeleteFromThreatList() - { - if(!IllidanGUID) return; // If we do not have Illidan's GUID, do not proceed - // Create a pointer to Illidan - Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); - if(!Illidan) return; // No use to continue if Illidan does not exist - std::list::iterator itr = Illidan->getThreatManager().getThreatList().begin(); - for( ; itr != Illidan->getThreatManager().getThreatList().end(); ++itr) - { - // 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. - } - } - - // Now we delete our threatlist to prevent attacking anyone for now - m_creature->DeleteThreatList(); - } - - void UpdateAI(const uint32 diff) - { - if(IllidanGUID) - { - Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); - if(Illidan) - { - if(Illidan->IsInEvadeMode() && !m_creature->IsInEvadeMode()) - EnterEvadeMode(); - - if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 85) && InCombat && !FightMinions) - { - if(TalkTimer < diff) - { - switch(TalkCount) - { - case 0: - Illidan->Yell(SAY_AKAMA_MINION, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(Illidan, SOUND_AKAMA_MINION); - TalkTimer = 8000; - TalkCount = 1; - break; - case 1: - DoYell(SAY_AKAMA_LEAVE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AKAMA_LEAVE); - TalkTimer = 3000; - TalkCount = 2; - break; - case 2: - IsTalking = true; - TalkTimer = 2000; - m_creature->RemoveAllAuras(); - m_creature->CombatStop(); - 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->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - break; - } - }else TalkTimer -= diff; - } - - if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 4) && !IsReturningToIllidan) - ReturnToIllidan(); - } - }else - { - if(pInstance) - IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); - } - - if(IsWalking && WalkTimer) - { - if(WalkTimer <= diff) - { - if(WayPoint == WayPointList.end()) - return; - m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y,WayPoint->z); - WalkTimer = 0; - }else WalkTimer -= diff; - } - - if(StartChanneling) - { - if(ChannelTimer < diff) - { - switch(ChannelCount) - { - case 3: - if(!DoorOpen) - { - m_creature->InterruptNonMeleeSpells(true); - for(uint8 i = 0; i < 2; ++i) - { - if(SpiritGUID[i]) - { - Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]); - if(Spirit) - Spirit->InterruptNonMeleeSpells(true); - } - } - GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); - if(Gate) - Gate->SetGoState(0); - ChannelCount++; - ChannelTimer = 5000; - } - break; - case 4: - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); - ChannelTimer = 2000; - ChannelCount++; - break; - case 5: - DoYell(SAY_AKAMA_BEWARE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AKAMA_BEWARE); - if(ChannelGUID) - { - Unit* ChannelTarget = Unit::GetUnit((*m_creature), ChannelGUID); - if(ChannelTarget) - ChannelTarget->setDeathState(JUST_DIED); - } - for(uint8 i = 0; i < 2; ++i) - { - if(SpiritGUID[i]) - { - Unit* Spirit = Unit::GetUnit((*m_creature), 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; - } - - WayPoint = WayPointList.begin(); - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y, WayPoint->z); - IsWalking = true; - break; - default: - if(ChannelGUID) - { - Unit* Channel = Unit::GetUnit((*m_creature), ChannelGUID); - if(Channel) - { - m_creature->InterruptNonMeleeSpells(true); - - for(uint8 i = 0; i < 2; ++i) - { - if(SpiritGUID[i]) - { - Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]); - if(Spirit) - { - Spirit->InterruptNonMeleeSpells(true); - if(ChannelCount%2 == 0) - { - Spirit->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL,false); - DoCast(Channel, SPELL_AKAMA_DOOR_CHANNEL); - } - else - { - if(Spirit->GetVisibility() == VISIBILITY_OFF) - Spirit->SetVisibility(VISIBILITY_ON); - } - } - } - } - if(ChannelCount < 3) - ChannelCount++; - ChannelTimer = 10000; - } - break; - } - } - }else ChannelTimer -= diff; - } - - if(FightMinions) - { - if(SummonMinionTimer < diff) - { - if(IllidanGUID) - { - Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); - if(!Illidan || Illidan->IsInEvadeMode()) - { - Reset(); - EnterEvadeMode(); - return; - } - } - - 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) - { - Elite->AI()->AttackStart(m_creature); - Elite->AddThreat(m_creature, 1000000.0f); - AttackStart(Elite); - } - SummonMinionTimer = 10000 + rand()%6000; - }else SummonMinionTimer -= diff; - } - - // If we don't have a target, or is talking, or has run away, return - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return; - - DoMeleeAttackIfReady(); - } -}; - -/************* Custom check used for Agonizing Flames ***************/ -class AgonizingFlamesTargetCheck -{ - public: - AgonizingFlamesTargetCheck(Unit const* unit) : pUnit(unit) {} - bool operator() (Player* plr) - { - // Faster than square rooting - if(!plr->isGameMaster() && pUnit->GetDistance2d(plr) > 225) - return true; - - return false; - } - - private: - Unit const* pUnit; -}; - -/************************************** Illidan's AI ***************************************/ -struct MANGOS_DLL_SPEC boss_illidan_stormrageAI : public ScriptedAI -{ - boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - /** Instance Data **/ - ScriptedInstance* pInstance; - - /** 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; - - // Check if any flames/glaives are alive/existing. Kill if alive and set GUIDs to 0 - for(uint8 i = 0; i < 2; i++) - { - if(FlameGUID[i]) - { - Unit* Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); - if(Flame) - Flame->setDeathState(JUST_DIED); - FlameGUID[i] = 0; - } - - if(GlaiveGUID[i]) - { - Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]); - if(Glaive) - Glaive->setDeathState(JUST_DIED); - GlaiveGUID[i] = 0; - } - } - - if(AkamaGUID) - { - Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID)); - if(Akama) - { - if(!Akama->isAlive()) - Akama->Respawn(); - ((npc_akama_illidanAI*)Akama->AI())->Reset(); - ((npc_akama_illidanAI*)Akama->AI())->EnterEvadeMode(); - Akama->GetMotionMaster()->MoveTargetedHome(); - } - } - - InformAkama = false; - RefaceVictim = false; - HasSummoned = false; - AkamaGUID = 0; - MaievGUID = 0; - - FaceVictimTimer = 1000; - BerserkTimer = 1500000; - GlobalTimer = 0; - DemonFormSequence = 0; - - /** Normal Form **/ - ShearTimer = 20000 + (rand()%11 * 1000); // 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->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135); - m_creature->InterruptNonMeleeSpells(false); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // Unequip warglaives if needed - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - - IsTalking = false; - - TalkCount = 0; - TalkTimer = 0; - - if(pInstance) - pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED); - } - - void Aggro(Unit *who) { DoZoneInCombat(); } - - void AttackStart(Unit *who) - { - if(!who || IsTalking || Phase == 2 || Phase == 4 || Phase == 6 || m_creature->HasAura(SPELL_KNEEL, 0)) - return; - - if (who->isTargetableForAttack() && who!= m_creature) - { - //Begin melee attack if we are within range - DoStartAttackAndMovement(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)) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - } - } - - void JustDied(Unit *killer) - { - IsTalking = false; - TalkCount = 0; - TalkTimer = 0; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - if(!pInstance) - return; - // Completed - pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, DONE); - - for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) - { - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); - if(Door) - Door->SetGoState(0); // Open Doors - } - - } - - void KilledUnit(Unit *victim) - { - if(victim == m_creature) return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL1, LANG_UNIVERSAL, victim); - DoPlaySoundToSet(m_creature, SOUND_KILL1); - break; - case 1: - DoYell(SAY_KILL2, LANG_UNIVERSAL, victim); - DoPlaySoundToSet(m_creature, SOUND_KILL2); - break; - } - } - - 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; - - DoYell(SAY_EYE_BLAST, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_EYE_BLAST); - - uint32 initial = rand()%4; - 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) - { - Creature* Trigger = NULL; - Trigger = m_creature->SummonCreature(DEMON_FIRE, initial_X, initial_Y, initial_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); - if(Trigger) - { - ((demonfireAI*)Trigger->AI())->IsTrigger = true; - Trigger->GetMotionMaster()->MovePoint(0, final_X, final_Y, final_Z); - - if(!i) - Trigger->CastSpell(Trigger, SPELL_EYE_BLAST_TRIGGER, true); - else - { - Trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Trigger->GetGUID()); - DoCast(Trigger, SPELL_EYE_BLAST); - } - } - } - } - - // It's only cast on players that are greater than 15 yards away from Illidan. If no one is found, cast it on MT instead (since selecting someone in that 15 yard radius would cause the flames to hit the MT anyway). - void CastAgonizingFlames() - { - // We'll use grid searching for this, using a custom searcher that selects a player that is at a distance >15 yards - Player* target = NULL; - - CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - AgonizingFlamesTargetCheck check(m_creature); - MaNGOS::PlayerSearcher searcher(target, check); - TypeContainerVisitor - , GridTypeMapContainer> visitor(searcher); - - CellLock cell_lock(cell, pair); - cell_lock->Visit(cell_lock, visitor, *(m_creature->GetMap())); - - if(target) - DoCast(target, SPELL_AGONIZING_FLAMES); - else - DoCast(m_creature->getVictim(), SPELL_AGONIZING_FLAMES); - } - - void Talk(uint32 count) - { - if(!m_creature->isAlive()) return; - uint32 sound = Conversation[count].sound; - char* text = NULL; - if(Conversation[count].text) - text = Conversation[count].text; - TalkTimer = Conversation[count].timer; - uint32 emote = Conversation[count].emote; - IsTalking = Conversation[count].Talk; - Creature* creature = NULL; - uint64 GUID = 0; - if(Conversation[count].creature == ILLIDAN_STORMRAGE) - creature = m_creature; - else if(Conversation[count].creature == AKAMA) - { - if(!AkamaGUID) - { - if(pInstance) - { - AkamaGUID = pInstance->GetData64(DATA_AKAMA); - if(!AkamaGUID) - return; - GUID = AkamaGUID; - } - } - 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 - creature = ((Creature*)Unit::GetUnit((*m_creature), GUID)); - - if(creature) - { - creature->HandleEmoteCommand(emote); // Make the creature do some animation! - if(text) - creature->Yell(text, LANG_UNIVERSAL, 0); // Have the creature yell out some text - if(sound) - DoPlaySoundToSet(creature, sound); // Play some sound on the creature - } - } - - void Move(float X, float Y, float Z, Creature* _Creature) - { - _Creature->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) - DoCast(m_creature, aura, true); - - if(displayid) - // It's morphin time! - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid); - /*if(size) - m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, size); // Let us grow! (or shrink)*/ - - if(DemonTransformation[count].equip) - { - // Requip warglaives if needed - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); - } - else - { - // Unequip warglaives if needed - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); - } - - 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()); - if(MaievGUID) Phase = PHASE_NORMAL_MAIEV; // Depending on whether we summoned Maiev, we switch to either phase 5 or 3 - 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, 0)) - DoCast(m_creature, SPELL_DEMON_FORM, true); - } - } - - /** To reduce the amount of code in UpdateAI, we can seperate them into different functions and simply call them from UpdateAI **/ - void EnterPhase2() - { - DoYell(SAY_TAKEOFF, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TAKEOFF); - - 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); - // Animate our take off! - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - // We now hover! - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - 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; - - DoCast(m_creature, SPELL_THROW_GLAIVE2); // Make it look like we're throwing the glaives on the ground - // We no longer wear the glaives! - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); - // since they are now channeling the flames (or will be) - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); - for(uint8 i = 0; i < 2; ++i) - { - Creature* Glaive = NULL; - Glaive = ((Creature*)Unit::GetUnit((*m_creature), GlaiveGUID[i])); - if(Glaive) - { - DoCast(Glaive, SPELL_THROW_GLAIVE, true); - Glaive->SetVisibility(VISIBILITY_ON); - } - } - } - - void SummonFlamesOfAzzinoth() - { - DoYell(SAY_SUMMONFLAMES, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMONFLAMES); - - for(uint8 i = 0; i < 2; ++i) - { - Creature* Flame = NULL; - Creature* Glaive = NULL; - Glaive = ((Creature*)Unit::GetUnit((*m_creature), 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) - { - // 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()); - FlameGUID[i] = Flame->GetGUID(); // Record GUID in order to check if they're dead later on to move to the next phase - // Glaives do some random Beam type channel on it. - Glaive->CastSpell(Flame, SPELL_AZZINOTH_CHANNEL, true); - if(m_creature->getVictim()) - Flame->AI()->AttackStart(m_creature->getVictim()); - } - else - { - DoTextEmote("is unable to summon a Flame of Azzinoth.", NULL); - error_log("SD2 ERROR: Illidan Stormrage AI: Unable to summon Flame of Azzinoth (entry: 22997), please check your database"); - EnterEvadeMode(); - } - } - else - { - DoTextEmote("is unable to summon a Blade of Azzinoth.", NULL); - error_log("SD2 ERROR: 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); - DoCast(m_creature, SPELL_SHADOW_PRISON, true); - 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(); - DoTextEmote("is unable to summon Maiev Shadowsong and enter Phase 4. Resetting Encounter.", NULL); - error_log("SD2 ERROR: 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(); - DoCast(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) - { - Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID)); - if(Maiev) - { - Maiev->CombatStop(); // 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->Relocate(dx,dy,Maiev->GetPositionZ()); - Maiev->SendMonsterMove(dx,dy,Maiev->GetPositionZ(), 0, 0, 0); - 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 - { - case 0: - // Time to stand up! - m_creature->RemoveAurasDueToSpell( SPELL_KNEEL ); - break; - case 8: - // Equip our warglaives! - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); - m_creature->setFaction(14); // Hostile if we weren't before - break; - case 9: - if(AkamaGUID) - { - Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID)); - if(Akama) - { - Akama->GetMotionMaster()->Clear(false); - // Akama runs to us! - Akama->GetMotionMaster()->MoveChase(m_creature); - m_creature->GetMotionMaster()->Clear(false); - // We run to Akama! - m_creature->GetMotionMaster()->MoveChase(Akama); - Akama->AddThreat(m_creature, 1000000.0f); - AttackStart(Akama); // Start attacking Akama - ((npc_akama_illidanAI*)Akama->AI())->IsTalking = false; - // Akama starts attacking us - ((npc_akama_illidanAI*)Akama->AI())->AttackStart(m_creature); - } - } - // We are now attackable! - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - break; - case 11: - if(MaievGUID) - { - Unit* Maiev = Unit::GetUnit((*m_creature), 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 = ((Creature*)Unit::GetUnit((*m_creature), 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); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - IsTalking = false; - FaceVictimTimer = 2000; - RefaceVictim = true; - break; - case 20: // Kill ourself. - if(MaievGUID) - { - Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), 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; - } - Talk(TalkCount); // This function does most of the talking - TalkCount++; - }else TalkTimer -= diff; - } - - // If we don't have a target, return. - if(!m_creature->SelectHostilTarget() || !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, 0)) - { - EnrageTimer = 40000; // Just so that he doesn't immediately enrage after he stops being caged. - CageTimer = 30000; - return; - } - - // Berserk Timer - flat 25 minutes - if(!m_creature->HasAura(SPELL_BERSERK, 0) && Phase != PHASE_DEMON_SEQUENCE) - if(BerserkTimer < diff) - { - DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - DoCast(m_creature, SPELL_BERSERK, true); - }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->GetHealth()*100 / m_creature->GetMaxHealth()) < 65) && (Phase == PHASE_NORMAL)) - EnterPhase2(); - - /** Signal to summon Maiev **/ - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) && !MaievGUID && - ((Phase != PHASE_DEMON) || (Phase != PHASE_DEMON_SEQUENCE))) - SummonMaiev(); - - /** Time for the death speech **/ - if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 1) && (!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 = rand()%4; - char* yell = RandomTaunts[random].text; - uint32 soundid = RandomTaunts[random].sound; - if(yell) - DoYell(yell, LANG_UNIVERSAL, NULL); - if(soundid) - DoPlaySoundToSet(m_creature, soundid); - TauntTimer = 32000; - }else TauntTimer -= diff; - - if(GlobalTimer < diff) // Global Timer so that spells do not overlap. - { - if(ShearTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SHEAR); - ShearTimer = 25000 + (rand()%16 * 1000); - GlobalTimer += 2000; - }else ShearTimer -= diff; - - if(FlameCrashTimer < diff) - { - // It spawns multiple flames sometimes. Therefore, we'll do this manually. - //DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH); - DoSpawnCreature(FLAME_CRASH, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 40000); - FlameCrashTimer = 35000; - GlobalTimer += 2000; - }else FlameCrashTimer -= diff; - - if(ParasiticShadowFiendTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,1); - if(target && target->isAlive() && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0)) - { - Cast(target, SPELL_PARASITIC_SHADOWFIEND); - ParasiticShadowFiendTimer = 40000; - } - }else ParasiticShadowFiendTimer -= diff; - - if(DrawSoulTimer < diff) - { - DoCast(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; - - if(SummonFlamesTimer < diff) - { - SummonFlamesOfAzzinoth(); - }else SummonFlamesTimer -= diff; - } - - if(!m_creature->GetMotionMaster()->empty() && (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)) - m_creature->GetMotionMaster()->Clear(false); - - if(HasSummoned) - { - if(CheckFlamesTimer) - if(CheckFlamesTimer <= diff) - { - // Check if flames are dead or non-existant. If so, set GUID to 0. - for(uint8 i = 0; i < 2; i++) - { - if(FlameGUID[i]) - { - Unit* Flame = NULL; - Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); - - // If the flame dies, or somehow the pointer becomes invalid, reset GUID to 0. - if(!Flame || !Flame->isAlive()) - FlameGUID[i] = 0; - } - } - 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; - } - - if(RetrieveBladesTimer) - if(RetrieveBladesTimer <= diff) // Time to get back our glaives! - { - // Interrupt any spells we might be doing *cough* DArk Barrage *cough* - m_creature->InterruptNonMeleeSpells(false); - for(uint8 i = 0; i < 2; i++) - { - if(GlaiveGUID[i]) - { - Unit* Glaive = NULL; - Glaive = Unit::GetUnit((*m_creature), 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; - } - } - // Re-equip our warblades! - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); - LandTimer = 5000; // Prepare for landin'! - RetrieveBladesTimer = 0; - }else RetrieveBladesTimer -= diff; - - if(LandTimer) - { - if(LandTimer <= diff) // Time to land! - { - DoResetThreat(); - // anndddd touchdown! - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - Phase = PHASE_NORMAL_2; - // 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()); - // 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. - } - } - - if(GlobalTimer < diff) - { - if(FireballTimer < diff) - { - Cast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL); - FireballTimer = 5000; - }else FireballTimer -= diff; - - if(DarkBarrageTimer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE); - DarkBarrageTimer = 35000; - GlobalTimer += 9000; - }else DarkBarrageTimer -= diff; - - if(EyeBlastTimer < diff) - { - CastEyeBlast(); - EyeBlastTimer = 30000; - }else EyeBlastTimer -= diff; - }else GlobalTimer -= diff; - } - - /** 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; - - if(TransformTimer < diff) - { - uint32 CurHealth = m_creature->GetHealth()*100 / m_creature->GetMaxHealth(); - // 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 && !MaievGUID) || (CurHealth < 5)) - return; - - Phase = PHASE_DEMON_SEQUENCE; // Transform sequence - DemonFormSequence = 0; - AnimationTimer = 0; - DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_MORPH); - TransformTimer = 60000; - FlameBurstTimer = 10000; - ShadowDemonTimer = 30000; - m_creature->GetMotionMaster()->Clear(false);// Stop moving - }else TransformTimer -= diff; - } - - /** Phase 4 spells only (Demon Form) **/ - if(Phase == PHASE_DEMON) - { - // Stop moving if we are by clearing movement generators. - if(!m_creature->GetMotionMaster()->empty()) - m_creature->GetMotionMaster()->Clear(false); - - if(TransformTimer < diff) - { - Phase = PHASE_DEMON_SEQUENCE; - DemonFormSequence = 5; - AnimationTimer = 100; - TransformTimer = 60000; - }else TransformTimer -= diff; - - if(ShadowDemonTimer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - Creature* ShadowDemon = NULL; - for(uint8 i = 0; i < 4; i++) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - // only on players. - if(target && target->GetTypeId() == TYPEID_PLAYER) - { - ShadowDemon = DoSpawnCreature(SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,25000); - if(ShadowDemon) - { - ShadowDemon->AddThreat(target, 5000000.0f); - ShadowDemon->AI()->AttackStart(target); - DoZoneInCombat(ShadowDemon); - } - } - } - ShadowDemonTimer = 60000; - }else ShadowDemonTimer -= diff; - - if(GlobalTimer < diff) - { - if(ShadowBlastTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); - if(target && target->isAlive()) - { - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); - DoCast(target, SPELL_SHADOW_BLAST); - ShadowBlastTimer = 4000; - GlobalTimer += 1500; - } - if(!m_creature->HasAura(SPELL_DEMON_FORM, 0)) - DoCast(m_creature, SPELL_DEMON_FORM, true); - }else ShadowBlastTimer -= diff; - - if(FlameBurstTimer < diff) - { - DoCast(m_creature, SPELL_FLAME_BURST); - FlameBurstTimer = 15000; - }else FlameBurstTimer -= diff; - }else GlobalTimer -= diff; - } - - /** Phase 5 timers. Enrage spell **/ - if(Phase == PHASE_NORMAL_MAIEV) - { - if(EnrageTimer < diff) - { - DoCast(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) - { - Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID); - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(!Maiev || !target || (target->GetTypeId() != TYPEID_PLAYER)) - return; - float X, Y, Z; - target->GetPosition(X, Y, Z); - Maiev->Relocate(X, Y, Z, Maiev->GetOrientation()); - // 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(Phase == PHASE_DEMON_SEQUENCE) // Demonic Transformation - { - if(AnimationTimer < diff) - { - HandleDemonTransformAnimation(DemonFormSequence); - DemonFormSequence++; - }else AnimationTimer -= diff; - } - } -}; - -/*********************** End of Illidan AI ******************************************/ - -void npc_akama_illidanAI::BeginEvent(uint64 PlayerGUID) -{ - debug_log("SD2: Akama - Illidan Introduction started. Illidan event properly begun."); - if(pInstance) - { - IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); - pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, IN_PROGRESS); - } - - if(pInstance) - for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i) - { - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); - if(Door) - Door->SetGoState(1); - } - - if(IllidanGUID) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); - if(Illidan) - { - Illidan->RemoveAurasDueToSpell(SPELL_KNEEL); // Time for Illidan to stand up. - // First line of Akama-Illidan convo - ((boss_illidan_stormrageAI*)Illidan->AI())->TalkCount = 0; - // Begin Talking - ((boss_illidan_stormrageAI*)Illidan->AI())->IsTalking = true; - ((boss_illidan_stormrageAI*)Illidan->AI())->AkamaGUID = m_creature->GetGUID(); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Illidan->GetGUID()); - Illidan->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); - IsTalking = true; // Prevent Akama from starting to attack him - // Prevent players from talking again - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Illidan->GetMotionMaster()->Clear(false); - Illidan->GetMotionMaster()->MoveIdle(); - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - - if(PlayerGUID) - { - Unit* player = Unit::GetUnit((*m_creature), PlayerGUID); - if(player) - Illidan->AddThreat(player, 100.0f); - } - } - } -} - -bool GossipSelect_npc_akama_at_illidan(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if(action == GOSSIP_ACTION_INFO_DEF) // Time to begin the event - { - player->CLOSE_GOSSIP_MENU(); - ((npc_akama_illidanAI*)_Creature->AI())->BeginDoorEvent(player); - } - return true; -} - -bool GossipHello_npc_akama_at_illidan(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(10465, _Creature->GetGUID()); - - return true; -} - -struct MANGOS_DLL_SPEC boss_maievAI : public ScriptedAI -{ - boss_maievAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - }; - - uint32 TauntTimer; - uint64 IllidanGUID; - - ScriptedInstance* pInstance; - - void Reset() - { - TauntTimer = 12000; - IllidanGUID = 0; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(!IllidanGUID) - { - if(pInstance) - IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); - }else - { - Creature* Illidan = NULL; - Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); - if(!Illidan || !Illidan->isAlive() || Illidan->IsInEvadeMode()) - { - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - else if(Illidan && ((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 2)) - return; - } - - // Return if we don't have a target - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(TauntTimer < diff) - { - uint32 random = rand()%4; - char* text = MaievTaunts[random].text; - uint32 sound = MaievTaunts[random].sound; - DoYell(text, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, sound); - TauntTimer = 22000 + rand()%21 * 1000; - }else TauntTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL cage_trap_triggerAI : public ScriptedAI -{ - cage_trap_triggerAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 IllidanGUID; - uint64 CageTrapGUID; - - uint32 DespawnTimer; - - bool Active; - bool SummonedBeams; - - void Reset() - { - IllidanGUID = 0; - CageTrapGUID = 0; - - Active = false; - SummonedBeams = false; - - DespawnTimer = 0; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit *who){} - - 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, 0)) - { - IllidanGUID = who->GetGUID(); - who->CastSpell(who, SPELL_CAGED, true); - DespawnTimer = 5000; - if(who->HasAura(SPELL_ENRAGE, 0)) - // Dispel his enrage - who->RemoveAurasDueToSpell(SPELL_ENRAGE); - - if(GameObject* CageTrap = GameObject::GetGameObject(*m_creature, CageTrapGUID)) - CageTrap->SetLootState(GO_JUST_DEACTIVATED); - } - } - } - } - - void UpdateAI(const uint32 diff) - { - if(DespawnTimer) - if(DespawnTimer < diff) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - else DespawnTimer -= diff; - - //if(IllidanGUID && !SummonedBeams) - //{ - // if(Unit* Illidan = Unit::GetUnit(*m_creature, IllidanGUID) - // { - // //TODO: Find proper spells and properly apply 'caged' Illidan effect - // } - //} - } -}; - -bool GOHello_cage_trap(Player* plr, GameObject* go) -{ - float x, y, z; - plr->GetPosition(x, y, z); - - Creature* trigger = NULL; - - CellPair pair(MaNGOS::ComputeCellPair(x, y)); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - // Grid search for nearest live creature of entry 23304 within 10 yards - MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck check(*plr, 23304, true, 10); - MaNGOS::CreatureLastSearcher searcher(trigger, check); - - TypeContainerVisitor, GridTypeMapContainer> cSearcher(searcher); - - CellLock cell_lock(cell, pair); - cell_lock->Visit(cell_lock, cSearcher, *(plr->GetMap())); - - if(!trigger) - { - plr->GetSession()->SendNotification("SD2: Summon failed. This trap is now useless.", LANG_UNIVERSAL, 0); - error_log("SD2: Cage Trap- Unable to find trigger. This Cage Trap is now useless"); - return false; - } - - ((cage_trap_triggerAI*)trigger->AI())->Active = true; - go->SetGoState(0); - return true; -} - -//This is used to sort the players by distance in preparation for being charged by the flames. -struct TargetDistanceOrder : public std::binary_function -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator ">" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return (MainTarget->GetDistance(_Left) > MainTarget->GetDistance(_Right)); - } -}; - -struct MANGOS_DLL_DECL flame_of_azzinothAI : public ScriptedAI -{ - flame_of_azzinothAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FlameBlastTimer; - uint32 SummonBlazeTimer; - uint32 ChargeTimer; - - void Reset() - { - FlameBlastTimer = 15000 + rand()%15000; - SummonBlazeTimer = 10000 + rand()%20000; - ChargeTimer = 5000; - } - - void Aggro(Unit *who) {} - - void Charge() - { - // Get the Threat List - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - - if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue - - std::list targets; - std::list::iterator itr = m_threatlist.begin(); - for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container - { - Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - //only on alive players - if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) - targets.push_back( target); - } - - //Sort the list of players - targets.sort(TargetDistanceOrder(m_creature)); - //Resize so we only get the furthest target - targets.resize(1); - - Unit* target = (*targets.begin()); - if(target && (!m_creature->IsWithinDistInMap(target, 40))) - { - DoCast(m_creature, SPELL_ENRAGE, true); - DoCast(target, SPELL_CHARGE); - } - } - - void UpdateAI(const uint32 diff) - { - // Return if we don't have a target - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(FlameBlastTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FLAME_BLAST); - FlameBlastTimer = 30000; - }else FlameBlastTimer -= diff; - - if(SummonBlazeTimer < diff) - { - DoCast(m_creature, SPELL_BLAZE_SUMMON); - SummonBlazeTimer = 30000 + rand()%20000; - }else SummonBlazeTimer -= diff; - - if(ChargeTimer < diff) - { - Charge(); - ChargeTimer = 5000; - }else ChargeTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL shadow_demonAI : public ScriptedAI -{ - shadow_demonAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 TargetGUID; - - void Reset() { TargetGUID = 0; } - - void Aggro(Unit *who) {} - - void JustDied(Unit *killer) - { - if(TargetGUID) - { - Unit* target = Unit::GetUnit((*m_creature), TargetGUID); - if(target) - target->RemoveAurasDueToSpell(SPELL_PARALYZE); - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !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, 0)) - { - TargetGUID = m_creature->getVictim()->GetGUID(); - m_creature->AddThreat(m_creature->getVictim(), 10000000.0f); - DoCast(m_creature, SPELL_SHADOW_DEMON_PASSIVE, true); - DoCast(m_creature->getVictim(), SPELL_PURPLE_BEAM, true); - DoCast(m_creature->getVictim(), SPELL_PARALYZE, true); - } - // Kill our target if we're very close. - if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 3)) - DoCast(m_creature->getVictim(), SPELL_CONSUME_SOUL); - } -}; - -struct MANGOS_DLL_DECL flamecrashAI : public ScriptedAI -{ - flamecrashAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FlameCrashTimer; - uint32 DespawnTimer; - - void Reset() - { - FlameCrashTimer = 3000 +rand()%5000; - DespawnTimer = 60000; - } - - void Aggro(Unit *who){ return; } - - void AttackStart(Unit *who) { } - - void MoveInLineOfSight(Unit *who){ } - - void UpdateAI(const uint32 diff) - { - if(FlameCrashTimer < diff) - { - DoCast(m_creature, SPELL_FLAME_CRASH_EFFECT); - FlameCrashTimer = 15000; - }else FlameCrashTimer -= diff; - - if(DespawnTimer < diff) - { - m_creature->SetVisibility(VISIBILITY_OFF); // So that players don't see the sparkly effect when we die. - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - }else DespawnTimer -= diff; - } -}; - -// Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap -struct MANGOS_DLL_SPEC mob_parasitic_shadowfiendAI : public ScriptedAI -{ - mob_parasitic_shadowfiendAI(Creature* c) : ScriptedAI(c) - { - Reset(); - } - - void Reset() {} - - void Aggro(Unit* who) {} - - 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, 0)) - DoCast(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND, true); - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - } - } -}; - -struct MANGOS_DLL_DECL blazeAI : public ScriptedAI -{ - blazeAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 BlazeTimer; - uint32 DespawnTimer; - - void Reset() - { - BlazeTimer = 2000; - DespawnTimer = 15000; - } - - void Aggro(Unit *who){ } - - void AttackStart(Unit* who) { } - - void MoveInLineOfSight(Unit *who){ } - - void UpdateAI(const uint32 diff) - { - if(BlazeTimer < diff) - { - DoCast(m_creature, SPELL_BLAZE_EFFECT); - BlazeTimer = 15000; - }else BlazeTimer -= diff; - - 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; - } -}; - -struct MANGOS_DLL_DECL blade_of_azzinothAI : public ScriptedAI -{ - blade_of_azzinothAI(Creature* c) : ScriptedAI(c) { Reset(); } - - void Reset() {} - // Do-Nothing-But-Stand-There - void Aggro(Unit* who) { } - void AttackStart(Unit* who) { } - void MoveInLineOfSight(Unit* who) { } - -}; - -CreatureAI* GetAI_boss_illidan_stormrage(Creature *_Creature) -{ - return new boss_illidan_stormrageAI (_Creature); -} - -CreatureAI* GetAI_npc_akama_at_illidan(Creature *_Creature) -{ - npc_akama_illidanAI* Akama_AI = new npc_akama_illidanAI(_Creature); - - for(uint8 i = 0; i < 13; ++i) - Akama_AI->AddWaypoint(i, AkamaWP[i].x, AkamaWP[i].y, AkamaWP[i].z); - - return ((CreatureAI*)Akama_AI); -} - -CreatureAI* GetAI_boss_maiev(Creature *_Creature) -{ - return new boss_maievAI (_Creature); -} - -CreatureAI* GetAI_mob_flame_of_azzinoth(Creature *_Creature) -{ - return new flame_of_azzinothAI (_Creature); -} - -CreatureAI* GetAI_cage_trap_trigger(Creature *_Creature) -{ - return new cage_trap_triggerAI (_Creature); -} - -CreatureAI* GetAI_shadow_demon(Creature *_Creature) -{ - return new shadow_demonAI (_Creature); -} - -CreatureAI* GetAI_flamecrash(Creature *_Creature) -{ - return new flamecrashAI (_Creature); -} - -CreatureAI* GetAI_demonfire(Creature *_Creature) -{ - return new demonfireAI (_Creature); -} - -CreatureAI* GetAI_blaze(Creature *_Creature) -{ - return new blazeAI (_Creature); -} - -CreatureAI* GetAI_blade_of_azzinoth(Creature *_Creature) -{ - return new blade_of_azzinothAI (_Creature); -} - -CreatureAI* GetAI_parasitic_shadowfiend(Creature *_Creature) -{ - return new mob_parasitic_shadowfiendAI (_Creature); -} - -void AddSC_boss_illidan() -{ - Script* newscript; - - newscript = new Script; - newscript->Name = "boss_illidan_stormrage"; - newscript->GetAI = GetAI_boss_illidan_stormrage; - m_scripts[nrscripts++] = newscript; - - 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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "boss_maiev_shadowsong"; - newscript->GetAI = GetAI_boss_maiev; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_flame_of_azzinoth"; - newscript->GetAI = GetAI_mob_flame_of_azzinoth; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_blade_of_azzinoth"; - newscript->GetAI = GetAI_blade_of_azzinoth; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "gameobject_cage_trap"; - newscript->pGOHello = GOHello_cage_trap; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_cage_trap_trigger"; - newscript->GetAI = GetAI_cage_trap_trigger; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_shadow_demon"; - newscript->GetAI = GetAI_shadow_demon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_flame_crash"; - newscript->GetAI = GetAI_flamecrash; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_demon_fire"; - newscript->GetAI = GetAI_demonfire; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_blaze"; - newscript->GetAI = GetAI_blaze; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_parasitic_shadowfiend"; - newscript->GetAI = GetAI_parasitic_shadowfiend; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_illidan_stormrage +SD%Complete: 90 +SDComment: +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" +#include "WorldPacket.h" + +/************* Quotes and Sounds ***********************/ +// Gossip for when a player clicks Akama +#define GOSSIP_ITEM "We are ready to face Illidan" + +// Yells for/by Akama +#define SAY_AKAMA_BEWARE "Be wary friends, The Betrayer meditates in the court just beyond." +#define SOUND_AKAMA_BEWARE 11388 +#define SAY_AKAMA_MINION "Come, my minions. Deal with this traitor as he deserves!" +#define SOUND_AKAMA_MINION 11465 +#define SAY_AKAMA_LEAVE "I'll deal with these mongrels. Strike now, friends! Strike at the betrayer!" +#define SOUND_AKAMA_LEAVE 11390 + +// Self explanatory +#define SAY_KILL1 "Who shall be next to taste my blades?!" +#define SOUND_KILL1 11473 +#define SAY_KILL2 "This is too easy!" +#define SOUND_KILL2 11472 + +// I think I'll fly now and let my subordinates take you on +#define SAY_TAKEOFF "I will not be touched by rabble such as you!" +#define SOUND_TAKEOFF 11479 +#define SAY_SUMMONFLAMES "Behold the flames of Azzinoth!" +#define SOUND_SUMMONFLAMES 11480 + +// When casting Eye Blast. Demon Fire will be appear on places that he casts this +#define SAY_EYE_BLAST "Stare into the eyes of the Betrayer!" +#define SOUND_EYE_BLAST 11481 + +// kk, I go big, dark and demon on you. +#define SAY_MORPH "Behold the power... of the demon within!" +#define SOUND_MORPH 11475 + +// I KILL! +#define SAY_ENRAGE "You've wasted too much time mortals, now you shall fall!" +#define SOUND_ENRAGE 11474 + +/************** 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.740 +#define CENTER_Y 305.297 +#define CENTER_Z 353.192 + +/**** Creature Summon and Recognition IDs ****/ +enum CreatureEntry +{ + EMPTY = 0, + AKAMA = 22990, + ILLIDAN_STORMRAGE = 22917, + BLADE_OF_AZZINOTH = 22996, + FLAME_OF_AZZINOTH = 22997, + MAIEV_SHADOWSONG = 23197, + SHADOW_DEMON = 23375, + DEMON_FIRE = 23069, + FLAME_CRASH = 23336, + ILLIDAN_DOOR_TRIGGER = 23412, + SPIRIT_OF_OLUM = 23411, + SPIRIT_OF_UDALO = 23410, + ILLIDARI_ELITE = 23226, + PARASITIC_SHADOWFIEND = 23498, + CAGE_TRAP_TRIGGER = 23292, +}; + +/*** 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 Yells +{ + uint32 sound; + char* text; + uint32 creature, timer, emote; + bool Talk; +}; + +static Yells Conversation[]= +{ + {11463, "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.", ILLIDAN_STORMRAGE, 8000, 0, true}, + {0, NULL, ILLIDAN_STORMRAGE, 5000, 396, true}, + {11389, "We've come to end your reign, Illidan. My people and all of Outland shall be free!", AKAMA, 7000, 25, true}, + {0, NULL, AKAMA, 5000, 66, true}, + {11464, "Boldly said. But I remain unconvinced.", ILLIDAN_STORMRAGE, 8000, 396, true}, + {11380, "The time has come! The moment is at hand!", AKAMA, 3000, 22, true}, + {0, NULL, AKAMA, 2000, 15, true}, + {11466, "You are not prepared!", ILLIDAN_STORMRAGE, 3000, 406, true}, + {0, NULL, EMPTY, 1000, 0, true}, + {0, NULL, EMPTY, 0, 0, false}, + {11476, "Is this it, mortals? Is this all the fury you can muster?", ILLIDAN_STORMRAGE, 8000, 0, true}, + {11491, "Their fury pales before mine, Illidan. We have some unsettled business between us.", MAIEV_SHADOWSONG, 8000, 5, true}, + {11477, "Maiev... How is this even possible?", ILLIDAN_STORMRAGE, 7000, 1, true}, + {11492, "Ah... my long hunt is finally over. Today, Justice will be done!", MAIEV_SHADOWSONG, 8000, 15, true}, + {11470, "Feel the hatred of ten thousand years!", ILLIDAN_STORMRAGE, 1000, 0, false}, + {11496, "Ahh... It is finished. You are beaten.", MAIEV_SHADOWSONG, 6000, 0, true}, + { // Emote dead for now. Kill him later + 11478, "You have won... Maiev...but the huntress... is nothing...without the hunt... you... are nothing... without me..", ILLIDAN_STORMRAGE, 22000, 65, true + }, + {11497, "He is right. I feel nothing... I am nothing... Farewell, champions.", MAIEV_SHADOWSONG, 9000, 0, true}, + {11498, NULL, MAIEV_SHADOWSONG, 0, true}, + {11387, "The Light will fill these dismal halls once again. I swear it.", AKAMA, 8000, 0, true}, + {0, NULL, EMPTY, 1000, 0, false} +}; + +static Yells RandomTaunts[]= +{ + {11467, "I can feel your hatred.", ILLIDAN_STORMRAGE, 0, 0, false}, + {11468, "Give in to your fear!", ILLIDAN_STORMRAGE, 0, 0, false}, + {11469, "You know nothing of power!", ILLIDAN_STORMRAGE, 0, 0, false}, + {11471, "Such... arrogance!", ILLIDAN_STORMRAGE, 0, 0, false} +}; + +static Yells MaievTaunts[]= +{ + {11493, "That is for Naisha!", MAIEV_SHADOWSONG, 0, false}, + {11494, "Bleed as I have bled!", MAIEV_SHADOWSONG, 0, 0, false}, + {11495, "There shall be no prison for you this time!", MAIEV_SHADOWSONG, 0, 0, false}, + {11500, "Meet your end, demon!", MAIEV_SHADOWSONG, 0, 0, false} +}; + +struct Locations +{ + float x, y, z; + uint32 id; +}; + +static Locations GlaivePosition[]= +{ + {695.105, 305.303, 354.256}, + {659.338, 305.303, 354.256}, + {700.105, 305.303, 354.256}, + {664.338, 305.303, 354.256} +}; + +static Locations EyeBlast[]= +{ + {650.697, 320.128, 353.730}, + {652.799, 275.091, 353.367}, + {701.527, 273.815, 353.230}, + {709.865, 325.654, 353.322} +}; + +static Locations AkamaWP[]= +{ + { 770.01, 304.50, 312.29 }, // Bottom of the first stairs, at the doors + { 780.66, 304.50, 319.74 }, // Top of the first stairs + { 790.13, 319.68, 319.76 }, // Bottom of the second stairs (left from the entrance) + { 787.17, 347.38, 341.42 }, // Top of the second stairs + { 781.34, 350.31, 341.44 }, // Bottom of the third stairs + { 762.60, 361.06, 353.60 }, // Top of the third stairs + { 756.35, 360.52, 353.27 }, // Before the door-thingy + { 743.82, 342.21, 353.00 }, // Somewhere further + { 732.69, 305.13, 353.00 }, // In front of Illidan + { 738.11, 365.44, 353.00 }, // in front of the door-thingy (the other one!) + { 792.18, 366.62, 341.42 }, // Down the first flight of stairs + { 796.84, 304.89, 319.76 }, // Down the second flight of stairs + { 782.01, 304.55, 319.76 } // 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.5426, 309.9156, 312.2129, SPIRIT_OF_UDALO}, + {755.5426, 298.7923, 312.0834, SPIRIT_OF_OLUM} +}; + +struct WayPoints +{ + WayPoints(uint32 _id, float _x, float _y, float _z) + { + id = _id; + x = _x; + y = _y; + z = _z; + } + uint32 id; + float x, y, z; +}; + +struct Animation // For the demon transformation +{ + uint32 aura, unaura, timer, size, displayid, phase; + bool equip; +}; + +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} +}; + +/**** 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 +{ + demonfireAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 IllidanGUID; + + bool IsTrigger; + + uint32 CheckTimer; + uint32 DemonFireTimer; + uint32 DespawnTimer; + + void Reset() + { + IllidanGUID = 0; + + IsTrigger = false; + + CheckTimer = 2000; + DemonFireTimer = 0; + DespawnTimer = 45000; + } + + void Aggro(Unit *who) {} + void AttackStart(Unit* who) { } + void MoveInLineOfSight(Unit *who){ } + + void UpdateAI(const uint32 diff) + { + if(IsTrigger) + return; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if(CheckTimer < diff) + { + if(!IllidanGUID && pInstance) + { + IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); + if(IllidanGUID) + { + Unit* Illidan = Unit::GetUnit((*m_creature), IllidanGUID); + if(Illidan && !Illidan->HasUnitMovementFlag(MOVEMENTFLAG_LEVITATING)) + m_creature->setDeathState(JUST_DIED); + } + } + CheckTimer = 2000; + }else CheckTimer -= diff; + + if(DemonFireTimer < diff) + { + DoCast(m_creature, SPELL_DEMON_FIRE); + DemonFireTimer = 30000; + }else DemonFireTimer -= diff; + + if(DespawnTimer < diff) + m_creature->setDeathState(JUST_DIED); + else DespawnTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +/******* Functions and vars for Akama's AI ******/ +struct MANGOS_DLL_SPEC npc_akama_illidanAI : public ScriptedAI +{ + npc_akama_illidanAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + WayPointList.clear(); + Reset(); + } + + /* Instance Data */ + ScriptedInstance* pInstance; + + /* 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 Aggro(Unit *who) {} + + void Reset() + { + if(pInstance) + { + pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED); + GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); + if( Gate && !Gate->GetGoState() ) + Gate->SetGoState(1); // close door if already open (when raid wipes or something) + + for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) + { + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); + if(Door) + Door->SetGoState(0); + } + } + + IllidanGUID = 0; + PlayerGUID = 0; + ChannelGUID = 0; + for(uint8 i = 0; i < 2; ++i) SpiritGUID[i] = 0; + + ChannelTimer = 0; + ChannelCount = 0; + SummonMinionTimer = 2000; + + WalkTimer = 0; + + TalkTimer = 0; + TalkCount = 0; + + KillAllElites(); + + IsReturningToIllidan = false; + FightMinions = false; + IsTalking = false; + StartChanneling = false; + DoorOpen = false; + + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has strange values.. + 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); + } + + // 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() + { + InCombat = false; + + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + } + + void KillAllElites() + { + std::list::iterator itr; + for(itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if(pUnit && (pUnit->GetTypeId() == TYPEID_UNIT) && (pUnit->GetEntry() == ILLIDARI_ELITE)) + pUnit->setDeathState(JUST_DIED); + } + } + + void ReturnToIllidan() + { + KillAllElites(); + InCombat = false; + FightMinions = false; + IsReturningToIllidan = true; + WayPoint = WayPointList.begin(); + m_creature->SetSpeed(MOVE_RUN, 2.0f); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + IsWalking = true; + } + + void AddWaypoint(uint32 id, float x, float y, float z) + { + WayPoints AkamaWP(id, x, y, z); + WayPointList.push_back(AkamaWP); + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if(damage > m_creature->GetHealth() && (done_by->GetGUID() != m_creature->GetGUID())) + { + damage = 0; + DoCast(m_creature, SPELL_HEALING_POTION); + } + } + + void BeginDoorEvent(Player* player) + { + if(!pInstance) + return; + + outstring_log("SD2: Akama - Door event initiated by player %s", player->GetName()); + PlayerGUID = player->GetGUID(); + + GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); + if(Gate) + { + float x,y,z; + Gate->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(); + // Invisible but spell visuals can still be seen. + Channel->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); + Channel->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + 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(); + } + } + StartChanneling = true; + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoCast(Channel, SPELL_AKAMA_DOOR_FAIL); + } + } + } + + void MovementInform(uint32 type, uint32 id) + { + if(type != POINT_MOTION_TYPE || !IsWalking) + return; + + if(WayPoint->id != id) + return; + + switch(id) + { + case 6: + if(!IsReturningToIllidan) + { // open the doors that close the summit + for(uint32 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i) + { + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); + if(Door) + Door->SetGoState(0); + } + } + case 7: + if(IsReturningToIllidan) + { + IsWalking = false; + if(IllidanGUID) + { + Unit* Illidan = Unit::GetUnit((*m_creature), 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); + } + } + } + break; + case 8: + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if(!IsReturningToIllidan) + { + IsWalking = false; + BeginEvent(PlayerGUID); + } + break; + case 12: + IsWalking = false; + FightMinions = true; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + break; + } + + ++WayPoint; + WalkTimer = 200; + } + + void DeleteFromThreatList() + { + if(!IllidanGUID) return; // If we do not have Illidan's GUID, do not proceed + // Create a pointer to Illidan + Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); + if(!Illidan) return; // No use to continue if Illidan does not exist + std::list::iterator itr = Illidan->getThreatManager().getThreatList().begin(); + for( ; itr != Illidan->getThreatManager().getThreatList().end(); ++itr) + { + // 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. + } + } + + // Now we delete our threatlist to prevent attacking anyone for now + m_creature->DeleteThreatList(); + } + + void UpdateAI(const uint32 diff) + { + if(IllidanGUID) + { + Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); + if(Illidan) + { + if(Illidan->IsInEvadeMode() && !m_creature->IsInEvadeMode()) + EnterEvadeMode(); + + if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 85) && InCombat && !FightMinions) + { + if(TalkTimer < diff) + { + switch(TalkCount) + { + case 0: + Illidan->Yell(SAY_AKAMA_MINION, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(Illidan, SOUND_AKAMA_MINION); + TalkTimer = 8000; + TalkCount = 1; + break; + case 1: + DoYell(SAY_AKAMA_LEAVE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AKAMA_LEAVE); + TalkTimer = 3000; + TalkCount = 2; + break; + case 2: + IsTalking = true; + TalkTimer = 2000; + m_creature->RemoveAllAuras(); + m_creature->CombatStop(); + 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->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + break; + } + }else TalkTimer -= diff; + } + + if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 4) && !IsReturningToIllidan) + ReturnToIllidan(); + } + }else + { + if(pInstance) + IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); + } + + if(IsWalking && WalkTimer) + { + if(WalkTimer <= diff) + { + if(WayPoint == WayPointList.end()) + return; + m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y,WayPoint->z); + WalkTimer = 0; + }else WalkTimer -= diff; + } + + if(StartChanneling) + { + if(ChannelTimer < diff) + { + switch(ChannelCount) + { + case 3: + if(!DoorOpen) + { + m_creature->InterruptNonMeleeSpells(true); + for(uint8 i = 0; i < 2; ++i) + { + if(SpiritGUID[i]) + { + Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]); + if(Spirit) + Spirit->InterruptNonMeleeSpells(true); + } + } + GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); + if(Gate) + Gate->SetGoState(0); + ChannelCount++; + ChannelTimer = 5000; + } + break; + case 4: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + ChannelTimer = 2000; + ChannelCount++; + break; + case 5: + DoYell(SAY_AKAMA_BEWARE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AKAMA_BEWARE); + if(ChannelGUID) + { + Unit* ChannelTarget = Unit::GetUnit((*m_creature), ChannelGUID); + if(ChannelTarget) + ChannelTarget->setDeathState(JUST_DIED); + } + for(uint8 i = 0; i < 2; ++i) + { + if(SpiritGUID[i]) + { + Unit* Spirit = Unit::GetUnit((*m_creature), 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; + } + + WayPoint = WayPointList.begin(); + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y, WayPoint->z); + IsWalking = true; + break; + default: + if(ChannelGUID) + { + Unit* Channel = Unit::GetUnit((*m_creature), ChannelGUID); + if(Channel) + { + m_creature->InterruptNonMeleeSpells(true); + + for(uint8 i = 0; i < 2; ++i) + { + if(SpiritGUID[i]) + { + Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]); + if(Spirit) + { + Spirit->InterruptNonMeleeSpells(true); + if(ChannelCount%2 == 0) + { + Spirit->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL,false); + DoCast(Channel, SPELL_AKAMA_DOOR_CHANNEL); + } + else + { + if(Spirit->GetVisibility() == VISIBILITY_OFF) + Spirit->SetVisibility(VISIBILITY_ON); + } + } + } + } + if(ChannelCount < 3) + ChannelCount++; + ChannelTimer = 10000; + } + break; + } + } + }else ChannelTimer -= diff; + } + + if(FightMinions) + { + if(SummonMinionTimer < diff) + { + if(IllidanGUID) + { + Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); + if(!Illidan || Illidan->IsInEvadeMode()) + { + Reset(); + EnterEvadeMode(); + return; + } + } + + 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) + { + Elite->AI()->AttackStart(m_creature); + Elite->AddThreat(m_creature, 1000000.0f); + AttackStart(Elite); + } + SummonMinionTimer = 10000 + rand()%6000; + }else SummonMinionTimer -= diff; + } + + // If we don't have a target, or is talking, or has run away, return + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return; + + DoMeleeAttackIfReady(); + } +}; + +/************* Custom check used for Agonizing Flames ***************/ +class AgonizingFlamesTargetCheck +{ + public: + AgonizingFlamesTargetCheck(Unit const* unit) : pUnit(unit) {} + bool operator() (Player* plr) + { + // Faster than square rooting + if(!plr->isGameMaster() && pUnit->GetDistance2d(plr) > 225) + return true; + + return false; + } + + private: + Unit const* pUnit; +}; + +/************************************** Illidan's AI ***************************************/ +struct MANGOS_DLL_SPEC boss_illidan_stormrageAI : public ScriptedAI +{ + boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + /** Instance Data **/ + ScriptedInstance* pInstance; + + /** 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; + + // Check if any flames/glaives are alive/existing. Kill if alive and set GUIDs to 0 + for(uint8 i = 0; i < 2; i++) + { + if(FlameGUID[i]) + { + Unit* Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); + if(Flame) + Flame->setDeathState(JUST_DIED); + FlameGUID[i] = 0; + } + + if(GlaiveGUID[i]) + { + Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]); + if(Glaive) + Glaive->setDeathState(JUST_DIED); + GlaiveGUID[i] = 0; + } + } + + if(AkamaGUID) + { + Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID)); + if(Akama) + { + if(!Akama->isAlive()) + Akama->Respawn(); + ((npc_akama_illidanAI*)Akama->AI())->Reset(); + ((npc_akama_illidanAI*)Akama->AI())->EnterEvadeMode(); + Akama->GetMotionMaster()->MoveTargetedHome(); + } + } + + InformAkama = false; + RefaceVictim = false; + HasSummoned = false; + AkamaGUID = 0; + MaievGUID = 0; + + FaceVictimTimer = 1000; + BerserkTimer = 1500000; + GlobalTimer = 0; + DemonFormSequence = 0; + + /** Normal Form **/ + ShearTimer = 20000 + (rand()%11 * 1000); // 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->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135); + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // Unequip warglaives if needed + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + + IsTalking = false; + + TalkCount = 0; + TalkTimer = 0; + + if(pInstance) + pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED); + } + + void Aggro(Unit *who) { DoZoneInCombat(); } + + void AttackStart(Unit *who) + { + if(!who || IsTalking || Phase == 2 || Phase == 4 || Phase == 6 || m_creature->HasAura(SPELL_KNEEL, 0)) + return; + + if (who->isTargetableForAttack() && who!= m_creature) + { + //Begin melee attack if we are within range + DoStartAttackAndMovement(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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + DoStartAttackAndMovement(who); + } + } + } + + void JustDied(Unit *killer) + { + IsTalking = false; + TalkCount = 0; + TalkTimer = 0; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if(!pInstance) + return; + // Completed + pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, DONE); + + for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) + { + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); + if(Door) + Door->SetGoState(0); // Open Doors + } + + } + + void KilledUnit(Unit *victim) + { + if(victim == m_creature) return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL1, LANG_UNIVERSAL, victim); + DoPlaySoundToSet(m_creature, SOUND_KILL1); + break; + case 1: + DoYell(SAY_KILL2, LANG_UNIVERSAL, victim); + DoPlaySoundToSet(m_creature, SOUND_KILL2); + break; + } + } + + 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; + + DoYell(SAY_EYE_BLAST, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_EYE_BLAST); + + uint32 initial = rand()%4; + 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) + { + Creature* Trigger = NULL; + Trigger = m_creature->SummonCreature(DEMON_FIRE, initial_X, initial_Y, initial_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); + if(Trigger) + { + ((demonfireAI*)Trigger->AI())->IsTrigger = true; + Trigger->GetMotionMaster()->MovePoint(0, final_X, final_Y, final_Z); + + if(!i) + Trigger->CastSpell(Trigger, SPELL_EYE_BLAST_TRIGGER, true); + else + { + Trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Trigger->GetGUID()); + DoCast(Trigger, SPELL_EYE_BLAST); + } + } + } + } + + // It's only cast on players that are greater than 15 yards away from Illidan. If no one is found, cast it on MT instead (since selecting someone in that 15 yard radius would cause the flames to hit the MT anyway). + void CastAgonizingFlames() + { + // We'll use grid searching for this, using a custom searcher that selects a player that is at a distance >15 yards + Player* target = NULL; + + CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + AgonizingFlamesTargetCheck check(m_creature); + MaNGOS::PlayerSearcher searcher(target, check); + TypeContainerVisitor + , GridTypeMapContainer> visitor(searcher); + + CellLock cell_lock(cell, pair); + cell_lock->Visit(cell_lock, visitor, *(m_creature->GetMap())); + + if(target) + DoCast(target, SPELL_AGONIZING_FLAMES); + else + DoCast(m_creature->getVictim(), SPELL_AGONIZING_FLAMES); + } + + void Talk(uint32 count) + { + if(!m_creature->isAlive()) return; + uint32 sound = Conversation[count].sound; + char* text = NULL; + if(Conversation[count].text) + text = Conversation[count].text; + TalkTimer = Conversation[count].timer; + uint32 emote = Conversation[count].emote; + IsTalking = Conversation[count].Talk; + Creature* creature = NULL; + uint64 GUID = 0; + if(Conversation[count].creature == ILLIDAN_STORMRAGE) + creature = m_creature; + else if(Conversation[count].creature == AKAMA) + { + if(!AkamaGUID) + { + if(pInstance) + { + AkamaGUID = pInstance->GetData64(DATA_AKAMA); + if(!AkamaGUID) + return; + GUID = AkamaGUID; + } + } + 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 + creature = ((Creature*)Unit::GetUnit((*m_creature), GUID)); + + if(creature) + { + creature->HandleEmoteCommand(emote); // Make the creature do some animation! + if(text) + creature->Yell(text, LANG_UNIVERSAL, 0); // Have the creature yell out some text + if(sound) + DoPlaySoundToSet(creature, sound); // Play some sound on the creature + } + } + + void Move(float X, float Y, float Z, Creature* _Creature) + { + _Creature->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) + DoCast(m_creature, aura, true); + + if(displayid) + // It's morphin time! + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid); + /*if(size) + m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, size); // Let us grow! (or shrink)*/ + + if(DemonTransformation[count].equip) + { + // Requip warglaives if needed + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); + } + else + { + // Unequip warglaives if needed + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); + } + + 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()); + if(MaievGUID) Phase = PHASE_NORMAL_MAIEV; // Depending on whether we summoned Maiev, we switch to either phase 5 or 3 + 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, 0)) + DoCast(m_creature, SPELL_DEMON_FORM, true); + } + } + + /** To reduce the amount of code in UpdateAI, we can seperate them into different functions and simply call them from UpdateAI **/ + void EnterPhase2() + { + DoYell(SAY_TAKEOFF, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TAKEOFF); + + 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); + // Animate our take off! + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + // We now hover! + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + 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; + + DoCast(m_creature, SPELL_THROW_GLAIVE2); // Make it look like we're throwing the glaives on the ground + // We no longer wear the glaives! + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); + // since they are now channeling the flames (or will be) + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); + for(uint8 i = 0; i < 2; ++i) + { + Creature* Glaive = NULL; + Glaive = ((Creature*)Unit::GetUnit((*m_creature), GlaiveGUID[i])); + if(Glaive) + { + DoCast(Glaive, SPELL_THROW_GLAIVE, true); + Glaive->SetVisibility(VISIBILITY_ON); + } + } + } + + void SummonFlamesOfAzzinoth() + { + DoYell(SAY_SUMMONFLAMES, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMONFLAMES); + + for(uint8 i = 0; i < 2; ++i) + { + Creature* Flame = NULL; + Creature* Glaive = NULL; + Glaive = ((Creature*)Unit::GetUnit((*m_creature), 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) + { + // 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()); + FlameGUID[i] = Flame->GetGUID(); // Record GUID in order to check if they're dead later on to move to the next phase + // Glaives do some random Beam type channel on it. + Glaive->CastSpell(Flame, SPELL_AZZINOTH_CHANNEL, true); + if(m_creature->getVictim()) + Flame->AI()->AttackStart(m_creature->getVictim()); + } + else + { + DoTextEmote("is unable to summon a Flame of Azzinoth.", NULL); + error_log("SD2 ERROR: Illidan Stormrage AI: Unable to summon Flame of Azzinoth (entry: 22997), please check your database"); + EnterEvadeMode(); + } + } + else + { + DoTextEmote("is unable to summon a Blade of Azzinoth.", NULL); + error_log("SD2 ERROR: 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); + DoCast(m_creature, SPELL_SHADOW_PRISON, true); + 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(); + DoTextEmote("is unable to summon Maiev Shadowsong and enter Phase 4. Resetting Encounter.", NULL); + error_log("SD2 ERROR: 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(); + DoCast(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) + { + Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID)); + if(Maiev) + { + Maiev->CombatStop(); // 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->Relocate(dx,dy,Maiev->GetPositionZ()); + Maiev->SendMonsterMove(dx,dy,Maiev->GetPositionZ(), 0, 0, 0); + 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 + { + case 0: + // Time to stand up! + m_creature->RemoveAurasDueToSpell( SPELL_KNEEL ); + break; + case 8: + // Equip our warglaives! + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); + m_creature->setFaction(14); // Hostile if we weren't before + break; + case 9: + if(AkamaGUID) + { + Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID)); + if(Akama) + { + Akama->GetMotionMaster()->Clear(false); + // Akama runs to us! + Akama->GetMotionMaster()->MoveChase(m_creature); + m_creature->GetMotionMaster()->Clear(false); + // We run to Akama! + m_creature->GetMotionMaster()->MoveChase(Akama); + Akama->AddThreat(m_creature, 1000000.0f); + AttackStart(Akama); // Start attacking Akama + ((npc_akama_illidanAI*)Akama->AI())->IsTalking = false; + // Akama starts attacking us + ((npc_akama_illidanAI*)Akama->AI())->AttackStart(m_creature); + } + } + // We are now attackable! + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + break; + case 11: + if(MaievGUID) + { + Unit* Maiev = Unit::GetUnit((*m_creature), 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 = ((Creature*)Unit::GetUnit((*m_creature), 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); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + IsTalking = false; + FaceVictimTimer = 2000; + RefaceVictim = true; + break; + case 20: // Kill ourself. + if(MaievGUID) + { + Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), 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; + } + Talk(TalkCount); // This function does most of the talking + TalkCount++; + }else TalkTimer -= diff; + } + + // If we don't have a target, return. + if(!m_creature->SelectHostilTarget() || !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, 0)) + { + EnrageTimer = 40000; // Just so that he doesn't immediately enrage after he stops being caged. + CageTimer = 30000; + return; + } + + // Berserk Timer - flat 25 minutes + if(!m_creature->HasAura(SPELL_BERSERK, 0) && Phase != PHASE_DEMON_SEQUENCE) + if(BerserkTimer < diff) + { + DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + DoCast(m_creature, SPELL_BERSERK, true); + }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->GetHealth()*100 / m_creature->GetMaxHealth()) < 65) && (Phase == PHASE_NORMAL)) + EnterPhase2(); + + /** Signal to summon Maiev **/ + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) && !MaievGUID && + ((Phase != PHASE_DEMON) || (Phase != PHASE_DEMON_SEQUENCE))) + SummonMaiev(); + + /** Time for the death speech **/ + if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 1) && (!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 = rand()%4; + char* yell = RandomTaunts[random].text; + uint32 soundid = RandomTaunts[random].sound; + if(yell) + DoYell(yell, LANG_UNIVERSAL, NULL); + if(soundid) + DoPlaySoundToSet(m_creature, soundid); + TauntTimer = 32000; + }else TauntTimer -= diff; + + if(GlobalTimer < diff) // Global Timer so that spells do not overlap. + { + if(ShearTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SHEAR); + ShearTimer = 25000 + (rand()%16 * 1000); + GlobalTimer += 2000; + }else ShearTimer -= diff; + + if(FlameCrashTimer < diff) + { + // It spawns multiple flames sometimes. Therefore, we'll do this manually. + //DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH); + DoSpawnCreature(FLAME_CRASH, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 40000); + FlameCrashTimer = 35000; + GlobalTimer += 2000; + }else FlameCrashTimer -= diff; + + if(ParasiticShadowFiendTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,1); + if(target && target->isAlive() && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0)) + { + Cast(target, SPELL_PARASITIC_SHADOWFIEND); + ParasiticShadowFiendTimer = 40000; + } + }else ParasiticShadowFiendTimer -= diff; + + if(DrawSoulTimer < diff) + { + DoCast(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; + + if(SummonFlamesTimer < diff) + { + SummonFlamesOfAzzinoth(); + }else SummonFlamesTimer -= diff; + } + + if(!m_creature->GetMotionMaster()->empty() && (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)) + m_creature->GetMotionMaster()->Clear(false); + + if(HasSummoned) + { + if(CheckFlamesTimer) + if(CheckFlamesTimer <= diff) + { + // Check if flames are dead or non-existant. If so, set GUID to 0. + for(uint8 i = 0; i < 2; i++) + { + if(FlameGUID[i]) + { + Unit* Flame = NULL; + Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); + + // If the flame dies, or somehow the pointer becomes invalid, reset GUID to 0. + if(!Flame || !Flame->isAlive()) + FlameGUID[i] = 0; + } + } + 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; + } + + if(RetrieveBladesTimer) + if(RetrieveBladesTimer <= diff) // Time to get back our glaives! + { + // Interrupt any spells we might be doing *cough* DArk Barrage *cough* + m_creature->InterruptNonMeleeSpells(false); + for(uint8 i = 0; i < 2; i++) + { + if(GlaiveGUID[i]) + { + Unit* Glaive = NULL; + Glaive = Unit::GetUnit((*m_creature), 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; + } + } + // Re-equip our warblades! + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); + LandTimer = 5000; // Prepare for landin'! + RetrieveBladesTimer = 0; + }else RetrieveBladesTimer -= diff; + + if(LandTimer) + { + if(LandTimer <= diff) // Time to land! + { + DoResetThreat(); + // anndddd touchdown! + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + Phase = PHASE_NORMAL_2; + // 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()); + // 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. + } + } + + if(GlobalTimer < diff) + { + if(FireballTimer < diff) + { + Cast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL); + FireballTimer = 5000; + }else FireballTimer -= diff; + + if(DarkBarrageTimer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE); + DarkBarrageTimer = 35000; + GlobalTimer += 9000; + }else DarkBarrageTimer -= diff; + + if(EyeBlastTimer < diff) + { + CastEyeBlast(); + EyeBlastTimer = 30000; + }else EyeBlastTimer -= diff; + }else GlobalTimer -= diff; + } + + /** 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; + + if(TransformTimer < diff) + { + uint32 CurHealth = m_creature->GetHealth()*100 / m_creature->GetMaxHealth(); + // 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 && !MaievGUID) || (CurHealth < 5)) + return; + + Phase = PHASE_DEMON_SEQUENCE; // Transform sequence + DemonFormSequence = 0; + AnimationTimer = 0; + DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_MORPH); + TransformTimer = 60000; + FlameBurstTimer = 10000; + ShadowDemonTimer = 30000; + m_creature->GetMotionMaster()->Clear(false);// Stop moving + }else TransformTimer -= diff; + } + + /** Phase 4 spells only (Demon Form) **/ + if(Phase == PHASE_DEMON) + { + // Stop moving if we are by clearing movement generators. + if(!m_creature->GetMotionMaster()->empty()) + m_creature->GetMotionMaster()->Clear(false); + + if(TransformTimer < diff) + { + Phase = PHASE_DEMON_SEQUENCE; + DemonFormSequence = 5; + AnimationTimer = 100; + TransformTimer = 60000; + }else TransformTimer -= diff; + + if(ShadowDemonTimer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + Creature* ShadowDemon = NULL; + for(uint8 i = 0; i < 4; i++) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + // only on players. + if(target && target->GetTypeId() == TYPEID_PLAYER) + { + ShadowDemon = DoSpawnCreature(SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,25000); + if(ShadowDemon) + { + ShadowDemon->AddThreat(target, 5000000.0f); + ShadowDemon->AI()->AttackStart(target); + DoZoneInCombat(ShadowDemon); + } + } + } + ShadowDemonTimer = 60000; + }else ShadowDemonTimer -= diff; + + if(GlobalTimer < diff) + { + if(ShadowBlastTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); + if(target && target->isAlive()) + { + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); + DoCast(target, SPELL_SHADOW_BLAST); + ShadowBlastTimer = 4000; + GlobalTimer += 1500; + } + if(!m_creature->HasAura(SPELL_DEMON_FORM, 0)) + DoCast(m_creature, SPELL_DEMON_FORM, true); + }else ShadowBlastTimer -= diff; + + if(FlameBurstTimer < diff) + { + DoCast(m_creature, SPELL_FLAME_BURST); + FlameBurstTimer = 15000; + }else FlameBurstTimer -= diff; + }else GlobalTimer -= diff; + } + + /** Phase 5 timers. Enrage spell **/ + if(Phase == PHASE_NORMAL_MAIEV) + { + if(EnrageTimer < diff) + { + DoCast(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) + { + Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID); + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(!Maiev || !target || (target->GetTypeId() != TYPEID_PLAYER)) + return; + float X, Y, Z; + target->GetPosition(X, Y, Z); + Maiev->Relocate(X, Y, Z, Maiev->GetOrientation()); + // 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(Phase == PHASE_DEMON_SEQUENCE) // Demonic Transformation + { + if(AnimationTimer < diff) + { + HandleDemonTransformAnimation(DemonFormSequence); + DemonFormSequence++; + }else AnimationTimer -= diff; + } + } +}; + +/*********************** End of Illidan AI ******************************************/ + +void npc_akama_illidanAI::BeginEvent(uint64 PlayerGUID) +{ + debug_log("SD2: Akama - Illidan Introduction started. Illidan event properly begun."); + if(pInstance) + { + IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); + pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, IN_PROGRESS); + } + + if(pInstance) + for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i) + { + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); + if(Door) + Door->SetGoState(1); + } + + if(IllidanGUID) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); + if(Illidan) + { + Illidan->RemoveAurasDueToSpell(SPELL_KNEEL); // Time for Illidan to stand up. + // First line of Akama-Illidan convo + ((boss_illidan_stormrageAI*)Illidan->AI())->TalkCount = 0; + // Begin Talking + ((boss_illidan_stormrageAI*)Illidan->AI())->IsTalking = true; + ((boss_illidan_stormrageAI*)Illidan->AI())->AkamaGUID = m_creature->GetGUID(); + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Illidan->GetGUID()); + Illidan->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); + IsTalking = true; // Prevent Akama from starting to attack him + // Prevent players from talking again + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Illidan->GetMotionMaster()->Clear(false); + Illidan->GetMotionMaster()->MoveIdle(); + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + + if(PlayerGUID) + { + Unit* player = Unit::GetUnit((*m_creature), PlayerGUID); + if(player) + Illidan->AddThreat(player, 100.0f); + } + } + } +} + +bool GossipSelect_npc_akama_at_illidan(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if(action == GOSSIP_ACTION_INFO_DEF) // Time to begin the event + { + player->CLOSE_GOSSIP_MENU(); + ((npc_akama_illidanAI*)_Creature->AI())->BeginDoorEvent(player); + } + return true; +} + +bool GossipHello_npc_akama_at_illidan(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(10465, _Creature->GetGUID()); + + return true; +} + +struct MANGOS_DLL_SPEC boss_maievAI : public ScriptedAI +{ + boss_maievAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + }; + + uint32 TauntTimer; + uint64 IllidanGUID; + + ScriptedInstance* pInstance; + + void Reset() + { + TauntTimer = 12000; + IllidanGUID = 0; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(!IllidanGUID) + { + if(pInstance) + IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); + }else + { + Creature* Illidan = NULL; + Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); + if(!Illidan || !Illidan->isAlive() || Illidan->IsInEvadeMode()) + { + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + else if(Illidan && ((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 2)) + return; + } + + // Return if we don't have a target + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(TauntTimer < diff) + { + uint32 random = rand()%4; + char* text = MaievTaunts[random].text; + uint32 sound = MaievTaunts[random].sound; + DoYell(text, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, sound); + TauntTimer = 22000 + rand()%21 * 1000; + }else TauntTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL cage_trap_triggerAI : public ScriptedAI +{ + cage_trap_triggerAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 IllidanGUID; + uint64 CageTrapGUID; + + uint32 DespawnTimer; + + bool Active; + bool SummonedBeams; + + void Reset() + { + IllidanGUID = 0; + CageTrapGUID = 0; + + Active = false; + SummonedBeams = false; + + DespawnTimer = 0; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit *who){} + + 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, 0)) + { + IllidanGUID = who->GetGUID(); + who->CastSpell(who, SPELL_CAGED, true); + DespawnTimer = 5000; + if(who->HasAura(SPELL_ENRAGE, 0)) + // Dispel his enrage + who->RemoveAurasDueToSpell(SPELL_ENRAGE); + + if(GameObject* CageTrap = GameObject::GetGameObject(*m_creature, CageTrapGUID)) + CageTrap->SetLootState(GO_JUST_DEACTIVATED); + } + } + } + } + + void UpdateAI(const uint32 diff) + { + if(DespawnTimer) + if(DespawnTimer < diff) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + else DespawnTimer -= diff; + + //if(IllidanGUID && !SummonedBeams) + //{ + // if(Unit* Illidan = Unit::GetUnit(*m_creature, IllidanGUID) + // { + // //TODO: Find proper spells and properly apply 'caged' Illidan effect + // } + //} + } +}; + +bool GOHello_cage_trap(Player* plr, GameObject* go) +{ + float x, y, z; + plr->GetPosition(x, y, z); + + Creature* trigger = NULL; + + CellPair pair(MaNGOS::ComputeCellPair(x, y)); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + // Grid search for nearest live creature of entry 23304 within 10 yards + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck check(*plr, 23304, true, 10); + MaNGOS::CreatureLastSearcher searcher(trigger, check); + + TypeContainerVisitor, GridTypeMapContainer> cSearcher(searcher); + + CellLock cell_lock(cell, pair); + cell_lock->Visit(cell_lock, cSearcher, *(plr->GetMap())); + + if(!trigger) + { + plr->GetSession()->SendNotification("SD2: Summon failed. This trap is now useless.", LANG_UNIVERSAL, 0); + error_log("SD2: Cage Trap- Unable to find trigger. This Cage Trap is now useless"); + return false; + } + + ((cage_trap_triggerAI*)trigger->AI())->Active = true; + go->SetGoState(0); + return true; +} + +//This is used to sort the players by distance in preparation for being charged by the flames. +struct TargetDistanceOrder : public std::binary_function +{ + const Unit* MainTarget; + TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; + // functor for operator ">" + bool operator()(const Unit* _Left, const Unit* _Right) const + { + return (MainTarget->GetDistance(_Left) > MainTarget->GetDistance(_Right)); + } +}; + +struct MANGOS_DLL_DECL flame_of_azzinothAI : public ScriptedAI +{ + flame_of_azzinothAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FlameBlastTimer; + uint32 SummonBlazeTimer; + uint32 ChargeTimer; + + void Reset() + { + FlameBlastTimer = 15000 + rand()%15000; + SummonBlazeTimer = 10000 + rand()%20000; + ChargeTimer = 5000; + } + + void Aggro(Unit *who) {} + + void Charge() + { + // Get the Threat List + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + + if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue + + std::list targets; + std::list::iterator itr = m_threatlist.begin(); + for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container + { + Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + //only on alive players + if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) + targets.push_back( target); + } + + //Sort the list of players + targets.sort(TargetDistanceOrder(m_creature)); + //Resize so we only get the furthest target + targets.resize(1); + + Unit* target = (*targets.begin()); + if(target && (!m_creature->IsWithinDistInMap(target, 40))) + { + DoCast(m_creature, SPELL_ENRAGE, true); + DoCast(target, SPELL_CHARGE); + } + } + + void UpdateAI(const uint32 diff) + { + // Return if we don't have a target + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(FlameBlastTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FLAME_BLAST); + FlameBlastTimer = 30000; + }else FlameBlastTimer -= diff; + + if(SummonBlazeTimer < diff) + { + DoCast(m_creature, SPELL_BLAZE_SUMMON); + SummonBlazeTimer = 30000 + rand()%20000; + }else SummonBlazeTimer -= diff; + + if(ChargeTimer < diff) + { + Charge(); + ChargeTimer = 5000; + }else ChargeTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL shadow_demonAI : public ScriptedAI +{ + shadow_demonAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 TargetGUID; + + void Reset() { TargetGUID = 0; } + + void Aggro(Unit *who) {} + + void JustDied(Unit *killer) + { + if(TargetGUID) + { + Unit* target = Unit::GetUnit((*m_creature), TargetGUID); + if(target) + target->RemoveAurasDueToSpell(SPELL_PARALYZE); + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !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, 0)) + { + TargetGUID = m_creature->getVictim()->GetGUID(); + m_creature->AddThreat(m_creature->getVictim(), 10000000.0f); + DoCast(m_creature, SPELL_SHADOW_DEMON_PASSIVE, true); + DoCast(m_creature->getVictim(), SPELL_PURPLE_BEAM, true); + DoCast(m_creature->getVictim(), SPELL_PARALYZE, true); + } + // Kill our target if we're very close. + if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 3)) + DoCast(m_creature->getVictim(), SPELL_CONSUME_SOUL); + } +}; + +struct MANGOS_DLL_DECL flamecrashAI : public ScriptedAI +{ + flamecrashAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FlameCrashTimer; + uint32 DespawnTimer; + + void Reset() + { + FlameCrashTimer = 3000 +rand()%5000; + DespawnTimer = 60000; + } + + void Aggro(Unit *who){ return; } + + void AttackStart(Unit *who) { } + + void MoveInLineOfSight(Unit *who){ } + + void UpdateAI(const uint32 diff) + { + if(FlameCrashTimer < diff) + { + DoCast(m_creature, SPELL_FLAME_CRASH_EFFECT); + FlameCrashTimer = 15000; + }else FlameCrashTimer -= diff; + + if(DespawnTimer < diff) + { + m_creature->SetVisibility(VISIBILITY_OFF); // So that players don't see the sparkly effect when we die. + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + }else DespawnTimer -= diff; + } +}; + +// Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap +struct MANGOS_DLL_SPEC mob_parasitic_shadowfiendAI : public ScriptedAI +{ + mob_parasitic_shadowfiendAI(Creature* c) : ScriptedAI(c) + { + Reset(); + } + + void Reset() {} + + void Aggro(Unit* who) {} + + 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, 0)) + DoCast(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND, true); + m_creature->AttackerStateUpdate(m_creature->getVictim()); + m_creature->resetAttackTimer(); + } + } + } +}; + +struct MANGOS_DLL_DECL blazeAI : public ScriptedAI +{ + blazeAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 BlazeTimer; + uint32 DespawnTimer; + + void Reset() + { + BlazeTimer = 2000; + DespawnTimer = 15000; + } + + void Aggro(Unit *who){ } + + void AttackStart(Unit* who) { } + + void MoveInLineOfSight(Unit *who){ } + + void UpdateAI(const uint32 diff) + { + if(BlazeTimer < diff) + { + DoCast(m_creature, SPELL_BLAZE_EFFECT); + BlazeTimer = 15000; + }else BlazeTimer -= diff; + + 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; + } +}; + +struct MANGOS_DLL_DECL blade_of_azzinothAI : public ScriptedAI +{ + blade_of_azzinothAI(Creature* c) : ScriptedAI(c) { Reset(); } + + void Reset() {} + // Do-Nothing-But-Stand-There + void Aggro(Unit* who) { } + void AttackStart(Unit* who) { } + void MoveInLineOfSight(Unit* who) { } + +}; + +CreatureAI* GetAI_boss_illidan_stormrage(Creature *_Creature) +{ + return new boss_illidan_stormrageAI (_Creature); +} + +CreatureAI* GetAI_npc_akama_at_illidan(Creature *_Creature) +{ + npc_akama_illidanAI* Akama_AI = new npc_akama_illidanAI(_Creature); + + for(uint8 i = 0; i < 13; ++i) + Akama_AI->AddWaypoint(i, AkamaWP[i].x, AkamaWP[i].y, AkamaWP[i].z); + + return ((CreatureAI*)Akama_AI); +} + +CreatureAI* GetAI_boss_maiev(Creature *_Creature) +{ + return new boss_maievAI (_Creature); +} + +CreatureAI* GetAI_mob_flame_of_azzinoth(Creature *_Creature) +{ + return new flame_of_azzinothAI (_Creature); +} + +CreatureAI* GetAI_cage_trap_trigger(Creature *_Creature) +{ + return new cage_trap_triggerAI (_Creature); +} + +CreatureAI* GetAI_shadow_demon(Creature *_Creature) +{ + return new shadow_demonAI (_Creature); +} + +CreatureAI* GetAI_flamecrash(Creature *_Creature) +{ + return new flamecrashAI (_Creature); +} + +CreatureAI* GetAI_demonfire(Creature *_Creature) +{ + return new demonfireAI (_Creature); +} + +CreatureAI* GetAI_blaze(Creature *_Creature) +{ + return new blazeAI (_Creature); +} + +CreatureAI* GetAI_blade_of_azzinoth(Creature *_Creature) +{ + return new blade_of_azzinothAI (_Creature); +} + +CreatureAI* GetAI_parasitic_shadowfiend(Creature *_Creature) +{ + return new mob_parasitic_shadowfiendAI (_Creature); +} + +void AddSC_boss_illidan() +{ + Script* newscript; + + newscript = new Script; + newscript->Name = "boss_illidan_stormrage"; + newscript->GetAI = GetAI_boss_illidan_stormrage; + m_scripts[nrscripts++] = newscript; + + 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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "boss_maiev_shadowsong"; + newscript->GetAI = GetAI_boss_maiev; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_flame_of_azzinoth"; + newscript->GetAI = GetAI_mob_flame_of_azzinoth; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_blade_of_azzinoth"; + newscript->GetAI = GetAI_blade_of_azzinoth; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "gameobject_cage_trap"; + newscript->pGOHello = GOHello_cage_trap; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_cage_trap_trigger"; + newscript->GetAI = GetAI_cage_trap_trigger; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_shadow_demon"; + newscript->GetAI = GetAI_shadow_demon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_flame_crash"; + newscript->GetAI = GetAI_flamecrash; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_demon_fire"; + newscript->GetAI = GetAI_demonfire; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_blaze"; + newscript->GetAI = GetAI_blaze; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_parasitic_shadowfiend"; + newscript->GetAI = GetAI_parasitic_shadowfiend; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp index 383e3b05656..c651c3a629a 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp @@ -1,353 +1,353 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_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 -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -//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[]= -{ - 40880, // Shadow - 40882, // Fire - 40883, // Nature - 40891, // Arcane - 40896, // Frost - 40897, // Holy -}; - -//Speech'n'Sounds -#define SAY_TAUNT1 "You play, you pay." -#define SOUND_TAUNT1 11501 - -#define SAY_TAUNT2 "I'm not impressed." -#define SOUND_TAUNT2 11502 - -#define SAY_TAUNT3 "Enjoying yourselves?" -#define SOUND_TAUNT3 11503 - -#define SAY_AGGRO "So, business... Or pleasure?" -#define SOUND_AGGRO 11504 - -#define SAY_SPELL1 "You seem a little tense." -#define SOUND_SPELL1 11505 - -#define SAY_SPELL2 "Don't be shy." -#define SOUND_SPELL2 11506 - -#define SAY_SPELL3 "I'm all... yours." -#define SOUND_SPELL3 11507 - -#define SAY_SLAY1 "Easy come, easy go." -#define SOUND_SLAY1 11508 - -#define SAY_SLAY2 "So much for a happy ending." -#define SOUND_SLAY2 11509 - -#define SAY_ENRAGE "Stop toying with my emotions!" -#define SOUND_ENRAGE 11510 - -#define SAY_DEATH "I wasn't... finished." -#define SOUND_DEATH 11511 - -struct Locations -{ - float x,y,z; -}; - -static Locations TeleportPoint[]= -{ - {959.996, 212.576, 193.843}, - {932.537, 231.813, 193.838}, - {958.675, 254.767, 193.822}, - {946.955, 201.316, 192.535}, - {944.294, 149.676, 197.551}, - {930.548, 284.888, 193.367}, - {965.997, 278.398, 195.777} -}; - -struct MANGOS_DLL_DECL boss_shahrazAI : public ScriptedAI -{ - boss_shahrazAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 TargetGUID[3]; - uint32 BeamTimer; - uint32 BeamCount; - uint32 CurrentBeam; - uint32 PrismaticShieldTimer; - uint32 FatalAttractionTimer; - uint32 FatalAttractionExplodeTimer; - uint32 ShriekTimer; - uint32 RandomYellTimer; - uint32 EnrageTimer; - uint32 ExplosionCount; - - bool Enraged; - - void Reset() - { - if(pInstance) - pInstance->SetData(DATA_MOTHERSHAHRAZEVENT, NOT_STARTED); - - 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 = 70000 + rand()%41 * 1000; - EnrageTimer = 600000; - ExplosionCount = 0; - - Enraged = false; - } - - void Aggro(Unit *who) - { - if(pInstance) - pInstance->SetData(DATA_MOTHERSHAHRAZEVENT, IN_PROGRESS); - - DoZoneInCombat(); - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - if(pInstance) - pInstance->SetData(DATA_MOTHERSHAHRAZEVENT, DONE); - - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void TeleportPlayers() - { - uint32 random = rand()%7; - float X = TeleportPoint[random].x; - float Y = TeleportPoint[random].y; - float Z = TeleportPoint[random].z; - for(uint8 i = 0; i < 3; i++) - { - Unit* pUnit = SelectUnit(SELECT_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) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !Enraged) - { - Enraged = true; - DoCast(m_creature, SPELL_ENRAGE, true); - DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - } - - //Randomly cast one beam. - if(BeamTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(!target || !target->isAlive()) - return; - - BeamTimer = 9000; - - switch(CurrentBeam) - { - case 0: - DoCast(target, SPELL_BEAM_SINISTER); - break; - case 1: - DoCast(target, SPELL_BEAM_VILE); - break; - case 2: - DoCast(target, SPELL_BEAM_WICKED); - break; - case 3: - DoCast(target, SPELL_BEAM_SINFUL); - break; - } - BeamCount++; - uint32 Beam = CurrentBeam; - if(BeamCount > 3) - while(CurrentBeam == Beam) - CurrentBeam = rand()%3; - - }else BeamTimer -= diff; - - // Random Prismatic Shield every 15 seconds. - if(PrismaticShieldTimer < diff) - { - uint32 random = rand()%6; - if(PrismaticAuras[random]) - DoCast(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) - { - ExplosionCount = 0; - - TeleportPlayers(); - - switch(rand()%2) - { - case 0: - DoYell(SAY_SPELL2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SPELL2); - break; - case 1: - DoYell(SAY_SPELL3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SPELL3); - break; - } - FatalAttractionExplodeTimer = 2000; - FatalAttractionTimer = 40000 + rand()%31 * 1000; - }else FatalAttractionTimer -= diff; - - if(FatalAttractionExplodeTimer < diff) - { - // 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) - { - for(uint8 i = 0; i < 4; i++) - { - Unit* pUnit = NULL; - if(TargetGUID[i]) - { - pUnit = Unit::GetUnit((*m_creature), TargetGUID[i]); - if(pUnit) - pUnit->CastSpell(pUnit, SPELL_ATTRACTION, true); - TargetGUID[i] = 0; - } - } - - ExplosionCount++; - FatalAttractionExplodeTimer = 1000; - } - else - { - FatalAttractionExplodeTimer = FatalAttractionTimer + 2000; - ExplosionCount = 0; - } - }else FatalAttractionExplodeTimer -= diff; - - if(ShriekTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SILENCING_SHRIEK); - ShriekTimer = 30000; - }else ShriekTimer -= diff; - - //Enrage - if(!m_creature->HasAura(SPELL_BERSERK, 0)) - if(EnrageTimer < diff) - { - DoCast(m_creature, SPELL_BERSERK); - DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - }else EnrageTimer -= diff; - - //Random taunts - if(RandomYellTimer < diff) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_TAUNT1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_TAUNT1); - break; - case 1: - DoYell(SAY_TAUNT2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_TAUNT2); - break; - case 2: - DoYell(SAY_TAUNT3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_TAUNT3); - break; - } - RandomYellTimer = 60000 + rand()%91 * 1000; - }else RandomYellTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_shahraz(Creature *_Creature) -{ - return new boss_shahrazAI (_Creature); -} - -void AddSC_boss_mother_shahraz() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_mother_shahraz"; - newscript->GetAI = GetAI_boss_shahraz; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_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 +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +//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[]= +{ + 40880, // Shadow + 40882, // Fire + 40883, // Nature + 40891, // Arcane + 40896, // Frost + 40897, // Holy +}; + +//Speech'n'Sounds +#define SAY_TAUNT1 "You play, you pay." +#define SOUND_TAUNT1 11501 + +#define SAY_TAUNT2 "I'm not impressed." +#define SOUND_TAUNT2 11502 + +#define SAY_TAUNT3 "Enjoying yourselves?" +#define SOUND_TAUNT3 11503 + +#define SAY_AGGRO "So, business... Or pleasure?" +#define SOUND_AGGRO 11504 + +#define SAY_SPELL1 "You seem a little tense." +#define SOUND_SPELL1 11505 + +#define SAY_SPELL2 "Don't be shy." +#define SOUND_SPELL2 11506 + +#define SAY_SPELL3 "I'm all... yours." +#define SOUND_SPELL3 11507 + +#define SAY_SLAY1 "Easy come, easy go." +#define SOUND_SLAY1 11508 + +#define SAY_SLAY2 "So much for a happy ending." +#define SOUND_SLAY2 11509 + +#define SAY_ENRAGE "Stop toying with my emotions!" +#define SOUND_ENRAGE 11510 + +#define SAY_DEATH "I wasn't... finished." +#define SOUND_DEATH 11511 + +struct Locations +{ + float x,y,z; +}; + +static Locations TeleportPoint[]= +{ + {959.996, 212.576, 193.843}, + {932.537, 231.813, 193.838}, + {958.675, 254.767, 193.822}, + {946.955, 201.316, 192.535}, + {944.294, 149.676, 197.551}, + {930.548, 284.888, 193.367}, + {965.997, 278.398, 195.777} +}; + +struct MANGOS_DLL_DECL boss_shahrazAI : public ScriptedAI +{ + boss_shahrazAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 TargetGUID[3]; + uint32 BeamTimer; + uint32 BeamCount; + uint32 CurrentBeam; + uint32 PrismaticShieldTimer; + uint32 FatalAttractionTimer; + uint32 FatalAttractionExplodeTimer; + uint32 ShriekTimer; + uint32 RandomYellTimer; + uint32 EnrageTimer; + uint32 ExplosionCount; + + bool Enraged; + + void Reset() + { + if(pInstance) + pInstance->SetData(DATA_MOTHERSHAHRAZEVENT, NOT_STARTED); + + 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 = 70000 + rand()%41 * 1000; + EnrageTimer = 600000; + ExplosionCount = 0; + + Enraged = false; + } + + void Aggro(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_MOTHERSHAHRAZEVENT, IN_PROGRESS); + + DoZoneInCombat(); + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + if(pInstance) + pInstance->SetData(DATA_MOTHERSHAHRAZEVENT, DONE); + + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void TeleportPlayers() + { + uint32 random = rand()%7; + float X = TeleportPoint[random].x; + float Y = TeleportPoint[random].y; + float Z = TeleportPoint[random].z; + for(uint8 i = 0; i < 3; i++) + { + Unit* pUnit = SelectUnit(SELECT_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) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !Enraged) + { + Enraged = true; + DoCast(m_creature, SPELL_ENRAGE, true); + DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + } + + //Randomly cast one beam. + if(BeamTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(!target || !target->isAlive()) + return; + + BeamTimer = 9000; + + switch(CurrentBeam) + { + case 0: + DoCast(target, SPELL_BEAM_SINISTER); + break; + case 1: + DoCast(target, SPELL_BEAM_VILE); + break; + case 2: + DoCast(target, SPELL_BEAM_WICKED); + break; + case 3: + DoCast(target, SPELL_BEAM_SINFUL); + break; + } + BeamCount++; + uint32 Beam = CurrentBeam; + if(BeamCount > 3) + while(CurrentBeam == Beam) + CurrentBeam = rand()%3; + + }else BeamTimer -= diff; + + // Random Prismatic Shield every 15 seconds. + if(PrismaticShieldTimer < diff) + { + uint32 random = rand()%6; + if(PrismaticAuras[random]) + DoCast(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) + { + ExplosionCount = 0; + + TeleportPlayers(); + + switch(rand()%2) + { + case 0: + DoYell(SAY_SPELL2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SPELL2); + break; + case 1: + DoYell(SAY_SPELL3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SPELL3); + break; + } + FatalAttractionExplodeTimer = 2000; + FatalAttractionTimer = 40000 + rand()%31 * 1000; + }else FatalAttractionTimer -= diff; + + if(FatalAttractionExplodeTimer < diff) + { + // 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) + { + for(uint8 i = 0; i < 4; i++) + { + Unit* pUnit = NULL; + if(TargetGUID[i]) + { + pUnit = Unit::GetUnit((*m_creature), TargetGUID[i]); + if(pUnit) + pUnit->CastSpell(pUnit, SPELL_ATTRACTION, true); + TargetGUID[i] = 0; + } + } + + ExplosionCount++; + FatalAttractionExplodeTimer = 1000; + } + else + { + FatalAttractionExplodeTimer = FatalAttractionTimer + 2000; + ExplosionCount = 0; + } + }else FatalAttractionExplodeTimer -= diff; + + if(ShriekTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SILENCING_SHRIEK); + ShriekTimer = 30000; + }else ShriekTimer -= diff; + + //Enrage + if(!m_creature->HasAura(SPELL_BERSERK, 0)) + if(EnrageTimer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + }else EnrageTimer -= diff; + + //Random taunts + if(RandomYellTimer < diff) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_TAUNT1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_TAUNT1); + break; + case 1: + DoYell(SAY_TAUNT2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_TAUNT2); + break; + case 2: + DoYell(SAY_TAUNT3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_TAUNT3); + break; + } + RandomYellTimer = 60000 + rand()%91 * 1000; + }else RandomYellTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_shahraz(Creature *_Creature) +{ + return new boss_shahrazAI (_Creature); +} + +void AddSC_boss_mother_shahraz() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_mother_shahraz"; + newscript->GetAI = GetAI_boss_shahraz; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp index 19ba2784880..1a1037e5efe 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp @@ -1,1051 +1,1051 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Reliquary_of_Souls -SD%Complete: 90 -SDComment: Persistent Area Auras for each Essence (Aura of Suffering, Aura of Desire, Aura of Anger) requires core support. -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -//Sound'n'speech -//Suffering -#define SUFF_SAY_FREED "Pain and suffering are all that await you!" -#define SUFF_SOUND_FREED 11415 -#define SUFF_SAY_AGGRO "Don't leave me alone!" -#define SUFF_SOUND_AGGRO 11416 -#define SUFF_SAY_SLAY1 "Look at what you make me do!" -#define SUFF_SOUND_SLAY1 11417 -#define SUFF_SAY_SLAY2 "I didn't ask for this!" -#define SUFF_SOUND_SLAY2 11418 -#define SUFF_SAY_SLAY3 "The pain is only beginning!" -#define SUFF_SOUND_SLAY3 11419 -#define SUFF_SAY_RECAP "I don't want to go back!" -#define SUFF_SOUND_RECAP 11420 -#define SUFF_SAY_AFTER "Now what do I do?" -#define SUFF_SOUND_AFTER 11421 - -//Desire -#define DESI_SAY_FREED "You can have anything you desire... for a price." -#define DESI_SOUND_FREED 11408 -#define DESI_SAY_SLAY1 "Fulfilment is at hand!" -#define DESI_SOUND_SLAY1 11409 -#define DESI_SAY_SLAY2 "Yes... you'll stay with us now..." -#define DESI_SOUND_SLAY2 11410 -#define DESI_SAY_SLAY3 "Your reach exceeds your grasp." -#define DESI_SOUND_SLAY3 11412 -#define DESI_SAY_SPEC "Be careful what you wish for..." -#define DESI_SOUND_SPEC 11411 -#define DESI_SAY_RECAP "I'll be waiting..." -#define DESI_SOUND_RECAP 11413 -#define DESI_SAY_AFTER "I won't be far..." -#define DESI_SOUND_AFTER 11414 - -//Anger -#define ANGER_SAY_FREED "Beware... I live." -#define ANGER_SOUND_FREED 11399 -#define ANGER_SAY_FREED2 "So... foolish." -#define ANGER_SOUND_FREED2 11400 -#define ANGER_SOUND_SLAY1 11401 -#define ANGER_SAY_SLAY2 "Enough. No more." -#define ANGER_SOUND_SLAY2 11402 -#define ANGER_SAY_SPEC "On your knees!" -#define ANGER_SOUND_SPEC 11403 -#define ANGER_SAY_BEFORE "Beware, coward." -#define ANGER_SOUND_BEFORE 11405 -#define ANGER_SAY_DEATH "I won't... be... ignored." -#define ANGER_SOUND_DEATH 11404 - -//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 Position -{ - float x,y; -}; - -static Position Coords[]= -{ - {450.4, 212.3}, - {542.1, 212.3}, - {542.1, 168.3}, - {542.1, 137.4}, - {450.4, 137.4}, - {450.4, 168.3} -}; - -struct MANGOS_DLL_DECL npc_enslaved_soulAI : public ScriptedAI -{ - npc_enslaved_soulAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 ReliquaryGUID; - - void Reset() - { - ReliquaryGUID = 0; - } - - void Aggro(Unit* who) {} - - 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)); - } - } - DoCast(done_by, SPELL_SOUL_RELEASE); - } - } - - void JustDied(Unit *killer); -}; - -struct MANGOS_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI -{ - boss_reliquary_of_soulsAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 SufferingGUID; - uint64 DesireGUID; - uint64 AngerGUID; - - uint32 SoulDeathCount; - // 0 = Out of Combat, 1 = Not started, 2 = Suffering, 3 = Souls, 4 = Desire, 5 = Souls, 6 = Anger - uint32 Phase; - uint32 SummonEssenceTimer; - uint32 DespawnEssenceTimer; - uint32 SoulCount; - uint32 SummonSoulTimer; - uint32 AnimationTimer; - - bool IsDead; - bool EndingPhase; - - void Reset() - { - if(pInstance) - pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, NOT_STARTED); - - DespawnEssences(); - - SufferingGUID = 0; - DesireGUID = 0; - AngerGUID = 0; - - SoulDeathCount = 0; - Phase = 0; - SummonEssenceTimer = 8000; - DespawnEssenceTimer = 2000; - SoulCount = 0; - SummonSoulTimer = 1000; - AnimationTimer = 8000; - - IsDead = false; - EndingPhase = false; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); - m_creature->GetMotionMaster()->Clear(false); - } - - void Aggro(Unit* who) { } - - void AttackStart(Unit* who) { } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if(!InCombat) - { - if(pInstance) - pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, IN_PROGRESS); - - Phase = 1; - // I R ANNNGRRRY! - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,375); - SummonEssenceTimer = 8000; - AnimationTimer = 5100; - m_creature->AddThreat(who, 1.0f); - - InCombat = true; - } - } - } - } - - void SummonSoul() - { - uint32 random = rand()%6; - 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 = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (target && Soul) - { - ((npc_enslaved_soulAI*)Soul->AI())->ReliquaryGUID = m_creature->GetGUID(); - Soul->CastSpell(Soul, ENSLAVED_SOUL_PASSIVE, true); - Soul->AddThreat(target, 1.0f); - SoulCount++; - } - } - - void MergeThreatList(Creature* target) - { - if(!target) return; - - std::list& m_threatlist = target->getThreatManager().getThreatList(); - std::list::iterator itr = m_threatlist.begin(); - for( ; itr != m_threatlist.end(); itr++) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); - if(pUnit) - { - m_creature->AddThreat(pUnit, 1.0f); // 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). - } - } - } - - void DespawnEssences() - { - // Despawn Essences - Unit* Essence = NULL; - if(SufferingGUID) - Essence = ((Creature*)Unit::GetUnit((*m_creature), SufferingGUID)); - else if(DesireGUID) - Essence = ((Creature*)Unit::GetUnit((*m_creature), DesireGUID)); - else if(AngerGUID) - Essence = ((Creature*)Unit::GetUnit((*m_creature), AngerGUID)); - if(Essence && Essence->isAlive()) - Essence->setDeathState(JUST_DIED); - } - - void JustDied(Unit* killer) - { - if(pInstance) - pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, DONE); - - InCombat = false; - } - - void UpdateAI(const uint32 diff) - { - if(!Phase) - 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); - Creature* EssenceSuffering = NULL; - EssenceSuffering = m_creature->SummonCreature(23418, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); - - if(EssenceSuffering) - { - EssenceSuffering->Yell(SUFF_SAY_FREED, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(m_creature, SUFF_SOUND_FREED); - Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); - if(target) - { - EssenceSuffering->AddThreat(target, 1.0f); - EssenceSuffering->AI()->AttackStart(target); - } - SufferingGUID = EssenceSuffering->GetGUID(); - } - - EndingPhase = false; - Phase = 2; - }else SummonEssenceTimer -= diff; - } - - if(Phase == 2) - { - if(SufferingGUID) - { - Creature* EssenceSuffering = NULL; - EssenceSuffering = ((Creature*)Unit::GetUnit((*m_creature), SufferingGUID)); - - if(!EssenceSuffering || (!EssenceSuffering->isAlive())) - EnterEvadeMode(); - - if(!EndingPhase) - { - if(EssenceSuffering) - { - if(EssenceSuffering->GetHealth() < (EssenceSuffering->GetMaxHealth()*0.1)) - { - MergeThreatList(EssenceSuffering); - EssenceSuffering->RemoveAllAuras(); - EssenceSuffering->DeleteThreatList(); - EssenceSuffering->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); - EssenceSuffering->Yell(SUFF_SAY_RECAP,LANG_UNIVERSAL,0); - DoPlaySoundToSet(m_creature, SUFF_SOUND_RECAP); - 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) - { - EssenceSuffering->DeleteThreatList(); - EssenceSuffering->Yell(SUFF_SAY_AFTER,LANG_UNIVERSAL,0); - DoPlaySoundToSet(m_creature, SUFF_SOUND_AFTER); - EssenceSuffering->SetUInt32Value(UNIT_FIELD_DISPLAYID, 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; - } - } - } - - if(Phase == 3) - { - if(SoulCount < 36) - { - 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 = NULL; - EssenceDesire = m_creature->SummonCreature(23419, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); - - if(EssenceDesire) - { - EssenceDesire->Yell(DESI_SAY_FREED, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, DESI_SOUND_FREED); - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - EssenceDesire->AddThreat(target, 1.0f); - EssenceDesire->AI()->AttackStart(target); - } - DesireGUID = EssenceDesire->GetGUID(); - SoulDeathCount = 0; - } - - Phase = 4; - }else SummonEssenceTimer -= diff; - } - } - - if(Phase == 4) - { - if(DesireGUID) - { - Creature* EssenceDesire = NULL; - EssenceDesire = ((Creature*)Unit::GetUnit((*m_creature), DesireGUID)); - - if(!EssenceDesire || !EssenceDesire->isAlive()) - EnterEvadeMode(); - - if(!EndingPhase && EssenceDesire) - { - if(EssenceDesire->GetHealth() < (EssenceDesire->GetMaxHealth()*0.1)) - { - MergeThreatList(EssenceDesire); - EssenceDesire->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); - EssenceDesire->RemoveAllAuras(); - EssenceDesire->DeleteThreatList(); - EssenceDesire->Yell(DESI_SAY_RECAP,LANG_UNIVERSAL,0); - DoPlaySoundToSet(m_creature, DESI_SOUND_RECAP); - EssenceDesire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DespawnEssenceTimer = 4000; - AnimationTimer = 2200; - EndingPhase = true; - } - } - - if(EndingPhase && EssenceDesire) - { - 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); - EssenceDesire->Yell(DESI_SAY_AFTER, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(m_creature, DESI_SOUND_AFTER); - EssenceDesire->SetUInt32Value(UNIT_FIELD_DISPLAYID, 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; - } - } - } - } - - if(Phase == 5) - { - if(SoulCount < 36) - { - 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* EssenceAnger = NULL; - EssenceAnger = m_creature->SummonCreature(23420, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); - - if(EssenceAnger) - { - Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); - if(target) - { - EssenceAnger->AddThreat(target, 1.0f); - EssenceAnger->AI()->AttackStart(target); - } - AngerGUID = EssenceAnger->GetGUID(); - DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED); - EssenceAnger->Yell(ANGER_SAY_FREED, LANG_UNIVERSAL, 0); - SoulDeathCount = 0; - } - - Phase = 6; - }else SummonEssenceTimer -= diff; - } - } - - if(Phase == 6) - { - if(AngerGUID) - { - Creature* EssenceAnger = NULL; - EssenceAnger = ((Creature*)Unit::GetUnit((*m_creature), 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); - } - } - } - } - } -}; - -//This is used to sort the players by distance in preparation for the Fixate cast. -struct TargetDistanceOrder : public std::binary_function -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator "<" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); - } -}; - -struct MANGOS_DLL_DECL boss_essence_of_sufferingAI : public ScriptedAI -{ - boss_essence_of_sufferingAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 StatAuraGUID; - - uint32 AggroYellTimer; - uint32 FixateTimer; - uint32 EnrageTimer; - uint32 SoulDrainTimer; - - void Reset() - { - StatAuraGUID = 0; - - AggroYellTimer = 5000; - FixateTimer = 5000; - EnrageTimer = 30000; - SoulDrainTimer = 150000; - } - - 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); - if(StatAuraGUID) - { - Unit* pUnit = Unit::GetUnit((*m_creature), StatAuraGUID); - if(pUnit) - pUnit->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR); - } - } - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - DoCast(who, AURA_OF_SUFFERING, true); - DoCast(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, true); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoYell(SUFF_SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY1); - break; - case 1: - DoYell(SUFF_SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY2); - break; - case 2: - DoYell(SUFF_SAY_SLAY3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY3); - break; - } - } - - void JustDied(Unit* killer) - { - } - - void CastFixate() - { - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - if(m_threatlist.empty()) - return; // No point continuing if empty threatlist. - std::list targets; - std::list::iterator itr = m_threatlist.begin(); - for( ; itr != m_threatlist.end(); ++itr) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); - // Only alive players - if(pUnit && pUnit->isAlive() && (pUnit->GetTypeId() == TYPEID_PLAYER)) - targets.push_back(pUnit); - } - if(targets.empty()) - return; // No targets added for some reason. No point continuing. - targets.sort(TargetDistanceOrder(m_creature)); // Sort players by distance. - targets.resize(1); // Only need closest target. - Unit* target = targets.front(); // Get the first target. - // Add threat equivalent to threat on victim. - m_creature->AddThreat(target, m_creature->getThreatManager().getThreat(m_creature->getVictim())); - DoCast(target, SPELL_FIXATE); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1)) - { - if(StatAuraGUID) - { - Unit* pUnit = NULL; - pUnit = Unit::GetUnit((*m_creature), StatAuraGUID); - if(pUnit) - pUnit->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR); - } - } - - if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1)) - { - 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(AggroYellTimer < diff) - { - DoYell(SUFF_SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SUFF_SOUND_AGGRO); - AggroYellTimer = 0; - }else AggroYellTimer -= diff; - - //Supposed to be cast on nearest target - if(FixateTimer < diff) - { - CastFixate(); - FixateTimer = 5000; - }else FixateTimer -= diff; - - if(EnrageTimer < diff) - { - DoCast(m_creature, SPELL_ENRAGE); - EnrageTimer = 60000; - }else EnrageTimer -= diff; - - if(SoulDrainTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if(target) - DoCast(target, SPELL_SOUL_DRAIN); - SoulDrainTimer = 60000; - }else SoulDrainTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; -struct MANGOS_DLL_DECL boss_essence_of_desireAI : public ScriptedAI -{ - boss_essence_of_desireAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 AggroYellTimer; - uint32 RuneShieldTimer; - uint32 DeadenTimer; - uint32 SoulShockTimer; - - void Reset() - { - AggroYellTimer = 5000; - RuneShieldTimer = 60000; - DeadenTimer = 15000; - SoulShockTimer = 40000; - } - - 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); - } - } - - void Aggro(Unit *who) { DoZoneInCombat(); } - - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoYell(DESI_SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY1); - break; - case 1: - DoYell(DESI_SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY2); - break; - case 2: - DoYell(DESI_SAY_SLAY3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY3); - break; - } - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - //Begin melee attack if we are within range - DoStartAttackAndMovement(who); - - if (!InCombat) - { - DoCast(who, AURA_OF_DESIRE); - } - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1)) - { - if(m_creature->getVictim()) - m_creature->DeleteThreatList(); // Delete our threatlist if below 10% as we should no longer attack. - return; - } - - if(RuneShieldTimer < diff) - { - DoCast(m_creature, SPELL_RUNE_SHIELD); - RuneShieldTimer = 60000; - }else RuneShieldTimer -= diff; - - if(DeadenTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_DEADEN); - DeadenTimer = 30000 + rand()%30001; - }else DeadenTimer -= diff; - - if(SoulShockTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SOUL_SHOCK); - SoulShockTimer = 40000; - if(rand()%2 == 0) - { - DoYell(DESI_SAY_SPEC,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, DESI_SOUND_SPEC); - } - - }else SoulShockTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_essence_of_angerAI : public ScriptedAI -{ - boss_essence_of_angerAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 AggroTargetGUID; - - uint32 AggroYellTimer; - uint32 CheckTankTimer; - uint32 SoulScreamTimer; - uint32 SpiteTimer; - - bool CheckedAggro; - - void Reset() - { - AggroTargetGUID = 0; - - AggroYellTimer = 5000; - CheckTankTimer = 5000; - SoulScreamTimer = 10000; - SpiteTimer = 30000; - - CheckedAggro = false; - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - DoCast(m_creature->getVictim(), AURA_OF_ANGER, true); - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - //Begin melee attack if we are within range - DoStartAttackAndMovement(who); - - if (!InCombat) - { - DoCast(who, AURA_OF_ANGER); - } - } - } - } - - void JustDied(Unit *victim) - { - DoYell(ANGER_SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,ANGER_SOUND_DEATH); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY1); - break; - case 1: - DoYell(ANGER_SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY2); - break; - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(!CheckedAggro) - { - AggroTargetGUID = m_creature->getVictim()->GetGUID(); - CheckedAggro = true; - } - - if(AggroYellTimer) - if(AggroYellTimer < diff) - { - DoYell(ANGER_SAY_FREED2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED2); - AggroYellTimer = 0; - }else AggroYellTimer -= diff; - - if(CheckTankTimer < diff) - { - if(m_creature->getVictim()->GetGUID() != AggroTargetGUID) - { - DoYell(ANGER_SAY_BEFORE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, ANGER_SOUND_BEFORE); - DoCast(m_creature, SPELL_SELF_SEETHE); - DoCast(m_creature->getVictim(), SPELL_ENEMY_SEETHE, true); - AggroTargetGUID = m_creature->getVictim()->GetGUID(); - } - CheckTankTimer = 2000; - }else CheckTankTimer -= diff; - - if(SoulScreamTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SOUL_SCREAM); - SoulScreamTimer = 10000; - }else SoulScreamTimer -= diff; - - if(SpiteTimer < diff) - { - for(uint8 i = 0; i < 4; i++) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if(target) - DoCast(target, SPELL_SPITE); - - } - - SpiteTimer = 30000; - DoYell(ANGER_SAY_SPEC,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, ANGER_SOUND_SPEC); - }else SpiteTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -void npc_enslaved_soulAI::JustDied(Unit *killer) -{ - if(ReliquaryGUID) - { - Creature* Reliquary = ((Creature*)Unit::GetUnit((*m_creature), ReliquaryGUID)); - if(Reliquary) - ((boss_reliquary_of_soulsAI*)Reliquary->AI())->SoulDeathCount++; - } -} - -CreatureAI* GetAI_boss_reliquary_of_souls(Creature *_Creature) -{ - return new boss_reliquary_of_soulsAI (_Creature); -} - -CreatureAI* GetAI_boss_essence_of_suffering(Creature *_Creature) -{ - return new boss_essence_of_sufferingAI (_Creature); -} - -CreatureAI* GetAI_boss_essence_of_desire(Creature *_Creature) -{ - return new boss_essence_of_desireAI (_Creature); -} - -CreatureAI* GetAI_boss_essence_of_anger(Creature *_Creature) -{ - return new boss_essence_of_angerAI (_Creature); -} - -CreatureAI* GetAI_npc_enslaved_soul(Creature *_Creature) -{ - return new npc_enslaved_soulAI (_Creature); -} - -void AddSC_boss_reliquary_of_souls() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_reliquary_of_souls"; - newscript->GetAI = GetAI_boss_reliquary_of_souls; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_essence_of_suffering"; - newscript->GetAI = GetAI_boss_essence_of_suffering; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_essence_of_desire"; - newscript->GetAI = GetAI_boss_essence_of_desire; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_essence_of_anger"; - newscript->GetAI = GetAI_boss_essence_of_anger; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_enslaved_soul"; - newscript->GetAI = GetAI_npc_enslaved_soul; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Reliquary_of_Souls +SD%Complete: 90 +SDComment: Persistent Area Auras for each Essence (Aura of Suffering, Aura of Desire, Aura of Anger) requires core support. +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +//Sound'n'speech +//Suffering +#define SUFF_SAY_FREED "Pain and suffering are all that await you!" +#define SUFF_SOUND_FREED 11415 +#define SUFF_SAY_AGGRO "Don't leave me alone!" +#define SUFF_SOUND_AGGRO 11416 +#define SUFF_SAY_SLAY1 "Look at what you make me do!" +#define SUFF_SOUND_SLAY1 11417 +#define SUFF_SAY_SLAY2 "I didn't ask for this!" +#define SUFF_SOUND_SLAY2 11418 +#define SUFF_SAY_SLAY3 "The pain is only beginning!" +#define SUFF_SOUND_SLAY3 11419 +#define SUFF_SAY_RECAP "I don't want to go back!" +#define SUFF_SOUND_RECAP 11420 +#define SUFF_SAY_AFTER "Now what do I do?" +#define SUFF_SOUND_AFTER 11421 + +//Desire +#define DESI_SAY_FREED "You can have anything you desire... for a price." +#define DESI_SOUND_FREED 11408 +#define DESI_SAY_SLAY1 "Fulfilment is at hand!" +#define DESI_SOUND_SLAY1 11409 +#define DESI_SAY_SLAY2 "Yes... you'll stay with us now..." +#define DESI_SOUND_SLAY2 11410 +#define DESI_SAY_SLAY3 "Your reach exceeds your grasp." +#define DESI_SOUND_SLAY3 11412 +#define DESI_SAY_SPEC "Be careful what you wish for..." +#define DESI_SOUND_SPEC 11411 +#define DESI_SAY_RECAP "I'll be waiting..." +#define DESI_SOUND_RECAP 11413 +#define DESI_SAY_AFTER "I won't be far..." +#define DESI_SOUND_AFTER 11414 + +//Anger +#define ANGER_SAY_FREED "Beware... I live." +#define ANGER_SOUND_FREED 11399 +#define ANGER_SAY_FREED2 "So... foolish." +#define ANGER_SOUND_FREED2 11400 +#define ANGER_SOUND_SLAY1 11401 +#define ANGER_SAY_SLAY2 "Enough. No more." +#define ANGER_SOUND_SLAY2 11402 +#define ANGER_SAY_SPEC "On your knees!" +#define ANGER_SOUND_SPEC 11403 +#define ANGER_SAY_BEFORE "Beware, coward." +#define ANGER_SOUND_BEFORE 11405 +#define ANGER_SAY_DEATH "I won't... be... ignored." +#define ANGER_SOUND_DEATH 11404 + +//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 Position +{ + float x,y; +}; + +static Position Coords[]= +{ + {450.4, 212.3}, + {542.1, 212.3}, + {542.1, 168.3}, + {542.1, 137.4}, + {450.4, 137.4}, + {450.4, 168.3} +}; + +struct MANGOS_DLL_DECL npc_enslaved_soulAI : public ScriptedAI +{ + npc_enslaved_soulAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 ReliquaryGUID; + + void Reset() + { + ReliquaryGUID = 0; + } + + void Aggro(Unit* who) {} + + 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)); + } + } + DoCast(done_by, SPELL_SOUL_RELEASE); + } + } + + void JustDied(Unit *killer); +}; + +struct MANGOS_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI +{ + boss_reliquary_of_soulsAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 SufferingGUID; + uint64 DesireGUID; + uint64 AngerGUID; + + uint32 SoulDeathCount; + // 0 = Out of Combat, 1 = Not started, 2 = Suffering, 3 = Souls, 4 = Desire, 5 = Souls, 6 = Anger + uint32 Phase; + uint32 SummonEssenceTimer; + uint32 DespawnEssenceTimer; + uint32 SoulCount; + uint32 SummonSoulTimer; + uint32 AnimationTimer; + + bool IsDead; + bool EndingPhase; + + void Reset() + { + if(pInstance) + pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, NOT_STARTED); + + DespawnEssences(); + + SufferingGUID = 0; + DesireGUID = 0; + AngerGUID = 0; + + SoulDeathCount = 0; + Phase = 0; + SummonEssenceTimer = 8000; + DespawnEssenceTimer = 2000; + SoulCount = 0; + SummonSoulTimer = 1000; + AnimationTimer = 8000; + + IsDead = false; + EndingPhase = false; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); + m_creature->GetMotionMaster()->Clear(false); + } + + void Aggro(Unit* who) { } + + void AttackStart(Unit* who) { } + + void MoveInLineOfSight(Unit *who) + { + 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(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if(!InCombat) + { + if(pInstance) + pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, IN_PROGRESS); + + Phase = 1; + // I R ANNNGRRRY! + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,375); + SummonEssenceTimer = 8000; + AnimationTimer = 5100; + m_creature->AddThreat(who, 1.0f); + + InCombat = true; + } + } + } + } + + void SummonSoul() + { + uint32 random = rand()%6; + 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 = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (target && Soul) + { + ((npc_enslaved_soulAI*)Soul->AI())->ReliquaryGUID = m_creature->GetGUID(); + Soul->CastSpell(Soul, ENSLAVED_SOUL_PASSIVE, true); + Soul->AddThreat(target, 1.0f); + SoulCount++; + } + } + + void MergeThreatList(Creature* target) + { + if(!target) return; + + std::list& m_threatlist = target->getThreatManager().getThreatList(); + std::list::iterator itr = m_threatlist.begin(); + for( ; itr != m_threatlist.end(); itr++) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if(pUnit) + { + m_creature->AddThreat(pUnit, 1.0f); // 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). + } + } + } + + void DespawnEssences() + { + // Despawn Essences + Unit* Essence = NULL; + if(SufferingGUID) + Essence = ((Creature*)Unit::GetUnit((*m_creature), SufferingGUID)); + else if(DesireGUID) + Essence = ((Creature*)Unit::GetUnit((*m_creature), DesireGUID)); + else if(AngerGUID) + Essence = ((Creature*)Unit::GetUnit((*m_creature), AngerGUID)); + if(Essence && Essence->isAlive()) + Essence->setDeathState(JUST_DIED); + } + + void JustDied(Unit* killer) + { + if(pInstance) + pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, DONE); + + InCombat = false; + } + + void UpdateAI(const uint32 diff) + { + if(!Phase) + 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); + Creature* EssenceSuffering = NULL; + EssenceSuffering = m_creature->SummonCreature(23418, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); + + if(EssenceSuffering) + { + EssenceSuffering->Yell(SUFF_SAY_FREED, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(m_creature, SUFF_SOUND_FREED); + Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); + if(target) + { + EssenceSuffering->AddThreat(target, 1.0f); + EssenceSuffering->AI()->AttackStart(target); + } + SufferingGUID = EssenceSuffering->GetGUID(); + } + + EndingPhase = false; + Phase = 2; + }else SummonEssenceTimer -= diff; + } + + if(Phase == 2) + { + if(SufferingGUID) + { + Creature* EssenceSuffering = NULL; + EssenceSuffering = ((Creature*)Unit::GetUnit((*m_creature), SufferingGUID)); + + if(!EssenceSuffering || (!EssenceSuffering->isAlive())) + EnterEvadeMode(); + + if(!EndingPhase) + { + if(EssenceSuffering) + { + if(EssenceSuffering->GetHealth() < (EssenceSuffering->GetMaxHealth()*0.1)) + { + MergeThreatList(EssenceSuffering); + EssenceSuffering->RemoveAllAuras(); + EssenceSuffering->DeleteThreatList(); + EssenceSuffering->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); + EssenceSuffering->Yell(SUFF_SAY_RECAP,LANG_UNIVERSAL,0); + DoPlaySoundToSet(m_creature, SUFF_SOUND_RECAP); + 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) + { + EssenceSuffering->DeleteThreatList(); + EssenceSuffering->Yell(SUFF_SAY_AFTER,LANG_UNIVERSAL,0); + DoPlaySoundToSet(m_creature, SUFF_SOUND_AFTER); + EssenceSuffering->SetUInt32Value(UNIT_FIELD_DISPLAYID, 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; + } + } + } + + if(Phase == 3) + { + if(SoulCount < 36) + { + 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 = NULL; + EssenceDesire = m_creature->SummonCreature(23419, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); + + if(EssenceDesire) + { + EssenceDesire->Yell(DESI_SAY_FREED, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, DESI_SOUND_FREED); + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + EssenceDesire->AddThreat(target, 1.0f); + EssenceDesire->AI()->AttackStart(target); + } + DesireGUID = EssenceDesire->GetGUID(); + SoulDeathCount = 0; + } + + Phase = 4; + }else SummonEssenceTimer -= diff; + } + } + + if(Phase == 4) + { + if(DesireGUID) + { + Creature* EssenceDesire = NULL; + EssenceDesire = ((Creature*)Unit::GetUnit((*m_creature), DesireGUID)); + + if(!EssenceDesire || !EssenceDesire->isAlive()) + EnterEvadeMode(); + + if(!EndingPhase && EssenceDesire) + { + if(EssenceDesire->GetHealth() < (EssenceDesire->GetMaxHealth()*0.1)) + { + MergeThreatList(EssenceDesire); + EssenceDesire->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); + EssenceDesire->RemoveAllAuras(); + EssenceDesire->DeleteThreatList(); + EssenceDesire->Yell(DESI_SAY_RECAP,LANG_UNIVERSAL,0); + DoPlaySoundToSet(m_creature, DESI_SOUND_RECAP); + EssenceDesire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DespawnEssenceTimer = 4000; + AnimationTimer = 2200; + EndingPhase = true; + } + } + + if(EndingPhase && EssenceDesire) + { + 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); + EssenceDesire->Yell(DESI_SAY_AFTER, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(m_creature, DESI_SOUND_AFTER); + EssenceDesire->SetUInt32Value(UNIT_FIELD_DISPLAYID, 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; + } + } + } + } + + if(Phase == 5) + { + if(SoulCount < 36) + { + 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* EssenceAnger = NULL; + EssenceAnger = m_creature->SummonCreature(23420, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); + + if(EssenceAnger) + { + Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); + if(target) + { + EssenceAnger->AddThreat(target, 1.0f); + EssenceAnger->AI()->AttackStart(target); + } + AngerGUID = EssenceAnger->GetGUID(); + DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED); + EssenceAnger->Yell(ANGER_SAY_FREED, LANG_UNIVERSAL, 0); + SoulDeathCount = 0; + } + + Phase = 6; + }else SummonEssenceTimer -= diff; + } + } + + if(Phase == 6) + { + if(AngerGUID) + { + Creature* EssenceAnger = NULL; + EssenceAnger = ((Creature*)Unit::GetUnit((*m_creature), 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); + } + } + } + } + } +}; + +//This is used to sort the players by distance in preparation for the Fixate cast. +struct TargetDistanceOrder : public std::binary_function +{ + const Unit* MainTarget; + TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; + // functor for operator "<" + bool operator()(const Unit* _Left, const Unit* _Right) const + { + return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); + } +}; + +struct MANGOS_DLL_DECL boss_essence_of_sufferingAI : public ScriptedAI +{ + boss_essence_of_sufferingAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 StatAuraGUID; + + uint32 AggroYellTimer; + uint32 FixateTimer; + uint32 EnrageTimer; + uint32 SoulDrainTimer; + + void Reset() + { + StatAuraGUID = 0; + + AggroYellTimer = 5000; + FixateTimer = 5000; + EnrageTimer = 30000; + SoulDrainTimer = 150000; + } + + 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); + if(StatAuraGUID) + { + Unit* pUnit = Unit::GetUnit((*m_creature), StatAuraGUID); + if(pUnit) + pUnit->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR); + } + } + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + DoCast(who, AURA_OF_SUFFERING, true); + DoCast(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, true); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoYell(SUFF_SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY1); + break; + case 1: + DoYell(SUFF_SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY2); + break; + case 2: + DoYell(SUFF_SAY_SLAY3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY3); + break; + } + } + + void JustDied(Unit* killer) + { + } + + void CastFixate() + { + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + if(m_threatlist.empty()) + return; // No point continuing if empty threatlist. + std::list targets; + std::list::iterator itr = m_threatlist.begin(); + for( ; itr != m_threatlist.end(); ++itr) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + // Only alive players + if(pUnit && pUnit->isAlive() && (pUnit->GetTypeId() == TYPEID_PLAYER)) + targets.push_back(pUnit); + } + if(targets.empty()) + return; // No targets added for some reason. No point continuing. + targets.sort(TargetDistanceOrder(m_creature)); // Sort players by distance. + targets.resize(1); // Only need closest target. + Unit* target = targets.front(); // Get the first target. + // Add threat equivalent to threat on victim. + m_creature->AddThreat(target, m_creature->getThreatManager().getThreat(m_creature->getVictim())); + DoCast(target, SPELL_FIXATE); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1)) + { + if(StatAuraGUID) + { + Unit* pUnit = NULL; + pUnit = Unit::GetUnit((*m_creature), StatAuraGUID); + if(pUnit) + pUnit->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR); + } + } + + if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1)) + { + 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(AggroYellTimer < diff) + { + DoYell(SUFF_SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SUFF_SOUND_AGGRO); + AggroYellTimer = 0; + }else AggroYellTimer -= diff; + + //Supposed to be cast on nearest target + if(FixateTimer < diff) + { + CastFixate(); + FixateTimer = 5000; + }else FixateTimer -= diff; + + if(EnrageTimer < diff) + { + DoCast(m_creature, SPELL_ENRAGE); + EnrageTimer = 60000; + }else EnrageTimer -= diff; + + if(SoulDrainTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if(target) + DoCast(target, SPELL_SOUL_DRAIN); + SoulDrainTimer = 60000; + }else SoulDrainTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; +struct MANGOS_DLL_DECL boss_essence_of_desireAI : public ScriptedAI +{ + boss_essence_of_desireAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 AggroYellTimer; + uint32 RuneShieldTimer; + uint32 DeadenTimer; + uint32 SoulShockTimer; + + void Reset() + { + AggroYellTimer = 5000; + RuneShieldTimer = 60000; + DeadenTimer = 15000; + SoulShockTimer = 40000; + } + + 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); + } + } + + void Aggro(Unit *who) { DoZoneInCombat(); } + + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoYell(DESI_SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY1); + break; + case 1: + DoYell(DESI_SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY2); + break; + case 2: + DoYell(DESI_SAY_SLAY3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY3); + break; + } + } + + void MoveInLineOfSight(Unit *who) + { + 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(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + //Begin melee attack if we are within range + DoStartAttackAndMovement(who); + + if (!InCombat) + { + DoCast(who, AURA_OF_DESIRE); + } + } + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1)) + { + if(m_creature->getVictim()) + m_creature->DeleteThreatList(); // Delete our threatlist if below 10% as we should no longer attack. + return; + } + + if(RuneShieldTimer < diff) + { + DoCast(m_creature, SPELL_RUNE_SHIELD); + RuneShieldTimer = 60000; + }else RuneShieldTimer -= diff; + + if(DeadenTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_DEADEN); + DeadenTimer = 30000 + rand()%30001; + }else DeadenTimer -= diff; + + if(SoulShockTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SOUL_SHOCK); + SoulShockTimer = 40000; + if(rand()%2 == 0) + { + DoYell(DESI_SAY_SPEC,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, DESI_SOUND_SPEC); + } + + }else SoulShockTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_essence_of_angerAI : public ScriptedAI +{ + boss_essence_of_angerAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 AggroTargetGUID; + + uint32 AggroYellTimer; + uint32 CheckTankTimer; + uint32 SoulScreamTimer; + uint32 SpiteTimer; + + bool CheckedAggro; + + void Reset() + { + AggroTargetGUID = 0; + + AggroYellTimer = 5000; + CheckTankTimer = 5000; + SoulScreamTimer = 10000; + SpiteTimer = 30000; + + CheckedAggro = false; + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + DoCast(m_creature->getVictim(), AURA_OF_ANGER, true); + } + + void MoveInLineOfSight(Unit *who) + { + 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(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + //Begin melee attack if we are within range + DoStartAttackAndMovement(who); + + if (!InCombat) + { + DoCast(who, AURA_OF_ANGER); + } + } + } + } + + void JustDied(Unit *victim) + { + DoYell(ANGER_SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,ANGER_SOUND_DEATH); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY1); + break; + case 1: + DoYell(ANGER_SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY2); + break; + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(!CheckedAggro) + { + AggroTargetGUID = m_creature->getVictim()->GetGUID(); + CheckedAggro = true; + } + + if(AggroYellTimer) + if(AggroYellTimer < diff) + { + DoYell(ANGER_SAY_FREED2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED2); + AggroYellTimer = 0; + }else AggroYellTimer -= diff; + + if(CheckTankTimer < diff) + { + if(m_creature->getVictim()->GetGUID() != AggroTargetGUID) + { + DoYell(ANGER_SAY_BEFORE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, ANGER_SOUND_BEFORE); + DoCast(m_creature, SPELL_SELF_SEETHE); + DoCast(m_creature->getVictim(), SPELL_ENEMY_SEETHE, true); + AggroTargetGUID = m_creature->getVictim()->GetGUID(); + } + CheckTankTimer = 2000; + }else CheckTankTimer -= diff; + + if(SoulScreamTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SOUL_SCREAM); + SoulScreamTimer = 10000; + }else SoulScreamTimer -= diff; + + if(SpiteTimer < diff) + { + for(uint8 i = 0; i < 4; i++) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if(target) + DoCast(target, SPELL_SPITE); + + } + + SpiteTimer = 30000; + DoYell(ANGER_SAY_SPEC,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, ANGER_SOUND_SPEC); + }else SpiteTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +void npc_enslaved_soulAI::JustDied(Unit *killer) +{ + if(ReliquaryGUID) + { + Creature* Reliquary = ((Creature*)Unit::GetUnit((*m_creature), ReliquaryGUID)); + if(Reliquary) + ((boss_reliquary_of_soulsAI*)Reliquary->AI())->SoulDeathCount++; + } +} + +CreatureAI* GetAI_boss_reliquary_of_souls(Creature *_Creature) +{ + return new boss_reliquary_of_soulsAI (_Creature); +} + +CreatureAI* GetAI_boss_essence_of_suffering(Creature *_Creature) +{ + return new boss_essence_of_sufferingAI (_Creature); +} + +CreatureAI* GetAI_boss_essence_of_desire(Creature *_Creature) +{ + return new boss_essence_of_desireAI (_Creature); +} + +CreatureAI* GetAI_boss_essence_of_anger(Creature *_Creature) +{ + return new boss_essence_of_angerAI (_Creature); +} + +CreatureAI* GetAI_npc_enslaved_soul(Creature *_Creature) +{ + return new npc_enslaved_soulAI (_Creature); +} + +void AddSC_boss_reliquary_of_souls() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_reliquary_of_souls"; + newscript->GetAI = GetAI_boss_reliquary_of_souls; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_essence_of_suffering"; + newscript->GetAI = GetAI_boss_essence_of_suffering; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_essence_of_desire"; + newscript->GetAI = GetAI_boss_essence_of_desire; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_essence_of_anger"; + newscript->GetAI = GetAI_boss_essence_of_anger; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_enslaved_soul"; + newscript->GetAI = GetAI_npc_enslaved_soul; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_shade_of_akama.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_shade_of_akama.cpp index 2f1034e2c08..803c7f7863d 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_shade_of_akama.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_shade_of_akama.cpp @@ -1,813 +1,813 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Shade_of_Akama -SD%Complete: 99 -SDComment: Seems to be complete. -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" -#include "sc_grid_searchers.h" - -struct Location -{ - float x, y, o, z; -}; - -static Location ChannelerLocations[]= -{ - {463.161285, 401.219757, 3.141592}, - {457.377625, 391.227661, 2.106461}, - {446.012421, 391.227661, 1.071904}, - {439.533783, 401.219757, 0.000000}, - {446.012421, 411.211853, 5.210546}, - {457.377625, 411.211853, 4.177494} -}; - -static Location SpawnLocations[]= -{ - {498.652740, 461.728119, 0}, - {498.505003, 339.619324, 0} -}; - -static Location AkamaWP[]= -{ - {482.352448, 401.162720, 0, 112.783928}, - {469.597443, 402.264404, 0, 118.537910} -}; - -static Location BrokenCoords[]= -{ - {541.375916, 401.439575, M_PI, 112.783997}, // The place where Akama channels - {534.130005, 352.394531, 2.164150, 112.783737}, // Behind a 'pillar' which is behind the east alcove - {499.621185, 341.534729, 1.652856, 112.783730}, // East Alcove - {499.151093, 461.036438, 4.770888, 112.78370}, // West Alcove -}; - -static Location BrokenWP[]= -{ - {492.491638, 400.744690, 3.122336, 112.783737}, - {494.335724, 382.221771, 2.676230, 112.783737}, - {489.555939, 373.507202, 2.416263, 112.783737}, - {491.136353, 427.868774, 3.519748, 112.783737}, -}; - -// Locations -#define Z1 118.543144 -#define Z2 120.783768 -#define Z_SPAWN 113.537949 -#define AGGRO_X 482.793182 -#define AGGRO_Y 401.270172 -#define AGGRO_Z 112.783928 -#define AKAMA_X 514.583984 -#define AKAMA_Y 400.601013 -#define AKAMA_Z 112.783997 - -// Texts -#define SOUND_DEATH 11386 -#define SAY_DEATH "No! Not yet..." -#define SOUND_LOW_HEALTH 11385 -#define SAY_LOW_HEALTH "I will not last much longer..." - -// Ending cinematic text -#define SAY_FREE "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!" -#define SAY_BROKEN_FREE_01 "Hail our leader! Hail Akama!" -#define SAY_BROKEN_FREE_02 "Hail Akama!" - -// Gossips -#define GOSSIP_ITEM "We are ready to fight alongside you, Akama" - -// Spells -#define SPELL_VERTEX_SHADE_BLACK 39833 -#define SPELL_SHADE_SOUL_CHANNEL 40401 -#define SPELL_DESTRUCTIVE_POISON 40874 -#define SPELL_LIGHTNING_BOLT 42024 -#define SPELL_AKAMA_SOUL_CHANNEL 40447 -#define SPELL_AKAMA_SOUL_RETRIEVE 40902 -#define AKAMA_SOUL_EXPEL 40855 -#define SPELL_SHADE_SOUL_CHANNEL_2 40520 - -// Channeler entry -#define CREATURE_CHANNELER 23421 -#define CREATURE_SORCERER 23215 -#define CREATURE_DEFENDER 23216 -#define CREATURE_BROKEN 23319 - -const uint32 spawnEntries[4]= { 23523, 23318, 23524 }; - -struct MANGOS_DLL_DECL mob_ashtongue_channelerAI : public ScriptedAI -{ - mob_ashtongue_channelerAI(Creature* c) : ScriptedAI(c) { Reset(); } - - uint64 ShadeGUID; - - void Reset() { ShadeGUID = 0; } - void JustDied(Unit* killer); - void Aggro(Unit* who) {} - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - void UpdateAI(const uint32 diff) {} -}; - -struct MANGOS_DLL_DECL mob_ashtongue_sorcererAI : public ScriptedAI -{ - mob_ashtongue_sorcererAI(Creature* c) : ScriptedAI(c) { Reset(); } - - uint64 ShadeGUID; - uint32 CheckTimer; - bool StartBanishing; - - void Reset() - { - StartBanishing = false; - CheckTimer = 5000; - ShadeGUID = 0; - } - - void JustDied(Unit* killer); - void Aggro(Unit* who) {} - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - void UpdateAI(const uint32 diff) - { - if(StartBanishing) - return; - - if(CheckTimer < diff) - { - Unit* Shade = Unit::GetUnit((*m_creature), ShadeGUID); - if(Shade && Shade->isAlive() && m_creature->isAlive()) - { - if(m_creature->GetDistance2d(Shade) < 20) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - DoCast(Shade, SPELL_SHADE_SOUL_CHANNEL, true); - DoCast(Shade, SPELL_SHADE_SOUL_CHANNEL_2, true); - - StartBanishing = true; - } - } - CheckTimer = 2000; - }else CheckTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL boss_shade_of_akamaAI : public ScriptedAI -{ - boss_shade_of_akamaAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - AkamaGUID = pInstance ? pInstance->GetData64(DATA_AKAMA_SHADE) : 0; - Reset(); - } - - ScriptedInstance* pInstance; - - std::list Channelers; - std::list Sorcerers; - uint64 AkamaGUID; - - uint32 SorcererCount; - uint32 DeathCount; - - uint32 ReduceHealthTimer; - uint32 SummonTimer; - uint32 ResetTimer; - uint32 DefenderTimer; // They are on a flat 15 second timer, independant of the other summon creature timer. - - bool IsBanished; - bool HasKilledAkama; - - void Reset() - { - FindChannelers(); - - if(!Channelers.empty()) - for(std::list::iterator itr = Channelers.begin(); itr != Channelers.end(); ++itr) - { - Creature* Channeler = NULL; - Channeler = ((Creature*)Unit::GetUnit(*m_creature, *itr)); - if(Channeler) - { - if(Channeler->isDead()) - { - Channeler->RemoveCorpse(); - Channeler->Respawn(); - } - Channeler->CastSpell(m_creature, SPELL_SHADE_SOUL_CHANNEL, true); - Channeler->CastSpell(m_creature, SPELL_SHADE_SOUL_CHANNEL_2, true); - Channeler->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - } - else error_log("SD2 ERROR: No Channelers are stored in the list. This encounter will not work properly"); - - if(!Sorcerers.empty()) - for(std::list::iterator itr = Sorcerers.begin(); itr != Sorcerers.end(); ++itr) - if(Creature* Sorcerer = ((Creature*)Unit::GetUnit(*m_creature, *itr))) - if(Sorcerer->isAlive()) - { - Sorcerer->SetVisibility(VISIBILITY_OFF); - Sorcerer->DealDamage(Sorcerer, Sorcerer->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - - Sorcerers.clear(); - - if(Unit* Akama = Unit::GetUnit(*m_creature, AkamaGUID)) - Akama->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - SorcererCount = 0; - DeathCount = 0; - - SummonTimer = 10000; - ReduceHealthTimer = 0; - ResetTimer = 60000; - DefenderTimer = 15000; - - IsBanished = true; - HasKilledAkama = false; - - m_creature->SetVisibility(VISIBILITY_ON); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STUN); - - if(pInstance && m_creature->isAlive()) - pInstance->SetData(DATA_SHADEOFAKAMAEVENT, NOT_STARTED); - } - - void Aggro(Unit* who) { } - - void AttackStart(Unit* who) - { - if(!who || IsBanished) return; - - if(who->isTargetableForAttack() && who != m_creature) - DoStartAttackAndMovement(who); - } - - void MoveInLineOfSight(Unit* who) - { - if(IsBanished) return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void IncrementDeathCount(uint64 guid = 0) // If guid is set, will remove it from list of sorcerer - { - debug_log("SD2: Increasing Death Count for Shade of Akama encounter"); - ++DeathCount; - m_creature->RemoveSingleAuraFromStack(SPELL_SHADE_SOUL_CHANNEL_2, 0); - if(guid) - { - if(Sorcerers.empty()) - error_log("SD2 ERROR: Shade of Akama - attempt to remove guid %u from Sorcerers list but list is already empty", guid); - else Sorcerers.remove(guid); - } - } - - void SummonCreature() - { - uint32 random = rand()%2; - float X = SpawnLocations[random].x; - float Y = SpawnLocations[random].y; - // max of 6 sorcerers can be summoned - if((rand()%3 == 0) && (DeathCount > 0) && (SorcererCount < 7)) - { - Creature* Sorcerer = m_creature->SummonCreature(CREATURE_SORCERER, X, Y, Z_SPAWN, 0, TEMPSUMMON_DEAD_DESPAWN, 0); - if(Sorcerer) - { - ((mob_ashtongue_sorcererAI*)Sorcerer->AI())->ShadeGUID = m_creature->GetGUID(); - Sorcerer->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - Sorcerer->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); - Sorcerer->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); - Sorcerers.push_back(Sorcerer->GetGUID()); - --DeathCount; - ++SorcererCount; - } - } - else - { - for(uint8 i = 0; i < 3; ++i) - { - Creature* Spawn = m_creature->SummonCreature(spawnEntries[i], X, Y, Z_SPAWN, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000); - if(Spawn) - { - Spawn->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - Spawn->GetMotionMaster()->MovePoint(0, AGGRO_X, AGGRO_Y, AGGRO_Z); - } - } - } - } - - void FindChannelers() - { - CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list ChannelerList; - - AllCreaturesOfEntryInRange check(m_creature, CREATURE_CHANNELER, 50); - MaNGOS::CreatureListSearcher searcher(ChannelerList, check); - TypeContainerVisitor, GridTypeMapContainer> visitor(searcher); - - CellLock cell_lock(cell, pair); - cell_lock->Visit(cell_lock, visitor, *(m_creature->GetMap())); - - if(!ChannelerList.empty()) - { - Channelers.clear(); - for(std::list::iterator itr = ChannelerList.begin(); itr != ChannelerList.end(); ++itr) - { - ((mob_ashtongue_channelerAI*)(*itr)->AI())->ShadeGUID = m_creature->GetGUID(); - Channelers.push_back((*itr)->GetGUID()); - debug_log("SD2: Shade of Akama Grid Search found channeler %u. Adding to list", (*itr)->GetGUID()); - } - } - else error_log("SD2 ERROR: Grid Search was unable to find any channelers. Shade of Akama encounter will be buggy"); - } - - void SetSelectableChannelers() - { - if(Channelers.empty()) - { - error_log("SD2 ERROR: Channeler List is empty, Shade of Akama encounter will be buggy"); - return; - } - - for(std::list::iterator itr = Channelers.begin(); itr != Channelers.end(); ++itr) - if(Creature* Channeler = ((Creature*)Unit::GetUnit(*m_creature, *itr))) - Channeler->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void SetAkamaGUID(uint64 guid) { AkamaGUID = guid; } - - void UpdateAI(const uint32 diff) - { - if(!InCombat) - return; - - if(IsBanished) - { - // 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) - EnterEvadeMode(); - - if(DefenderTimer < diff) - { - uint32 ran = rand()%2; - Creature* Defender = m_creature->SummonCreature(CREATURE_DEFENDER, SpawnLocations[ran].x, SpawnLocations[ran].y, Z_SPAWN, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000); - if(Defender) - { - Defender->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - bool move = true; - if(AkamaGUID) - { - if(Unit* Akama = Unit::GetUnit(*m_creature, AkamaGUID)) - { - float x, y, z; - Akama->GetPosition(x,y,z); - // They move towards AKama - Defender->GetMotionMaster()->MovePoint(0, x, y, z); - }else move = false; - }else move = false; - if(!move) - Defender->GetMotionMaster()->MovePoint(0, AKAMA_X, AKAMA_Y, AKAMA_Z); - } - DefenderTimer = 15000; - }else DefenderTimer -= diff; - - if(SummonTimer < diff) - { - SummonCreature(); - SummonTimer = 35000; - }else SummonTimer -= diff; - - if(DeathCount >= 6) - { - if(AkamaGUID) - { - Unit* Akama = Unit::GetUnit((*m_creature), AkamaGUID); - if(Akama && Akama->isAlive()) - { - IsBanished = false; - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveChase(Akama); - Akama->GetMotionMaster()->Clear(); - // Shade should move to Akama, not the other way around - Akama->GetMotionMaster()->MoveIdle(); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // Crazy amount of threat - m_creature->AddThreat(Akama, 10000000.0f); - Akama->AddThreat(m_creature, 10000000.0f); - m_creature->Attack(Akama, true); - Akama->Attack(m_creature, true); - } - } - } - } - else // No longer banished, let's fight Akama now - { - if(ReduceHealthTimer < diff) - { - if(AkamaGUID) - { - Unit* Akama = Unit::GetUnit((*m_creature), AkamaGUID); - if(Akama && Akama->isAlive()) - { - //10 % less health every few seconds. - m_creature->DealDamage(Akama, Akama->GetMaxHealth()/10, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - ReduceHealthTimer = 12000; - } - else - { - HasKilledAkama = true; // Akama is dead or missing, we stop fighting and disappear - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->SetHealth(m_creature->GetMaxHealth()); - m_creature->RemoveAllAuras(); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - } - }else ReduceHealthTimer -= diff; - - if(HasKilledAkama) - { - if(ResetTimer < diff) - { - InCombat = false; - EnterEvadeMode(); // Reset a little while after killing Akama - } - else ResetTimer -= diff; - } - - DoMeleeAttackIfReady(); - } - } -}; - -void mob_ashtongue_channelerAI::JustDied(Unit* killer) -{ - Creature* Shade = ((Creature*)Unit::GetUnit((*m_creature), ShadeGUID)); - if(Shade && Shade->isAlive()) - ((boss_shade_of_akamaAI*)Shade->AI())->IncrementDeathCount(); - else error_log("SD2 ERROR: Channeler dead but unable to increment DeathCount for Shade of Akama."); -} - -void mob_ashtongue_sorcererAI::JustDied(Unit* killer) -{ - Creature* Shade = ((Creature*)Unit::GetUnit((*m_creature), ShadeGUID)); - if(Shade && Shade->isAlive()) - ((boss_shade_of_akamaAI*)Shade->AI())->IncrementDeathCount(m_creature->GetGUID()); - else error_log("SD2 ERROR: Sorcerer dead but unable to increment DeathCount for Shade of Akama."); -} - -struct MANGOS_DLL_DECL npc_akamaAI : public ScriptedAI -{ - npc_akamaAI(Creature* c) : ScriptedAI(c) - { - ShadeHasDied = false; - StartCombat = false; - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - ShadeGUID = pInstance ? pInstance->GetData64(DATA_SHADEOFAKAMA) : 0; - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 ShadeGUID; - - uint32 DestructivePoisonTimer; - uint32 LightningBoltTimer; - uint32 CheckTimer; - uint32 CastSoulRetrieveTimer; - uint32 SoulRetrieveTimer; - uint32 SummonBrokenTimer; - uint32 EndingTalkCount; - uint32 WayPointId; - uint32 BrokenSummonIndex; - - std::list BrokenList; - - bool EventBegun; - bool ShadeHasDied; - bool StartCombat; - bool HasYelledOnce; - - void Reset() - { - DestructivePoisonTimer = 15000; - LightningBoltTimer = 10000; - CheckTimer = 2000; - CastSoulRetrieveTimer = 0; - SoulRetrieveTimer = 0; - SummonBrokenTimer = 0; - EndingTalkCount = 0; - WayPointId = 0; - BrokenSummonIndex = 0; - - BrokenList.clear(); - - EventBegun = false; - HasYelledOnce = false; - - m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has very very strange values - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - } - - void Aggro(Unit* who) {} - - void BeginEvent(Player* pl) - { - if(!pInstance) - return; - - ShadeGUID = pInstance->GetData64(DATA_SHADEOFAKAMA); - if(!ShadeGUID) - return; - - Creature* Shade = ((Creature*)Unit::GetUnit((*m_creature), ShadeGUID)); - if(Shade) - { - pInstance->SetData(DATA_SHADEOFAKAMAEVENT, IN_PROGRESS); - // Prevent players from trying to restart event - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - ((boss_shade_of_akamaAI*)Shade->AI())->SetAkamaGUID(m_creature->GetGUID()); - ((boss_shade_of_akamaAI*)Shade->AI())->SetSelectableChannelers(); - ((boss_shade_of_akamaAI*)Shade->AI())->InCombat = true; - Shade->AddThreat(m_creature, 1000000.0f); - Shade->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - Shade->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); - if(pl) Shade->AddThreat(pl, 1.0f); - DoZoneInCombat(Shade); - EventBegun = true; - } - } - - void MovementInform(uint32 type, uint32 id) - { - if(type != POINT_MOTION_TYPE) - return; - - switch(id) - { - case 0: ++WayPointId; break; - - case 1: - if(Unit* Shade = Unit::GetUnit(*m_creature, ShadeGUID)) - { - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, ShadeGUID); - DoCast(Shade, SPELL_AKAMA_SOUL_RETRIEVE); - EndingTalkCount = 0; - SoulRetrieveTimer = 16000; - } - break; - } - } - - void JustDied(Unit* killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if(!EventBegun) - return; - - if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 15 && !HasYelledOnce) - { - DoYell(SAY_LOW_HEALTH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_LOW_HEALTH); - HasYelledOnce = true; - } - - if(ShadeGUID && !StartCombat) - { - Creature* Shade = ((Creature*)Unit::GetUnit((*m_creature), ShadeGUID)); - if(Shade && Shade->isAlive()) - { - if(((boss_shade_of_akamaAI*)Shade->AI())->IsBanished) - { - if(CastSoulRetrieveTimer < diff) - { - DoCast(Shade, SPELL_AKAMA_SOUL_CHANNEL); - CastSoulRetrieveTimer = 500; - }else CastSoulRetrieveTimer -= diff; - } - else - { - m_creature->InterruptNonMeleeSpells(false); - StartCombat = true; - } - } - } - - if(ShadeHasDied && (WayPointId == 1)) - { - if(pInstance) pInstance->SetData(DATA_SHADEOFAKAMAEVENT, DONE); - m_creature->GetMotionMaster()->MovePoint(WayPointId, AkamaWP[1].x, AkamaWP[1].y, AkamaWP[1].z); - ++WayPointId; - } - - if(!ShadeHasDied && StartCombat) - { - if(CheckTimer < diff) - { - if(ShadeGUID) - { - Unit* Shade = Unit::GetUnit((*m_creature), ShadeGUID); - if(Shade && !Shade->isAlive()) - { - ShadeHasDied = true; - WayPointId = 0; - m_creature->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); - m_creature->GetMotionMaster()->MovePoint(WayPointId, AkamaWP[0].x, AkamaWP[0].y, AkamaWP[0].z); - } - } - CheckTimer = 5000; - }else CheckTimer -= diff; - } - - if(SummonBrokenTimer && BrokenSummonIndex < 4) - if(SummonBrokenTimer <= diff) - { - for(uint8 i = 0; i < 4; ++i) - { - float x = BrokenCoords[BrokenSummonIndex].x + (i*5); - float y = BrokenCoords[BrokenSummonIndex].y + (1*5); - float z = BrokenCoords[BrokenSummonIndex].z; - float o = BrokenCoords[BrokenSummonIndex].o; - Creature* Broken = m_creature->SummonCreature(CREATURE_BROKEN, x, y, z, o, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000); - if(Broken) - { - float wx = BrokenWP[BrokenSummonIndex].x + (i*5); - float wy = BrokenWP[BrokenSummonIndex].y + (i*5); - float wz = BrokenWP[BrokenSummonIndex].z; - Broken->GetMotionMaster()->MovePoint(0, wx, wy, wz); - Broken->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - BrokenList.push_back(Broken->GetGUID()); - } - } - ++BrokenSummonIndex; - SummonBrokenTimer = 1000; - }else SummonBrokenTimer -= diff; - - if(SoulRetrieveTimer) - if(SoulRetrieveTimer <= diff) - { - switch(EndingTalkCount) - { - case 0: - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); - ++EndingTalkCount; - SoulRetrieveTimer = 2000; - SummonBrokenTimer = 1; - case 1: - DoYell(SAY_FREE, LANG_UNIVERSAL, NULL); - ++EndingTalkCount; - SoulRetrieveTimer = 25000; - break; - case 2: - if(!BrokenList.empty()) - { - bool Yelled = false; - for(std::list::iterator itr = BrokenList.begin(); itr != BrokenList.end(); ++itr) - if(Unit* pUnit = Unit::GetUnit(*m_creature, *itr)) - { - if(!Yelled) - { - pUnit->MonsterYell(SAY_BROKEN_FREE_01, LANG_UNIVERSAL, 0); - Yelled = true; - } - pUnit->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); - } - } - ++EndingTalkCount; - SoulRetrieveTimer = 1500; - break; - case 3: - if(!BrokenList.empty()) - for(std::list::iterator itr = BrokenList.begin(); itr != BrokenList.end(); ++itr) - if(Unit* pUnit = Unit::GetUnit(*m_creature, *itr)) - // This is the incorrect spell, but can't seem to find the right one. - pUnit->CastSpell(pUnit, 39656, true); - ++EndingTalkCount; - SoulRetrieveTimer = 5000; - case 4: - if(!BrokenList.empty()) - for(std::list::iterator itr = BrokenList.begin(); itr != BrokenList.end(); ++itr) - if(Unit* pUnit = Unit::GetUnit((*m_creature), *itr)) - pUnit->MonsterYell(SAY_BROKEN_FREE_02, LANG_UNIVERSAL, 0); - SoulRetrieveTimer = 0; - break; - } - }else SoulRetrieveTimer -= diff; - - if(!m_creature->getVictim() || !m_creature->SelectHostilTarget()) - return; - - if(DestructivePoisonTimer < diff) - { - // SPELL_DESTRUCTIVE_POISON is self-cast only for some reason so we make our target cast it on itself - m_creature->getVictim()->CastSpell(m_creature->getVictim(), SPELL_DESTRUCTIVE_POISON, true); - DestructivePoisonTimer = 15000; - }else DestructivePoisonTimer -= diff; - - if(LightningBoltTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_LIGHTNING_BOLT); - LightningBoltTimer = 10000; - }else LightningBoltTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_shade_of_akama(Creature *_Creature) -{ - return new boss_shade_of_akamaAI (_Creature); -} - -CreatureAI* GetAI_mob_ashtongue_channeler(Creature *_Creature) -{ - return new mob_ashtongue_channelerAI (_Creature); -} - -CreatureAI* GetAI_mob_ashtongue_sorcerer(Creature *_Creature) -{ - return new mob_ashtongue_sorcererAI (_Creature); -} - -CreatureAI* GetAI_npc_akama_shade(Creature *_Creature) -{ - return new npc_akamaAI (_Creature); -} - -bool GossipSelect_npc_akama(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) //Fight time - { - player->CLOSE_GOSSIP_MENU(); - ((npc_akamaAI*)_Creature->AI())->BeginEvent(player); - } - - return true; -} - -bool GossipHello_npc_akama(Player *player, Creature *_Creature) -{ - if(player->isAlive()) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(907, _Creature->GetGUID()); - } - - return true; -} - -void AddSC_boss_shade_of_akama() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_shade_of_akama"; - newscript->GetAI = GetAI_boss_shade_of_akama; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_ashtongue_channeler"; - newscript->GetAI = GetAI_mob_ashtongue_channeler; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_ashtongue_sorcerer"; - newscript->GetAI = GetAI_mob_ashtongue_sorcerer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_akama_shade"; - newscript->GetAI = GetAI_npc_akama_shade; - newscript->pGossipHello = &GossipHello_npc_akama; - newscript->pGossipSelect = &GossipSelect_npc_akama; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Shade_of_Akama +SD%Complete: 99 +SDComment: Seems to be complete. +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" +#include "sc_grid_searchers.h" + +struct Location +{ + float x, y, o, z; +}; + +static Location ChannelerLocations[]= +{ + {463.161285, 401.219757, 3.141592}, + {457.377625, 391.227661, 2.106461}, + {446.012421, 391.227661, 1.071904}, + {439.533783, 401.219757, 0.000000}, + {446.012421, 411.211853, 5.210546}, + {457.377625, 411.211853, 4.177494} +}; + +static Location SpawnLocations[]= +{ + {498.652740, 461.728119, 0}, + {498.505003, 339.619324, 0} +}; + +static Location AkamaWP[]= +{ + {482.352448, 401.162720, 0, 112.783928}, + {469.597443, 402.264404, 0, 118.537910} +}; + +static Location BrokenCoords[]= +{ + {541.375916, 401.439575, M_PI, 112.783997}, // The place where Akama channels + {534.130005, 352.394531, 2.164150, 112.783737}, // Behind a 'pillar' which is behind the east alcove + {499.621185, 341.534729, 1.652856, 112.783730}, // East Alcove + {499.151093, 461.036438, 4.770888, 112.78370}, // West Alcove +}; + +static Location BrokenWP[]= +{ + {492.491638, 400.744690, 3.122336, 112.783737}, + {494.335724, 382.221771, 2.676230, 112.783737}, + {489.555939, 373.507202, 2.416263, 112.783737}, + {491.136353, 427.868774, 3.519748, 112.783737}, +}; + +// Locations +#define Z1 118.543144 +#define Z2 120.783768 +#define Z_SPAWN 113.537949 +#define AGGRO_X 482.793182 +#define AGGRO_Y 401.270172 +#define AGGRO_Z 112.783928 +#define AKAMA_X 514.583984 +#define AKAMA_Y 400.601013 +#define AKAMA_Z 112.783997 + +// Texts +#define SOUND_DEATH 11386 +#define SAY_DEATH "No! Not yet..." +#define SOUND_LOW_HEALTH 11385 +#define SAY_LOW_HEALTH "I will not last much longer..." + +// Ending cinematic text +#define SAY_FREE "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!" +#define SAY_BROKEN_FREE_01 "Hail our leader! Hail Akama!" +#define SAY_BROKEN_FREE_02 "Hail Akama!" + +// Gossips +#define GOSSIP_ITEM "We are ready to fight alongside you, Akama" + +// Spells +#define SPELL_VERTEX_SHADE_BLACK 39833 +#define SPELL_SHADE_SOUL_CHANNEL 40401 +#define SPELL_DESTRUCTIVE_POISON 40874 +#define SPELL_LIGHTNING_BOLT 42024 +#define SPELL_AKAMA_SOUL_CHANNEL 40447 +#define SPELL_AKAMA_SOUL_RETRIEVE 40902 +#define AKAMA_SOUL_EXPEL 40855 +#define SPELL_SHADE_SOUL_CHANNEL_2 40520 + +// Channeler entry +#define CREATURE_CHANNELER 23421 +#define CREATURE_SORCERER 23215 +#define CREATURE_DEFENDER 23216 +#define CREATURE_BROKEN 23319 + +const uint32 spawnEntries[4]= { 23523, 23318, 23524 }; + +struct MANGOS_DLL_DECL mob_ashtongue_channelerAI : public ScriptedAI +{ + mob_ashtongue_channelerAI(Creature* c) : ScriptedAI(c) { Reset(); } + + uint64 ShadeGUID; + + void Reset() { ShadeGUID = 0; } + void JustDied(Unit* killer); + void Aggro(Unit* who) {} + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) {} +}; + +struct MANGOS_DLL_DECL mob_ashtongue_sorcererAI : public ScriptedAI +{ + mob_ashtongue_sorcererAI(Creature* c) : ScriptedAI(c) { Reset(); } + + uint64 ShadeGUID; + uint32 CheckTimer; + bool StartBanishing; + + void Reset() + { + StartBanishing = false; + CheckTimer = 5000; + ShadeGUID = 0; + } + + void JustDied(Unit* killer); + void Aggro(Unit* who) {} + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) + { + if(StartBanishing) + return; + + if(CheckTimer < diff) + { + Unit* Shade = Unit::GetUnit((*m_creature), ShadeGUID); + if(Shade && Shade->isAlive() && m_creature->isAlive()) + { + if(m_creature->GetDistance2d(Shade) < 20) + { + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + DoCast(Shade, SPELL_SHADE_SOUL_CHANNEL, true); + DoCast(Shade, SPELL_SHADE_SOUL_CHANNEL_2, true); + + StartBanishing = true; + } + } + CheckTimer = 2000; + }else CheckTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL boss_shade_of_akamaAI : public ScriptedAI +{ + boss_shade_of_akamaAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + AkamaGUID = pInstance ? pInstance->GetData64(DATA_AKAMA_SHADE) : 0; + Reset(); + } + + ScriptedInstance* pInstance; + + std::list Channelers; + std::list Sorcerers; + uint64 AkamaGUID; + + uint32 SorcererCount; + uint32 DeathCount; + + uint32 ReduceHealthTimer; + uint32 SummonTimer; + uint32 ResetTimer; + uint32 DefenderTimer; // They are on a flat 15 second timer, independant of the other summon creature timer. + + bool IsBanished; + bool HasKilledAkama; + + void Reset() + { + FindChannelers(); + + if(!Channelers.empty()) + for(std::list::iterator itr = Channelers.begin(); itr != Channelers.end(); ++itr) + { + Creature* Channeler = NULL; + Channeler = ((Creature*)Unit::GetUnit(*m_creature, *itr)); + if(Channeler) + { + if(Channeler->isDead()) + { + Channeler->RemoveCorpse(); + Channeler->Respawn(); + } + Channeler->CastSpell(m_creature, SPELL_SHADE_SOUL_CHANNEL, true); + Channeler->CastSpell(m_creature, SPELL_SHADE_SOUL_CHANNEL_2, true); + Channeler->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + else error_log("SD2 ERROR: No Channelers are stored in the list. This encounter will not work properly"); + + if(!Sorcerers.empty()) + for(std::list::iterator itr = Sorcerers.begin(); itr != Sorcerers.end(); ++itr) + if(Creature* Sorcerer = ((Creature*)Unit::GetUnit(*m_creature, *itr))) + if(Sorcerer->isAlive()) + { + Sorcerer->SetVisibility(VISIBILITY_OFF); + Sorcerer->DealDamage(Sorcerer, Sorcerer->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + Sorcerers.clear(); + + if(Unit* Akama = Unit::GetUnit(*m_creature, AkamaGUID)) + Akama->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + SorcererCount = 0; + DeathCount = 0; + + SummonTimer = 10000; + ReduceHealthTimer = 0; + ResetTimer = 60000; + DefenderTimer = 15000; + + IsBanished = true; + HasKilledAkama = false; + + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STUN); + + if(pInstance && m_creature->isAlive()) + pInstance->SetData(DATA_SHADEOFAKAMAEVENT, NOT_STARTED); + } + + void Aggro(Unit* who) { } + + void AttackStart(Unit* who) + { + if(!who || IsBanished) return; + + if(who->isTargetableForAttack() && who != m_creature) + DoStartAttackAndMovement(who); + } + + void MoveInLineOfSight(Unit* who) + { + if(IsBanished) return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void IncrementDeathCount(uint64 guid = 0) // If guid is set, will remove it from list of sorcerer + { + debug_log("SD2: Increasing Death Count for Shade of Akama encounter"); + ++DeathCount; + m_creature->RemoveSingleAuraFromStack(SPELL_SHADE_SOUL_CHANNEL_2, 0); + if(guid) + { + if(Sorcerers.empty()) + error_log("SD2 ERROR: Shade of Akama - attempt to remove guid %u from Sorcerers list but list is already empty", guid); + else Sorcerers.remove(guid); + } + } + + void SummonCreature() + { + uint32 random = rand()%2; + float X = SpawnLocations[random].x; + float Y = SpawnLocations[random].y; + // max of 6 sorcerers can be summoned + if((rand()%3 == 0) && (DeathCount > 0) && (SorcererCount < 7)) + { + Creature* Sorcerer = m_creature->SummonCreature(CREATURE_SORCERER, X, Y, Z_SPAWN, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + if(Sorcerer) + { + ((mob_ashtongue_sorcererAI*)Sorcerer->AI())->ShadeGUID = m_creature->GetGUID(); + Sorcerer->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + Sorcerer->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + Sorcerer->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); + Sorcerers.push_back(Sorcerer->GetGUID()); + --DeathCount; + ++SorcererCount; + } + } + else + { + for(uint8 i = 0; i < 3; ++i) + { + Creature* Spawn = m_creature->SummonCreature(spawnEntries[i], X, Y, Z_SPAWN, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000); + if(Spawn) + { + Spawn->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + Spawn->GetMotionMaster()->MovePoint(0, AGGRO_X, AGGRO_Y, AGGRO_Z); + } + } + } + } + + void FindChannelers() + { + CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + std::list ChannelerList; + + AllCreaturesOfEntryInRange check(m_creature, CREATURE_CHANNELER, 50); + MaNGOS::CreatureListSearcher searcher(ChannelerList, check); + TypeContainerVisitor, GridTypeMapContainer> visitor(searcher); + + CellLock cell_lock(cell, pair); + cell_lock->Visit(cell_lock, visitor, *(m_creature->GetMap())); + + if(!ChannelerList.empty()) + { + Channelers.clear(); + for(std::list::iterator itr = ChannelerList.begin(); itr != ChannelerList.end(); ++itr) + { + ((mob_ashtongue_channelerAI*)(*itr)->AI())->ShadeGUID = m_creature->GetGUID(); + Channelers.push_back((*itr)->GetGUID()); + debug_log("SD2: Shade of Akama Grid Search found channeler %u. Adding to list", (*itr)->GetGUID()); + } + } + else error_log("SD2 ERROR: Grid Search was unable to find any channelers. Shade of Akama encounter will be buggy"); + } + + void SetSelectableChannelers() + { + if(Channelers.empty()) + { + error_log("SD2 ERROR: Channeler List is empty, Shade of Akama encounter will be buggy"); + return; + } + + for(std::list::iterator itr = Channelers.begin(); itr != Channelers.end(); ++itr) + if(Creature* Channeler = ((Creature*)Unit::GetUnit(*m_creature, *itr))) + Channeler->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void SetAkamaGUID(uint64 guid) { AkamaGUID = guid; } + + void UpdateAI(const uint32 diff) + { + if(!InCombat) + return; + + if(IsBanished) + { + // 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) + EnterEvadeMode(); + + if(DefenderTimer < diff) + { + uint32 ran = rand()%2; + Creature* Defender = m_creature->SummonCreature(CREATURE_DEFENDER, SpawnLocations[ran].x, SpawnLocations[ran].y, Z_SPAWN, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000); + if(Defender) + { + Defender->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + bool move = true; + if(AkamaGUID) + { + if(Unit* Akama = Unit::GetUnit(*m_creature, AkamaGUID)) + { + float x, y, z; + Akama->GetPosition(x,y,z); + // They move towards AKama + Defender->GetMotionMaster()->MovePoint(0, x, y, z); + }else move = false; + }else move = false; + if(!move) + Defender->GetMotionMaster()->MovePoint(0, AKAMA_X, AKAMA_Y, AKAMA_Z); + } + DefenderTimer = 15000; + }else DefenderTimer -= diff; + + if(SummonTimer < diff) + { + SummonCreature(); + SummonTimer = 35000; + }else SummonTimer -= diff; + + if(DeathCount >= 6) + { + if(AkamaGUID) + { + Unit* Akama = Unit::GetUnit((*m_creature), AkamaGUID); + if(Akama && Akama->isAlive()) + { + IsBanished = false; + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveChase(Akama); + Akama->GetMotionMaster()->Clear(); + // Shade should move to Akama, not the other way around + Akama->GetMotionMaster()->MoveIdle(); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // Crazy amount of threat + m_creature->AddThreat(Akama, 10000000.0f); + Akama->AddThreat(m_creature, 10000000.0f); + m_creature->Attack(Akama, true); + Akama->Attack(m_creature, true); + } + } + } + } + else // No longer banished, let's fight Akama now + { + if(ReduceHealthTimer < diff) + { + if(AkamaGUID) + { + Unit* Akama = Unit::GetUnit((*m_creature), AkamaGUID); + if(Akama && Akama->isAlive()) + { + //10 % less health every few seconds. + m_creature->DealDamage(Akama, Akama->GetMaxHealth()/10, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + ReduceHealthTimer = 12000; + } + else + { + HasKilledAkama = true; // Akama is dead or missing, we stop fighting and disappear + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->RemoveAllAuras(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + }else ReduceHealthTimer -= diff; + + if(HasKilledAkama) + { + if(ResetTimer < diff) + { + InCombat = false; + EnterEvadeMode(); // Reset a little while after killing Akama + } + else ResetTimer -= diff; + } + + DoMeleeAttackIfReady(); + } + } +}; + +void mob_ashtongue_channelerAI::JustDied(Unit* killer) +{ + Creature* Shade = ((Creature*)Unit::GetUnit((*m_creature), ShadeGUID)); + if(Shade && Shade->isAlive()) + ((boss_shade_of_akamaAI*)Shade->AI())->IncrementDeathCount(); + else error_log("SD2 ERROR: Channeler dead but unable to increment DeathCount for Shade of Akama."); +} + +void mob_ashtongue_sorcererAI::JustDied(Unit* killer) +{ + Creature* Shade = ((Creature*)Unit::GetUnit((*m_creature), ShadeGUID)); + if(Shade && Shade->isAlive()) + ((boss_shade_of_akamaAI*)Shade->AI())->IncrementDeathCount(m_creature->GetGUID()); + else error_log("SD2 ERROR: Sorcerer dead but unable to increment DeathCount for Shade of Akama."); +} + +struct MANGOS_DLL_DECL npc_akamaAI : public ScriptedAI +{ + npc_akamaAI(Creature* c) : ScriptedAI(c) + { + ShadeHasDied = false; + StartCombat = false; + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + ShadeGUID = pInstance ? pInstance->GetData64(DATA_SHADEOFAKAMA) : 0; + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 ShadeGUID; + + uint32 DestructivePoisonTimer; + uint32 LightningBoltTimer; + uint32 CheckTimer; + uint32 CastSoulRetrieveTimer; + uint32 SoulRetrieveTimer; + uint32 SummonBrokenTimer; + uint32 EndingTalkCount; + uint32 WayPointId; + uint32 BrokenSummonIndex; + + std::list BrokenList; + + bool EventBegun; + bool ShadeHasDied; + bool StartCombat; + bool HasYelledOnce; + + void Reset() + { + DestructivePoisonTimer = 15000; + LightningBoltTimer = 10000; + CheckTimer = 2000; + CastSoulRetrieveTimer = 0; + SoulRetrieveTimer = 0; + SummonBrokenTimer = 0; + EndingTalkCount = 0; + WayPointId = 0; + BrokenSummonIndex = 0; + + BrokenList.clear(); + + EventBegun = false; + HasYelledOnce = false; + + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has very very strange values + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + void Aggro(Unit* who) {} + + void BeginEvent(Player* pl) + { + if(!pInstance) + return; + + ShadeGUID = pInstance->GetData64(DATA_SHADEOFAKAMA); + if(!ShadeGUID) + return; + + Creature* Shade = ((Creature*)Unit::GetUnit((*m_creature), ShadeGUID)); + if(Shade) + { + pInstance->SetData(DATA_SHADEOFAKAMAEVENT, IN_PROGRESS); + // Prevent players from trying to restart event + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + ((boss_shade_of_akamaAI*)Shade->AI())->SetAkamaGUID(m_creature->GetGUID()); + ((boss_shade_of_akamaAI*)Shade->AI())->SetSelectableChannelers(); + ((boss_shade_of_akamaAI*)Shade->AI())->InCombat = true; + Shade->AddThreat(m_creature, 1000000.0f); + Shade->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + Shade->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); + if(pl) Shade->AddThreat(pl, 1.0f); + DoZoneInCombat(Shade); + EventBegun = true; + } + } + + void MovementInform(uint32 type, uint32 id) + { + if(type != POINT_MOTION_TYPE) + return; + + switch(id) + { + case 0: ++WayPointId; break; + + case 1: + if(Unit* Shade = Unit::GetUnit(*m_creature, ShadeGUID)) + { + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, ShadeGUID); + DoCast(Shade, SPELL_AKAMA_SOUL_RETRIEVE); + EndingTalkCount = 0; + SoulRetrieveTimer = 16000; + } + break; + } + } + + void JustDied(Unit* killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if(!EventBegun) + return; + + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 15 && !HasYelledOnce) + { + DoYell(SAY_LOW_HEALTH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_LOW_HEALTH); + HasYelledOnce = true; + } + + if(ShadeGUID && !StartCombat) + { + Creature* Shade = ((Creature*)Unit::GetUnit((*m_creature), ShadeGUID)); + if(Shade && Shade->isAlive()) + { + if(((boss_shade_of_akamaAI*)Shade->AI())->IsBanished) + { + if(CastSoulRetrieveTimer < diff) + { + DoCast(Shade, SPELL_AKAMA_SOUL_CHANNEL); + CastSoulRetrieveTimer = 500; + }else CastSoulRetrieveTimer -= diff; + } + else + { + m_creature->InterruptNonMeleeSpells(false); + StartCombat = true; + } + } + } + + if(ShadeHasDied && (WayPointId == 1)) + { + if(pInstance) pInstance->SetData(DATA_SHADEOFAKAMAEVENT, DONE); + m_creature->GetMotionMaster()->MovePoint(WayPointId, AkamaWP[1].x, AkamaWP[1].y, AkamaWP[1].z); + ++WayPointId; + } + + if(!ShadeHasDied && StartCombat) + { + if(CheckTimer < diff) + { + if(ShadeGUID) + { + Unit* Shade = Unit::GetUnit((*m_creature), ShadeGUID); + if(Shade && !Shade->isAlive()) + { + ShadeHasDied = true; + WayPointId = 0; + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); + m_creature->GetMotionMaster()->MovePoint(WayPointId, AkamaWP[0].x, AkamaWP[0].y, AkamaWP[0].z); + } + } + CheckTimer = 5000; + }else CheckTimer -= diff; + } + + if(SummonBrokenTimer && BrokenSummonIndex < 4) + if(SummonBrokenTimer <= diff) + { + for(uint8 i = 0; i < 4; ++i) + { + float x = BrokenCoords[BrokenSummonIndex].x + (i*5); + float y = BrokenCoords[BrokenSummonIndex].y + (1*5); + float z = BrokenCoords[BrokenSummonIndex].z; + float o = BrokenCoords[BrokenSummonIndex].o; + Creature* Broken = m_creature->SummonCreature(CREATURE_BROKEN, x, y, z, o, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000); + if(Broken) + { + float wx = BrokenWP[BrokenSummonIndex].x + (i*5); + float wy = BrokenWP[BrokenSummonIndex].y + (i*5); + float wz = BrokenWP[BrokenSummonIndex].z; + Broken->GetMotionMaster()->MovePoint(0, wx, wy, wz); + Broken->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + BrokenList.push_back(Broken->GetGUID()); + } + } + ++BrokenSummonIndex; + SummonBrokenTimer = 1000; + }else SummonBrokenTimer -= diff; + + if(SoulRetrieveTimer) + if(SoulRetrieveTimer <= diff) + { + switch(EndingTalkCount) + { + case 0: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + ++EndingTalkCount; + SoulRetrieveTimer = 2000; + SummonBrokenTimer = 1; + case 1: + DoYell(SAY_FREE, LANG_UNIVERSAL, NULL); + ++EndingTalkCount; + SoulRetrieveTimer = 25000; + break; + case 2: + if(!BrokenList.empty()) + { + bool Yelled = false; + for(std::list::iterator itr = BrokenList.begin(); itr != BrokenList.end(); ++itr) + if(Unit* pUnit = Unit::GetUnit(*m_creature, *itr)) + { + if(!Yelled) + { + pUnit->MonsterYell(SAY_BROKEN_FREE_01, LANG_UNIVERSAL, 0); + Yelled = true; + } + pUnit->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); + } + } + ++EndingTalkCount; + SoulRetrieveTimer = 1500; + break; + case 3: + if(!BrokenList.empty()) + for(std::list::iterator itr = BrokenList.begin(); itr != BrokenList.end(); ++itr) + if(Unit* pUnit = Unit::GetUnit(*m_creature, *itr)) + // This is the incorrect spell, but can't seem to find the right one. + pUnit->CastSpell(pUnit, 39656, true); + ++EndingTalkCount; + SoulRetrieveTimer = 5000; + case 4: + if(!BrokenList.empty()) + for(std::list::iterator itr = BrokenList.begin(); itr != BrokenList.end(); ++itr) + if(Unit* pUnit = Unit::GetUnit((*m_creature), *itr)) + pUnit->MonsterYell(SAY_BROKEN_FREE_02, LANG_UNIVERSAL, 0); + SoulRetrieveTimer = 0; + break; + } + }else SoulRetrieveTimer -= diff; + + if(!m_creature->getVictim() || !m_creature->SelectHostilTarget()) + return; + + if(DestructivePoisonTimer < diff) + { + // SPELL_DESTRUCTIVE_POISON is self-cast only for some reason so we make our target cast it on itself + m_creature->getVictim()->CastSpell(m_creature->getVictim(), SPELL_DESTRUCTIVE_POISON, true); + DestructivePoisonTimer = 15000; + }else DestructivePoisonTimer -= diff; + + if(LightningBoltTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_LIGHTNING_BOLT); + LightningBoltTimer = 10000; + }else LightningBoltTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_shade_of_akama(Creature *_Creature) +{ + return new boss_shade_of_akamaAI (_Creature); +} + +CreatureAI* GetAI_mob_ashtongue_channeler(Creature *_Creature) +{ + return new mob_ashtongue_channelerAI (_Creature); +} + +CreatureAI* GetAI_mob_ashtongue_sorcerer(Creature *_Creature) +{ + return new mob_ashtongue_sorcererAI (_Creature); +} + +CreatureAI* GetAI_npc_akama_shade(Creature *_Creature) +{ + return new npc_akamaAI (_Creature); +} + +bool GossipSelect_npc_akama(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) //Fight time + { + player->CLOSE_GOSSIP_MENU(); + ((npc_akamaAI*)_Creature->AI())->BeginEvent(player); + } + + return true; +} + +bool GossipHello_npc_akama(Player *player, Creature *_Creature) +{ + if(player->isAlive()) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(907, _Creature->GetGUID()); + } + + return true; +} + +void AddSC_boss_shade_of_akama() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_shade_of_akama"; + newscript->GetAI = GetAI_boss_shade_of_akama; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_ashtongue_channeler"; + newscript->GetAI = GetAI_mob_ashtongue_channeler; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_ashtongue_sorcerer"; + newscript->GetAI = GetAI_mob_ashtongue_sorcerer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_akama_shade"; + newscript->GetAI = GetAI_npc_akama_shade; + newscript->pGossipHello = &GossipHello_npc_akama; + newscript->pGossipSelect = &GossipSelect_npc_akama; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp index f3b06ea6940..acdc421ced4 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp @@ -1,406 +1,406 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Supremus -SD%Complete: 95 -SDComment: Need to implement doors. -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -//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 -{ - molten_flameAI(Creature *c) : ScriptedAI(c) - { - Reset(); - } - - uint64 SupremusGUID; - bool TargetLocked; - uint32 CheckTimer; - - void Reset() - { - SupremusGUID = 0; - TargetLocked = false; - - CheckTimer = 1000; - } - - void Aggro(Unit *who) {} - 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); - } - - void SetSupremusGUID(uint64 GUID) { SupremusGUID = GUID; } - - void StalkTarget(Unit* target) - { - if(!target) return; - - m_creature->AddThreat(target, 50000000.0f); - m_creature->GetMotionMaster()->MoveChase(target); - DoCast(m_creature, SPELL_DEMON_FIRE, true); - // DoCast(m_creature, SPELL_MOLTEN_FLAME, true); // This spell damages self, so disabled for now - TargetLocked = true; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget()) - return; - - if(m_creature->getVictim() && m_creature->isAlive()) - { - if(CheckTimer < diff) - { - if(SupremusGUID) - { - Unit* Supremus = NULL; - Supremus = Unit::GetUnit((*m_creature), 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; - } - } -}; - -struct MANGOS_DLL_DECL npc_volcanoAI : public ScriptedAI -{ - npc_volcanoAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 CheckTimer; - uint64 SupremusGUID; - uint32 FireballTimer; - uint32 GeyserTimer; - - void Reset() - { - CheckTimer = 1000; - SupremusGUID = 0; - FireballTimer = 500; - GeyserTimer = 0; - } - - void Aggro(Unit *who) {} - 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 = NULL; - Supremus = Unit::GetUnit((*m_creature), 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) - { - DoCast(m_creature, SPELL_VOLCANIC_GEYSER); - GeyserTimer = 18000; - }else GeyserTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI -{ - boss_supremusAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 SummonFlameTimer; - uint32 SwitchTargetTimer; - uint32 PhaseSwitchTimer; - uint32 SummonVolcanoTimer; - uint32 HurtfulStrikeTimer; - uint32 BerserkTimer; - - bool Phase1; - - void Reset() - { - if(pInstance) - { - if(m_creature->isAlive()) - { - pInstance->SetData(DATA_SUPREMUSEVENT, NOT_STARTED); - ToggleDoors(true); - } - else ToggleDoors(false); - } - - HurtfulStrikeTimer = 5000; - SummonFlameTimer = 20000; - SwitchTargetTimer = 90000; - PhaseSwitchTimer = 60000; - SummonVolcanoTimer = 5000; - BerserkTimer = 900000; // 15 minute enrage - - Phase1 = true; - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - - if(pInstance) - pInstance->SetData(DATA_SUPREMUSEVENT, IN_PROGRESS); - } - - void ToggleDoors(bool close) - { - if(GameObject* Doors = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_SUPREMUS_DOORS))) - { - if(close) Doors->SetGoState(1); // Closed - else Doors->SetGoState(0); // Open - } - } - - void JustDied(Unit *killer) - { - if(pInstance) - { - pInstance->SetData(DATA_SUPREMUSEVENT, DONE); - ToggleDoors(false); - } - } - - float CalculateRandomCoord(float initial) - { - float coord = 0; - - switch(rand()%2) - { - case 0: coord = initial + 20 + rand()%20; break; - case 1: coord = initial - 20 - rand()%20; break; - } - - return coord; - } - - Creature* SummonCreature(uint32 entry, Unit* target) - { - if(target && entry) - { - Creature* Summon = m_creature->SummonCreature(entry, CalculateRandomCoord(target->GetPositionX()), CalculateRandomCoord(target->GetPositionY()), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 20000); - if(Summon) - { - Summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Summon->setFaction(m_creature->getFaction()); - return Summon; - } - } - return NULL; - } - - Unit* CalculateHurtfulStrikeTarget() - { - uint32 health = 0; - Unit* target = NULL; - - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list::iterator i = m_threatlist.begin(); - for (i = m_threatlist.begin(); i!= m_threatlist.end();++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && m_creature->IsWithinDistInMap(pUnit, ATTACK_DISTANCE)) - { - if(pUnit->GetHealth() > health) - { - health = pUnit->GetHealth(); - target = pUnit; - } - } - } - - return target; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(!m_creature->HasAura(SPELL_BERSERK, 0)) - if(BerserkTimer < diff) - DoCast(m_creature, SPELL_BERSERK); - else BerserkTimer -= diff; - - if(SummonFlameTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 1); - - if(!target) // someone is trying to solo, set target as current victim. - target = m_creature->getVictim(); - - if(target) - { - Creature* MoltenFlame = SummonCreature(CREATURE_STALKER, target); - if(MoltenFlame) - { - // Invisible model - MoltenFlame->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); - ((molten_flameAI*)MoltenFlame->AI())->SetSupremusGUID(m_creature->GetGUID()); - ((molten_flameAI*)MoltenFlame->AI())->StalkTarget(target); - SummonFlameTimer = 20000; - } - } - }else SummonFlameTimer -= diff; - - if(Phase1) - { - if(HurtfulStrikeTimer < diff) - { - Unit* target = CalculateHurtfulStrikeTarget(); - if(target) - { - DoCast(target, SPELL_HURTFUL_STRIKE); - HurtfulStrikeTimer = 5000; - } - }else HurtfulStrikeTimer -= diff; - } - - if(!Phase1) - { - if(SwitchTargetTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - DoResetThreat(); - m_creature->AddThreat(target, 5000000.0f); - DoTextEmote("acquires a new target!", NULL); - SwitchTargetTimer = 10000; - } - - }else SwitchTargetTimer -= diff; - - if(SummonVolcanoTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - - if(!target) - target = m_creature->getVictim(); - - if(target) - { - Creature* Volcano = NULL; - Volcano = SummonCreature(CREATURE_VOLCANO, target); - - if(Volcano) - { - DoCast(target, SPELL_VOLCANIC_ERUPTION); - ((npc_volcanoAI*)Volcano->AI())->SetSupremusGUID(m_creature->GetGUID()); - } - - DoTextEmote("roars and the ground begins to crack open!", NULL); - SummonVolcanoTimer = 10000; - } - }else SummonVolcanoTimer -= diff; - } - - if(PhaseSwitchTimer < diff) - { - if(!Phase1) - { - Phase1 = true; - DoResetThreat(); - PhaseSwitchTimer = 60000; - m_creature->SetSpeed(MOVE_RUN, 1.0f); - } - else - { - Phase1 = false; - DoResetThreat(); - SwitchTargetTimer = 10000; - SummonVolcanoTimer = 2000; - PhaseSwitchTimer = 60000; - m_creature->SetSpeed(MOVE_RUN, 0.9f); - } - }else PhaseSwitchTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_supremus(Creature *_Creature) -{ - return new boss_supremusAI (_Creature); -} - -CreatureAI* GetAI_molten_flame(Creature *_Creature) -{ - return new molten_flameAI (_Creature); -} - -CreatureAI* GetAI_npc_volcano(Creature *_Creature) -{ - return new npc_volcanoAI (_Creature); -} - -void AddSC_boss_supremus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_supremus"; - newscript->GetAI = GetAI_boss_supremus; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="molten_flame"; - newscript->GetAI = GetAI_molten_flame; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_volcano"; - newscript->GetAI = GetAI_npc_volcano; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Supremus +SD%Complete: 95 +SDComment: Need to implement doors. +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +//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 +{ + molten_flameAI(Creature *c) : ScriptedAI(c) + { + Reset(); + } + + uint64 SupremusGUID; + bool TargetLocked; + uint32 CheckTimer; + + void Reset() + { + SupremusGUID = 0; + TargetLocked = false; + + CheckTimer = 1000; + } + + void Aggro(Unit *who) {} + 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); + } + + void SetSupremusGUID(uint64 GUID) { SupremusGUID = GUID; } + + void StalkTarget(Unit* target) + { + if(!target) return; + + m_creature->AddThreat(target, 50000000.0f); + m_creature->GetMotionMaster()->MoveChase(target); + DoCast(m_creature, SPELL_DEMON_FIRE, true); + // DoCast(m_creature, SPELL_MOLTEN_FLAME, true); // This spell damages self, so disabled for now + TargetLocked = true; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget()) + return; + + if(m_creature->getVictim() && m_creature->isAlive()) + { + if(CheckTimer < diff) + { + if(SupremusGUID) + { + Unit* Supremus = NULL; + Supremus = Unit::GetUnit((*m_creature), 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; + } + } +}; + +struct MANGOS_DLL_DECL npc_volcanoAI : public ScriptedAI +{ + npc_volcanoAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 CheckTimer; + uint64 SupremusGUID; + uint32 FireballTimer; + uint32 GeyserTimer; + + void Reset() + { + CheckTimer = 1000; + SupremusGUID = 0; + FireballTimer = 500; + GeyserTimer = 0; + } + + void Aggro(Unit *who) {} + 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 = NULL; + Supremus = Unit::GetUnit((*m_creature), 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) + { + DoCast(m_creature, SPELL_VOLCANIC_GEYSER); + GeyserTimer = 18000; + }else GeyserTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI +{ + boss_supremusAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 SummonFlameTimer; + uint32 SwitchTargetTimer; + uint32 PhaseSwitchTimer; + uint32 SummonVolcanoTimer; + uint32 HurtfulStrikeTimer; + uint32 BerserkTimer; + + bool Phase1; + + void Reset() + { + if(pInstance) + { + if(m_creature->isAlive()) + { + pInstance->SetData(DATA_SUPREMUSEVENT, NOT_STARTED); + ToggleDoors(true); + } + else ToggleDoors(false); + } + + HurtfulStrikeTimer = 5000; + SummonFlameTimer = 20000; + SwitchTargetTimer = 90000; + PhaseSwitchTimer = 60000; + SummonVolcanoTimer = 5000; + BerserkTimer = 900000; // 15 minute enrage + + Phase1 = true; + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + + if(pInstance) + pInstance->SetData(DATA_SUPREMUSEVENT, IN_PROGRESS); + } + + void ToggleDoors(bool close) + { + if(GameObject* Doors = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_SUPREMUS_DOORS))) + { + if(close) Doors->SetGoState(1); // Closed + else Doors->SetGoState(0); // Open + } + } + + void JustDied(Unit *killer) + { + if(pInstance) + { + pInstance->SetData(DATA_SUPREMUSEVENT, DONE); + ToggleDoors(false); + } + } + + float CalculateRandomCoord(float initial) + { + float coord = 0; + + switch(rand()%2) + { + case 0: coord = initial + 20 + rand()%20; break; + case 1: coord = initial - 20 - rand()%20; break; + } + + return coord; + } + + Creature* SummonCreature(uint32 entry, Unit* target) + { + if(target && entry) + { + Creature* Summon = m_creature->SummonCreature(entry, CalculateRandomCoord(target->GetPositionX()), CalculateRandomCoord(target->GetPositionY()), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 20000); + if(Summon) + { + Summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Summon->setFaction(m_creature->getFaction()); + return Summon; + } + } + return NULL; + } + + Unit* CalculateHurtfulStrikeTarget() + { + uint32 health = 0; + Unit* target = NULL; + + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + std::list::iterator i = m_threatlist.begin(); + for (i = m_threatlist.begin(); i!= m_threatlist.end();++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && m_creature->IsWithinDistInMap(pUnit, ATTACK_DISTANCE)) + { + if(pUnit->GetHealth() > health) + { + health = pUnit->GetHealth(); + target = pUnit; + } + } + } + + return target; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(!m_creature->HasAura(SPELL_BERSERK, 0)) + if(BerserkTimer < diff) + DoCast(m_creature, SPELL_BERSERK); + else BerserkTimer -= diff; + + if(SummonFlameTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 1); + + if(!target) // someone is trying to solo, set target as current victim. + target = m_creature->getVictim(); + + if(target) + { + Creature* MoltenFlame = SummonCreature(CREATURE_STALKER, target); + if(MoltenFlame) + { + // Invisible model + MoltenFlame->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); + ((molten_flameAI*)MoltenFlame->AI())->SetSupremusGUID(m_creature->GetGUID()); + ((molten_flameAI*)MoltenFlame->AI())->StalkTarget(target); + SummonFlameTimer = 20000; + } + } + }else SummonFlameTimer -= diff; + + if(Phase1) + { + if(HurtfulStrikeTimer < diff) + { + Unit* target = CalculateHurtfulStrikeTarget(); + if(target) + { + DoCast(target, SPELL_HURTFUL_STRIKE); + HurtfulStrikeTimer = 5000; + } + }else HurtfulStrikeTimer -= diff; + } + + if(!Phase1) + { + if(SwitchTargetTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + DoResetThreat(); + m_creature->AddThreat(target, 5000000.0f); + DoTextEmote("acquires a new target!", NULL); + SwitchTargetTimer = 10000; + } + + }else SwitchTargetTimer -= diff; + + if(SummonVolcanoTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + + if(!target) + target = m_creature->getVictim(); + + if(target) + { + Creature* Volcano = NULL; + Volcano = SummonCreature(CREATURE_VOLCANO, target); + + if(Volcano) + { + DoCast(target, SPELL_VOLCANIC_ERUPTION); + ((npc_volcanoAI*)Volcano->AI())->SetSupremusGUID(m_creature->GetGUID()); + } + + DoTextEmote("roars and the ground begins to crack open!", NULL); + SummonVolcanoTimer = 10000; + } + }else SummonVolcanoTimer -= diff; + } + + if(PhaseSwitchTimer < diff) + { + if(!Phase1) + { + Phase1 = true; + DoResetThreat(); + PhaseSwitchTimer = 60000; + m_creature->SetSpeed(MOVE_RUN, 1.0f); + } + else + { + Phase1 = false; + DoResetThreat(); + SwitchTargetTimer = 10000; + SummonVolcanoTimer = 2000; + PhaseSwitchTimer = 60000; + m_creature->SetSpeed(MOVE_RUN, 0.9f); + } + }else PhaseSwitchTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_supremus(Creature *_Creature) +{ + return new boss_supremusAI (_Creature); +} + +CreatureAI* GetAI_molten_flame(Creature *_Creature) +{ + return new molten_flameAI (_Creature); +} + +CreatureAI* GetAI_npc_volcano(Creature *_Creature) +{ + return new npc_volcanoAI (_Creature); +} + +void AddSC_boss_supremus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_supremus"; + newscript->GetAI = GetAI_boss_supremus; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="molten_flame"; + newscript->GetAI = GetAI_molten_flame; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_volcano"; + newscript->GetAI = GetAI_npc_volcano; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp index 9c1182cfd0e..e8ab3c6d490 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp @@ -1,589 +1,589 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Teron_Gorefiend -SD%Complete: 60 -SDComment: Requires Mind Control support for Ghosts. -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -//Spells -#define SPELL_INCINERATE 40239 -#define SPELL_CRUSHING_SHADOWS 40243 -#define SPELL_SHADOWBOLT 40185 -#define SPELL_PASSIVE_SHADOWFORM 40326 -#define SPELL_SHADOW_OF_DEATH 40251 -#define SPELL_BERSERK 45078 - -#define SPELL_ATROPHY 40327 // Shadowy Constructs use this when they get within melee range of a player - -//Speech'n'sound -#define SAY_INTRO "I was the first, you know. For me, the wheel of death has spun many times. So much time has passed. I have a lot of catching up to do..." -#define SOUND_INTRO 11512 - -#define SAY_AGGRO "Vengeance is mine!" -#define SOUND_AGGRO 11513 - -#define SAY_SLAY1 "I have use for you!" -#define SOUND_SLAY1 11514 - -#define SAY_SLAY2 "It gets worse..." -#define SOUND_SLAY2 11515 - -#define SAY_SPELL1 "What are you afraid of?" -#define SOUND_SPELL1 11517 - -#define SAY_SPELL2 "Death... really isn't so bad." -#define SOUND_SPELL2 11516 - -#define SAY_SPECIAL1 "Give in!" -#define SOUND_SPECIAL1 11518 - -#define SAY_SPECIAL2 "I have something for you..." -#define SOUND_SPECIAL2 11519 - -#define SAY_ENRAGE "YOU WILL SHOW THE PROPER RESPECT!" -#define SOUND_ENRAGE 11520 - -#define SAY_DEATH "The wheel...spins...again...." -#define SOUND_DEATH 11521 - -#define CREATURE_DOOM_BLOSSOM 23123 -#define CREATURE_SHADOWY_CONSTRUCT 23111 - -struct MANGOS_DLL_DECL mob_doom_blossomAI : public ScriptedAI -{ - mob_doom_blossomAI(Creature *c) : ScriptedAI(c) - { - Reset(); - } - - uint32 CheckTeronTimer; - uint32 ShadowBoltTimer; - uint64 TeronGUID; - - void Reset() - { - CheckTeronTimer = 5000; - ShadowBoltTimer = 12000; - TeronGUID = 0; - } - - void Aggro(Unit *who) { } - void AttackStart(Unit* who) { } - void MoveInLineOfSight(Unit* who) { } - - void UpdateAI(const uint32 diff) - { - if(CheckTeronTimer < diff) - { - if(TeronGUID) - { - DoZoneInCombat(); - - Creature* Teron = ((Creature*)Unit::GetUnit((*m_creature), TeronGUID)); - if((Teron) && (!Teron->isAlive() || Teron->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); - - CheckTeronTimer = 5000; - }else CheckTeronTimer -= diff; - - if(!m_creature->getVictim() || !m_creature->SelectHostilTarget()) - return; - - if(ShadowBoltTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_SHADOWBOLT); - ShadowBoltTimer = 10000; - }else ShadowBoltTimer -= diff; - } - - void SetTeronGUID(uint64 guid){ TeronGUID = guid; } -}; - -//This is used to sort the players by distance for Constructs to see who to cast Atrophy on -struct TargetDistanceOrder : public std::binary_function -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator "<" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); - } -}; - -struct MANGOS_DLL_DECL mob_shadowy_constructAI : public ScriptedAI -{ - mob_shadowy_constructAI(Creature* c) : ScriptedAI(c) - { - Reset(); - } - - uint64 GhostGUID; - uint64 TeronGUID; - - uint32 CheckPlayerTimer; - uint32 CheckTeronTimer; - - void Reset() - { - GhostGUID = 0; - TeronGUID = 0; - - CheckPlayerTimer = 2000; - CheckTeronTimer = 5000; - } - - void Aggro(Unit* who) { } - - void MoveInLineOfSight(Unit *who) - { - if(!who || (!who->isAlive()) || (who->GetGUID() == GhostGUID)) - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - m_creature->AddThreat(who, 1.0f); - } - } - } - -/* 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() != GhostGUID) - damage = 0; // Only the ghost can deal damage. - } - */ - - void CheckPlayers() - { - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - if(m_threatlist.empty()) - return; // No threat list. Don't continue. - std::list::iterator itr = m_threatlist.begin(); - std::list targets; - for( ; itr != m_threatlist.end(); ++itr) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); - if(pUnit && pUnit->isAlive()) - targets.push_back(pUnit); - } - targets.sort(TargetDistanceOrder(m_creature)); - Unit* target = targets.front(); - if(target && m_creature->IsWithinDistInMap(target, m_creature->GetAttackDistance(target))) - { - DoCast(target, SPELL_ATROPHY); - m_creature->AI()->AttackStart(target); - } - } - - void UpdateAI(const uint32 diff) - { - if(CheckPlayerTimer < diff) - { - CheckPlayers(); - CheckPlayerTimer = 3000; - }else CheckPlayerTimer -= diff; - - if(CheckTeronTimer < diff) - { - Creature* Teron = ((Creature*)Unit::GetUnit((*m_creature), TeronGUID)); - if(!Teron || !Teron->isAlive() || Teron->IsInEvadeMode()) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - CheckTeronTimer = 5000; - }else CheckTeronTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI -{ - boss_teron_gorefiendAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 IncinerateTimer; - uint32 SummonDoomBlossomTimer; - uint32 EnrageTimer; - uint32 CrushingShadowsTimer; - uint32 ShadowOfDeathTimer; - uint32 SummonShadowsTimer; - uint32 RandomYellTimer; - uint32 AggroTimer; - - uint64 AggroTargetGUID; - uint64 GhostGUID; // Player that gets killed by Shadow of Death and gets turned into a ghost - - bool Intro; - - void Reset() - { - if(pInstance) - pInstance->SetData(DATA_TERONGOREFIENDEVENT, NOT_STARTED); - - IncinerateTimer = 20000 + rand()%11000; - SummonDoomBlossomTimer = 12000; - EnrageTimer = 600000; - CrushingShadowsTimer = 22000; - SummonShadowsTimer = 60000; - RandomYellTimer = 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); - - AggroTimer = 20000; - AggroTargetGUID = 0; - Intro = false; - } - - void Aggro(Unit *who) {} - - void MoveInLineOfSight(Unit *who) - { - if(!who || (!who->isAlive())) 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - m_creature->AddThreat(who, 1.0f); - } - - if(!InCombat && !Intro && m_creature->IsWithinDistInMap(who, 200.0f) && (who->GetTypeId() == TYPEID_PLAYER)) - { - if(pInstance) - pInstance->SetData(DATA_TERONGOREFIENDEVENT, IN_PROGRESS); - - m_creature->GetMotionMaster()->Clear(false); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoYell(SAY_INTRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_INTRO); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); - AggroTargetGUID = who->GetGUID(); - Intro = true; - } - } - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - if(pInstance) - pInstance->SetData(DATA_TERONGOREFIENDEVENT, DONE); - - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - float CalculateRandomLocation(float Loc, uint32 radius) - { - float coord = Loc; - switch(rand()%2) - { - case 0: - coord += rand()%radius; - break; - case 1: - coord -= rand()%radius; - break; - } - return coord; - } - - void SetThreatList(Creature* Blossom) - { - if(!Blossom) return; - - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list::iterator i = m_threatlist.begin(); - for(i = m_threatlist.begin(); i != m_threatlist.end(); i++) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && pUnit->isAlive()) - { - float threat = m_creature->getThreatManager().getThreat(pUnit); - Blossom->AddThreat(pUnit, threat); - } - } - } - - void MindControlGhost() - { - /************************************************************************/ - /** 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 *****/ - /************************************************************************/ - - Unit* Ghost = NULL; - if(GhostGUID) - Ghost = Unit::GetUnit((*m_creature), GhostGUID); - if(Ghost && Ghost->isAlive() && Ghost->HasAura(SPELL_SHADOW_OF_DEATH, 0)) - { - /*float x,y,z; - Ghost->GetPosition(x,y,z); - Creature* control = m_creature->SummonCreature(CREATURE_GHOST, x, y, z, 0, TEMPSUMMON_TIMED_DESAWN, 30000); - if(control) - { - ((Player*)Ghost)->Possess(control); - Ghost->DealDamage(Ghost, Ghost->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, - false); - }*/ - for(uint8 i = 0; i < 4; ++i) - { - Creature* Construct = NULL; - float X = CalculateRandomLocation(Ghost->GetPositionX(), 10); - float Y = CalculateRandomLocation(Ghost->GetPositionY(), 10); - Construct = m_creature->SummonCreature(CREATURE_SHADOWY_CONSTRUCT, X, Y, Ghost->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); - if(Construct) - { - Construct->CastSpell(Construct, SPELL_PASSIVE_SHADOWFORM, true); - SetThreatList(Construct); // Use same function as Doom Blossom to set Threat List. - ((mob_shadowy_constructAI*)Construct->AI())->GhostGUID = GhostGUID; - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(!target) // someone's trying to solo. - target = m_creature->getVictim(); - - if(target) - Construct->GetMotionMaster()->MoveChase(target); - } - } - } - } - - void UpdateAI(const uint32 diff) - { - if(Intro) - { - if(AggroTimer < diff) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - Intro = false; - if(AggroTargetGUID) - { - Unit* pUnit = Unit::GetUnit((*m_creature), AggroTargetGUID); - if(pUnit) - { - m_creature->GetMotionMaster()->MoveChase(pUnit); - AttackStart(pUnit); - } - DoZoneInCombat(); - }else EnterEvadeMode(); - - }else AggroTimer -= diff; - } - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || Intro) - return; - - if(SummonShadowsTimer < diff) - { - //MindControlGhost(); - - for(uint8 i = 0; i < 2; ++i) - { - Creature* Shadow = NULL; - float X = CalculateRandomLocation(m_creature->GetPositionX(), 10); - Shadow = m_creature->SummonCreature(CREATURE_SHADOWY_CONSTRUCT, X, m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 0); - if(Shadow) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(!target) - target = m_creature->getVictim(); - - if(target) - Shadow->AI()->AttackStart(target); - } - } - SummonShadowsTimer = 60000; - }else SummonShadowsTimer -= diff; - - if(SummonDoomBlossomTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - float X = CalculateRandomLocation(target->GetPositionX(), 20); - float Y = CalculateRandomLocation(target->GetPositionY(), 20); - Creature* DoomBlossom = m_creature->SummonCreature(CREATURE_DOOM_BLOSSOM, X, Y, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); - if(DoomBlossom) - { - DoomBlossom->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoomBlossom->setFaction(m_creature->getFaction()); - DoomBlossom->AddThreat(target, 1.0f); - ((mob_doom_blossomAI*)DoomBlossom->AI())->SetTeronGUID(m_creature->GetGUID()); - ((mob_doom_blossomAI*)DoomBlossom->AI())->InCombat = true; - SetThreatList(DoomBlossom); - SummonDoomBlossomTimer = 35000; - } - } - }else SummonDoomBlossomTimer -= diff; - - if(IncinerateTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(!target) - target = m_creature->getVictim(); - - if(target) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SPECIAL1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SPECIAL1); - break; - case 1: - DoYell(SAY_SPECIAL2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SPECIAL2); - break; - } - DoCast(target, SPELL_INCINERATE); - IncinerateTimer = 20000 + rand()%31 * 1000; - } - }else IncinerateTimer -= diff; - - if(CrushingShadowsTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target && target->isAlive()) - DoCast(target, SPELL_CRUSHING_SHADOWS); - CrushingShadowsTimer = 10000 + rand()%16 * 1000; - }else CrushingShadowsTimer -= diff; - - /*** NOTE FOR FUTURE DEV: UNCOMMENT BELOW ONLY IF MIND CONTROL IS FULLY IMPLEMENTED **/ - /*if(ShadowOfDeathTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - - if(!target) - target = m_creature->getVictim(); - - if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) - { - DoCast(target, SPELL_SHADOW_OF_DEATH); - GhostGUID = target->GetGUID(); - ShadowOfDeathTimer = 30000; - SummonShadowsTimer = 53000; // Make it VERY close but slightly less so that we can check if the aura is still on the player - } - }else ShadowOfDeathTimer -= diff;*/ - - if(RandomYellTimer < diff) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SPELL1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SPELL1); - break; - case 1: - DoYell(SAY_SPELL2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SPELL2); - break; - } - RandomYellTimer = 50000 + rand()%51 * 1000; - }else RandomYellTimer -= diff; - - if(!m_creature->HasAura(SPELL_BERSERK, 0)) - if(EnrageTimer < diff) - { - DoCast(m_creature, SPELL_BERSERK); - DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - }else EnrageTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_doom_blossom(Creature *_Creature) -{ - return new mob_doom_blossomAI(_Creature); -} - -CreatureAI* GetAI_mob_shadowy_construct(Creature *_Creature) -{ - return new mob_shadowy_constructAI(_Creature); -} - -CreatureAI* GetAI_boss_teron_gorefiend(Creature *_Creature) -{ - return new boss_teron_gorefiendAI (_Creature); -} - -void AddSC_boss_teron_gorefiend() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "mob_doom_blossom"; - newscript->GetAI = GetAI_mob_doom_blossom; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_shadowy_construct"; - newscript->GetAI = GetAI_mob_shadowy_construct; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_teron_gorefiend"; - newscript->GetAI = GetAI_boss_teron_gorefiend; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Teron_Gorefiend +SD%Complete: 60 +SDComment: Requires Mind Control support for Ghosts. +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +//Spells +#define SPELL_INCINERATE 40239 +#define SPELL_CRUSHING_SHADOWS 40243 +#define SPELL_SHADOWBOLT 40185 +#define SPELL_PASSIVE_SHADOWFORM 40326 +#define SPELL_SHADOW_OF_DEATH 40251 +#define SPELL_BERSERK 45078 + +#define SPELL_ATROPHY 40327 // Shadowy Constructs use this when they get within melee range of a player + +//Speech'n'sound +#define SAY_INTRO "I was the first, you know. For me, the wheel of death has spun many times. So much time has passed. I have a lot of catching up to do..." +#define SOUND_INTRO 11512 + +#define SAY_AGGRO "Vengeance is mine!" +#define SOUND_AGGRO 11513 + +#define SAY_SLAY1 "I have use for you!" +#define SOUND_SLAY1 11514 + +#define SAY_SLAY2 "It gets worse..." +#define SOUND_SLAY2 11515 + +#define SAY_SPELL1 "What are you afraid of?" +#define SOUND_SPELL1 11517 + +#define SAY_SPELL2 "Death... really isn't so bad." +#define SOUND_SPELL2 11516 + +#define SAY_SPECIAL1 "Give in!" +#define SOUND_SPECIAL1 11518 + +#define SAY_SPECIAL2 "I have something for you..." +#define SOUND_SPECIAL2 11519 + +#define SAY_ENRAGE "YOU WILL SHOW THE PROPER RESPECT!" +#define SOUND_ENRAGE 11520 + +#define SAY_DEATH "The wheel...spins...again...." +#define SOUND_DEATH 11521 + +#define CREATURE_DOOM_BLOSSOM 23123 +#define CREATURE_SHADOWY_CONSTRUCT 23111 + +struct MANGOS_DLL_DECL mob_doom_blossomAI : public ScriptedAI +{ + mob_doom_blossomAI(Creature *c) : ScriptedAI(c) + { + Reset(); + } + + uint32 CheckTeronTimer; + uint32 ShadowBoltTimer; + uint64 TeronGUID; + + void Reset() + { + CheckTeronTimer = 5000; + ShadowBoltTimer = 12000; + TeronGUID = 0; + } + + void Aggro(Unit *who) { } + void AttackStart(Unit* who) { } + void MoveInLineOfSight(Unit* who) { } + + void UpdateAI(const uint32 diff) + { + if(CheckTeronTimer < diff) + { + if(TeronGUID) + { + DoZoneInCombat(); + + Creature* Teron = ((Creature*)Unit::GetUnit((*m_creature), TeronGUID)); + if((Teron) && (!Teron->isAlive() || Teron->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); + + CheckTeronTimer = 5000; + }else CheckTeronTimer -= diff; + + if(!m_creature->getVictim() || !m_creature->SelectHostilTarget()) + return; + + if(ShadowBoltTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_SHADOWBOLT); + ShadowBoltTimer = 10000; + }else ShadowBoltTimer -= diff; + } + + void SetTeronGUID(uint64 guid){ TeronGUID = guid; } +}; + +//This is used to sort the players by distance for Constructs to see who to cast Atrophy on +struct TargetDistanceOrder : public std::binary_function +{ + const Unit* MainTarget; + TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; + // functor for operator "<" + bool operator()(const Unit* _Left, const Unit* _Right) const + { + return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); + } +}; + +struct MANGOS_DLL_DECL mob_shadowy_constructAI : public ScriptedAI +{ + mob_shadowy_constructAI(Creature* c) : ScriptedAI(c) + { + Reset(); + } + + uint64 GhostGUID; + uint64 TeronGUID; + + uint32 CheckPlayerTimer; + uint32 CheckTeronTimer; + + void Reset() + { + GhostGUID = 0; + TeronGUID = 0; + + CheckPlayerTimer = 2000; + CheckTeronTimer = 5000; + } + + void Aggro(Unit* who) { } + + void MoveInLineOfSight(Unit *who) + { + if(!who || (!who->isAlive()) || (who->GetGUID() == GhostGUID)) + 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(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + m_creature->AddThreat(who, 1.0f); + } + } + } + +/* 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() != GhostGUID) + damage = 0; // Only the ghost can deal damage. + } + */ + + void CheckPlayers() + { + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + if(m_threatlist.empty()) + return; // No threat list. Don't continue. + std::list::iterator itr = m_threatlist.begin(); + std::list targets; + for( ; itr != m_threatlist.end(); ++itr) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if(pUnit && pUnit->isAlive()) + targets.push_back(pUnit); + } + targets.sort(TargetDistanceOrder(m_creature)); + Unit* target = targets.front(); + if(target && m_creature->IsWithinDistInMap(target, m_creature->GetAttackDistance(target))) + { + DoCast(target, SPELL_ATROPHY); + m_creature->AI()->AttackStart(target); + } + } + + void UpdateAI(const uint32 diff) + { + if(CheckPlayerTimer < diff) + { + CheckPlayers(); + CheckPlayerTimer = 3000; + }else CheckPlayerTimer -= diff; + + if(CheckTeronTimer < diff) + { + Creature* Teron = ((Creature*)Unit::GetUnit((*m_creature), TeronGUID)); + if(!Teron || !Teron->isAlive() || Teron->IsInEvadeMode()) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + CheckTeronTimer = 5000; + }else CheckTeronTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI +{ + boss_teron_gorefiendAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 IncinerateTimer; + uint32 SummonDoomBlossomTimer; + uint32 EnrageTimer; + uint32 CrushingShadowsTimer; + uint32 ShadowOfDeathTimer; + uint32 SummonShadowsTimer; + uint32 RandomYellTimer; + uint32 AggroTimer; + + uint64 AggroTargetGUID; + uint64 GhostGUID; // Player that gets killed by Shadow of Death and gets turned into a ghost + + bool Intro; + + void Reset() + { + if(pInstance) + pInstance->SetData(DATA_TERONGOREFIENDEVENT, NOT_STARTED); + + IncinerateTimer = 20000 + rand()%11000; + SummonDoomBlossomTimer = 12000; + EnrageTimer = 600000; + CrushingShadowsTimer = 22000; + SummonShadowsTimer = 60000; + RandomYellTimer = 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); + + AggroTimer = 20000; + AggroTargetGUID = 0; + Intro = false; + } + + void Aggro(Unit *who) {} + + void MoveInLineOfSight(Unit *who) + { + if(!who || (!who->isAlive())) 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(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + m_creature->AddThreat(who, 1.0f); + } + + if(!InCombat && !Intro && m_creature->IsWithinDistInMap(who, 200.0f) && (who->GetTypeId() == TYPEID_PLAYER)) + { + if(pInstance) + pInstance->SetData(DATA_TERONGOREFIENDEVENT, IN_PROGRESS); + + m_creature->GetMotionMaster()->Clear(false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoYell(SAY_INTRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_INTRO); + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); + AggroTargetGUID = who->GetGUID(); + Intro = true; + } + } + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + if(pInstance) + pInstance->SetData(DATA_TERONGOREFIENDEVENT, DONE); + + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + float CalculateRandomLocation(float Loc, uint32 radius) + { + float coord = Loc; + switch(rand()%2) + { + case 0: + coord += rand()%radius; + break; + case 1: + coord -= rand()%radius; + break; + } + return coord; + } + + void SetThreatList(Creature* Blossom) + { + if(!Blossom) return; + + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + std::list::iterator i = m_threatlist.begin(); + for(i = m_threatlist.begin(); i != m_threatlist.end(); i++) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && pUnit->isAlive()) + { + float threat = m_creature->getThreatManager().getThreat(pUnit); + Blossom->AddThreat(pUnit, threat); + } + } + } + + void MindControlGhost() + { + /************************************************************************/ + /** 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 *****/ + /************************************************************************/ + + Unit* Ghost = NULL; + if(GhostGUID) + Ghost = Unit::GetUnit((*m_creature), GhostGUID); + if(Ghost && Ghost->isAlive() && Ghost->HasAura(SPELL_SHADOW_OF_DEATH, 0)) + { + /*float x,y,z; + Ghost->GetPosition(x,y,z); + Creature* control = m_creature->SummonCreature(CREATURE_GHOST, x, y, z, 0, TEMPSUMMON_TIMED_DESAWN, 30000); + if(control) + { + ((Player*)Ghost)->Possess(control); + Ghost->DealDamage(Ghost, Ghost->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, + false); + }*/ + for(uint8 i = 0; i < 4; ++i) + { + Creature* Construct = NULL; + float X = CalculateRandomLocation(Ghost->GetPositionX(), 10); + float Y = CalculateRandomLocation(Ghost->GetPositionY(), 10); + Construct = m_creature->SummonCreature(CREATURE_SHADOWY_CONSTRUCT, X, Y, Ghost->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); + if(Construct) + { + Construct->CastSpell(Construct, SPELL_PASSIVE_SHADOWFORM, true); + SetThreatList(Construct); // Use same function as Doom Blossom to set Threat List. + ((mob_shadowy_constructAI*)Construct->AI())->GhostGUID = GhostGUID; + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(!target) // someone's trying to solo. + target = m_creature->getVictim(); + + if(target) + Construct->GetMotionMaster()->MoveChase(target); + } + } + } + } + + void UpdateAI(const uint32 diff) + { + if(Intro) + { + if(AggroTimer < diff) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + Intro = false; + if(AggroTargetGUID) + { + Unit* pUnit = Unit::GetUnit((*m_creature), AggroTargetGUID); + if(pUnit) + { + m_creature->GetMotionMaster()->MoveChase(pUnit); + AttackStart(pUnit); + } + DoZoneInCombat(); + }else EnterEvadeMode(); + + }else AggroTimer -= diff; + } + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || Intro) + return; + + if(SummonShadowsTimer < diff) + { + //MindControlGhost(); + + for(uint8 i = 0; i < 2; ++i) + { + Creature* Shadow = NULL; + float X = CalculateRandomLocation(m_creature->GetPositionX(), 10); + Shadow = m_creature->SummonCreature(CREATURE_SHADOWY_CONSTRUCT, X, m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 0); + if(Shadow) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(!target) + target = m_creature->getVictim(); + + if(target) + Shadow->AI()->AttackStart(target); + } + } + SummonShadowsTimer = 60000; + }else SummonShadowsTimer -= diff; + + if(SummonDoomBlossomTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + float X = CalculateRandomLocation(target->GetPositionX(), 20); + float Y = CalculateRandomLocation(target->GetPositionY(), 20); + Creature* DoomBlossom = m_creature->SummonCreature(CREATURE_DOOM_BLOSSOM, X, Y, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); + if(DoomBlossom) + { + DoomBlossom->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoomBlossom->setFaction(m_creature->getFaction()); + DoomBlossom->AddThreat(target, 1.0f); + ((mob_doom_blossomAI*)DoomBlossom->AI())->SetTeronGUID(m_creature->GetGUID()); + ((mob_doom_blossomAI*)DoomBlossom->AI())->InCombat = true; + SetThreatList(DoomBlossom); + SummonDoomBlossomTimer = 35000; + } + } + }else SummonDoomBlossomTimer -= diff; + + if(IncinerateTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(!target) + target = m_creature->getVictim(); + + if(target) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SPECIAL1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SPECIAL1); + break; + case 1: + DoYell(SAY_SPECIAL2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SPECIAL2); + break; + } + DoCast(target, SPELL_INCINERATE); + IncinerateTimer = 20000 + rand()%31 * 1000; + } + }else IncinerateTimer -= diff; + + if(CrushingShadowsTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target && target->isAlive()) + DoCast(target, SPELL_CRUSHING_SHADOWS); + CrushingShadowsTimer = 10000 + rand()%16 * 1000; + }else CrushingShadowsTimer -= diff; + + /*** NOTE FOR FUTURE DEV: UNCOMMENT BELOW ONLY IF MIND CONTROL IS FULLY IMPLEMENTED **/ + /*if(ShadowOfDeathTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + + if(!target) + target = m_creature->getVictim(); + + if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) + { + DoCast(target, SPELL_SHADOW_OF_DEATH); + GhostGUID = target->GetGUID(); + ShadowOfDeathTimer = 30000; + SummonShadowsTimer = 53000; // Make it VERY close but slightly less so that we can check if the aura is still on the player + } + }else ShadowOfDeathTimer -= diff;*/ + + if(RandomYellTimer < diff) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SPELL1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SPELL1); + break; + case 1: + DoYell(SAY_SPELL2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SPELL2); + break; + } + RandomYellTimer = 50000 + rand()%51 * 1000; + }else RandomYellTimer -= diff; + + if(!m_creature->HasAura(SPELL_BERSERK, 0)) + if(EnrageTimer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + }else EnrageTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_doom_blossom(Creature *_Creature) +{ + return new mob_doom_blossomAI(_Creature); +} + +CreatureAI* GetAI_mob_shadowy_construct(Creature *_Creature) +{ + return new mob_shadowy_constructAI(_Creature); +} + +CreatureAI* GetAI_boss_teron_gorefiend(Creature *_Creature) +{ + return new boss_teron_gorefiendAI (_Creature); +} + +void AddSC_boss_teron_gorefiend() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "mob_doom_blossom"; + newscript->GetAI = GetAI_mob_doom_blossom; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_shadowy_construct"; + newscript->GetAI = GetAI_mob_shadowy_construct; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_teron_gorefiend"; + newscript->GetAI = GetAI_boss_teron_gorefiend; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp index 93d27c3d0d1..39d00f62cd1 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp @@ -1,435 +1,435 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Najentus -SD%Complete: 90 -SDComment: Using a creature workaround instead of a GO for Impaling Spine. -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -//Aggro -#define SAY_AGGRO "You will die, in the name of Lady Vashj!" -#define SOUND_AGGRO 11450 - -//Needle (Random) -#define SAY_NEEDLE1 "Stick around!" -#define SOUND_NEEDLE1 11451 - -#define SAY_NEEDLE2 "I'll deal with you later!" -#define SOUND_NEEDLE2 11452 - -//Slay -#define SAY_SLAY1 "Your success was short lived!" -#define SOUND_SLAY1 11455 - -#define SAY_SLAY2 "Time for you to go!" -#define SOUND_SLAY2 11456 - -//Special -#define SAY_SPECIAL1 "Bel'anen dal'lorei!" -#define SOUND_SPECIAL1 11453 - -#define SAY_SPECIAL2 "Blood will flow!" -#define SOUND_SPECIAL2 11454 - -//Enrage -#define SAY_ENRAGE "My patience has ran out! Die, DIE!" -#define SOUND_ENRAGE 11458 - -//Death -#define SAY_DEATH "Lord Illidan will... crush you." -#define SOUND_DEATH 11459 - -//Spells -#define SPELL_CRASHINGWAVE 40100 -#define SPELL_NEEDLE_SPINE 39835 -#define SPELL_NEEDLE_AOE 39968 -#define SPELL_TIDAL_BURST 39878 -#define SPELL_TIDAL_SHIELD 39872 // Not going to use this since Hurl Spine doesn't dispel it. -#define SPELL_IMPALING_SPINE 39837 -#define SPELL_CREATE_NAJENTUS_SPINE 39956 -#define SPELL_HURL_SPINE 39948 -#define SPELL_SHIELD_VISUAL 37136 -#define SPELL_BERSERK 45078 - -#define DISPLAYID_SPINE 7362 - -struct MANGOS_DLL_DECL mob_najentus_spineAI : public ScriptedAI -{ - mob_najentus_spineAI(Creature *c) : ScriptedAI(c) - { - Reset(); - } - - uint64 SpineVictimGUID; - - void Reset() { SpineVictimGUID = 0; } - - void SetSpineVictimGUID(uint64 guid){ SpineVictimGUID = guid; } - - void JustDied(Unit *killer) - { - // Make the killer have the Najentus Spine item to pierce Tidal Shield - if(killer) - killer->CastSpell(killer, SPELL_CREATE_NAJENTUS_SPINE, true); - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if(damage < m_creature->GetHealth()) return; - - // Remove the Impaling Spine DoT from whoever was affected - if(SpineVictimGUID) - { - Unit* victim = Unit::GetUnit((*m_creature), SpineVictimGUID); - if(victim && ((victim->HasAura(SPELL_IMPALING_SPINE, 0)) || (victim->HasAura(SPELL_IMPALING_SPINE, 1)) || (victim->HasAura(SPELL_IMPALING_SPINE, 2)))) - victim->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); - } - } - - void Aggro(Unit* who) {} - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - void UpdateAI(const uint32 diff) {} -}; - -struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI -{ - boss_najentusAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - uint32 CrashingWaveTimer; - uint32 NeedleSpineTimer; - uint32 EnrageTimer; - uint32 SpecialYellTimer; - uint32 TidalShieldTimer; - uint32 ImpalingSpineTimer; - uint32 CheckTimer; // This timer checks if Najentus is Tidal Shielded and if so, regens health. If not, sets IsShielded to false - uint32 DispelShieldTimer; // This shield is only supposed to last 30 seconds, but the SPELL_SHIELD_VISUAL lasts forever - - uint64 SpineTargetGUID; - uint64 SpineGUID; - - bool IsShielded; - - void Reset() - { - IsShielded = false; - - CrashingWaveTimer = 28000; - NeedleSpineTimer = 10000; - EnrageTimer = 480000; - SpecialYellTimer = 45000 + (rand()%76)*1000; - TidalShieldTimer = 60000; - ImpalingSpineTimer = 45000; - CheckTimer = 2000; - DispelShieldTimer = 30000; - - SpineTargetGUID = 0; - SpineGUID = 0; - - if(pInstance) - { - if(m_creature->isAlive()) - { - pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, NOT_STARTED); - ToggleGate(true); - } - else ToggleGate(false); - } - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - if(pInstance) - { - pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, DONE); - ToggleGate(false); - } - - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void ToggleGate(bool close) - { - if(GameObject* Gate = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_NAJENTUS_GATE))) - if(close) Gate->SetGoState(0); // Closed - else Gate->SetGoState(2); // Opened - } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if(IsShielded) - { - if(spell->Id == SPELL_HURL_SPINE) - { - if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) - m_creature->RemoveAurasDueToSpell(SPELL_SHIELD_VISUAL); - if(m_creature->HasAura(SPELL_TIDAL_SHIELD, 0)) - m_creature->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD); - DoCast(m_creature->getVictim(), SPELL_TIDAL_BURST); - IsShielded = false; - } - } - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if(IsShielded) - damage = 0; - } - - void Aggro(Unit *who) - { - if(pInstance) - pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, IN_PROGRESS); - - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - - DoZoneInCombat(); - } - - // This is a workaround since we cannot summon GameObjects at will. - // Instead, we create a custom creature on top of the player. - // When someone kills the creature, the killer gets the "Naj'entus Spine" item. - // This item is the only item that should be able to pierce Tidal Shield - void DoImpalingSpineWorkaround(Unit* target) - { - Creature* Spine = NULL; - Spine = m_creature->SummonCreature(500000, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 10000); - if(Spine) - { - Spine->setFaction(m_creature->getFaction()); - ((mob_najentus_spineAI*)Spine->AI())->SetSpineVictimGUID(target->GetGUID()); - SpineTargetGUID = target->GetGUID(); - } - } - - bool RemoveImpalingSpine(uint64 guid) - { - if(!IsShielded || guid == SpineTargetGUID) return false; - - if(SpineTargetGUID) - { - Unit* target = Unit::GetUnit((*m_creature), SpineTargetGUID); - if(target && target->HasAura(SPELL_IMPALING_SPINE, 0)) - { - target->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); - return true; - } - } - - return false; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(CheckTimer < diff) - { - // if(m_creature->HasAura(SPELL_TIDAL_SHIELD, 0)) - if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) - m_creature->SetHealth(m_creature->GetHealth() + (m_creature->GetMaxHealth()/100)); - else - IsShielded = false; - - CheckTimer = 2000; - }else CheckTimer -= diff; - - if(IsShielded) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - if(!m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) - DoCast(m_creature, SPELL_SHIELD_VISUAL); - if(DispelShieldTimer < diff) - { - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) - m_creature->RemoveAurasDueToSpell(SPELL_SHIELD_VISUAL); - IsShielded = false; - }else DispelShieldTimer -= diff; - - return; // Don't cast or do anything while Shielded - } - - // Crashing Wave - if(CrashingWaveTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CRASHINGWAVE); - CrashingWaveTimer = 28500; - }else CrashingWaveTimer -= diff; - - if(!m_creature->HasAura(SPELL_BERSERK, 0)) - if(EnrageTimer < diff) - { - DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - DoCast(m_creature, SPELL_BERSERK); - }else EnrageTimer -= diff; - - // Needle - if(NeedleSpineTimer < diff) - { - for(uint8 i = 0; i < 3; ++i) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(!target) - target = m_creature->getVictim(); - - DoCast(target, SPELL_NEEDLE_AOE, true); - DoCast(target, SPELL_NEEDLE_SPINE); - } - - NeedleSpineTimer = 60000; - }else NeedleSpineTimer -= diff; - - if(SpecialYellTimer < diff) - { - switch(rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_SPECIAL1); - break; - case 1: - DoYell(SAY_SPECIAL2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SPECIAL2); - break; - } - SpecialYellTimer = 25000 + (rand()%76)*1000; - }else SpecialYellTimer -= diff; - - if(ImpalingSpineTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(!target) - target = m_creature->getVictim(); - - if(target && (target->GetTypeId() == TYPEID_PLAYER)) - { - DoCast(target, SPELL_IMPALING_SPINE); - //DoImpalingSpineWorkaround(target); - SpineTargetGUID = target->GetGUID(); - ImpalingSpineTimer = 45000; - - switch(rand()%2) - { - case 0: - DoYell(SAY_NEEDLE1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_NEEDLE1); - break; - case 1: - DoYell(SAY_NEEDLE2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_NEEDLE2); - break; - } - } - }else ImpalingSpineTimer -= diff; - - if(TidalShieldTimer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature, SPELL_SHIELD_VISUAL, true); - // DoCast(m_creature, SPELL_TIDAL_SHIELD); - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - IsShielded = true; - TidalShieldTimer = 60000; - CheckTimer = 2000; - DispelShieldTimer = 30000; - }else TidalShieldTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -bool GOHello_go_najentus_spine(Player *player, GameObject* _GO) -{ - ScriptedInstance* pInstance = ((ScriptedInstance*)_GO->GetInstanceData()); - if(pInstance) - { - uint64 NajentusGUID = pInstance->GetData64(DATA_HIGHWARLORDNAJENTUS); - if(NajentusGUID) - { - Creature* Najentus = ((Creature*)Unit::GetUnit((*_GO), NajentusGUID)); - if(Najentus) - { - if(((boss_najentusAI*)Najentus->AI())->RemoveImpalingSpine(player->GetGUID())) - return true; - }else error_log("ERROR: Na'entus Spine GameObject unable to find Naj'entus"); - }else error_log("ERROR: Invalid GUID acquired for Naj'entus by Naj'entus Spine GameObject"); - } - else error_log("ERROR: Naj'entus Spine spawned in invalid instance or location"); - - return true; -} - -CreatureAI* GetAI_mob_najentus_spine(Creature *_Creature) -{ - return new mob_najentus_spineAI (_Creature); -} - -CreatureAI* GetAI_boss_najentus(Creature *_Creature) -{ - return new boss_najentusAI (_Creature); -} - -void AddSC_boss_najentus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_najentus"; - newscript->GetAI = GetAI_boss_najentus; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_najentus_spine"; - newscript->GetAI = GetAI_mob_najentus_spine; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "go_najentus_spine"; - newscript->pGOHello = &GOHello_go_najentus_spine; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Najentus +SD%Complete: 90 +SDComment: Using a creature workaround instead of a GO for Impaling Spine. +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +//Aggro +#define SAY_AGGRO "You will die, in the name of Lady Vashj!" +#define SOUND_AGGRO 11450 + +//Needle (Random) +#define SAY_NEEDLE1 "Stick around!" +#define SOUND_NEEDLE1 11451 + +#define SAY_NEEDLE2 "I'll deal with you later!" +#define SOUND_NEEDLE2 11452 + +//Slay +#define SAY_SLAY1 "Your success was short lived!" +#define SOUND_SLAY1 11455 + +#define SAY_SLAY2 "Time for you to go!" +#define SOUND_SLAY2 11456 + +//Special +#define SAY_SPECIAL1 "Bel'anen dal'lorei!" +#define SOUND_SPECIAL1 11453 + +#define SAY_SPECIAL2 "Blood will flow!" +#define SOUND_SPECIAL2 11454 + +//Enrage +#define SAY_ENRAGE "My patience has ran out! Die, DIE!" +#define SOUND_ENRAGE 11458 + +//Death +#define SAY_DEATH "Lord Illidan will... crush you." +#define SOUND_DEATH 11459 + +//Spells +#define SPELL_CRASHINGWAVE 40100 +#define SPELL_NEEDLE_SPINE 39835 +#define SPELL_NEEDLE_AOE 39968 +#define SPELL_TIDAL_BURST 39878 +#define SPELL_TIDAL_SHIELD 39872 // Not going to use this since Hurl Spine doesn't dispel it. +#define SPELL_IMPALING_SPINE 39837 +#define SPELL_CREATE_NAJENTUS_SPINE 39956 +#define SPELL_HURL_SPINE 39948 +#define SPELL_SHIELD_VISUAL 37136 +#define SPELL_BERSERK 45078 + +#define DISPLAYID_SPINE 7362 + +struct MANGOS_DLL_DECL mob_najentus_spineAI : public ScriptedAI +{ + mob_najentus_spineAI(Creature *c) : ScriptedAI(c) + { + Reset(); + } + + uint64 SpineVictimGUID; + + void Reset() { SpineVictimGUID = 0; } + + void SetSpineVictimGUID(uint64 guid){ SpineVictimGUID = guid; } + + void JustDied(Unit *killer) + { + // Make the killer have the Najentus Spine item to pierce Tidal Shield + if(killer) + killer->CastSpell(killer, SPELL_CREATE_NAJENTUS_SPINE, true); + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if(damage < m_creature->GetHealth()) return; + + // Remove the Impaling Spine DoT from whoever was affected + if(SpineVictimGUID) + { + Unit* victim = Unit::GetUnit((*m_creature), SpineVictimGUID); + if(victim && ((victim->HasAura(SPELL_IMPALING_SPINE, 0)) || (victim->HasAura(SPELL_IMPALING_SPINE, 1)) || (victim->HasAura(SPELL_IMPALING_SPINE, 2)))) + victim->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); + } + } + + void Aggro(Unit* who) {} + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) {} +}; + +struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI +{ + boss_najentusAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + uint32 CrashingWaveTimer; + uint32 NeedleSpineTimer; + uint32 EnrageTimer; + uint32 SpecialYellTimer; + uint32 TidalShieldTimer; + uint32 ImpalingSpineTimer; + uint32 CheckTimer; // This timer checks if Najentus is Tidal Shielded and if so, regens health. If not, sets IsShielded to false + uint32 DispelShieldTimer; // This shield is only supposed to last 30 seconds, but the SPELL_SHIELD_VISUAL lasts forever + + uint64 SpineTargetGUID; + uint64 SpineGUID; + + bool IsShielded; + + void Reset() + { + IsShielded = false; + + CrashingWaveTimer = 28000; + NeedleSpineTimer = 10000; + EnrageTimer = 480000; + SpecialYellTimer = 45000 + (rand()%76)*1000; + TidalShieldTimer = 60000; + ImpalingSpineTimer = 45000; + CheckTimer = 2000; + DispelShieldTimer = 30000; + + SpineTargetGUID = 0; + SpineGUID = 0; + + if(pInstance) + { + if(m_creature->isAlive()) + { + pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, NOT_STARTED); + ToggleGate(true); + } + else ToggleGate(false); + } + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + if(pInstance) + { + pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, DONE); + ToggleGate(false); + } + + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void ToggleGate(bool close) + { + if(GameObject* Gate = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_NAJENTUS_GATE))) + if(close) Gate->SetGoState(0); // Closed + else Gate->SetGoState(2); // Opened + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if(IsShielded) + { + if(spell->Id == SPELL_HURL_SPINE) + { + if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) + m_creature->RemoveAurasDueToSpell(SPELL_SHIELD_VISUAL); + if(m_creature->HasAura(SPELL_TIDAL_SHIELD, 0)) + m_creature->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD); + DoCast(m_creature->getVictim(), SPELL_TIDAL_BURST); + IsShielded = false; + } + } + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if(IsShielded) + damage = 0; + } + + void Aggro(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, IN_PROGRESS); + + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + + DoZoneInCombat(); + } + + // This is a workaround since we cannot summon GameObjects at will. + // Instead, we create a custom creature on top of the player. + // When someone kills the creature, the killer gets the "Naj'entus Spine" item. + // This item is the only item that should be able to pierce Tidal Shield + void DoImpalingSpineWorkaround(Unit* target) + { + Creature* Spine = NULL; + Spine = m_creature->SummonCreature(500000, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 10000); + if(Spine) + { + Spine->setFaction(m_creature->getFaction()); + ((mob_najentus_spineAI*)Spine->AI())->SetSpineVictimGUID(target->GetGUID()); + SpineTargetGUID = target->GetGUID(); + } + } + + bool RemoveImpalingSpine(uint64 guid) + { + if(!IsShielded || guid == SpineTargetGUID) return false; + + if(SpineTargetGUID) + { + Unit* target = Unit::GetUnit((*m_creature), SpineTargetGUID); + if(target && target->HasAura(SPELL_IMPALING_SPINE, 0)) + { + target->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); + return true; + } + } + + return false; + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(CheckTimer < diff) + { + // if(m_creature->HasAura(SPELL_TIDAL_SHIELD, 0)) + if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) + m_creature->SetHealth(m_creature->GetHealth() + (m_creature->GetMaxHealth()/100)); + else + IsShielded = false; + + CheckTimer = 2000; + }else CheckTimer -= diff; + + if(IsShielded) + { + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + if(!m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) + DoCast(m_creature, SPELL_SHIELD_VISUAL); + if(DispelShieldTimer < diff) + { + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) + m_creature->RemoveAurasDueToSpell(SPELL_SHIELD_VISUAL); + IsShielded = false; + }else DispelShieldTimer -= diff; + + return; // Don't cast or do anything while Shielded + } + + // Crashing Wave + if(CrashingWaveTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CRASHINGWAVE); + CrashingWaveTimer = 28500; + }else CrashingWaveTimer -= diff; + + if(!m_creature->HasAura(SPELL_BERSERK, 0)) + if(EnrageTimer < diff) + { + DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + DoCast(m_creature, SPELL_BERSERK); + }else EnrageTimer -= diff; + + // Needle + if(NeedleSpineTimer < diff) + { + for(uint8 i = 0; i < 3; ++i) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(!target) + target = m_creature->getVictim(); + + DoCast(target, SPELL_NEEDLE_AOE, true); + DoCast(target, SPELL_NEEDLE_SPINE); + } + + NeedleSpineTimer = 60000; + }else NeedleSpineTimer -= diff; + + if(SpecialYellTimer < diff) + { + switch(rand()%2) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_SPECIAL1); + break; + case 1: + DoYell(SAY_SPECIAL2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SPECIAL2); + break; + } + SpecialYellTimer = 25000 + (rand()%76)*1000; + }else SpecialYellTimer -= diff; + + if(ImpalingSpineTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(!target) + target = m_creature->getVictim(); + + if(target && (target->GetTypeId() == TYPEID_PLAYER)) + { + DoCast(target, SPELL_IMPALING_SPINE); + //DoImpalingSpineWorkaround(target); + SpineTargetGUID = target->GetGUID(); + ImpalingSpineTimer = 45000; + + switch(rand()%2) + { + case 0: + DoYell(SAY_NEEDLE1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_NEEDLE1); + break; + case 1: + DoYell(SAY_NEEDLE2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_NEEDLE2); + break; + } + } + }else ImpalingSpineTimer -= diff; + + if(TidalShieldTimer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_SHIELD_VISUAL, true); + // DoCast(m_creature, SPELL_TIDAL_SHIELD); + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + IsShielded = true; + TidalShieldTimer = 60000; + CheckTimer = 2000; + DispelShieldTimer = 30000; + }else TidalShieldTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +bool GOHello_go_najentus_spine(Player *player, GameObject* _GO) +{ + ScriptedInstance* pInstance = ((ScriptedInstance*)_GO->GetInstanceData()); + if(pInstance) + { + uint64 NajentusGUID = pInstance->GetData64(DATA_HIGHWARLORDNAJENTUS); + if(NajentusGUID) + { + Creature* Najentus = ((Creature*)Unit::GetUnit((*_GO), NajentusGUID)); + if(Najentus) + { + if(((boss_najentusAI*)Najentus->AI())->RemoveImpalingSpine(player->GetGUID())) + return true; + }else error_log("ERROR: Na'entus Spine GameObject unable to find Naj'entus"); + }else error_log("ERROR: Invalid GUID acquired for Naj'entus by Naj'entus Spine GameObject"); + } + else error_log("ERROR: Naj'entus Spine spawned in invalid instance or location"); + + return true; +} + +CreatureAI* GetAI_mob_najentus_spine(Creature *_Creature) +{ + return new mob_najentus_spineAI (_Creature); +} + +CreatureAI* GetAI_boss_najentus(Creature *_Creature) +{ + return new boss_najentusAI (_Creature); +} + +void AddSC_boss_najentus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_najentus"; + newscript->GetAI = GetAI_boss_najentus; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_najentus_spine"; + newscript->GetAI = GetAI_mob_najentus_spine; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "go_najentus_spine"; + newscript->pGOHello = &GOHello_go_najentus_spine; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/def_black_temple.h b/src/bindings/scripts/scripts/zone/black_temple/def_black_temple.h index 53e099f7835..3b48c6f7755 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/def_black_temple.h +++ b/src/bindings/scripts/scripts/zone/black_temple/def_black_temple.h @@ -1,34 +1,34 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_BLACK_TEMPLE_H -#define DEF_BLACK_TEMPLE_H - -#define DATA_AKAMA 1 -#define DATA_AKAMA_SHADE 2 -#define DATA_GURTOGGBLOODBOILEVENT 3 -#define DATA_HIGHWARLORDNAJENTUS 4 -#define DATA_HIGHWARLORDNAJENTUSEVENT 5 -#define DATA_ILLIDANSTORMRAGE 6 -#define DATA_ILLIDANSTORMRAGEEVENT 7 -#define DATA_ILLIDARICOUNCILEVENT 8 -#define DATA_ILLIDARICOUNCIL 9 -#define DATA_LADYMALANDE 10 -#define DATA_HIGHNETHERMANCERZEREVOR 11 -#define DATA_GATHIOSTHESHATTERER 12 -#define DATA_VERASDARKSHADOW 13 -#define DATA_MOTHERSHAHRAZEVENT 14 -#define DATA_RELIQUARYOFSOULSEVENT 15 -#define DATA_SHADEOFAKAMA 16 -#define DATA_SHADEOFAKAMAEVENT 17 -#define DATA_SUPREMUS 18 -#define DATA_SUPREMUSEVENT 19 -#define DATA_TERONGOREFIENDEVENT 20 -#define DATA_GAMEOBJECT_NAJENTUS_GATE 21 -#define DATA_GAMEOBJECT_ILLIDAN_GATE 22 -#define DATA_GAMEOBJECT_ILLIDAN_DOOR_R 23 -#define DATA_GAMEOBJECT_ILLIDAN_DOOR_L 24 -#define DATA_GAMEOBJECT_SUPREMUS_DOORS 25 -#define DATA_BLOOD_ELF_COUNCIL_VOICE 26 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_BLACK_TEMPLE_H +#define DEF_BLACK_TEMPLE_H + +#define DATA_AKAMA 1 +#define DATA_AKAMA_SHADE 2 +#define DATA_GURTOGGBLOODBOILEVENT 3 +#define DATA_HIGHWARLORDNAJENTUS 4 +#define DATA_HIGHWARLORDNAJENTUSEVENT 5 +#define DATA_ILLIDANSTORMRAGE 6 +#define DATA_ILLIDANSTORMRAGEEVENT 7 +#define DATA_ILLIDARICOUNCILEVENT 8 +#define DATA_ILLIDARICOUNCIL 9 +#define DATA_LADYMALANDE 10 +#define DATA_HIGHNETHERMANCERZEREVOR 11 +#define DATA_GATHIOSTHESHATTERER 12 +#define DATA_VERASDARKSHADOW 13 +#define DATA_MOTHERSHAHRAZEVENT 14 +#define DATA_RELIQUARYOFSOULSEVENT 15 +#define DATA_SHADEOFAKAMA 16 +#define DATA_SHADEOFAKAMAEVENT 17 +#define DATA_SUPREMUS 18 +#define DATA_SUPREMUSEVENT 19 +#define DATA_TERONGOREFIENDEVENT 20 +#define DATA_GAMEOBJECT_NAJENTUS_GATE 21 +#define DATA_GAMEOBJECT_ILLIDAN_GATE 22 +#define DATA_GAMEOBJECT_ILLIDAN_DOOR_R 23 +#define DATA_GAMEOBJECT_ILLIDAN_DOOR_L 24 +#define DATA_GAMEOBJECT_SUPREMUS_DOORS 25 +#define DATA_BLOOD_ELF_COUNCIL_VOICE 26 +#endif diff --git a/src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp b/src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp index 4169f1d764f..e080b5c4c61 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp @@ -1,885 +1,885 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Illidari_Council -SD%Complete: 95 -SDComment: Circle of Healing not working properly. -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -// 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 - -//Speech'n'Sounds -#define SAY_GATH_AGGRO "I have better things to do!" -#define SOUND_GATH_AGGRO 11422 -#define SAY_GATH_SLAY "Selama am'oronor!" -#define SOUND_GATH_SLAY 11423 -#define SAY_GATH_COMNT "Well done!" -#define SOUND_GATH_COMNT 11424 -#define SAY_GATH_DEATH "Lord Illidan... I..." -#define SOUND_GATH_DEATH 11425 -#define SAY_GATH_SPECIAL1 "Enjoy your final moments!" -#define SOUND_GATH_SPECIAL1 11426 -#define SAY_GATH_SPECIAL2 "You are mine!" -#define SOUND_GATH_SPECIAL2 11427 - -#define SAY_MALA_AGGRO "Flee, or die!" -#define SOUND_MALA_AGGRO 11482 -#define SAY_MALA_SLAY "My work is done." -#define SOUND_MALA_SLAY 11483 -#define SAY_MALA_COMNT "As it should be!" -#define SOUND_MALA_COMNT 11484 -#define SAY_MALA_DEATH "Destiny... awaits." -#define SOUND_MALA_DEATH 11485 -#define SAY_MALA_SPECIAL1 "No second chances!" -#define SOUND_MALA_SPECIAL1 11486 -#define SAY_MALA_SPECIAL2 "I'm full of surprises!" -#define SOUND_MALA_SPECIAL2 11487 - -#define SAY_ZERE_AGGRO "Common... such a crude language. Bandal!" -#define SOUND_ZERE_AGGRO 11440 -#define SAY_ZERE_SLAY "Shorel'aran." -#define SOUND_ZERE_SLAY 11441 -#define SAY_ZERE_COMNT "Belesa menoor!" -#define SOUND_ZERE_COMNT 11442 -#define SAY_ZERE_DEATH "Diel ma'ahn... oreindel'o" -#define SOUND_ZERE_DEATH 11443 -#define SAY_ZERE_SPECIAL1 "Diel fin'al" -#define SOUND_ZERE_SPECIAL1 11444 -#define SAY_ZERE_SPECIAL2 "Sha'amoor ara mashal?" -#define SOUND_ZERE_SPECIAL2 11445 - -#define SAY_VERA_AGGRO "You wish to test me?" -#define SOUND_VERA_AGGRO 11524 -#define SAY_VERA_SLAY "Valiant effort!" -#define SOUND_VERA_SLAY 11525 -#define SAY_VERA_COMNT "A glorious kill!" -#define SOUND_VERA_COMNT 11526 -#define SAY_VERA_DEATH "You got lucky!" -#define SOUND_VERA_DEATH 11527 -#define SAY_VERA_SPECIAL1 "You're not caught up for this!" -#define SOUND_VERA_SPECIAL1 11528 -#define SAY_VERA_SPECIAL2 "Anar'alah belore!" -#define SOUND_VERA_SPECIAL2 11529 - -#define ERROR_INST_DATA "SD2 ERROR: Instance Data for Black Temple not set properly; Illidari Council event will not function properly." - -struct CouncilYells -{ - char* text; - uint32 soundId, timer; -}; - -static CouncilYells CouncilAggro[]= -{ - {"I have better things to do!", 11422, 5000}, // Gathios - {"You wish to test me?", 11524, 5500}, // Veras - {"Flee, or die!", 11482, 5000}, // Malande - {"Common... such a crude language. Bandal!", 11440, 0}, // Zerevor -}; - -// Need to get proper timers for this later -static CouncilYells CouncilEnrage[]= -{ - {"Enough games!", 11428, 2000}, // Gathios - {"You wish to kill me? Hahaha, you first!", 11530, 6000},//Veras - {"For Quel'Thalas! For the Sunwell!", 11488, 5000}, // Malande - {"Sha'amoor sine menoor!", 11446, 0}, // Zerevor -}; - -struct MANGOS_DLL_DECL mob_blood_elf_council_voice_triggerAI : public ScriptedAI -{ - mob_blood_elf_council_voice_triggerAI(Creature* c) : ScriptedAI(c) - { - for(uint8 i = 0; i < 4; ++i) - Council[i] = 0; - Reset(); - } - - uint64 Council[4]; - - uint32 EnrageTimer; - uint32 AggroYellTimer; - - uint8 YellCounter; // Serves as the counter for both the aggro and enrage yells - - bool EventStarted; - - void Reset() - { - EnrageTimer = 900000; // 15 minutes - AggroYellTimer = 500; - - YellCounter = 0; - - EventStarted = false; - } - - // finds and stores the GUIDs for each Council member using instance data system. - void LoadCouncilGUIDs() - { - 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); - } - - void Aggro(Unit* who) {} - - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - - void UpdateAI(const uint32 diff) - { - if(!EventStarted) - return; - - if(YellCounter > 3) - return; - - if(AggroYellTimer) - if(AggroYellTimer <= diff) - { - if(Unit* pMember = Unit::GetUnit(*m_creature, Council[YellCounter])) - { - pMember->MonsterYell(CouncilAggro[YellCounter].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(pMember, CouncilAggro[YellCounter].soundId); - AggroYellTimer = CouncilAggro[YellCounter].timer; - } - ++YellCounter; - if(YellCounter > 3) - YellCounter = 0; // Reuse for Enrage Yells - }else AggroYellTimer -= diff; - - if(EnrageTimer) - if(EnrageTimer <= diff) - { - if(Unit* pMember = Unit::GetUnit(*m_creature, Council[YellCounter])) - { - pMember->CastSpell(pMember, SPELL_BERSERK, true); - pMember->MonsterYell(CouncilEnrage[YellCounter].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(pMember, CouncilEnrage[YellCounter].soundId); - EnrageTimer = CouncilEnrage[YellCounter].timer; - } - ++YellCounter; - }else EnrageTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL mob_illidari_councilAI : public ScriptedAI -{ - mob_illidari_councilAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - for(uint8 i = 0; i < 4; ++i) - Council[i] = 0; - - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 Council[4]; - - uint32 CheckTimer; - uint32 EndEventTimer; - - uint8 DeathCount; - - bool EventBegun; - - void Reset() - { - CheckTimer = 2000; - EndEventTimer = 0; - - DeathCount = 0; - - Creature* pMember = NULL; - for(uint8 i = 0; i < 4; ++i) - { - if(pMember = ((Creature*)Unit::GetUnit((*m_creature), Council[i]))) - { - if(!pMember->isAlive()) - { - pMember->RemoveCorpse(); - pMember->Respawn(); - } - pMember->AI()->EnterEvadeMode(); - } - } - - if(pInstance) - { - pInstance->SetData(DATA_ILLIDARICOUNCILEVENT, NOT_STARTED); - if(Creature* VoiceTrigger = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE)))) - VoiceTrigger->AI()->EnterEvadeMode(); - } - - EventBegun = false; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); - } - - void Aggro(Unit *who) {} - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - - void StartEvent(Unit *target) - { - if(!pInstance) return; - - if(target && target->isAlive()) - { - Council[0] = pInstance->GetData64(DATA_GATHIOSTHESHATTERER); - Council[1] = pInstance->GetData64(DATA_HIGHNETHERMANCERZEREVOR); - Council[2] = pInstance->GetData64(DATA_LADYMALANDE); - Council[3] = pInstance->GetData64(DATA_VERASDARKSHADOW); - - // Start the event for the Voice Trigger - if(Creature* VoiceTrigger = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE)))) - { - ((mob_blood_elf_council_voice_triggerAI*)VoiceTrigger->AI())->LoadCouncilGUIDs(); - ((mob_blood_elf_council_voice_triggerAI*)VoiceTrigger->AI())->EventStarted = true; - } - - for(uint8 i = 0; i < 4; ++i) - { - Unit* Member = NULL; - if(Council[i]) - { - Member = Unit::GetUnit((*m_creature), Council[i]); - if(Member && Member->isAlive()) - Member->AddThreat(target, 1.0f); - } - } - - pInstance->SetData(DATA_ILLIDARICOUNCILEVENT, IN_PROGRESS); - - EventBegun = true; - } - } - - void UpdateAI(const uint32 diff) - { - if(!EventBegun) return; - - if(EndEventTimer) - if(EndEventTimer <= diff) - { - if(DeathCount > 3) - { - if(pInstance) - { - if(Creature* VoiceTrigger = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE)))) - VoiceTrigger->DealDamage(VoiceTrigger, VoiceTrigger->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - pInstance->SetData(DATA_ILLIDARICOUNCILEVENT, DONE); - } - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - return; - } - - Creature* pMember = ((Creature*)Unit::GetUnit(*m_creature, Council[DeathCount])); - if(pMember && pMember->isAlive()) - pMember->DealDamage(pMember, pMember->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - ++DeathCount; - EndEventTimer = 1500; - }else EndEventTimer -= diff; - - if(CheckTimer) - if(CheckTimer <= diff) - { - uint8 EvadeCheck = 0; - for(uint8 i = 0; i < 4; ++i) - { - if(Council[i]) - { - if(Creature* Member = ((Creature*)Unit::GetUnit((*m_creature), Council[i]))) - { - // This is the evade/death check. - if(Member->isAlive() && !Member->SelectHostilTarget()) - ++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; - - } -}; - -struct MANGOS_DLL_DECL boss_illidari_councilAI : public ScriptedAI -{ - boss_illidari_councilAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - for(uint8 i = 0; i < 4; ++i) - Council[i] = 0; - LoadedGUIDs = false; - } - - uint64 Council[4]; - - ScriptedInstance* pInstance; - - bool LoadedGUIDs; - - void Aggro(Unit* who) - { - if(pInstance) - { - Creature* Controller = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_ILLIDARICOUNCIL))); - if(Controller) - ((mob_illidari_councilAI*)Controller->AI())->StartEvent(who); - } - else - { - error_log(ERROR_INST_DATA); - EnterEvadeMode(); - } - DoZoneInCombat(); - // 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(); - } - - void DamageTaken(Unit* done_by, uint32 &damage) - { - if(done_by == m_creature) - return; - - damage /= 4; - for(uint8 i = 0; i < 4; ++i) - { - if(Unit* pUnit = Unit::GetUnit(*m_creature, Council[i])) - if(pUnit != m_creature && damage < pUnit->GetHealth()) - pUnit->SetHealth(pUnit->GetHealth() - damage); - } - } - - void LoadGUIDs() - { - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - Council[0] = pInstance->GetData64(DATA_LADYMALANDE); - Council[1] = pInstance->GetData64(DATA_HIGHNETHERMANCERZEREVOR); - Council[2] = pInstance->GetData64(DATA_GATHIOSTHESHATTERER); - Council[3] = pInstance->GetData64(DATA_VERASDARKSHADOW); - - LoadedGUIDs = true; - } -}; - -struct MANGOS_DLL_DECL boss_gathios_the_shattererAI : public boss_illidari_councilAI -{ - boss_gathios_the_shattererAI(Creature *c) : boss_illidari_councilAI(c) { Reset(); } - - uint32 ConsecrationTimer; - uint32 HammerOfJusticeTimer; - uint32 SealTimer; - uint32 AuraTimer; - uint32 BlessingTimer; - - void Reset() - { - ConsecrationTimer = 40000; - HammerOfJusticeTimer = 10000; - SealTimer = 40000; - AuraTimer = 90000; - BlessingTimer = 60000; - } - - void KilledUnit(Unit *victim) - { - DoYell(SAY_GATH_SLAY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_GATH_SLAY); - } - - void JustDied(Unit *victim) - { - DoYell(SAY_GATH_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_GATH_DEATH); - } - - Unit* SelectCouncilMember() - { - Unit* pUnit = m_creature; - uint32 member = 0; // He chooses Lady Malande most often - - if(rand()%10 == 0) // But there is a chance he picks someone else. - member = urand(1, 3); - - if(member != 2) // No need to create another pointer to us using Unit::GetUnit - pUnit = Unit::GetUnit((*m_creature), Council[member]); - return pUnit; - } - - void CastAuraOnCouncil() - { - uint32 spellid = 0; - switch(rand()%2) - { - case 0: spellid = SPELL_DEVOTION_AURA; break; - case 1: spellid = SPELL_CHROMATIC_AURA; break; - } - for(uint8 i = 0; i < 4; ++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), Council[i]); - if(pUnit) - pUnit->CastSpell(pUnit, spellid, true, 0, 0, m_creature->GetGUID()); - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(BlessingTimer < diff) - { - if(Unit* pUnit = SelectCouncilMember()) - { - switch(rand()%2) - { - case 0: DoCast(pUnit, SPELL_BLESS_SPELLWARD); break; - case 1: DoCast(pUnit, SPELL_BLESS_PROTECTION); break; - } - } - BlessingTimer = 60000; - }else BlessingTimer -= diff; - - if(ConsecrationTimer < diff) - { - DoCast(m_creature, SPELL_CONSECRATION); - ConsecrationTimer = 40000; - }else ConsecrationTimer -= diff; - - if(HammerOfJusticeTimer < diff) - { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - { - // is in ~10-40 yd range - if(m_creature->GetDistance2d(target) > 10 && m_creature->GetDistance2d(target) < 40) - { - DoCast(target, SPELL_HAMMER_OF_JUSTICE); - HammerOfJusticeTimer = 20000; - } - } - }else HammerOfJusticeTimer -= diff; - - if(SealTimer < diff) - { - switch(rand()%2) - { - case 0: DoCast(m_creature, SPELL_SEAL_OF_COMMAND); break; - case 1: DoCast(m_creature, SPELL_SEAL_OF_BLOOD); break; - } - SealTimer = 40000; - }else SealTimer -= diff; - - if(AuraTimer < diff) - { - CastAuraOnCouncil(); - AuraTimer = 90000; - }else AuraTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_high_nethermancer_zerevorAI : public boss_illidari_councilAI -{ - boss_high_nethermancer_zerevorAI(Creature *c) : boss_illidari_councilAI(c) { Reset(); } - - uint32 BlizzardTimer; - uint32 FlamestrikeTimer; - uint32 ArcaneBoltTimer; - uint32 DampenMagicTimer; - uint32 Cooldown; - uint32 ArcaneExplosionTimer; - - void Reset() - { - BlizzardTimer = 30000 + rand()%61 * 1000; - FlamestrikeTimer = 30000 + rand()%61 * 1000; - ArcaneBoltTimer = 10000; - DampenMagicTimer = 2000; - ArcaneExplosionTimer = 14000; - Cooldown = 0; - } - - void KilledUnit(Unit *victim) - { - DoYell(SAY_ZERE_SLAY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_ZERE_SLAY); - } - - void JustDied(Unit *victim) - { - DoYell(SAY_ZERE_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_ZERE_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(Cooldown) - { - if(Cooldown < diff) Cooldown = 0; - else - { - Cooldown -= diff; - return; // Don't cast any other spells if global cooldown is still ticking - } - } - - if(DampenMagicTimer < diff) - { - DoCast(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) - { - DoCast(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); - Cooldown = 1000; - ArcaneExplosionTimer = 14000; - }else ArcaneExplosionTimer -= diff; - - if(ArcaneBoltTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ARCANE_BOLT); - ArcaneBoltTimer = 3000; - Cooldown = 2000; - }else ArcaneBoltTimer -= diff; - - if(BlizzardTimer < diff) - { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_BLIZZARD); - BlizzardTimer = 45000 + rand()%46 * 1000; - FlamestrikeTimer += 10000; - Cooldown = 1000; - } - }else BlizzardTimer -= diff; - - if(FlamestrikeTimer < diff) - { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_FLAMESTRIKE); - FlamestrikeTimer = 55000 + rand()%46 * 1000; - BlizzardTimer += 10000; - Cooldown = 2000; - } - }else FlamestrikeTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI -{ - boss_lady_malandeAI(Creature *c) : boss_illidari_councilAI(c) { Reset(); } - - uint32 EmpoweredSmiteTimer; - uint32 CircleOfHealingTimer; - uint32 DivineWrathTimer; - uint32 ReflectiveShieldTimer; - - void Reset() - { - EmpoweredSmiteTimer = 38000; - CircleOfHealingTimer = 20000; - DivineWrathTimer = 40000; - ReflectiveShieldTimer = 0; - } - - void KilledUnit(Unit *victim) - { - DoYell(SAY_MALA_SLAY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_MALA_SLAY); - } - - void JustDied(Unit *victim) - { - DoYell(SAY_MALA_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_MALA_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(EmpoweredSmiteTimer < diff) - { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_EMPOWERED_SMITE); - EmpoweredSmiteTimer = 38000; - } - }else EmpoweredSmiteTimer -= diff; - - if(CircleOfHealingTimer < diff) - { - //Currently bugged and puts Malande on the threatlist of the other council members. It also heals players. - //DoCast(m_creature, SPELL_CIRCLE_OF_HEALING); - CircleOfHealingTimer = 60000; - }else CircleOfHealingTimer -= diff; - - if(DivineWrathTimer < diff) - { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_DIVINE_WRATH); - DivineWrathTimer = 40000 + rand()%41 * 1000; - } - }else DivineWrathTimer -= diff; - - if(ReflectiveShieldTimer < diff) - { - DoCast(m_creature, SPELL_REFLECTIVE_SHIELD); - ReflectiveShieldTimer = 65000; - }else ReflectiveShieldTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_veras_darkshadowAI : public boss_illidari_councilAI -{ - boss_veras_darkshadowAI(Creature *c) : boss_illidari_councilAI(c) { Reset(); } - - uint64 EnvenomTargetGUID; - - uint32 DeadlyPoisonTimer; - uint32 VanishTimer; - uint32 AppearEnvenomTimer; - - bool HasVanished; - - void Reset() - { - EnvenomTargetGUID = 0; - - DeadlyPoisonTimer = 20000; - VanishTimer = 60000 + rand()%61 * 1000; - AppearEnvenomTimer = 150000; - - HasVanished = false; - m_creature->SetVisibility(VISIBILITY_ON); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void KilledUnit(Unit *victim) - { - DoYell(SAY_VERA_SLAY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_VERA_SLAY); - } - - void JustDied(Unit *victim) - { - DoYell(SAY_VERA_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_VERA_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(!HasVanished) - { - if(DeadlyPoisonTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_DEADLY_POISON); - DeadlyPoisonTimer = 15000 + rand()%31 * 1000; - }else DeadlyPoisonTimer -= diff; - - if(AppearEnvenomTimer < diff) // Cast Envenom. This is cast 4 seconds after Vanish is over - { - DoCast(m_creature->getVictim(), SPELL_ENVENOM); - AppearEnvenomTimer = 90000; - }else AppearEnvenomTimer -= diff; - - if(VanishTimer < diff) // Disappear and stop attacking, but follow a random unit - { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - { - 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); - } - }else VanishTimer -= diff; - - DoMeleeAttackIfReady(); - } - else - { - if(VanishTimer < diff) // Become attackable and poison current target - { - Unit* target = m_creature->getVictim(); - DoCast(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) - { - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - m_creature->SetVisibility(VISIBILITY_ON); - AppearEnvenomTimer = 6000; - }else AppearEnvenomTimer -= diff; - } - } -}; - -CreatureAI* GetAI_mob_blood_elf_council_voice_trigger(Creature* c) -{ - return new mob_blood_elf_council_voice_triggerAI(c); -} - -CreatureAI* GetAI_mob_illidari_council(Creature *_Creature) -{ - return new mob_illidari_councilAI (_Creature); -} - -CreatureAI* GetAI_boss_gathios_the_shatterer(Creature *_Creature) -{ - return new boss_gathios_the_shattererAI (_Creature); -} - -CreatureAI* GetAI_boss_lady_malande(Creature *_Creature) -{ - return new boss_lady_malandeAI (_Creature); -} - -CreatureAI* GetAI_boss_veras_darkshadow(Creature *_Creature) -{ - return new boss_veras_darkshadowAI (_Creature); -} - -CreatureAI* GetAI_boss_high_nethermancer_zerevor(Creature *_Creature) -{ - return new boss_high_nethermancer_zerevorAI (_Creature); -} - -void AddSC_boss_illidari_council() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_illidari_council"; - newscript->GetAI = GetAI_mob_illidari_council; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_blood_elf_council_voice_trigger"; - newscript->GetAI = GetAI_mob_blood_elf_council_voice_trigger; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_gathios_the_shatterer"; - newscript->GetAI = GetAI_boss_gathios_the_shatterer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_lady_malande"; - newscript->GetAI = GetAI_boss_lady_malande; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_veras_darkshadow"; - newscript->GetAI = GetAI_boss_veras_darkshadow; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_high_nethermancer_zerevor"; - newscript->GetAI = GetAI_boss_high_nethermancer_zerevor; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Illidari_Council +SD%Complete: 95 +SDComment: Circle of Healing not working properly. +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +// 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 + +//Speech'n'Sounds +#define SAY_GATH_AGGRO "I have better things to do!" +#define SOUND_GATH_AGGRO 11422 +#define SAY_GATH_SLAY "Selama am'oronor!" +#define SOUND_GATH_SLAY 11423 +#define SAY_GATH_COMNT "Well done!" +#define SOUND_GATH_COMNT 11424 +#define SAY_GATH_DEATH "Lord Illidan... I..." +#define SOUND_GATH_DEATH 11425 +#define SAY_GATH_SPECIAL1 "Enjoy your final moments!" +#define SOUND_GATH_SPECIAL1 11426 +#define SAY_GATH_SPECIAL2 "You are mine!" +#define SOUND_GATH_SPECIAL2 11427 + +#define SAY_MALA_AGGRO "Flee, or die!" +#define SOUND_MALA_AGGRO 11482 +#define SAY_MALA_SLAY "My work is done." +#define SOUND_MALA_SLAY 11483 +#define SAY_MALA_COMNT "As it should be!" +#define SOUND_MALA_COMNT 11484 +#define SAY_MALA_DEATH "Destiny... awaits." +#define SOUND_MALA_DEATH 11485 +#define SAY_MALA_SPECIAL1 "No second chances!" +#define SOUND_MALA_SPECIAL1 11486 +#define SAY_MALA_SPECIAL2 "I'm full of surprises!" +#define SOUND_MALA_SPECIAL2 11487 + +#define SAY_ZERE_AGGRO "Common... such a crude language. Bandal!" +#define SOUND_ZERE_AGGRO 11440 +#define SAY_ZERE_SLAY "Shorel'aran." +#define SOUND_ZERE_SLAY 11441 +#define SAY_ZERE_COMNT "Belesa menoor!" +#define SOUND_ZERE_COMNT 11442 +#define SAY_ZERE_DEATH "Diel ma'ahn... oreindel'o" +#define SOUND_ZERE_DEATH 11443 +#define SAY_ZERE_SPECIAL1 "Diel fin'al" +#define SOUND_ZERE_SPECIAL1 11444 +#define SAY_ZERE_SPECIAL2 "Sha'amoor ara mashal?" +#define SOUND_ZERE_SPECIAL2 11445 + +#define SAY_VERA_AGGRO "You wish to test me?" +#define SOUND_VERA_AGGRO 11524 +#define SAY_VERA_SLAY "Valiant effort!" +#define SOUND_VERA_SLAY 11525 +#define SAY_VERA_COMNT "A glorious kill!" +#define SOUND_VERA_COMNT 11526 +#define SAY_VERA_DEATH "You got lucky!" +#define SOUND_VERA_DEATH 11527 +#define SAY_VERA_SPECIAL1 "You're not caught up for this!" +#define SOUND_VERA_SPECIAL1 11528 +#define SAY_VERA_SPECIAL2 "Anar'alah belore!" +#define SOUND_VERA_SPECIAL2 11529 + +#define ERROR_INST_DATA "SD2 ERROR: Instance Data for Black Temple not set properly; Illidari Council event will not function properly." + +struct CouncilYells +{ + char* text; + uint32 soundId, timer; +}; + +static CouncilYells CouncilAggro[]= +{ + {"I have better things to do!", 11422, 5000}, // Gathios + {"You wish to test me?", 11524, 5500}, // Veras + {"Flee, or die!", 11482, 5000}, // Malande + {"Common... such a crude language. Bandal!", 11440, 0}, // Zerevor +}; + +// Need to get proper timers for this later +static CouncilYells CouncilEnrage[]= +{ + {"Enough games!", 11428, 2000}, // Gathios + {"You wish to kill me? Hahaha, you first!", 11530, 6000},//Veras + {"For Quel'Thalas! For the Sunwell!", 11488, 5000}, // Malande + {"Sha'amoor sine menoor!", 11446, 0}, // Zerevor +}; + +struct MANGOS_DLL_DECL mob_blood_elf_council_voice_triggerAI : public ScriptedAI +{ + mob_blood_elf_council_voice_triggerAI(Creature* c) : ScriptedAI(c) + { + for(uint8 i = 0; i < 4; ++i) + Council[i] = 0; + Reset(); + } + + uint64 Council[4]; + + uint32 EnrageTimer; + uint32 AggroYellTimer; + + uint8 YellCounter; // Serves as the counter for both the aggro and enrage yells + + bool EventStarted; + + void Reset() + { + EnrageTimer = 900000; // 15 minutes + AggroYellTimer = 500; + + YellCounter = 0; + + EventStarted = false; + } + + // finds and stores the GUIDs for each Council member using instance data system. + void LoadCouncilGUIDs() + { + 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); + } + + void Aggro(Unit* who) {} + + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if(!EventStarted) + return; + + if(YellCounter > 3) + return; + + if(AggroYellTimer) + if(AggroYellTimer <= diff) + { + if(Unit* pMember = Unit::GetUnit(*m_creature, Council[YellCounter])) + { + pMember->MonsterYell(CouncilAggro[YellCounter].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(pMember, CouncilAggro[YellCounter].soundId); + AggroYellTimer = CouncilAggro[YellCounter].timer; + } + ++YellCounter; + if(YellCounter > 3) + YellCounter = 0; // Reuse for Enrage Yells + }else AggroYellTimer -= diff; + + if(EnrageTimer) + if(EnrageTimer <= diff) + { + if(Unit* pMember = Unit::GetUnit(*m_creature, Council[YellCounter])) + { + pMember->CastSpell(pMember, SPELL_BERSERK, true); + pMember->MonsterYell(CouncilEnrage[YellCounter].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(pMember, CouncilEnrage[YellCounter].soundId); + EnrageTimer = CouncilEnrage[YellCounter].timer; + } + ++YellCounter; + }else EnrageTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL mob_illidari_councilAI : public ScriptedAI +{ + mob_illidari_councilAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + for(uint8 i = 0; i < 4; ++i) + Council[i] = 0; + + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 Council[4]; + + uint32 CheckTimer; + uint32 EndEventTimer; + + uint8 DeathCount; + + bool EventBegun; + + void Reset() + { + CheckTimer = 2000; + EndEventTimer = 0; + + DeathCount = 0; + + Creature* pMember = NULL; + for(uint8 i = 0; i < 4; ++i) + { + if(pMember = ((Creature*)Unit::GetUnit((*m_creature), Council[i]))) + { + if(!pMember->isAlive()) + { + pMember->RemoveCorpse(); + pMember->Respawn(); + } + pMember->AI()->EnterEvadeMode(); + } + } + + if(pInstance) + { + pInstance->SetData(DATA_ILLIDARICOUNCILEVENT, NOT_STARTED); + if(Creature* VoiceTrigger = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE)))) + VoiceTrigger->AI()->EnterEvadeMode(); + } + + EventBegun = false; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); + } + + void Aggro(Unit *who) {} + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + + void StartEvent(Unit *target) + { + if(!pInstance) return; + + if(target && target->isAlive()) + { + Council[0] = pInstance->GetData64(DATA_GATHIOSTHESHATTERER); + Council[1] = pInstance->GetData64(DATA_HIGHNETHERMANCERZEREVOR); + Council[2] = pInstance->GetData64(DATA_LADYMALANDE); + Council[3] = pInstance->GetData64(DATA_VERASDARKSHADOW); + + // Start the event for the Voice Trigger + if(Creature* VoiceTrigger = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE)))) + { + ((mob_blood_elf_council_voice_triggerAI*)VoiceTrigger->AI())->LoadCouncilGUIDs(); + ((mob_blood_elf_council_voice_triggerAI*)VoiceTrigger->AI())->EventStarted = true; + } + + for(uint8 i = 0; i < 4; ++i) + { + Unit* Member = NULL; + if(Council[i]) + { + Member = Unit::GetUnit((*m_creature), Council[i]); + if(Member && Member->isAlive()) + Member->AddThreat(target, 1.0f); + } + } + + pInstance->SetData(DATA_ILLIDARICOUNCILEVENT, IN_PROGRESS); + + EventBegun = true; + } + } + + void UpdateAI(const uint32 diff) + { + if(!EventBegun) return; + + if(EndEventTimer) + if(EndEventTimer <= diff) + { + if(DeathCount > 3) + { + if(pInstance) + { + if(Creature* VoiceTrigger = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE)))) + VoiceTrigger->DealDamage(VoiceTrigger, VoiceTrigger->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + pInstance->SetData(DATA_ILLIDARICOUNCILEVENT, DONE); + } + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + return; + } + + Creature* pMember = ((Creature*)Unit::GetUnit(*m_creature, Council[DeathCount])); + if(pMember && pMember->isAlive()) + pMember->DealDamage(pMember, pMember->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + ++DeathCount; + EndEventTimer = 1500; + }else EndEventTimer -= diff; + + if(CheckTimer) + if(CheckTimer <= diff) + { + uint8 EvadeCheck = 0; + for(uint8 i = 0; i < 4; ++i) + { + if(Council[i]) + { + if(Creature* Member = ((Creature*)Unit::GetUnit((*m_creature), Council[i]))) + { + // This is the evade/death check. + if(Member->isAlive() && !Member->SelectHostilTarget()) + ++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; + + } +}; + +struct MANGOS_DLL_DECL boss_illidari_councilAI : public ScriptedAI +{ + boss_illidari_councilAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + for(uint8 i = 0; i < 4; ++i) + Council[i] = 0; + LoadedGUIDs = false; + } + + uint64 Council[4]; + + ScriptedInstance* pInstance; + + bool LoadedGUIDs; + + void Aggro(Unit* who) + { + if(pInstance) + { + Creature* Controller = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_ILLIDARICOUNCIL))); + if(Controller) + ((mob_illidari_councilAI*)Controller->AI())->StartEvent(who); + } + else + { + error_log(ERROR_INST_DATA); + EnterEvadeMode(); + } + DoZoneInCombat(); + // 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(); + } + + void DamageTaken(Unit* done_by, uint32 &damage) + { + if(done_by == m_creature) + return; + + damage /= 4; + for(uint8 i = 0; i < 4; ++i) + { + if(Unit* pUnit = Unit::GetUnit(*m_creature, Council[i])) + if(pUnit != m_creature && damage < pUnit->GetHealth()) + pUnit->SetHealth(pUnit->GetHealth() - damage); + } + } + + void LoadGUIDs() + { + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + Council[0] = pInstance->GetData64(DATA_LADYMALANDE); + Council[1] = pInstance->GetData64(DATA_HIGHNETHERMANCERZEREVOR); + Council[2] = pInstance->GetData64(DATA_GATHIOSTHESHATTERER); + Council[3] = pInstance->GetData64(DATA_VERASDARKSHADOW); + + LoadedGUIDs = true; + } +}; + +struct MANGOS_DLL_DECL boss_gathios_the_shattererAI : public boss_illidari_councilAI +{ + boss_gathios_the_shattererAI(Creature *c) : boss_illidari_councilAI(c) { Reset(); } + + uint32 ConsecrationTimer; + uint32 HammerOfJusticeTimer; + uint32 SealTimer; + uint32 AuraTimer; + uint32 BlessingTimer; + + void Reset() + { + ConsecrationTimer = 40000; + HammerOfJusticeTimer = 10000; + SealTimer = 40000; + AuraTimer = 90000; + BlessingTimer = 60000; + } + + void KilledUnit(Unit *victim) + { + DoYell(SAY_GATH_SLAY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_GATH_SLAY); + } + + void JustDied(Unit *victim) + { + DoYell(SAY_GATH_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_GATH_DEATH); + } + + Unit* SelectCouncilMember() + { + Unit* pUnit = m_creature; + uint32 member = 0; // He chooses Lady Malande most often + + if(rand()%10 == 0) // But there is a chance he picks someone else. + member = urand(1, 3); + + if(member != 2) // No need to create another pointer to us using Unit::GetUnit + pUnit = Unit::GetUnit((*m_creature), Council[member]); + return pUnit; + } + + void CastAuraOnCouncil() + { + uint32 spellid = 0; + switch(rand()%2) + { + case 0: spellid = SPELL_DEVOTION_AURA; break; + case 1: spellid = SPELL_CHROMATIC_AURA; break; + } + for(uint8 i = 0; i < 4; ++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), Council[i]); + if(pUnit) + pUnit->CastSpell(pUnit, spellid, true, 0, 0, m_creature->GetGUID()); + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(BlessingTimer < diff) + { + if(Unit* pUnit = SelectCouncilMember()) + { + switch(rand()%2) + { + case 0: DoCast(pUnit, SPELL_BLESS_SPELLWARD); break; + case 1: DoCast(pUnit, SPELL_BLESS_PROTECTION); break; + } + } + BlessingTimer = 60000; + }else BlessingTimer -= diff; + + if(ConsecrationTimer < diff) + { + DoCast(m_creature, SPELL_CONSECRATION); + ConsecrationTimer = 40000; + }else ConsecrationTimer -= diff; + + if(HammerOfJusticeTimer < diff) + { + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + // is in ~10-40 yd range + if(m_creature->GetDistance2d(target) > 10 && m_creature->GetDistance2d(target) < 40) + { + DoCast(target, SPELL_HAMMER_OF_JUSTICE); + HammerOfJusticeTimer = 20000; + } + } + }else HammerOfJusticeTimer -= diff; + + if(SealTimer < diff) + { + switch(rand()%2) + { + case 0: DoCast(m_creature, SPELL_SEAL_OF_COMMAND); break; + case 1: DoCast(m_creature, SPELL_SEAL_OF_BLOOD); break; + } + SealTimer = 40000; + }else SealTimer -= diff; + + if(AuraTimer < diff) + { + CastAuraOnCouncil(); + AuraTimer = 90000; + }else AuraTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_high_nethermancer_zerevorAI : public boss_illidari_councilAI +{ + boss_high_nethermancer_zerevorAI(Creature *c) : boss_illidari_councilAI(c) { Reset(); } + + uint32 BlizzardTimer; + uint32 FlamestrikeTimer; + uint32 ArcaneBoltTimer; + uint32 DampenMagicTimer; + uint32 Cooldown; + uint32 ArcaneExplosionTimer; + + void Reset() + { + BlizzardTimer = 30000 + rand()%61 * 1000; + FlamestrikeTimer = 30000 + rand()%61 * 1000; + ArcaneBoltTimer = 10000; + DampenMagicTimer = 2000; + ArcaneExplosionTimer = 14000; + Cooldown = 0; + } + + void KilledUnit(Unit *victim) + { + DoYell(SAY_ZERE_SLAY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_ZERE_SLAY); + } + + void JustDied(Unit *victim) + { + DoYell(SAY_ZERE_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_ZERE_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(Cooldown) + { + if(Cooldown < diff) Cooldown = 0; + else + { + Cooldown -= diff; + return; // Don't cast any other spells if global cooldown is still ticking + } + } + + if(DampenMagicTimer < diff) + { + DoCast(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) + { + DoCast(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); + Cooldown = 1000; + ArcaneExplosionTimer = 14000; + }else ArcaneExplosionTimer -= diff; + + if(ArcaneBoltTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ARCANE_BOLT); + ArcaneBoltTimer = 3000; + Cooldown = 2000; + }else ArcaneBoltTimer -= diff; + + if(BlizzardTimer < diff) + { + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + DoCast(target, SPELL_BLIZZARD); + BlizzardTimer = 45000 + rand()%46 * 1000; + FlamestrikeTimer += 10000; + Cooldown = 1000; + } + }else BlizzardTimer -= diff; + + if(FlamestrikeTimer < diff) + { + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + DoCast(target, SPELL_FLAMESTRIKE); + FlamestrikeTimer = 55000 + rand()%46 * 1000; + BlizzardTimer += 10000; + Cooldown = 2000; + } + }else FlamestrikeTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI +{ + boss_lady_malandeAI(Creature *c) : boss_illidari_councilAI(c) { Reset(); } + + uint32 EmpoweredSmiteTimer; + uint32 CircleOfHealingTimer; + uint32 DivineWrathTimer; + uint32 ReflectiveShieldTimer; + + void Reset() + { + EmpoweredSmiteTimer = 38000; + CircleOfHealingTimer = 20000; + DivineWrathTimer = 40000; + ReflectiveShieldTimer = 0; + } + + void KilledUnit(Unit *victim) + { + DoYell(SAY_MALA_SLAY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_MALA_SLAY); + } + + void JustDied(Unit *victim) + { + DoYell(SAY_MALA_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_MALA_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(EmpoweredSmiteTimer < diff) + { + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + DoCast(target, SPELL_EMPOWERED_SMITE); + EmpoweredSmiteTimer = 38000; + } + }else EmpoweredSmiteTimer -= diff; + + if(CircleOfHealingTimer < diff) + { + //Currently bugged and puts Malande on the threatlist of the other council members. It also heals players. + //DoCast(m_creature, SPELL_CIRCLE_OF_HEALING); + CircleOfHealingTimer = 60000; + }else CircleOfHealingTimer -= diff; + + if(DivineWrathTimer < diff) + { + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + DoCast(target, SPELL_DIVINE_WRATH); + DivineWrathTimer = 40000 + rand()%41 * 1000; + } + }else DivineWrathTimer -= diff; + + if(ReflectiveShieldTimer < diff) + { + DoCast(m_creature, SPELL_REFLECTIVE_SHIELD); + ReflectiveShieldTimer = 65000; + }else ReflectiveShieldTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_veras_darkshadowAI : public boss_illidari_councilAI +{ + boss_veras_darkshadowAI(Creature *c) : boss_illidari_councilAI(c) { Reset(); } + + uint64 EnvenomTargetGUID; + + uint32 DeadlyPoisonTimer; + uint32 VanishTimer; + uint32 AppearEnvenomTimer; + + bool HasVanished; + + void Reset() + { + EnvenomTargetGUID = 0; + + DeadlyPoisonTimer = 20000; + VanishTimer = 60000 + rand()%61 * 1000; + AppearEnvenomTimer = 150000; + + HasVanished = false; + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void KilledUnit(Unit *victim) + { + DoYell(SAY_VERA_SLAY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_VERA_SLAY); + } + + void JustDied(Unit *victim) + { + DoYell(SAY_VERA_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_VERA_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(!HasVanished) + { + if(DeadlyPoisonTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_DEADLY_POISON); + DeadlyPoisonTimer = 15000 + rand()%31 * 1000; + }else DeadlyPoisonTimer -= diff; + + if(AppearEnvenomTimer < diff) // Cast Envenom. This is cast 4 seconds after Vanish is over + { + DoCast(m_creature->getVictim(), SPELL_ENVENOM); + AppearEnvenomTimer = 90000; + }else AppearEnvenomTimer -= diff; + + if(VanishTimer < diff) // Disappear and stop attacking, but follow a random unit + { + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + 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); + } + }else VanishTimer -= diff; + + DoMeleeAttackIfReady(); + } + else + { + if(VanishTimer < diff) // Become attackable and poison current target + { + Unit* target = m_creature->getVictim(); + DoCast(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) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_creature->SetVisibility(VISIBILITY_ON); + AppearEnvenomTimer = 6000; + }else AppearEnvenomTimer -= diff; + } + } +}; + +CreatureAI* GetAI_mob_blood_elf_council_voice_trigger(Creature* c) +{ + return new mob_blood_elf_council_voice_triggerAI(c); +} + +CreatureAI* GetAI_mob_illidari_council(Creature *_Creature) +{ + return new mob_illidari_councilAI (_Creature); +} + +CreatureAI* GetAI_boss_gathios_the_shatterer(Creature *_Creature) +{ + return new boss_gathios_the_shattererAI (_Creature); +} + +CreatureAI* GetAI_boss_lady_malande(Creature *_Creature) +{ + return new boss_lady_malandeAI (_Creature); +} + +CreatureAI* GetAI_boss_veras_darkshadow(Creature *_Creature) +{ + return new boss_veras_darkshadowAI (_Creature); +} + +CreatureAI* GetAI_boss_high_nethermancer_zerevor(Creature *_Creature) +{ + return new boss_high_nethermancer_zerevorAI (_Creature); +} + +void AddSC_boss_illidari_council() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_illidari_council"; + newscript->GetAI = GetAI_mob_illidari_council; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_blood_elf_council_voice_trigger"; + newscript->GetAI = GetAI_mob_blood_elf_council_voice_trigger; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_gathios_the_shatterer"; + newscript->GetAI = GetAI_boss_gathios_the_shatterer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_lady_malande"; + newscript->GetAI = GetAI_boss_lady_malande; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_veras_darkshadow"; + newscript->GetAI = GetAI_boss_veras_darkshadow; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_high_nethermancer_zerevor"; + newscript->GetAI = GetAI_boss_high_nethermancer_zerevor; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp b/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp index 3251c93cafa..07ad3b996fd 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp @@ -1,252 +1,252 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Black_Temple -SD%Complete: 100 -SDComment: Instance Data Scripts and functions to acquire mobs and set encounter status for use in various Black Temple Scripts -SDCategory: Black Temple -EndScriptData */ - -#include "precompiled.h" -#include "def_black_temple.h" - -#define ENCOUNTERS 9 - -/* Black Temple encounters: -0 - High Warlord Naj'entus event -1 - Supremus Event -2 - Shade of Akama Event -3 - Teron Gorefiend Event -4 - Gurtogg Bloodboil Event -5 - Reliquary Of Souls Event -6 - Mother Shahraz Event -7 - Illidari Council Event -8 - Illidan Stormrage Event -*/ - -struct MANGOS_DLL_DECL instance_black_temple : public ScriptedInstance -{ - instance_black_temple(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint64 Najentus; - uint64 Akama; // This is the Akama that starts the Illidan encounter. - uint64 Akama_Shade; // This is the Akama that starts the Shade of Akama encounter. - uint64 ShadeOfAkama; - uint64 Supremus; - uint64 LadyMalande; - uint64 GathiosTheShatterer; - uint64 HighNethermancerZerevor; - uint64 VerasDarkshadow; - uint64 IllidariCouncil; - uint64 BloodElfCouncilVoice; - uint64 IllidanStormrage; - - uint64 NajentusGate; - uint64 MainTempleDoors; - uint64 IllidanGate; - uint64 IllidanDoor[2]; - - uint32 Encounters[ENCOUNTERS]; - - void Initialize() - { - Najentus = 0; - Akama = 0; - Akama_Shade = 0; - ShadeOfAkama = 0; - Supremus = 0; - LadyMalande = 0; - GathiosTheShatterer = 0; - HighNethermancerZerevor = 0; - VerasDarkshadow = 0; - IllidariCouncil = 0; - BloodElfCouncilVoice = 0; - IllidanStormrage = 0; - - NajentusGate = 0; - MainTempleDoors = 0; - IllidanGate = 0; - IllidanDoor[0] = 0; - IllidanDoor[1] = 0; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounters[i] = NOT_STARTED; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; i++) - if(Encounters[i] == IN_PROGRESS) return true; - - return false; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case 22887: Najentus = creature->GetGUID(); break; - case 23089: Akama = creature->GetGUID(); break; - case 22990: Akama_Shade = creature->GetGUID(); break; - case 22841: ShadeOfAkama = creature->GetGUID(); break; - case 22898: Supremus = creature->GetGUID(); break; - case 22917: IllidanStormrage = creature->GetGUID(); break; - case 22949: GathiosTheShatterer = creature->GetGUID(); break; - case 22950: HighNethermancerZerevor = creature->GetGUID(); break; - case 22951: LadyMalande = creature->GetGUID(); break; - case 22952: VerasDarkshadow = creature->GetGUID(); break; - case 23426: IllidariCouncil = creature->GetGUID(); break; - case 23499: BloodElfCouncilVoice = creature->GetGUID(); break; - } - } - - void OnObjectCreate(GameObject* go) - { - switch(go->GetEntry()) - { - case 185483: // Gate past Naj'entus (at the entrance to Supermoose's courtyards) - NajentusGate = go->GetGUID(); - break; - case 185882: // Main Temple Doors - right past Supermoose (Supremus) - MainTempleDoors = go->GetGUID(); - break; - case 185905: // Gate leading to Temple Summit - IllidanGate = go->GetGUID(); - break; - case 186261: // Right door at Temple Summit - IllidanDoor[0] = go->GetGUID(); - break; - case 186262: // Left door at Temple Summit - IllidanDoor[1] = go->GetGUID(); - break; - } - } - - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_HIGHWARLORDNAJENTUS: return Najentus; - case DATA_AKAMA: return Akama; - case DATA_AKAMA_SHADE: return Akama_Shade; - case DATA_SHADEOFAKAMA: return ShadeOfAkama; - case DATA_SUPREMUS: return Supremus; - case DATA_ILLIDANSTORMRAGE: return IllidanStormrage; - case DATA_GATHIOSTHESHATTERER: return GathiosTheShatterer; - case DATA_HIGHNETHERMANCERZEREVOR: return HighNethermancerZerevor; - case DATA_LADYMALANDE: return LadyMalande; - case DATA_VERASDARKSHADOW: return VerasDarkshadow; - case DATA_ILLIDARICOUNCIL: return IllidariCouncil; - case DATA_GAMEOBJECT_NAJENTUS_GATE: return NajentusGate; - case DATA_GAMEOBJECT_ILLIDAN_GATE: return IllidanGate; - case DATA_GAMEOBJECT_ILLIDAN_DOOR_R: return IllidanDoor[0]; - case DATA_GAMEOBJECT_ILLIDAN_DOOR_L: return IllidanDoor[1]; - case DATA_GAMEOBJECT_SUPREMUS_DOORS: return MainTempleDoors; - case DATA_BLOOD_ELF_COUNCIL_VOICE: return BloodElfCouncilVoice; - } - - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_HIGHWARLORDNAJENTUSEVENT: Encounters[0] = data; break; - case DATA_SUPREMUSEVENT: Encounters[1] = data; break; - case DATA_SHADEOFAKAMAEVENT: Encounters[2] = data; break; - case DATA_TERONGOREFIENDEVENT: Encounters[3] = data; break; - case DATA_GURTOGGBLOODBOILEVENT: Encounters[4] = data; break; - case DATA_RELIQUARYOFSOULSEVENT: Encounters[5] = data; break; - case DATA_MOTHERSHAHRAZEVENT: Encounters[6] = data; break; - case DATA_ILLIDARICOUNCILEVENT: Encounters[7] = data; break; - case DATA_ILLIDANSTORMRAGEEVENT: Encounters[8] = data; break; - } - - if(data == DONE) - SaveToDB(); - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_HIGHWARLORDNAJENTUSEVENT: return Encounters[0]; - case DATA_SUPREMUSEVENT: return Encounters[1]; - case DATA_SHADEOFAKAMAEVENT: return Encounters[2]; - case DATA_TERONGOREFIENDEVENT: return Encounters[3]; - case DATA_GURTOGGBLOODBOILEVENT: return Encounters[4]; - case DATA_RELIQUARYOFSOULSEVENT: return Encounters[5]; - case DATA_MOTHERSHAHRAZEVENT: return Encounters[6]; - case DATA_ILLIDARICOUNCILEVENT: return Encounters[7]; - case DATA_ILLIDANSTORMRAGEEVENT: return Encounters[8]; - } - - return 0; - } - - const char* Save() - { - OUT_SAVE_INST_DATA; - std::ostringstream stream; - stream << Encounters[0] << " " << Encounters[1] << " " << Encounters[2] << " " - << Encounters[3] << " " << Encounters[4] << " " << Encounters[5] << " " - << Encounters[6] << " " << Encounters[7] << " " << Encounters[8]; - char* out = new char[stream.str().length() + 1]; - strcpy(out, stream.str().c_str()); - if(out) - { - OUT_SAVE_INST_DATA_COMPLETE; - return out; - } - - return NULL; - } - - void Load(const char* in) - { - if(!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); - std::istringstream stream(in); - stream >> Encounters[0] >> Encounters[1] >> Encounters[2] >> Encounters[3] - >> Encounters[4] >> Encounters[5] >> Encounters[6] >> Encounters[7] - >> Encounters[8]; - for(uint8 i = 0; i < ENCOUNTERS; ++i) - if(Encounters[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. - Encounters[i] = NOT_STARTED; - OUT_LOAD_INST_DATA_COMPLETE; - } -}; - -InstanceData* GetInstanceData_instance_black_temple(Map* map) -{ - return new instance_black_temple(map); -} - -void AddSC_instance_black_temple() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_black_temple"; - newscript->GetInstanceData = GetInstanceData_instance_black_temple; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Black_Temple +SD%Complete: 100 +SDComment: Instance Data Scripts and functions to acquire mobs and set encounter status for use in various Black Temple Scripts +SDCategory: Black Temple +EndScriptData */ + +#include "precompiled.h" +#include "def_black_temple.h" + +#define ENCOUNTERS 9 + +/* Black Temple encounters: +0 - High Warlord Naj'entus event +1 - Supremus Event +2 - Shade of Akama Event +3 - Teron Gorefiend Event +4 - Gurtogg Bloodboil Event +5 - Reliquary Of Souls Event +6 - Mother Shahraz Event +7 - Illidari Council Event +8 - Illidan Stormrage Event +*/ + +struct MANGOS_DLL_DECL instance_black_temple : public ScriptedInstance +{ + instance_black_temple(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint64 Najentus; + uint64 Akama; // This is the Akama that starts the Illidan encounter. + uint64 Akama_Shade; // This is the Akama that starts the Shade of Akama encounter. + uint64 ShadeOfAkama; + uint64 Supremus; + uint64 LadyMalande; + uint64 GathiosTheShatterer; + uint64 HighNethermancerZerevor; + uint64 VerasDarkshadow; + uint64 IllidariCouncil; + uint64 BloodElfCouncilVoice; + uint64 IllidanStormrage; + + uint64 NajentusGate; + uint64 MainTempleDoors; + uint64 IllidanGate; + uint64 IllidanDoor[2]; + + uint32 Encounters[ENCOUNTERS]; + + void Initialize() + { + Najentus = 0; + Akama = 0; + Akama_Shade = 0; + ShadeOfAkama = 0; + Supremus = 0; + LadyMalande = 0; + GathiosTheShatterer = 0; + HighNethermancerZerevor = 0; + VerasDarkshadow = 0; + IllidariCouncil = 0; + BloodElfCouncilVoice = 0; + IllidanStormrage = 0; + + NajentusGate = 0; + MainTempleDoors = 0; + IllidanGate = 0; + IllidanDoor[0] = 0; + IllidanDoor[1] = 0; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounters[i] = NOT_STARTED; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounters[i] == IN_PROGRESS) return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case 22887: Najentus = creature->GetGUID(); break; + case 23089: Akama = creature->GetGUID(); break; + case 22990: Akama_Shade = creature->GetGUID(); break; + case 22841: ShadeOfAkama = creature->GetGUID(); break; + case 22898: Supremus = creature->GetGUID(); break; + case 22917: IllidanStormrage = creature->GetGUID(); break; + case 22949: GathiosTheShatterer = creature->GetGUID(); break; + case 22950: HighNethermancerZerevor = creature->GetGUID(); break; + case 22951: LadyMalande = creature->GetGUID(); break; + case 22952: VerasDarkshadow = creature->GetGUID(); break; + case 23426: IllidariCouncil = creature->GetGUID(); break; + case 23499: BloodElfCouncilVoice = creature->GetGUID(); break; + } + } + + void OnObjectCreate(GameObject* go) + { + switch(go->GetEntry()) + { + case 185483: // Gate past Naj'entus (at the entrance to Supermoose's courtyards) + NajentusGate = go->GetGUID(); + break; + case 185882: // Main Temple Doors - right past Supermoose (Supremus) + MainTempleDoors = go->GetGUID(); + break; + case 185905: // Gate leading to Temple Summit + IllidanGate = go->GetGUID(); + break; + case 186261: // Right door at Temple Summit + IllidanDoor[0] = go->GetGUID(); + break; + case 186262: // Left door at Temple Summit + IllidanDoor[1] = go->GetGUID(); + break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_HIGHWARLORDNAJENTUS: return Najentus; + case DATA_AKAMA: return Akama; + case DATA_AKAMA_SHADE: return Akama_Shade; + case DATA_SHADEOFAKAMA: return ShadeOfAkama; + case DATA_SUPREMUS: return Supremus; + case DATA_ILLIDANSTORMRAGE: return IllidanStormrage; + case DATA_GATHIOSTHESHATTERER: return GathiosTheShatterer; + case DATA_HIGHNETHERMANCERZEREVOR: return HighNethermancerZerevor; + case DATA_LADYMALANDE: return LadyMalande; + case DATA_VERASDARKSHADOW: return VerasDarkshadow; + case DATA_ILLIDARICOUNCIL: return IllidariCouncil; + case DATA_GAMEOBJECT_NAJENTUS_GATE: return NajentusGate; + case DATA_GAMEOBJECT_ILLIDAN_GATE: return IllidanGate; + case DATA_GAMEOBJECT_ILLIDAN_DOOR_R: return IllidanDoor[0]; + case DATA_GAMEOBJECT_ILLIDAN_DOOR_L: return IllidanDoor[1]; + case DATA_GAMEOBJECT_SUPREMUS_DOORS: return MainTempleDoors; + case DATA_BLOOD_ELF_COUNCIL_VOICE: return BloodElfCouncilVoice; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_HIGHWARLORDNAJENTUSEVENT: Encounters[0] = data; break; + case DATA_SUPREMUSEVENT: Encounters[1] = data; break; + case DATA_SHADEOFAKAMAEVENT: Encounters[2] = data; break; + case DATA_TERONGOREFIENDEVENT: Encounters[3] = data; break; + case DATA_GURTOGGBLOODBOILEVENT: Encounters[4] = data; break; + case DATA_RELIQUARYOFSOULSEVENT: Encounters[5] = data; break; + case DATA_MOTHERSHAHRAZEVENT: Encounters[6] = data; break; + case DATA_ILLIDARICOUNCILEVENT: Encounters[7] = data; break; + case DATA_ILLIDANSTORMRAGEEVENT: Encounters[8] = data; break; + } + + if(data == DONE) + SaveToDB(); + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_HIGHWARLORDNAJENTUSEVENT: return Encounters[0]; + case DATA_SUPREMUSEVENT: return Encounters[1]; + case DATA_SHADEOFAKAMAEVENT: return Encounters[2]; + case DATA_TERONGOREFIENDEVENT: return Encounters[3]; + case DATA_GURTOGGBLOODBOILEVENT: return Encounters[4]; + case DATA_RELIQUARYOFSOULSEVENT: return Encounters[5]; + case DATA_MOTHERSHAHRAZEVENT: return Encounters[6]; + case DATA_ILLIDARICOUNCILEVENT: return Encounters[7]; + case DATA_ILLIDANSTORMRAGEEVENT: return Encounters[8]; + } + + return 0; + } + + const char* Save() + { + OUT_SAVE_INST_DATA; + std::ostringstream stream; + stream << Encounters[0] << " " << Encounters[1] << " " << Encounters[2] << " " + << Encounters[3] << " " << Encounters[4] << " " << Encounters[5] << " " + << Encounters[6] << " " << Encounters[7] << " " << Encounters[8]; + char* out = new char[stream.str().length() + 1]; + strcpy(out, stream.str().c_str()); + if(out) + { + OUT_SAVE_INST_DATA_COMPLETE; + return out; + } + + return NULL; + } + + void Load(const char* in) + { + if(!in) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(in); + std::istringstream stream(in); + stream >> Encounters[0] >> Encounters[1] >> Encounters[2] >> Encounters[3] + >> Encounters[4] >> Encounters[5] >> Encounters[6] >> Encounters[7] + >> Encounters[8]; + for(uint8 i = 0; i < ENCOUNTERS; ++i) + if(Encounters[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. + Encounters[i] = NOT_STARTED; + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_black_temple(Map* map) +{ + return new instance_black_temple(map); +} + +void AddSC_instance_black_temple() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_black_temple"; + newscript->GetInstanceData = GetInstanceData_instance_black_temple; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/blackrock_depths.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/blackrock_depths.cpp index b4b2b177f19..42409f1af35 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/blackrock_depths.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/blackrock_depths.cpp @@ -1,237 +1,237 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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: 95 -SDComment: Quest support: 4001, 4342, 7604. Vendor Lokhtos Darkbargainer. -SDCategory: Blackrock Depths -EndScriptData */ - -/* ContentData -mob_phalanx -npc_kharan_mighthammer -npc_lokhtos_darkbargainer -EndContentData */ - -#include "precompiled.h" - -/*###### -## mob_phalanx -######*/ - -#define SPELL_THUNDERCLAP 8732 -#define SPELL_FIREBALLVOLLEY 22425 -#define SPELL_MIGHTYBLOW 14099 - -struct MANGOS_DLL_DECL mob_phalanxAI : public ScriptedAI -{ - mob_phalanxAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ThunderClap_Timer; - uint32 FireballVolley_Timer; - uint32 MightyBlow_Timer; - - void Reset() - { - ThunderClap_Timer = 12000; - FireballVolley_Timer =0; - MightyBlow_Timer = 15000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ThunderClap_Timer - if( ThunderClap_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); - ThunderClap_Timer = 10000; - }else ThunderClap_Timer -= diff; - - //FireballVolley_Timer - if( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) - { - if (FireballVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIREBALLVOLLEY); - FireballVolley_Timer = 15000; - }else FireballVolley_Timer -= diff; - } - - //MightyBlow_Timer - if( MightyBlow_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_MIGHTYBLOW); - MightyBlow_Timer = 10000; - }else MightyBlow_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_mob_phalanx(Creature *_Creature) -{ - return new mob_phalanxAI (_Creature); -} - -/*###### -## npc_kharan_mighthammer -######*/ - -#define QUEST_4001 4001 -#define QUEST_4342 4342 - -bool GossipHello_npc_kharan_mighthammer(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->GetQuestStatus(QUEST_4001) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM( 0, "I need to know where the princess are, Kharan!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - if( player->GetQuestStatus(4342) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM( 0, "All is not lost, Kharan!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - - if( player->GetTeam() == HORDE ) player->SEND_GOSSIP_MENU(2473, _Creature->GetGUID()); - if( player->GetTeam() == ALLIANCE ) player->SEND_GOSSIP_MENU(2474, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_kharan_mighthammer(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, "Gor'shak is my friend, you can trust me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(2475, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(0, "Not enough, you need to tell me more.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(2476, _Creature->GetGUID()); - break; - - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(0, "So what happened?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(2477, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(0, "Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(2478, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM(0, "So you suspect that someone on the inside was involved? That they were tipped off?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - player->SEND_GOSSIP_MENU(2479, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM(0, "Continue with your story please.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); - player->SEND_GOSSIP_MENU(2480, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - player->ADD_GOSSIP_ITEM(0, "Indeed.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+8); - player->SEND_GOSSIP_MENU(2481, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+8: - player->ADD_GOSSIP_ITEM(0, "The door is open, Kharan. You are a free man.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); - player->SEND_GOSSIP_MENU(2482, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+9: - player->CLOSE_GOSSIP_MENU(); - if( player->GetTeam() == HORDE ) player->AreaExploredOrEventHappens(QUEST_4001); - if( player->GetTeam() == ALLIANCE ) player->AreaExploredOrEventHappens(QUEST_4342); - break; - } - return true; -} - -/*###### -## npc_lokhtos_darkbargainer -######*/ - -#define ITEM_THRORIUM_BROTHERHOOD_CONTRACT 18628 -#define ITEM_SULFURON_INGOT 17203 -#define QUEST_A_BINDING_CONTRACT 7604 -#define SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND 23059 - -bool GossipHello_npc_lokhtos_darkbargainer(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (_Creature->isVendor() && player->GetReputationRank(59) >= REP_FRIENDLY) - player->ADD_GOSSIP_ITEM( 1, "Show me what I have access to, Lothos.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - if (player->GetQuestRewardStatus(QUEST_A_BINDING_CONTRACT) != 1 && - !player->HasItemCount(ITEM_THRORIUM_BROTHERHOOD_CONTRACT, 1, true) && - player->HasItemCount(ITEM_SULFURON_INGOT, 1)) - { - player->ADD_GOSSIP_ITEM(0, "Get Thorium Brotherhood Contract", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - } - - if (player->GetReputationRank(59) < REP_FRIENDLY) - player->SEND_GOSSIP_MENU(3673, _Creature->GetGUID()); - else - player->SEND_GOSSIP_MENU(3677, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lokhtos_darkbargainer(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND, false); - } - if (action == GOSSIP_ACTION_TRADE) - { - player->SEND_VENDORLIST( _Creature->GetGUID() ); - } - return true; -} - -/*###### -## -######*/ - -void AddSC_blackrock_depths() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="phalanx"; - newscript->GetAI = GetAI_mob_phalanx; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_kharan_mighthammer"; - newscript->pGossipHello = &GossipHello_npc_kharan_mighthammer; - newscript->pGossipSelect = &GossipSelect_npc_kharan_mighthammer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_lokhtos_darkbargainer"; - newscript->pGossipHello = &GossipHello_npc_lokhtos_darkbargainer; - newscript->pGossipSelect = &GossipSelect_npc_lokhtos_darkbargainer; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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: 95 +SDComment: Quest support: 4001, 4342, 7604. Vendor Lokhtos Darkbargainer. +SDCategory: Blackrock Depths +EndScriptData */ + +/* ContentData +mob_phalanx +npc_kharan_mighthammer +npc_lokhtos_darkbargainer +EndContentData */ + +#include "precompiled.h" + +/*###### +## mob_phalanx +######*/ + +#define SPELL_THUNDERCLAP 8732 +#define SPELL_FIREBALLVOLLEY 22425 +#define SPELL_MIGHTYBLOW 14099 + +struct MANGOS_DLL_DECL mob_phalanxAI : public ScriptedAI +{ + mob_phalanxAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ThunderClap_Timer; + uint32 FireballVolley_Timer; + uint32 MightyBlow_Timer; + + void Reset() + { + ThunderClap_Timer = 12000; + FireballVolley_Timer =0; + MightyBlow_Timer = 15000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ThunderClap_Timer + if( ThunderClap_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); + ThunderClap_Timer = 10000; + }else ThunderClap_Timer -= diff; + + //FireballVolley_Timer + if( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) + { + if (FireballVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIREBALLVOLLEY); + FireballVolley_Timer = 15000; + }else FireballVolley_Timer -= diff; + } + + //MightyBlow_Timer + if( MightyBlow_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_MIGHTYBLOW); + MightyBlow_Timer = 10000; + }else MightyBlow_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_mob_phalanx(Creature *_Creature) +{ + return new mob_phalanxAI (_Creature); +} + +/*###### +## npc_kharan_mighthammer +######*/ + +#define QUEST_4001 4001 +#define QUEST_4342 4342 + +bool GossipHello_npc_kharan_mighthammer(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->GetQuestStatus(QUEST_4001) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM( 0, "I need to know where the princess are, Kharan!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + if( player->GetQuestStatus(4342) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM( 0, "All is not lost, Kharan!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + + if( player->GetTeam() == HORDE ) player->SEND_GOSSIP_MENU(2473, _Creature->GetGUID()); + if( player->GetTeam() == ALLIANCE ) player->SEND_GOSSIP_MENU(2474, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_kharan_mighthammer(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, "Gor'shak is my friend, you can trust me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(2475, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM(0, "Not enough, you need to tell me more.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(2476, _Creature->GetGUID()); + break; + + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM(0, "So what happened?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(2477, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM(0, "Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(2478, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM(0, "So you suspect that someone on the inside was involved? That they were tipped off?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + player->SEND_GOSSIP_MENU(2479, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + player->ADD_GOSSIP_ITEM(0, "Continue with your story please.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); + player->SEND_GOSSIP_MENU(2480, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+7: + player->ADD_GOSSIP_ITEM(0, "Indeed.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+8); + player->SEND_GOSSIP_MENU(2481, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+8: + player->ADD_GOSSIP_ITEM(0, "The door is open, Kharan. You are a free man.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); + player->SEND_GOSSIP_MENU(2482, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+9: + player->CLOSE_GOSSIP_MENU(); + if( player->GetTeam() == HORDE ) player->AreaExploredOrEventHappens(QUEST_4001); + if( player->GetTeam() == ALLIANCE ) player->AreaExploredOrEventHappens(QUEST_4342); + break; + } + return true; +} + +/*###### +## npc_lokhtos_darkbargainer +######*/ + +#define ITEM_THRORIUM_BROTHERHOOD_CONTRACT 18628 +#define ITEM_SULFURON_INGOT 17203 +#define QUEST_A_BINDING_CONTRACT 7604 +#define SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND 23059 + +bool GossipHello_npc_lokhtos_darkbargainer(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (_Creature->isVendor() && player->GetReputationRank(59) >= REP_FRIENDLY) + player->ADD_GOSSIP_ITEM( 1, "Show me what I have access to, Lothos.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + + if (player->GetQuestRewardStatus(QUEST_A_BINDING_CONTRACT) != 1 && + !player->HasItemCount(ITEM_THRORIUM_BROTHERHOOD_CONTRACT, 1, true) && + player->HasItemCount(ITEM_SULFURON_INGOT, 1)) + { + player->ADD_GOSSIP_ITEM(0, "Get Thorium Brotherhood Contract", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + if (player->GetReputationRank(59) < REP_FRIENDLY) + player->SEND_GOSSIP_MENU(3673, _Creature->GetGUID()); + else + player->SEND_GOSSIP_MENU(3677, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_lokhtos_darkbargainer(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player, SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND, false); + } + if (action == GOSSIP_ACTION_TRADE) + { + player->SEND_VENDORLIST( _Creature->GetGUID() ); + } + return true; +} + +/*###### +## +######*/ + +void AddSC_blackrock_depths() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="phalanx"; + newscript->GetAI = GetAI_mob_phalanx; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_kharan_mighthammer"; + newscript->pGossipHello = &GossipHello_npc_kharan_mighthammer; + newscript->pGossipSelect = &GossipSelect_npc_kharan_mighthammer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_lokhtos_darkbargainer"; + newscript->pGossipHello = &GossipHello_npc_lokhtos_darkbargainer; + newscript->pGossipSelect = &GossipSelect_npc_lokhtos_darkbargainer; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_ambassador_flamelash.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_ambassador_flamelash.cpp index 613da72ef3a..1df93fa1c8f 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_ambassador_flamelash.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_ambassador_flamelash.cpp @@ -1,106 +1,106 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {Reset();} - - uint32 FireBlast_Timer; - uint32 Spirit_Timer; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - FireBlast_Timer = 2000; - Spirit_Timer = 24000; - } - - void Aggro(Unit *who) {} - - void SummonSpirits(Unit* victim) - { - Rand = rand()%10; - switch (rand()%2) - { - case 0: RandX -= Rand; break; - case 1: RandX += Rand; break; - } - Rand = 0; - Rand = rand()%10; - switch (rand()%2) - { - 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) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //FireBlast_Timer - if (FireBlast_Timer < diff) - { - DoCast(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 *_Creature) -{ - return new boss_ambassador_flamelashAI (_Creature); -} - -void AddSC_boss_ambassador_flamelash() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ambassador_flamelash"; - newscript->GetAI = GetAI_boss_ambassador_flamelash; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {Reset();} + + uint32 FireBlast_Timer; + uint32 Spirit_Timer; + int Rand; + int RandX; + int RandY; + Creature* Summoned; + + void Reset() + { + FireBlast_Timer = 2000; + Spirit_Timer = 24000; + } + + void Aggro(Unit *who) {} + + void SummonSpirits(Unit* victim) + { + Rand = rand()%10; + switch (rand()%2) + { + case 0: RandX -= Rand; break; + case 1: RandX += Rand; break; + } + Rand = 0; + Rand = rand()%10; + switch (rand()%2) + { + 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) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //FireBlast_Timer + if (FireBlast_Timer < diff) + { + DoCast(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 *_Creature) +{ + return new boss_ambassador_flamelashAI (_Creature); +} + +void AddSC_boss_ambassador_flamelash() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ambassador_flamelash"; + newscript->GetAI = GetAI_boss_ambassador_flamelash; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_angerrel.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_angerrel.cpp index 98e382ae233..ccef8ab8428 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_angerrel.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_angerrel.cpp @@ -1,91 +1,91 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Angerrel -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SUNDERARMOR 24317 -#define SPELL_SHIELDBLOCK 12169 -#define SPELL_STRIKE 15580 - -struct MANGOS_DLL_DECL boss_angerrelAI : public ScriptedAI -{ - boss_angerrelAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 SunderArmor_Timer; - uint32 ShieldBlock_Timer; - uint32 Strike_Timer; - - void Reset() - { - SunderArmor_Timer = 8000; - ShieldBlock_Timer = 15000; - Strike_Timer = 12000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //SunderArmor_Timer - if (SunderArmor_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SUNDERARMOR); - SunderArmor_Timer = 28000; - }else SunderArmor_Timer -= diff; - - //ShieldBlock_Timer - if (ShieldBlock_Timer < diff) - { - DoCast(m_creature,SPELL_SHIELDBLOCK); - ShieldBlock_Timer = 25000; - }else ShieldBlock_Timer -= diff; - - //Strike_Timer - if (Strike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_STRIKE); - Strike_Timer = 10000; - }else Strike_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_angerrel(Creature *_Creature) -{ - return new boss_angerrelAI (_Creature); -} - -void AddSC_boss_angerrel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_angerrel"; - newscript->GetAI = GetAI_boss_angerrel; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Angerrel +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SUNDERARMOR 24317 +#define SPELL_SHIELDBLOCK 12169 +#define SPELL_STRIKE 15580 + +struct MANGOS_DLL_DECL boss_angerrelAI : public ScriptedAI +{ + boss_angerrelAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 SunderArmor_Timer; + uint32 ShieldBlock_Timer; + uint32 Strike_Timer; + + void Reset() + { + SunderArmor_Timer = 8000; + ShieldBlock_Timer = 15000; + Strike_Timer = 12000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //SunderArmor_Timer + if (SunderArmor_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SUNDERARMOR); + SunderArmor_Timer = 28000; + }else SunderArmor_Timer -= diff; + + //ShieldBlock_Timer + if (ShieldBlock_Timer < diff) + { + DoCast(m_creature,SPELL_SHIELDBLOCK); + ShieldBlock_Timer = 25000; + }else ShieldBlock_Timer -= diff; + + //Strike_Timer + if (Strike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_STRIKE); + Strike_Timer = 10000; + }else Strike_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_angerrel(Creature *_Creature) +{ + return new boss_angerrelAI (_Creature); +} + +void AddSC_boss_angerrel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_angerrel"; + newscript->GetAI = GetAI_boss_angerrel; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_anubshiah.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_anubshiah.cpp index 1cf80bfc8ec..eb878e71b62 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_anubshiah.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_anubshiah.cpp @@ -1,115 +1,115 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowBolt_Timer - if (ShadowBolt_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWBOLT); - ShadowBolt_Timer = 7000; - }else ShadowBolt_Timer -= diff; - - //CurseOfTongues_Timer - if (CurseOfTongues_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_CURSEOFTONGUES); - CurseOfTongues_Timer = 18000; - }else CurseOfTongues_Timer -= diff; - - //CurseOfWeakness_Timer - if (CurseOfWeakness_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CURSEOFWEAKNESS); - CurseOfWeakness_Timer = 45000; - }else CurseOfWeakness_Timer -= diff; - - //DemonArmor_Timer - if (DemonArmor_Timer < diff) - { - DoCast(m_creature,SPELL_DEMONARMOR); - DemonArmor_Timer = 300000; - }else DemonArmor_Timer -= diff; - - //EnvelopingWeb_Timer - if (EnvelopingWeb_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_ENVELOPINGWEB); - EnvelopingWeb_Timer = 12000; - }else EnvelopingWeb_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_anubshiah(Creature *_Creature) -{ - return new boss_anubshiahAI (_Creature); -} - -void AddSC_boss_anubshiah() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_anubshiah"; - newscript->GetAI = GetAI_boss_anubshiah; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowBolt_Timer + if (ShadowBolt_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWBOLT); + ShadowBolt_Timer = 7000; + }else ShadowBolt_Timer -= diff; + + //CurseOfTongues_Timer + if (CurseOfTongues_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_CURSEOFTONGUES); + CurseOfTongues_Timer = 18000; + }else CurseOfTongues_Timer -= diff; + + //CurseOfWeakness_Timer + if (CurseOfWeakness_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CURSEOFWEAKNESS); + CurseOfWeakness_Timer = 45000; + }else CurseOfWeakness_Timer -= diff; + + //DemonArmor_Timer + if (DemonArmor_Timer < diff) + { + DoCast(m_creature,SPELL_DEMONARMOR); + DemonArmor_Timer = 300000; + }else DemonArmor_Timer -= diff; + + //EnvelopingWeb_Timer + if (EnvelopingWeb_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_ENVELOPINGWEB); + EnvelopingWeb_Timer = 12000; + }else EnvelopingWeb_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_anubshiah(Creature *_Creature) +{ + return new boss_anubshiahAI (_Creature); +} + +void AddSC_boss_anubshiah() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_anubshiah"; + newscript->GetAI = GetAI_boss_anubshiah; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_doomrel.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_doomrel.cpp index 2f70b4ee14c..12904fd886f 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_doomrel.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_doomrel.cpp @@ -1,139 +1,139 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Doomrel -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOWBOLTVOLLEY 17228 -#define SPELL_IMMOLATE 15505 -#define SPELL_CURSEOFWEAKNESS 17227 -#define SPELL_DEMONARMOR 11735 - -struct MANGOS_DLL_DECL boss_doomrelAI : public ScriptedAI -{ - boss_doomrelAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ShadowVolley_Timer; - uint32 Immolate_Timer; - uint32 CurseOfWeakness_Timer; - uint32 DemonArmor_Timer; - bool Voidwalkers; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - ShadowVolley_Timer = 10000; - Immolate_Timer = 18000; - CurseOfWeakness_Timer = 5000; - DemonArmor_Timer = 16000; - Voidwalkers = false; - } - - void Aggro(Unit *who) - { - } - - void SummonVoidwalkers(Unit* victim) - { - Rand = rand()%5; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%5; - switch (rand()%2) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - Summoned = DoSpawnCreature(16119, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000); - if(Summoned) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowVolley_Timer - if (ShadowVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); - ShadowVolley_Timer = 12000; - }else ShadowVolley_Timer -= diff; - - //Immolate_Timer - if (Immolate_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target)DoCast(target,SPELL_IMMOLATE); - Immolate_Timer = 25000; - }else Immolate_Timer -= diff; - - //CurseOfWeakness_Timer - if (CurseOfWeakness_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CURSEOFWEAKNESS); - CurseOfWeakness_Timer = 45000; - }else CurseOfWeakness_Timer -= diff; - - //DemonArmor_Timer - if (DemonArmor_Timer < diff) - { - DoCast(m_creature,SPELL_DEMONARMOR); - DemonArmor_Timer = 300000; - }else DemonArmor_Timer -= diff; - - //Summon Voidwalkers - if (!Voidwalkers && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) - { - SummonVoidwalkers(m_creature->getVictim()); - SummonVoidwalkers(m_creature->getVictim()); - SummonVoidwalkers(m_creature->getVictim()); - Voidwalkers = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_doomrel(Creature *_Creature) -{ - return new boss_doomrelAI (_Creature); -} - -void AddSC_boss_doomrel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_doomrel"; - newscript->GetAI = GetAI_boss_doomrel; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Doomrel +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SHADOWBOLTVOLLEY 17228 +#define SPELL_IMMOLATE 15505 +#define SPELL_CURSEOFWEAKNESS 17227 +#define SPELL_DEMONARMOR 11735 + +struct MANGOS_DLL_DECL boss_doomrelAI : public ScriptedAI +{ + boss_doomrelAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ShadowVolley_Timer; + uint32 Immolate_Timer; + uint32 CurseOfWeakness_Timer; + uint32 DemonArmor_Timer; + bool Voidwalkers; + int Rand; + int RandX; + int RandY; + Creature* Summoned; + + void Reset() + { + ShadowVolley_Timer = 10000; + Immolate_Timer = 18000; + CurseOfWeakness_Timer = 5000; + DemonArmor_Timer = 16000; + Voidwalkers = false; + } + + void Aggro(Unit *who) + { + } + + void SummonVoidwalkers(Unit* victim) + { + Rand = rand()%5; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%5; + switch (rand()%2) + { + case 0: RandY = 0 - Rand; break; + case 1: RandY = 0 + Rand; break; + } + Rand = 0; + Summoned = DoSpawnCreature(16119, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000); + if(Summoned) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowVolley_Timer + if (ShadowVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); + ShadowVolley_Timer = 12000; + }else ShadowVolley_Timer -= diff; + + //Immolate_Timer + if (Immolate_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target)DoCast(target,SPELL_IMMOLATE); + Immolate_Timer = 25000; + }else Immolate_Timer -= diff; + + //CurseOfWeakness_Timer + if (CurseOfWeakness_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CURSEOFWEAKNESS); + CurseOfWeakness_Timer = 45000; + }else CurseOfWeakness_Timer -= diff; + + //DemonArmor_Timer + if (DemonArmor_Timer < diff) + { + DoCast(m_creature,SPELL_DEMONARMOR); + DemonArmor_Timer = 300000; + }else DemonArmor_Timer -= diff; + + //Summon Voidwalkers + if (!Voidwalkers && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) + { + SummonVoidwalkers(m_creature->getVictim()); + SummonVoidwalkers(m_creature->getVictim()); + SummonVoidwalkers(m_creature->getVictim()); + Voidwalkers = true; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_doomrel(Creature *_Creature) +{ + return new boss_doomrelAI (_Creature); +} + +void AddSC_boss_doomrel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_doomrel"; + newscript->GetAI = GetAI_boss_doomrel; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_doperel.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_doperel.cpp index 3aae6cb1adf..0696fdd7f30 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_doperel.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_doperel.cpp @@ -1,91 +1,91 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Doperel -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SINISTERSTRIKE 15581 -#define SPELL_BACKSTAB 15582 -#define SPELL_GOUGE 13579 - -struct MANGOS_DLL_DECL boss_doperelAI : public ScriptedAI -{ - boss_doperelAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 SinisterStrike_Timer; - uint32 BackStab_Timer; - uint32 Gouge_Timer; - - void Reset() - { - SinisterStrike_Timer = 8000; - BackStab_Timer = 12000; - Gouge_Timer = 6000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //SinisterStrike_Timer - if (SinisterStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SINISTERSTRIKE); - SinisterStrike_Timer = 7000; - }else SinisterStrike_Timer -= diff; - - //BackStab_Timer - if (BackStab_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_BACKSTAB); - BackStab_Timer = 6000; - }else BackStab_Timer -= diff; - - //Gouge_Timer - if (Gouge_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_GOUGE); - Gouge_Timer = 8000; - }else Gouge_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_doperel(Creature *_Creature) -{ - return new boss_doperelAI (_Creature); -} - -void AddSC_boss_doperel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_doperel"; - newscript->GetAI = GetAI_boss_doperel; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Doperel +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SINISTERSTRIKE 15581 +#define SPELL_BACKSTAB 15582 +#define SPELL_GOUGE 13579 + +struct MANGOS_DLL_DECL boss_doperelAI : public ScriptedAI +{ + boss_doperelAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 SinisterStrike_Timer; + uint32 BackStab_Timer; + uint32 Gouge_Timer; + + void Reset() + { + SinisterStrike_Timer = 8000; + BackStab_Timer = 12000; + Gouge_Timer = 6000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //SinisterStrike_Timer + if (SinisterStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SINISTERSTRIKE); + SinisterStrike_Timer = 7000; + }else SinisterStrike_Timer -= diff; + + //BackStab_Timer + if (BackStab_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_BACKSTAB); + BackStab_Timer = 6000; + }else BackStab_Timer -= diff; + + //Gouge_Timer + if (Gouge_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_GOUGE); + Gouge_Timer = 8000; + }else Gouge_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_doperel(Creature *_Creature) +{ + return new boss_doperelAI (_Creature); +} + +void AddSC_boss_doperel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_doperel"; + newscript->GetAI = GetAI_boss_doperel; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_emperor_dagran_thaurissan.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_emperor_dagran_thaurissan.cpp index cd03b6c1894..5c5c3ff9109 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_emperor_dagran_thaurissan.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_emperor_dagran_thaurissan.cpp @@ -1,104 +1,104 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Emperor_Dagran_Thaurissan -SD%Complete: 99 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_HANDOFTHAURISSAN 17492 -#define SPELL_AVATAROFFLAME 15636 - -#define SAY_AGGRO "Come to aid the Throne!" -#define SAY_SLAY "Hail to the king, baby!" - -struct MANGOS_DLL_DECL boss_draganthaurissanAI : public ScriptedAI -{ - boss_draganthaurissanAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 HandOfThaurissan_Timer; - uint32 AvatarOfFlame_Timer; - //uint32 Counter; - - void Reset() - { - HandOfThaurissan_Timer = 4000; - AvatarOfFlame_Timer = 25000; - //Counter= 0; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - } - - void KilledUnit(Unit* victim) - { - DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if (HandOfThaurissan_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_HANDOFTHAURISSAN); - - //3 Hands of Thaurissan will be casted - //if (Counter < 3) - //{ - // HandOfThaurissan_Timer = 1000; - // Counter++; - //} - //else - //{ - HandOfThaurissan_Timer = 5000; - //Counter=0; - //} - }else HandOfThaurissan_Timer -= diff; - - //AvatarOfFlame_Timer - if (AvatarOfFlame_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_AVATAROFFLAME); - AvatarOfFlame_Timer = 18000; - }else AvatarOfFlame_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_draganthaurissan(Creature *_Creature) -{ - return new boss_draganthaurissanAI (_Creature); -} - -void AddSC_boss_draganthaurissan() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_emperor_dagran_thaurissan"; - newscript->GetAI = GetAI_boss_draganthaurissan; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Emperor_Dagran_Thaurissan +SD%Complete: 99 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_HANDOFTHAURISSAN 17492 +#define SPELL_AVATAROFFLAME 15636 + +#define SAY_AGGRO "Come to aid the Throne!" +#define SAY_SLAY "Hail to the king, baby!" + +struct MANGOS_DLL_DECL boss_draganthaurissanAI : public ScriptedAI +{ + boss_draganthaurissanAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 HandOfThaurissan_Timer; + uint32 AvatarOfFlame_Timer; + //uint32 Counter; + + void Reset() + { + HandOfThaurissan_Timer = 4000; + AvatarOfFlame_Timer = 25000; + //Counter= 0; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + } + + void KilledUnit(Unit* victim) + { + DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if (HandOfThaurissan_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_HANDOFTHAURISSAN); + + //3 Hands of Thaurissan will be casted + //if (Counter < 3) + //{ + // HandOfThaurissan_Timer = 1000; + // Counter++; + //} + //else + //{ + HandOfThaurissan_Timer = 5000; + //Counter=0; + //} + }else HandOfThaurissan_Timer -= diff; + + //AvatarOfFlame_Timer + if (AvatarOfFlame_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_AVATAROFFLAME); + AvatarOfFlame_Timer = 18000; + }else AvatarOfFlame_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_draganthaurissan(Creature *_Creature) +{ + return new boss_draganthaurissanAI (_Creature); +} + +void AddSC_boss_draganthaurissan() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_emperor_dagran_thaurissan"; + newscript->GetAI = GetAI_boss_draganthaurissan; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_general_angerforge.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_general_angerforge.cpp index 2d481bdaeb0..470f04f1935 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_general_angerforge.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_general_angerforge.cpp @@ -1,167 +1,167 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void SummonAdds(Unit* victim) - { - Rand1 = rand()%15; - switch (rand()%2) - { - case 0: Rand1X = 0 - Rand1; break; - case 1: Rand1X = 0 + Rand1; break; - } - Rand1 = 0; - Rand1 = rand()%15; - switch (rand()%2) - { - 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) - ((CreatureAI*)SummonedAdds->AI())->AttackStart(victim); - } - - void SummonMedics(Unit* victim) - { - Rand2 = rand()%10; - switch (rand()%2) - { - case 0: Rand2X = 0 - Rand2; break; - case 1: Rand2X = 0 + Rand2; break; - } - Rand2 = 0; - Rand2 = rand()%10; - switch (rand()%2) - { - 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) - ((CreatureAI*)SummonedMedics->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //MightyBlow_Timer - if (MightyBlow_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MIGHTYBLOW); - MightyBlow_Timer = 18000; - }else MightyBlow_Timer -= diff; - - //HamString_Timer - if (HamString_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMSTRING); - HamString_Timer = 15000; - }else HamString_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 9000; - }else Cleave_Timer -= diff; - - //Adds_Timer - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 21 ) - { - 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->GetHealth()*100 / m_creature->GetMaxHealth() < 21 ) - { - SummonMedics(m_creature->getVictim()); - SummonMedics(m_creature->getVictim()); - Medics = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_general_angerforge(Creature *_Creature) -{ - return new boss_general_angerforgeAI (_Creature); -} - -void AddSC_boss_general_angerforge() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_general_angerforge"; - newscript->GetAI = GetAI_boss_general_angerforge; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void SummonAdds(Unit* victim) + { + Rand1 = rand()%15; + switch (rand()%2) + { + case 0: Rand1X = 0 - Rand1; break; + case 1: Rand1X = 0 + Rand1; break; + } + Rand1 = 0; + Rand1 = rand()%15; + switch (rand()%2) + { + 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) + ((CreatureAI*)SummonedAdds->AI())->AttackStart(victim); + } + + void SummonMedics(Unit* victim) + { + Rand2 = rand()%10; + switch (rand()%2) + { + case 0: Rand2X = 0 - Rand2; break; + case 1: Rand2X = 0 + Rand2; break; + } + Rand2 = 0; + Rand2 = rand()%10; + switch (rand()%2) + { + 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) + ((CreatureAI*)SummonedMedics->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //MightyBlow_Timer + if (MightyBlow_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MIGHTYBLOW); + MightyBlow_Timer = 18000; + }else MightyBlow_Timer -= diff; + + //HamString_Timer + if (HamString_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HAMSTRING); + HamString_Timer = 15000; + }else HamString_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 9000; + }else Cleave_Timer -= diff; + + //Adds_Timer + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 21 ) + { + 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->GetHealth()*100 / m_creature->GetMaxHealth() < 21 ) + { + SummonMedics(m_creature->getVictim()); + SummonMedics(m_creature->getVictim()); + Medics = true; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_general_angerforge(Creature *_Creature) +{ + return new boss_general_angerforgeAI (_Creature); +} + +void AddSC_boss_general_angerforge() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_general_angerforge"; + newscript->GetAI = GetAI_boss_general_angerforge; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_gloomrel.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_gloomrel.cpp index cb87855ee53..da40615d101 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_gloomrel.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_gloomrel.cpp @@ -1,142 +1,142 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Gloomrel -SD%Complete: 80 -SDComment: Learning Smelt Dark Iron if tribute quest rewarded. Missing event and re-spawn GO Spectral Chalice -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_HAMSTRING 9080 -#define SPELL_CLEAVE 15579 -#define SPELL_MORTALSTRIKE 15708 - -struct MANGOS_DLL_DECL boss_gloomrelAI : public ScriptedAI -{ - boss_gloomrelAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 HamString_Timer; - uint32 Cleave_Timer; - uint32 MortalStrike_Timer; - - void Reset() - { - HamString_Timer = 19000; - Cleave_Timer = 6000; - MortalStrike_Timer = 10000; - - m_creature->setFaction(734); - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //HamString_Timer - if (HamString_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMSTRING); - HamString_Timer = 14000; - }else HamString_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 8000; - }else Cleave_Timer -= diff; - - //MortalStrike_Timer - if (MortalStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); - MortalStrike_Timer = 12000; - }else MortalStrike_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gloomrel(Creature *_Creature) -{ - return new boss_gloomrelAI (_Creature); -} - -bool GossipHello_boss_gloomrel(Player *player, Creature *_Creature) -{ - if (player->GetQuestRewardStatus(4083) == 1 && player->GetSkillValue(SKILL_MINING) >= 230 && !player->HasSpell(14891) ) - player->ADD_GOSSIP_ITEM(0, "Teach me the art of smelting dark iron", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if (player->GetQuestRewardStatus(4083) == 0 && player->GetSkillValue(SKILL_MINING) >= 230) - player->ADD_GOSSIP_ITEM(0, "I want to pay tribute", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - player->ADD_GOSSIP_ITEM(0, "Challenge", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(2602, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_boss_gloomrel(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(2606, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player, 14894, false); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "[PH] Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); - player->SEND_GOSSIP_MENU(2604, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+22: - player->CLOSE_GOSSIP_MENU(); - //re-spawn object here - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "[PH] Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 33); - player->SEND_GOSSIP_MENU(2605, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+33: - player->CLOSE_GOSSIP_MENU(); - //start event here, below code just temporary - _Creature->setFaction(754); - break; - } - return true; -} - -void AddSC_boss_gloomrel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gloomrel"; - newscript->GetAI = GetAI_boss_gloomrel; - newscript->pGossipHello = &GossipHello_boss_gloomrel; - newscript->pGossipSelect = &GossipSelect_boss_gloomrel; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Gloomrel +SD%Complete: 80 +SDComment: Learning Smelt Dark Iron if tribute quest rewarded. Missing event and re-spawn GO Spectral Chalice +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_HAMSTRING 9080 +#define SPELL_CLEAVE 15579 +#define SPELL_MORTALSTRIKE 15708 + +struct MANGOS_DLL_DECL boss_gloomrelAI : public ScriptedAI +{ + boss_gloomrelAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 HamString_Timer; + uint32 Cleave_Timer; + uint32 MortalStrike_Timer; + + void Reset() + { + HamString_Timer = 19000; + Cleave_Timer = 6000; + MortalStrike_Timer = 10000; + + m_creature->setFaction(734); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //HamString_Timer + if (HamString_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HAMSTRING); + HamString_Timer = 14000; + }else HamString_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 8000; + }else Cleave_Timer -= diff; + + //MortalStrike_Timer + if (MortalStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); + MortalStrike_Timer = 12000; + }else MortalStrike_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_gloomrel(Creature *_Creature) +{ + return new boss_gloomrelAI (_Creature); +} + +bool GossipHello_boss_gloomrel(Player *player, Creature *_Creature) +{ + if (player->GetQuestRewardStatus(4083) == 1 && player->GetSkillValue(SKILL_MINING) >= 230 && !player->HasSpell(14891) ) + player->ADD_GOSSIP_ITEM(0, "Teach me the art of smelting dark iron", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + if (player->GetQuestRewardStatus(4083) == 0 && player->GetSkillValue(SKILL_MINING) >= 230) + player->ADD_GOSSIP_ITEM(0, "I want to pay tribute", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + + player->ADD_GOSSIP_ITEM(0, "Challenge", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(2602, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_boss_gloomrel(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(2606, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+11: + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player, 14894, false); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "[PH] Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); + player->SEND_GOSSIP_MENU(2604, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+22: + player->CLOSE_GOSSIP_MENU(); + //re-spawn object here + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "[PH] Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 33); + player->SEND_GOSSIP_MENU(2605, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+33: + player->CLOSE_GOSSIP_MENU(); + //start event here, below code just temporary + _Creature->setFaction(754); + break; + } + return true; +} + +void AddSC_boss_gloomrel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gloomrel"; + newscript->GetAI = GetAI_boss_gloomrel; + newscript->pGossipHello = &GossipHello_boss_gloomrel; + newscript->pGossipSelect = &GossipSelect_boss_gloomrel; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_gorosh_the_dervish.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_gorosh_the_dervish.cpp index df67093e61f..98f20a07222 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_gorosh_the_dervish.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_gorosh_the_dervish.cpp @@ -1,81 +1,81 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {Reset();} - - uint32 WhirlWind_Timer; - uint32 MortalStrike_Timer; - - void Reset() - { - WhirlWind_Timer = 12000; - MortalStrike_Timer = 22000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //WhirlWind_Timer - if (WhirlWind_Timer < diff) - { - DoCast(m_creature,SPELL_WHIRLWIND); - WhirlWind_Timer = 15000; - }else WhirlWind_Timer -= diff; - - //MortalStrike_Timer - if (MortalStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); - MortalStrike_Timer = 15000; - }else MortalStrike_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gorosh_the_dervish(Creature *_Creature) -{ - return new boss_gorosh_the_dervishAI (_Creature); -} - -void AddSC_boss_gorosh_the_dervish() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gorosh_the_dervish"; - newscript->GetAI = GetAI_boss_gorosh_the_dervish; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {Reset();} + + uint32 WhirlWind_Timer; + uint32 MortalStrike_Timer; + + void Reset() + { + WhirlWind_Timer = 12000; + MortalStrike_Timer = 22000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //WhirlWind_Timer + if (WhirlWind_Timer < diff) + { + DoCast(m_creature,SPELL_WHIRLWIND); + WhirlWind_Timer = 15000; + }else WhirlWind_Timer -= diff; + + //MortalStrike_Timer + if (MortalStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); + MortalStrike_Timer = 15000; + }else MortalStrike_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_gorosh_the_dervish(Creature *_Creature) +{ + return new boss_gorosh_the_dervishAI (_Creature); +} + +void AddSC_boss_gorosh_the_dervish() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gorosh_the_dervish"; + newscript->GetAI = GetAI_boss_gorosh_the_dervish; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_grizzle.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_grizzle.cpp index 7e248c2d17b..c859b3c1f0b 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_grizzle.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_grizzle.cpp @@ -1,86 +1,86 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 SPELL_GROUNDTREMOR 6524 -#define SPELL_FRENZY 28371 - -struct MANGOS_DLL_DECL boss_grizzleAI : public ScriptedAI -{ - boss_grizzleAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 GroundTremor_Timer; - uint32 Frenzy_Timer; - - void Reset() - { - GroundTremor_Timer = 12000; - Frenzy_Timer =0; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //GroundTremor_Timer - if (GroundTremor_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_GROUNDTREMOR); - GroundTremor_Timer = 8000; - }else GroundTremor_Timer -= diff; - - //Frenzy_Timer - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) - { - if (Frenzy_Timer < diff) - { - DoCast(m_creature,SPELL_FRENZY); - DoTextEmote("goes into a killing frenzy!",NULL); - - Frenzy_Timer = 15000; - }else Frenzy_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_grizzle(Creature *_Creature) -{ - return new boss_grizzleAI (_Creature); -} - -void AddSC_boss_grizzle() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_grizzle"; - newscript->GetAI = GetAI_boss_grizzle; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 SPELL_GROUNDTREMOR 6524 +#define SPELL_FRENZY 28371 + +struct MANGOS_DLL_DECL boss_grizzleAI : public ScriptedAI +{ + boss_grizzleAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 GroundTremor_Timer; + uint32 Frenzy_Timer; + + void Reset() + { + GroundTremor_Timer = 12000; + Frenzy_Timer =0; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //GroundTremor_Timer + if (GroundTremor_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_GROUNDTREMOR); + GroundTremor_Timer = 8000; + }else GroundTremor_Timer -= diff; + + //Frenzy_Timer + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) + { + if (Frenzy_Timer < diff) + { + DoCast(m_creature,SPELL_FRENZY); + DoTextEmote("goes into a killing frenzy!",NULL); + + Frenzy_Timer = 15000; + }else Frenzy_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_grizzle(Creature *_Creature) +{ + return new boss_grizzleAI (_Creature); +} + +void AddSC_boss_grizzle() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_grizzle"; + newscript->GetAI = GetAI_boss_grizzle; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_haterel.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_haterel.cpp index 1392eb54943..35a97f0fd46 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_haterel.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_haterel.cpp @@ -1,105 +1,105 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Haterel -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOWBOLT 17483 //Not sure if right ID -#define SPELL_MANABURN 10876 -#define SPELL_SHADOWSHIELD 22417 -#define SPELL_STRIKE 15580 - -struct MANGOS_DLL_DECL boss_haterelAI : public ScriptedAI -{ - boss_haterelAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ShadowBolt_Timer; - uint32 ManaBurn_Timer; - uint32 ShadowShield_Timer; - uint32 Strike_Timer; - - void Reset() - { - ShadowBolt_Timer = 15000; - ManaBurn_Timer = 3000; - ShadowShield_Timer = 8000; - Strike_Timer = 12000; - } - - void Aggro(Unit *who) - { - } - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowBolt_Timer - if (ShadowBolt_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_SHADOWBOLT); - ShadowBolt_Timer = 7000; - }else ShadowBolt_Timer -= diff; - - //ManaBurn_Timer - if (ManaBurn_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_MANABURN); - ManaBurn_Timer = 13000; - }else ManaBurn_Timer -= diff; - - //ShadowShield_Timer - if (ShadowShield_Timer < diff) - { - DoCast(m_creature,SPELL_SHADOWSHIELD); - ShadowShield_Timer = 25000; - }else ShadowShield_Timer -= diff; - - //Strike_Timer - if (Strike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_STRIKE); - Strike_Timer = 10000; - }else Strike_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_haterel(Creature *_Creature) -{ - return new boss_haterelAI (_Creature); -} - -void AddSC_boss_haterel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_haterel"; - newscript->GetAI = GetAI_boss_haterel; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Haterel +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SHADOWBOLT 17483 //Not sure if right ID +#define SPELL_MANABURN 10876 +#define SPELL_SHADOWSHIELD 22417 +#define SPELL_STRIKE 15580 + +struct MANGOS_DLL_DECL boss_haterelAI : public ScriptedAI +{ + boss_haterelAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ShadowBolt_Timer; + uint32 ManaBurn_Timer; + uint32 ShadowShield_Timer; + uint32 Strike_Timer; + + void Reset() + { + ShadowBolt_Timer = 15000; + ManaBurn_Timer = 3000; + ShadowShield_Timer = 8000; + Strike_Timer = 12000; + } + + void Aggro(Unit *who) + { + } + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowBolt_Timer + if (ShadowBolt_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_SHADOWBOLT); + ShadowBolt_Timer = 7000; + }else ShadowBolt_Timer -= diff; + + //ManaBurn_Timer + if (ManaBurn_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_MANABURN); + ManaBurn_Timer = 13000; + }else ManaBurn_Timer -= diff; + + //ShadowShield_Timer + if (ShadowShield_Timer < diff) + { + DoCast(m_creature,SPELL_SHADOWSHIELD); + ShadowShield_Timer = 25000; + }else ShadowShield_Timer -= diff; + + //Strike_Timer + if (Strike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_STRIKE); + Strike_Timer = 10000; + }else Strike_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_haterel(Creature *_Creature) +{ + return new boss_haterelAI (_Creature); +} + +void AddSC_boss_haterel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_haterel"; + newscript->GetAI = GetAI_boss_haterel; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_high_interrogator_gerstahn.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_high_interrogator_gerstahn.cpp index c4393560d10..12c377ab791 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_high_interrogator_gerstahn.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_high_interrogator_gerstahn.cpp @@ -1,105 +1,105 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Interrogator_Gerstahn -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOWWORDPAIN 10894 -#define SPELL_MANABURN 10876 -#define SPELL_PSYCHICSCREAM 8122 -#define SPELL_SHADOWSHIELD 22417 - -struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI -{ - boss_high_interrogator_gerstahnAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ShadowWordPain_Timer; - uint32 ManaBurn_Timer; - uint32 PsychicScream_Timer; - uint32 ShadowShield_Timer; - - void Reset() - { - ShadowWordPain_Timer = 4000; - ManaBurn_Timer = 14000; - PsychicScream_Timer = 32000; - ShadowShield_Timer = 8000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowWordPain_Timer - if (ShadowWordPain_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target)DoCast(target,SPELL_SHADOWWORDPAIN); - ShadowWordPain_Timer = 7000; - }else ShadowWordPain_Timer -= diff; - - //ManaBurn_Timer - if (ManaBurn_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target)DoCast(target,SPELL_MANABURN); - ManaBurn_Timer = 10000; - }else ManaBurn_Timer -= diff; - - //PsychicScream_Timer - if (PsychicScream_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_PSYCHICSCREAM); - PsychicScream_Timer = 30000; - }else PsychicScream_Timer -= diff; - - //ShadowShield_Timer - if (ShadowShield_Timer < diff) - { - DoCast(m_creature,SPELL_SHADOWSHIELD); - ShadowShield_Timer = 25000; - }else ShadowShield_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_high_interrogator_gerstahn(Creature *_Creature) -{ - return new boss_high_interrogator_gerstahnAI (_Creature); -} - -void AddSC_boss_high_interrogator_gerstahn() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_high_interrogator_gerstahn"; - newscript->GetAI = GetAI_boss_high_interrogator_gerstahn; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Interrogator_Gerstahn +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SHADOWWORDPAIN 10894 +#define SPELL_MANABURN 10876 +#define SPELL_PSYCHICSCREAM 8122 +#define SPELL_SHADOWSHIELD 22417 + +struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI +{ + boss_high_interrogator_gerstahnAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ShadowWordPain_Timer; + uint32 ManaBurn_Timer; + uint32 PsychicScream_Timer; + uint32 ShadowShield_Timer; + + void Reset() + { + ShadowWordPain_Timer = 4000; + ManaBurn_Timer = 14000; + PsychicScream_Timer = 32000; + ShadowShield_Timer = 8000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowWordPain_Timer + if (ShadowWordPain_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target)DoCast(target,SPELL_SHADOWWORDPAIN); + ShadowWordPain_Timer = 7000; + }else ShadowWordPain_Timer -= diff; + + //ManaBurn_Timer + if (ManaBurn_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target)DoCast(target,SPELL_MANABURN); + ManaBurn_Timer = 10000; + }else ManaBurn_Timer -= diff; + + //PsychicScream_Timer + if (PsychicScream_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_PSYCHICSCREAM); + PsychicScream_Timer = 30000; + }else PsychicScream_Timer -= diff; + + //ShadowShield_Timer + if (ShadowShield_Timer < diff) + { + DoCast(m_creature,SPELL_SHADOWSHIELD); + ShadowShield_Timer = 25000; + }else ShadowShield_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_high_interrogator_gerstahn(Creature *_Creature) +{ + return new boss_high_interrogator_gerstahnAI (_Creature); +} + +void AddSC_boss_high_interrogator_gerstahn() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_high_interrogator_gerstahn"; + newscript->GetAI = GetAI_boss_high_interrogator_gerstahn; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_magmus.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_magmus.cpp index 62d2f6d8147..81f98559c1c 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_magmus.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_magmus.cpp @@ -1,84 +1,84 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FIERYBURST 13900 -#define SPELL_WARSTOMP 24375 - -struct MANGOS_DLL_DECL boss_magmusAI : public ScriptedAI -{ - boss_magmusAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FieryBurst_Timer; - uint32 WarStomp_Timer; - - void Reset() - { - FieryBurst_Timer = 5000; - WarStomp_Timer =0; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //FieryBurst_Timer - if (FieryBurst_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIERYBURST); - FieryBurst_Timer = 6000; - }else FieryBurst_Timer -= diff; - - //WarStomp_Timer - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) - { - if (WarStomp_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_WARSTOMP); - WarStomp_Timer = 8000; - }else WarStomp_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_magmus(Creature *_Creature) -{ - return new boss_magmusAI (_Creature); -} - -void AddSC_boss_magmus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_magmus"; - newscript->GetAI = GetAI_boss_magmus; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_FIERYBURST 13900 +#define SPELL_WARSTOMP 24375 + +struct MANGOS_DLL_DECL boss_magmusAI : public ScriptedAI +{ + boss_magmusAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FieryBurst_Timer; + uint32 WarStomp_Timer; + + void Reset() + { + FieryBurst_Timer = 5000; + WarStomp_Timer =0; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //FieryBurst_Timer + if (FieryBurst_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIERYBURST); + FieryBurst_Timer = 6000; + }else FieryBurst_Timer -= diff; + + //WarStomp_Timer + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) + { + if (WarStomp_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_WARSTOMP); + WarStomp_Timer = 8000; + }else WarStomp_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_magmus(Creature *_Creature) +{ + return new boss_magmusAI (_Creature); +} + +void AddSC_boss_magmus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_magmus"; + newscript->GetAI = GetAI_boss_magmus; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_moira_bronzebeard.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_moira_bronzebeard.cpp index b7dfadd385d..13129a0921c 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_moira_bronzebeard.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_moira_bronzebeard.cpp @@ -1,99 +1,99 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Moira_Bronzbeard -SD%Complete: 90 -SDComment: Healing of Emperor NYI -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_HEAL 10917 -#define SPELL_RENEW 10929 -#define SPELL_SHIELD 10901 -#define SPELL_MINDBLAST 10947 -#define SPELL_SHADOWWORDPAIN 10894 -#define SPELL_SMITE 10934 - -struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI -{ - boss_moira_bronzebeardAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Heal_Timer; - uint32 MindBlast_Timer; - uint32 ShadowWordPain_Timer; - uint32 Smite_Timer; - Unit* PlayerHolder; - Unit* Target; - bool Heal; - - void Reset() - { - Target = NULL; - Heal_Timer = 12000; //These times are probably wrong - MindBlast_Timer = 16000; - ShadowWordPain_Timer = 2000; - Smite_Timer = 8000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //MindBlast_Timer - if (MindBlast_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST); - MindBlast_Timer = 14000; - }else MindBlast_Timer -= diff; - - //ShadowWordPain_Timer - if (ShadowWordPain_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); - ShadowWordPain_Timer = 18000; - }else ShadowWordPain_Timer -= diff; - - //Smite_Timer - if (Smite_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SMITE); - Smite_Timer = 10000; - }else Smite_Timer -= diff; - - } -}; -CreatureAI* GetAI_boss_moira_bronzebeard(Creature *_Creature) -{ - return new boss_moira_bronzebeardAI (_Creature); -} - -void AddSC_boss_moira_bronzebeard() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_moira_bronzebeard"; - newscript->GetAI = GetAI_boss_moira_bronzebeard; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Moira_Bronzbeard +SD%Complete: 90 +SDComment: Healing of Emperor NYI +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_HEAL 10917 +#define SPELL_RENEW 10929 +#define SPELL_SHIELD 10901 +#define SPELL_MINDBLAST 10947 +#define SPELL_SHADOWWORDPAIN 10894 +#define SPELL_SMITE 10934 + +struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI +{ + boss_moira_bronzebeardAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Heal_Timer; + uint32 MindBlast_Timer; + uint32 ShadowWordPain_Timer; + uint32 Smite_Timer; + Unit* PlayerHolder; + Unit* Target; + bool Heal; + + void Reset() + { + Target = NULL; + Heal_Timer = 12000; //These times are probably wrong + MindBlast_Timer = 16000; + ShadowWordPain_Timer = 2000; + Smite_Timer = 8000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //MindBlast_Timer + if (MindBlast_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MINDBLAST); + MindBlast_Timer = 14000; + }else MindBlast_Timer -= diff; + + //ShadowWordPain_Timer + if (ShadowWordPain_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); + ShadowWordPain_Timer = 18000; + }else ShadowWordPain_Timer -= diff; + + //Smite_Timer + if (Smite_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SMITE); + Smite_Timer = 10000; + }else Smite_Timer -= diff; + + } +}; +CreatureAI* GetAI_boss_moira_bronzebeard(Creature *_Creature) +{ + return new boss_moira_bronzebeardAI (_Creature); +} + +void AddSC_boss_moira_bronzebeard() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_moira_bronzebeard"; + newscript->GetAI = GetAI_boss_moira_bronzebeard; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_seethrel.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_seethrel.cpp index f1d703924fb..09552a28ca1 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_seethrel.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_seethrel.cpp @@ -1,115 +1,115 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Seethrel -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FROSTBOLT 16799 -#define SPELL_FROSTARMOR 15784 //This is actually a buff he gives himself -#define SPELL_BLIZZARD 19099 -#define SPELL_FROSTNOVA 15063 -#define SPELL_FROSTWARD 15004 - -struct MANGOS_DLL_DECL boss_seethrelAI : public ScriptedAI -{ - boss_seethrelAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FrostArmor_Timer; - uint32 Frostbolt_Timer; - uint32 Blizzard_Timer; - uint32 FrostNova_Timer; - uint32 FrostWard_Timer; - - void Reset() - { - FrostArmor_Timer = 2000; - Frostbolt_Timer = 6000; - Blizzard_Timer = 18000; - FrostNova_Timer = 12000; - FrostWard_Timer = 25000; - - m_creature->CastSpell(m_creature,SPELL_FROSTARMOR,true); - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //FrostArmor_Timer - if (FrostArmor_Timer < diff) - { - DoCast(m_creature, SPELL_FROSTARMOR); - FrostArmor_Timer = 180000; - }else FrostArmor_Timer -= diff; - - //Frostbolt_Timer - if (Frostbolt_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROSTBOLT); - Frostbolt_Timer = 15000; - }else Frostbolt_Timer -= diff; - - //Blizzard_Timer - if (Blizzard_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_BLIZZARD); - Blizzard_Timer = 22000; - }else Blizzard_Timer -= diff; - - //FrostNova_Timer - if (FrostNova_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROSTNOVA); - FrostNova_Timer = 14000; - }else FrostNova_Timer -= diff; - - //FrostWard_Timer - if (FrostWard_Timer < diff) - { - DoCast(m_creature,SPELL_FROSTWARD); - FrostWard_Timer = 68000; - }else FrostWard_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_seethrel(Creature *_Creature) -{ - return new boss_seethrelAI (_Creature); -} - -void AddSC_boss_seethrel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_seethrel"; - newscript->GetAI = GetAI_boss_seethrel; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Seethrel +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_FROSTBOLT 16799 +#define SPELL_FROSTARMOR 15784 //This is actually a buff he gives himself +#define SPELL_BLIZZARD 19099 +#define SPELL_FROSTNOVA 15063 +#define SPELL_FROSTWARD 15004 + +struct MANGOS_DLL_DECL boss_seethrelAI : public ScriptedAI +{ + boss_seethrelAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FrostArmor_Timer; + uint32 Frostbolt_Timer; + uint32 Blizzard_Timer; + uint32 FrostNova_Timer; + uint32 FrostWard_Timer; + + void Reset() + { + FrostArmor_Timer = 2000; + Frostbolt_Timer = 6000; + Blizzard_Timer = 18000; + FrostNova_Timer = 12000; + FrostWard_Timer = 25000; + + m_creature->CastSpell(m_creature,SPELL_FROSTARMOR,true); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //FrostArmor_Timer + if (FrostArmor_Timer < diff) + { + DoCast(m_creature, SPELL_FROSTARMOR); + FrostArmor_Timer = 180000; + }else FrostArmor_Timer -= diff; + + //Frostbolt_Timer + if (Frostbolt_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROSTBOLT); + Frostbolt_Timer = 15000; + }else Frostbolt_Timer -= diff; + + //Blizzard_Timer + if (Blizzard_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_BLIZZARD); + Blizzard_Timer = 22000; + }else Blizzard_Timer -= diff; + + //FrostNova_Timer + if (FrostNova_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROSTNOVA); + FrostNova_Timer = 14000; + }else FrostNova_Timer -= diff; + + //FrostWard_Timer + if (FrostWard_Timer < diff) + { + DoCast(m_creature,SPELL_FROSTWARD); + FrostWard_Timer = 68000; + }else FrostWard_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_seethrel(Creature *_Creature) +{ + return new boss_seethrelAI (_Creature); +} + +void AddSC_boss_seethrel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_seethrel"; + newscript->GetAI = GetAI_boss_seethrel; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_vilerel.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_vilerel.cpp index 2c7508a0311..b2739617bf7 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_vilerel.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_vilerel.cpp @@ -1,101 +1,101 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Vilerel -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_MINDBLAST 15587 -#define SPELL_HEAL 15586 -#define SPELL_PRAYEROFHEALING 15585 -#define SPELL_SHIELD 10901 - -struct MANGOS_DLL_DECL boss_vilerelAI : public ScriptedAI -{ - boss_vilerelAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 MindBlast_Timer; - uint32 Heal_Timer; - uint32 PrayerOfHealing_Timer; - uint32 Shield_Timer; - - void Reset() - { - MindBlast_Timer = 10000; - Heal_Timer = 35000; - PrayerOfHealing_Timer = 25000; - Shield_Timer = 3000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //MindBlast_Timer - if (MindBlast_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST); - MindBlast_Timer = 7000; - }else MindBlast_Timer -= diff; - - //Heal_Timer - if (Heal_Timer < diff) - { - DoCast(m_creature,SPELL_HEAL); - Heal_Timer = 20000; - }else Heal_Timer -= diff; - - //PrayerOfHealing_Timer - if (PrayerOfHealing_Timer < diff) - { - DoCast(m_creature,SPELL_PRAYEROFHEALING); - PrayerOfHealing_Timer = 30000; - }else PrayerOfHealing_Timer -= diff; - - //Shield_Timer - if (Shield_Timer < diff) - { - DoCast(m_creature,SPELL_SHIELD); - Shield_Timer = 30000; - }else Shield_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_vilerel(Creature *_Creature) -{ - return new boss_vilerelAI (_Creature); -} - -void AddSC_boss_vilerel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_vilerel"; - newscript->GetAI = GetAI_boss_vilerel; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Vilerel +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_MINDBLAST 15587 +#define SPELL_HEAL 15586 +#define SPELL_PRAYEROFHEALING 15585 +#define SPELL_SHIELD 10901 + +struct MANGOS_DLL_DECL boss_vilerelAI : public ScriptedAI +{ + boss_vilerelAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 MindBlast_Timer; + uint32 Heal_Timer; + uint32 PrayerOfHealing_Timer; + uint32 Shield_Timer; + + void Reset() + { + MindBlast_Timer = 10000; + Heal_Timer = 35000; + PrayerOfHealing_Timer = 25000; + Shield_Timer = 3000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //MindBlast_Timer + if (MindBlast_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MINDBLAST); + MindBlast_Timer = 7000; + }else MindBlast_Timer -= diff; + + //Heal_Timer + if (Heal_Timer < diff) + { + DoCast(m_creature,SPELL_HEAL); + Heal_Timer = 20000; + }else Heal_Timer -= diff; + + //PrayerOfHealing_Timer + if (PrayerOfHealing_Timer < diff) + { + DoCast(m_creature,SPELL_PRAYEROFHEALING); + PrayerOfHealing_Timer = 30000; + }else PrayerOfHealing_Timer -= diff; + + //Shield_Timer + if (Shield_Timer < diff) + { + DoCast(m_creature,SPELL_SHIELD); + Shield_Timer = 30000; + }else Shield_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_vilerel(Creature *_Creature) +{ + return new boss_vilerelAI (_Creature); +} + +void AddSC_boss_vilerel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_vilerel"; + newscript->GetAI = GetAI_boss_vilerel; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_drakkisath.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_drakkisath.cpp index a69334aeac8..830ae55dca8 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_drakkisath.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_drakkisath.cpp @@ -1,101 +1,101 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_FIRENOVA 23462 -#define SPELL_CLEAVE 20691 -#define SPELL_CONFLIGURATION 16805 -#define 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 *c) : ScriptedAI(c) {Reset();} - - uint32 FireNova_Timer; - uint32 Cleave_Timer; - uint32 Confliguration_Timer; - uint32 Thunderclap_Timer; - - void Reset() - { - FireNova_Timer = 6000; - Cleave_Timer = 8000; - Confliguration_Timer = 15000; - Thunderclap_Timer = 17000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //FireNova_Timer - if (FireNova_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIRENOVA); - FireNova_Timer = 10000; - }else FireNova_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 8000; - }else Cleave_Timer -= diff; - - //Confliguration_Timer - if (Confliguration_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CONFLIGURATION); - Confliguration_Timer = 18000; - }else Confliguration_Timer -= diff; - - //Thunderclap_Timer - if (Thunderclap_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); - Thunderclap_Timer = 20000; - }else Thunderclap_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_drakkisath(Creature *_Creature) -{ - return new boss_drakkisathAI (_Creature); -} - -void AddSC_boss_drakkisath() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_drakkisath"; - newscript->GetAI = GetAI_boss_drakkisath; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_FIRENOVA 23462 +#define SPELL_CLEAVE 20691 +#define SPELL_CONFLIGURATION 16805 +#define 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 *c) : ScriptedAI(c) {Reset();} + + uint32 FireNova_Timer; + uint32 Cleave_Timer; + uint32 Confliguration_Timer; + uint32 Thunderclap_Timer; + + void Reset() + { + FireNova_Timer = 6000; + Cleave_Timer = 8000; + Confliguration_Timer = 15000; + Thunderclap_Timer = 17000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //FireNova_Timer + if (FireNova_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIRENOVA); + FireNova_Timer = 10000; + }else FireNova_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 8000; + }else Cleave_Timer -= diff; + + //Confliguration_Timer + if (Confliguration_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CONFLIGURATION); + Confliguration_Timer = 18000; + }else Confliguration_Timer -= diff; + + //Thunderclap_Timer + if (Thunderclap_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); + Thunderclap_Timer = 20000; + }else Thunderclap_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_drakkisath(Creature *_Creature) +{ + return new boss_drakkisathAI (_Creature); +} + +void AddSC_boss_drakkisath() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_drakkisath"; + newscript->GetAI = GetAI_boss_drakkisath; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_gyth.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_gyth.cpp index e2edaf7d07d..3bf3e6c922f 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_gyth.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_gyth.cpp @@ -1,205 +1,205 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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: -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_CORROSIVEACID 20667 -#define SPELL_FREEZE 18763 -#define SPELL_FLAMEBREATH 20712 - -struct MANGOS_DLL_DECL boss_gythAI : public ScriptedAI -{ - boss_gythAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Aggro_Timer; - uint32 Dragons_Timer; - uint32 Orc_Timer; - uint32 CorrosiveAcid_Timer; - uint32 Freeze_Timer; - uint32 Flamebreath_Timer; - uint32 Line1Count; - uint32 Line2Count; - - bool Event; - bool SummonedDragons; - bool SummonedOrcs; - bool SummonedRend; - bool bAggro; - bool RootSelf; - Creature *SummonedCreature; - - void Reset() - { - Dragons_Timer = 3000; - Orc_Timer = 60000; - Aggro_Timer = 60000; - CorrosiveAcid_Timer = 8000; - Freeze_Timer = 11000; - Flamebreath_Timer = 4000; - Event = false; - SummonedDragons = false; - SummonedOrcs= false; - SummonedRend = false; - bAggro = false; - RootSelf = false; - - // how many times should the two lines of summoned creatures be spawned - // min 2 x 2, max 7 lines of attack in total - Line1Count = rand() % 4 + 2; - if (Line1Count < 5) - Line2Count = rand() % (5 - Line1Count) + 2; - else - Line2Count = 2; - - //Invisible for event start - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit *who) - { - } - - void SummonCreatureWithRandomTarget(uint32 creatureId) - { - Unit* Summoned = m_creature->SummonCreature(creatureId, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 240000); - if (Summoned) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (target) - Summoned->AddThreat(target, 1.0f); - } - } - - void UpdateAI(const uint32 diff) - { - //char buf[200]; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if (!RootSelf) - { - //m_creature->m_canMove = true; - DoCast(m_creature, 33356); - RootSelf = true; - } - - if (!bAggro && Line1Count == 0 && Line2Count == 0) - { - if (Aggro_Timer < diff) - { - bAggro = true; - // Visible now! - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 9723); - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } else Aggro_Timer -= diff; - } - - // Summon Dragon pack. 2 Dragons and 3 Whelps - if (!bAggro && !SummonedRend && Line1Count > 0) - { - if (Dragons_Timer < diff) - { - SummonCreatureWithRandomTarget(10372); - SummonCreatureWithRandomTarget(10372); - SummonCreatureWithRandomTarget(10442); - SummonCreatureWithRandomTarget(10442); - SummonCreatureWithRandomTarget(10442); - Line1Count = Line1Count - 1; - Dragons_Timer = 60000; - } else Dragons_Timer -= diff; - } - - //Summon Orc pack. 1 Orc Handler 1 Elite Dragonkin and 3 Whelps - if (!bAggro && !SummonedRend && Line1Count == 0 && Line2Count > 0) - { - if (Orc_Timer < diff) - { - SummonCreatureWithRandomTarget(10447); - SummonCreatureWithRandomTarget(10317); - SummonCreatureWithRandomTarget(10442); - SummonCreatureWithRandomTarget(10442); - SummonCreatureWithRandomTarget(10442); - Line2Count = Line2Count - 1; - Orc_Timer = 60000; - } else Orc_Timer -= diff; - } - - // we take part in the fight - if (bAggro) - { - // CorrosiveAcid_Timer - if (CorrosiveAcid_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CORROSIVEACID); - CorrosiveAcid_Timer = 7000; - } else CorrosiveAcid_Timer -= diff; - - // Freeze_Timer - if (Freeze_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FREEZE); - Freeze_Timer = 16000; - } else Freeze_Timer -= diff; - - // Flamebreath_Timer - if (Flamebreath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FLAMEBREATH); - Flamebreath_Timer = 10500; - } else Flamebreath_Timer -= diff; - - //Summon Rend - if (!SummonedRend && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11 - && m_creature->GetHealth() > 0 ) - { - //summon Rend and Change model to normal Gyth - //Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - //Gyth model - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 9806); - m_creature->SummonCreature(10429, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000); - SummonedRend = true; - } - - DoMeleeAttackIfReady(); - } // end if Aggro - } -}; - -CreatureAI* GetAI_boss_gyth(Creature *_Creature) -{ - return new boss_gythAI (_Creature); -} - -void AddSC_boss_gyth() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gyth"; - newscript->GetAI = GetAI_boss_gyth; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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: +SDCategory: Blackrock Spire +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_CORROSIVEACID 20667 +#define SPELL_FREEZE 18763 +#define SPELL_FLAMEBREATH 20712 + +struct MANGOS_DLL_DECL boss_gythAI : public ScriptedAI +{ + boss_gythAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Aggro_Timer; + uint32 Dragons_Timer; + uint32 Orc_Timer; + uint32 CorrosiveAcid_Timer; + uint32 Freeze_Timer; + uint32 Flamebreath_Timer; + uint32 Line1Count; + uint32 Line2Count; + + bool Event; + bool SummonedDragons; + bool SummonedOrcs; + bool SummonedRend; + bool bAggro; + bool RootSelf; + Creature *SummonedCreature; + + void Reset() + { + Dragons_Timer = 3000; + Orc_Timer = 60000; + Aggro_Timer = 60000; + CorrosiveAcid_Timer = 8000; + Freeze_Timer = 11000; + Flamebreath_Timer = 4000; + Event = false; + SummonedDragons = false; + SummonedOrcs= false; + SummonedRend = false; + bAggro = false; + RootSelf = false; + + // how many times should the two lines of summoned creatures be spawned + // min 2 x 2, max 7 lines of attack in total + Line1Count = rand() % 4 + 2; + if (Line1Count < 5) + Line2Count = rand() % (5 - Line1Count) + 2; + else + Line2Count = 2; + + //Invisible for event start + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit *who) + { + } + + void SummonCreatureWithRandomTarget(uint32 creatureId) + { + Unit* Summoned = m_creature->SummonCreature(creatureId, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 240000); + if (Summoned) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (target) + Summoned->AddThreat(target, 1.0f); + } + } + + void UpdateAI(const uint32 diff) + { + //char buf[200]; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if (!RootSelf) + { + //m_creature->m_canMove = true; + DoCast(m_creature, 33356); + RootSelf = true; + } + + if (!bAggro && Line1Count == 0 && Line2Count == 0) + { + if (Aggro_Timer < diff) + { + bAggro = true; + // Visible now! + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 9723); + m_creature->setFaction(14); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } else Aggro_Timer -= diff; + } + + // Summon Dragon pack. 2 Dragons and 3 Whelps + if (!bAggro && !SummonedRend && Line1Count > 0) + { + if (Dragons_Timer < diff) + { + SummonCreatureWithRandomTarget(10372); + SummonCreatureWithRandomTarget(10372); + SummonCreatureWithRandomTarget(10442); + SummonCreatureWithRandomTarget(10442); + SummonCreatureWithRandomTarget(10442); + Line1Count = Line1Count - 1; + Dragons_Timer = 60000; + } else Dragons_Timer -= diff; + } + + //Summon Orc pack. 1 Orc Handler 1 Elite Dragonkin and 3 Whelps + if (!bAggro && !SummonedRend && Line1Count == 0 && Line2Count > 0) + { + if (Orc_Timer < diff) + { + SummonCreatureWithRandomTarget(10447); + SummonCreatureWithRandomTarget(10317); + SummonCreatureWithRandomTarget(10442); + SummonCreatureWithRandomTarget(10442); + SummonCreatureWithRandomTarget(10442); + Line2Count = Line2Count - 1; + Orc_Timer = 60000; + } else Orc_Timer -= diff; + } + + // we take part in the fight + if (bAggro) + { + // CorrosiveAcid_Timer + if (CorrosiveAcid_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CORROSIVEACID); + CorrosiveAcid_Timer = 7000; + } else CorrosiveAcid_Timer -= diff; + + // Freeze_Timer + if (Freeze_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FREEZE); + Freeze_Timer = 16000; + } else Freeze_Timer -= diff; + + // Flamebreath_Timer + if (Flamebreath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FLAMEBREATH); + Flamebreath_Timer = 10500; + } else Flamebreath_Timer -= diff; + + //Summon Rend + if (!SummonedRend && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11 + && m_creature->GetHealth() > 0 ) + { + //summon Rend and Change model to normal Gyth + //Inturrupt any spell casting + m_creature->InterruptNonMeleeSpells(false); + //Gyth model + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 9806); + m_creature->SummonCreature(10429, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000); + SummonedRend = true; + } + + DoMeleeAttackIfReady(); + } // end if Aggro + } +}; + +CreatureAI* GetAI_boss_gyth(Creature *_Creature) +{ + return new boss_gythAI (_Creature); +} + +void AddSC_boss_gyth() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gyth"; + newscript->GetAI = GetAI_boss_gyth; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_halycon.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_halycon.cpp index 27509b43355..1effd8287e9 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_halycon.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_halycon.cpp @@ -1,95 +1,95 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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.839203 -#define ADD_1Y -324.961395 -#define ADD_1Z 64.401443 -#define ADD_1O 3.124724 - -struct MANGOS_DLL_DECL boss_halyconAI : public ScriptedAI -{ - boss_halyconAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 CrowdPummel_Timer; - uint32 MightyBlow_Timer; - bool Summoned; - - void Reset() - { - CrowdPummel_Timer = 8000; - MightyBlow_Timer = 14000; - Summoned = false; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //CrowdPummel_Timer - if (CrowdPummel_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CROWDPUMMEL); - CrowdPummel_Timer = 14000; - }else CrowdPummel_Timer -= diff; - - //MightyBlow_Timer - if (MightyBlow_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MIGHTYBLOW); - MightyBlow_Timer = 10000; - }else MightyBlow_Timer -= diff; - - //Summon Gizrul - if ( !Summoned && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 25 ) - { - m_creature->SummonCreature(10268,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,300000); - Summoned = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_halycon(Creature *_Creature) -{ - return new boss_halyconAI (_Creature); -} - -void AddSC_boss_halycon() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_halycon"; - newscript->GetAI = GetAI_boss_halycon; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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.839203 +#define ADD_1Y -324.961395 +#define ADD_1Z 64.401443 +#define ADD_1O 3.124724 + +struct MANGOS_DLL_DECL boss_halyconAI : public ScriptedAI +{ + boss_halyconAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 CrowdPummel_Timer; + uint32 MightyBlow_Timer; + bool Summoned; + + void Reset() + { + CrowdPummel_Timer = 8000; + MightyBlow_Timer = 14000; + Summoned = false; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //CrowdPummel_Timer + if (CrowdPummel_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CROWDPUMMEL); + CrowdPummel_Timer = 14000; + }else CrowdPummel_Timer -= diff; + + //MightyBlow_Timer + if (MightyBlow_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MIGHTYBLOW); + MightyBlow_Timer = 10000; + }else MightyBlow_Timer -= diff; + + //Summon Gizrul + if ( !Summoned && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 25 ) + { + m_creature->SummonCreature(10268,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,300000); + Summoned = true; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_halycon(Creature *_Creature) +{ + return new boss_halyconAI (_Creature); +} + +void AddSC_boss_halycon() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_halycon"; + newscript->GetAI = GetAI_boss_halycon; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_highlord_omokk.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_highlord_omokk.cpp index b0fc6b3ac14..e0bde6bca00 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_highlord_omokk.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_highlord_omokk.cpp @@ -1,131 +1,131 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_WARSTOMP 24375 -#define SPELL_CLEAVE 15579 -#define SPELL_STRIKE 18368 -#define SPELL_REND 18106 -#define SPELL_SUNDERARMOR 24317 -#define SPELL_KNOCKAWAY 20686 -#define SPELL_SLOW 22356 - -struct MANGOS_DLL_DECL boss_highlordomokkAI : public ScriptedAI -{ - boss_highlordomokkAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 WarStomp_Timer; - uint32 Cleave_Timer; - uint32 Strike_Timer; - uint32 Rend_Timer; - uint32 SunderArmor_Timer; - uint32 KnockAway_Timer; - uint32 Slow_Timer; - - void Reset() - { - WarStomp_Timer = 15000; - Cleave_Timer = 6000; - Strike_Timer = 10000; - Rend_Timer = 14000; - SunderArmor_Timer = 2000; - KnockAway_Timer = 18000; - Slow_Timer = 24000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //WarStomp_Timer - if (WarStomp_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_WARSTOMP); - WarStomp_Timer = 14000; - }else WarStomp_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 8000; - }else Cleave_Timer -= diff; - - //Strike_Timer - if (Strike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_STRIKE); - Strike_Timer = 10000; - }else Strike_Timer -= diff; - - //Rend_Timer - if (Rend_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_REND); - Rend_Timer = 18000; - }else Rend_Timer -= diff; - - //SunderArmor_Timer - if (SunderArmor_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SUNDERARMOR); - SunderArmor_Timer = 25000; - }else SunderArmor_Timer -= diff; - - //KnockAway_Timer - if (KnockAway_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); - KnockAway_Timer = 12000; - }else KnockAway_Timer -= diff; - - //Slow_Timer - if (Slow_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SLOW); - Slow_Timer = 18000; - }else Slow_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_highlordomokk(Creature *_Creature) -{ - return new boss_highlordomokkAI (_Creature); -} - -void AddSC_boss_highlordomokk() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_highlord_omokk"; - newscript->GetAI = GetAI_boss_highlordomokk; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_WARSTOMP 24375 +#define SPELL_CLEAVE 15579 +#define SPELL_STRIKE 18368 +#define SPELL_REND 18106 +#define SPELL_SUNDERARMOR 24317 +#define SPELL_KNOCKAWAY 20686 +#define SPELL_SLOW 22356 + +struct MANGOS_DLL_DECL boss_highlordomokkAI : public ScriptedAI +{ + boss_highlordomokkAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 WarStomp_Timer; + uint32 Cleave_Timer; + uint32 Strike_Timer; + uint32 Rend_Timer; + uint32 SunderArmor_Timer; + uint32 KnockAway_Timer; + uint32 Slow_Timer; + + void Reset() + { + WarStomp_Timer = 15000; + Cleave_Timer = 6000; + Strike_Timer = 10000; + Rend_Timer = 14000; + SunderArmor_Timer = 2000; + KnockAway_Timer = 18000; + Slow_Timer = 24000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //WarStomp_Timer + if (WarStomp_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_WARSTOMP); + WarStomp_Timer = 14000; + }else WarStomp_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 8000; + }else Cleave_Timer -= diff; + + //Strike_Timer + if (Strike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_STRIKE); + Strike_Timer = 10000; + }else Strike_Timer -= diff; + + //Rend_Timer + if (Rend_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_REND); + Rend_Timer = 18000; + }else Rend_Timer -= diff; + + //SunderArmor_Timer + if (SunderArmor_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SUNDERARMOR); + SunderArmor_Timer = 25000; + }else SunderArmor_Timer -= diff; + + //KnockAway_Timer + if (KnockAway_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); + KnockAway_Timer = 12000; + }else KnockAway_Timer -= diff; + + //Slow_Timer + if (Slow_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SLOW); + Slow_Timer = 18000; + }else Slow_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_highlordomokk(Creature *_Creature) +{ + return new boss_highlordomokkAI (_Creature); +} + +void AddSC_boss_highlordomokk() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_highlord_omokk"; + newscript->GetAI = GetAI_boss_highlordomokk; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_mother_smolderweb.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_mother_smolderweb.cpp index 04cef92dcc1..cd212627fe5 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_mother_smolderweb.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_mother_smolderweb.cpp @@ -1,86 +1,86 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_CRYSTALIZE 16104 -#define SPELL_MOTHERSMILK 16468 -#define SPELL_SUMMON_SPIRE_SPIDERLING 16103 - -struct MANGOS_DLL_DECL boss_mothersmolderwebAI : public ScriptedAI -{ - boss_mothersmolderwebAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Crystalize_Timer; - uint32 MothersMilk_Timer; - - void Reset() - { - Crystalize_Timer = 20000; - MothersMilk_Timer = 10000; - } - - void Aggro(Unit *who) { } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if( m_creature->GetHealth() <= damage ) - m_creature->CastSpell(m_creature,SPELL_SUMMON_SPIRE_SPIDERLING,true); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Crystalize_Timer - if( Crystalize_Timer < diff ) - { - DoCast(m_creature,SPELL_CRYSTALIZE); - Crystalize_Timer = 15000; - }else Crystalize_Timer -= diff; - - //MothersMilk_Timer - if( MothersMilk_Timer < diff ) - { - DoCast(m_creature,SPELL_MOTHERSMILK); - MothersMilk_Timer = 5000+rand()%7500; - }else MothersMilk_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_mothersmolderweb(Creature *_Creature) -{ - return new boss_mothersmolderwebAI (_Creature); -} - -void AddSC_boss_mothersmolderweb() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_mother_smolderweb"; - newscript->GetAI = GetAI_boss_mothersmolderweb; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_CRYSTALIZE 16104 +#define SPELL_MOTHERSMILK 16468 +#define SPELL_SUMMON_SPIRE_SPIDERLING 16103 + +struct MANGOS_DLL_DECL boss_mothersmolderwebAI : public ScriptedAI +{ + boss_mothersmolderwebAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Crystalize_Timer; + uint32 MothersMilk_Timer; + + void Reset() + { + Crystalize_Timer = 20000; + MothersMilk_Timer = 10000; + } + + void Aggro(Unit *who) { } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if( m_creature->GetHealth() <= damage ) + m_creature->CastSpell(m_creature,SPELL_SUMMON_SPIRE_SPIDERLING,true); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Crystalize_Timer + if( Crystalize_Timer < diff ) + { + DoCast(m_creature,SPELL_CRYSTALIZE); + Crystalize_Timer = 15000; + }else Crystalize_Timer -= diff; + + //MothersMilk_Timer + if( MothersMilk_Timer < diff ) + { + DoCast(m_creature,SPELL_MOTHERSMILK); + MothersMilk_Timer = 5000+rand()%7500; + }else MothersMilk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_mothersmolderweb(Creature *_Creature) +{ + return new boss_mothersmolderwebAI (_Creature); +} + +void AddSC_boss_mothersmolderweb() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_mother_smolderweb"; + newscript->GetAI = GetAI_boss_mothersmolderweb; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_overlord_wyrmthalak.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_overlord_wyrmthalak.cpp index 3eabd522ccc..33ab597f752 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_overlord_wyrmthalak.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_overlord_wyrmthalak.cpp @@ -1,127 +1,127 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Overlord_Wyrmthalak -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_BLASTWAVE 11130 -#define SPELL_SHOUT 23511 -#define SPELL_CLEAVE 20691 -#define SPELL_KNOCKAWAY 20686 - -#define ADD_1X -39.355381 -#define ADD_1Y -513.456482 -#define ADD_1Z 88.472046 -#define ADD_1O 4.679872 - -#define ADD_2X -49.875881 -#define ADD_2Y -511.896942 -#define ADD_2Z 88.195160 -#define ADD_2O 4.613114 - -struct MANGOS_DLL_DECL boss_overlordwyrmthalakAI : public ScriptedAI -{ - boss_overlordwyrmthalakAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 BlastWave_Timer; - uint32 Shout_Timer; - uint32 Cleave_Timer; - uint32 Knockaway_Timer; - bool Summoned; - Creature *SummonedCreature; - - void Reset() - { - BlastWave_Timer = 20000; - Shout_Timer = 2000; - Cleave_Timer = 6000; - Knockaway_Timer = 12000; - Summoned = false; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //BlastWave_Timer - if (BlastWave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_BLASTWAVE); - BlastWave_Timer = 20000; - }else BlastWave_Timer -= diff; - - //Shout_Timer - if (Shout_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHOUT); - Shout_Timer = 10000; - }else Shout_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - //Knockaway_Timer - if (Knockaway_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); - Knockaway_Timer = 14000; - }else Knockaway_Timer -= diff; - - //Summon two Beserks - if ( !Summoned && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - SummonedCreature = m_creature->SummonCreature(9216,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,300000); - ((CreatureAI*)SummonedCreature->AI())->AttackStart(target); - SummonedCreature = m_creature->SummonCreature(9268,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,300000); - ((CreatureAI*)SummonedCreature->AI())->AttackStart(target); - Summoned = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_overlordwyrmthalak(Creature *_Creature) -{ - return new boss_overlordwyrmthalakAI (_Creature); -} - -void AddSC_boss_overlordwyrmthalak() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_overlord_wyrmthalak"; - newscript->GetAI = GetAI_boss_overlordwyrmthalak; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Overlord_Wyrmthalak +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Spire +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_BLASTWAVE 11130 +#define SPELL_SHOUT 23511 +#define SPELL_CLEAVE 20691 +#define SPELL_KNOCKAWAY 20686 + +#define ADD_1X -39.355381 +#define ADD_1Y -513.456482 +#define ADD_1Z 88.472046 +#define ADD_1O 4.679872 + +#define ADD_2X -49.875881 +#define ADD_2Y -511.896942 +#define ADD_2Z 88.195160 +#define ADD_2O 4.613114 + +struct MANGOS_DLL_DECL boss_overlordwyrmthalakAI : public ScriptedAI +{ + boss_overlordwyrmthalakAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 BlastWave_Timer; + uint32 Shout_Timer; + uint32 Cleave_Timer; + uint32 Knockaway_Timer; + bool Summoned; + Creature *SummonedCreature; + + void Reset() + { + BlastWave_Timer = 20000; + Shout_Timer = 2000; + Cleave_Timer = 6000; + Knockaway_Timer = 12000; + Summoned = false; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //BlastWave_Timer + if (BlastWave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_BLASTWAVE); + BlastWave_Timer = 20000; + }else BlastWave_Timer -= diff; + + //Shout_Timer + if (Shout_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHOUT); + Shout_Timer = 10000; + }else Shout_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 7000; + }else Cleave_Timer -= diff; + + //Knockaway_Timer + if (Knockaway_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); + Knockaway_Timer = 14000; + }else Knockaway_Timer -= diff; + + //Summon two Beserks + if ( !Summoned && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 51 ) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + SummonedCreature = m_creature->SummonCreature(9216,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,300000); + ((CreatureAI*)SummonedCreature->AI())->AttackStart(target); + SummonedCreature = m_creature->SummonCreature(9268,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,300000); + ((CreatureAI*)SummonedCreature->AI())->AttackStart(target); + Summoned = true; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_overlordwyrmthalak(Creature *_Creature) +{ + return new boss_overlordwyrmthalakAI (_Creature); +} + +void AddSC_boss_overlordwyrmthalak() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_overlord_wyrmthalak"; + newscript->GetAI = GetAI_boss_overlordwyrmthalak; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_pyroguard_emberseer.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_pyroguard_emberseer.cpp index 248ea48f9e0..b75c3fa1d8d 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_pyroguard_emberseer.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_pyroguard_emberseer.cpp @@ -1,93 +1,93 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FIRENOVA 23462 -#define SPELL_FLAMEBUFFET 23341 -#define SPELL_PYROBLAST 17274 - -struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI -{ - boss_pyroguard_emberseerAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FireNova_Timer; - uint32 FlameBuffet_Timer; - uint32 PyroBlast_Timer; - - void Reset() - { - FireNova_Timer = 6000; - FlameBuffet_Timer = 3000; - PyroBlast_Timer = 14000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //FireNova_Timer - if (FireNova_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIRENOVA); - FireNova_Timer = 6000; - }else FireNova_Timer -= diff; - - //FlameBuffet_Timer - if (FlameBuffet_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FLAMEBUFFET); - FlameBuffet_Timer = 14000; - }else FlameBuffet_Timer -= diff; - - //PyroBlast_Timer - if (PyroBlast_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_PYROBLAST); - PyroBlast_Timer = 15000; - }else PyroBlast_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_pyroguard_emberseer(Creature *_Creature) -{ - return new boss_pyroguard_emberseerAI (_Creature); -} - -void AddSC_boss_pyroguard_emberseer() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_pyroguard_emberseer"; - newscript->GetAI = GetAI_boss_pyroguard_emberseer; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 +SDCategory: Blackrock Spire +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_FIRENOVA 23462 +#define SPELL_FLAMEBUFFET 23341 +#define SPELL_PYROBLAST 17274 + +struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI +{ + boss_pyroguard_emberseerAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FireNova_Timer; + uint32 FlameBuffet_Timer; + uint32 PyroBlast_Timer; + + void Reset() + { + FireNova_Timer = 6000; + FlameBuffet_Timer = 3000; + PyroBlast_Timer = 14000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //FireNova_Timer + if (FireNova_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIRENOVA); + FireNova_Timer = 6000; + }else FireNova_Timer -= diff; + + //FlameBuffet_Timer + if (FlameBuffet_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FLAMEBUFFET); + FlameBuffet_Timer = 14000; + }else FlameBuffet_Timer -= diff; + + //PyroBlast_Timer + if (PyroBlast_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_PYROBLAST); + PyroBlast_Timer = 15000; + }else PyroBlast_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_pyroguard_emberseer(Creature *_Creature) +{ + return new boss_pyroguard_emberseerAI (_Creature); +} + +void AddSC_boss_pyroguard_emberseer() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_pyroguard_emberseer"; + newscript->GetAI = GetAI_boss_pyroguard_emberseer; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_quartermaster_zigris.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_quartermaster_zigris.cpp index 6955ae8ad71..fd0798337f6 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_quartermaster_zigris.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_quartermaster_zigris.cpp @@ -1,85 +1,85 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_SHOOT 16496 -#define SPELL_STUNBOMB 16497 -#define SPELL_HEALING_POTION 15504 -#define SPELL_HOOKEDNET 15609 - -struct MANGOS_DLL_DECL boss_quatermasterzigrisAI : public ScriptedAI -{ - boss_quatermasterzigrisAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Shoot_Timer; - uint32 StunBomb_Timer; - //uint32 HelingPotion_Timer; - - void Reset() - { - Shoot_Timer = 1000; - StunBomb_Timer = 16000; - //HelingPotion_Timer = 25000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Shoot_Timer - if (Shoot_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHOOT); - Shoot_Timer = 500; - }else Shoot_Timer -= diff; - - //StunBomb_Timer - if (StunBomb_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_STUNBOMB); - StunBomb_Timer = 14000; - }else StunBomb_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_quatermasterzigris(Creature *_Creature) -{ - return new boss_quatermasterzigrisAI (_Creature); -} - -void AddSC_boss_quatermasterzigris() -{ - Script *newscript; - newscript = new Script; - newscript->Name="quartermaster_zigris"; - newscript->GetAI = GetAI_boss_quatermasterzigris; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_SHOOT 16496 +#define SPELL_STUNBOMB 16497 +#define SPELL_HEALING_POTION 15504 +#define SPELL_HOOKEDNET 15609 + +struct MANGOS_DLL_DECL boss_quatermasterzigrisAI : public ScriptedAI +{ + boss_quatermasterzigrisAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Shoot_Timer; + uint32 StunBomb_Timer; + //uint32 HelingPotion_Timer; + + void Reset() + { + Shoot_Timer = 1000; + StunBomb_Timer = 16000; + //HelingPotion_Timer = 25000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Shoot_Timer + if (Shoot_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHOOT); + Shoot_Timer = 500; + }else Shoot_Timer -= diff; + + //StunBomb_Timer + if (StunBomb_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_STUNBOMB); + StunBomb_Timer = 14000; + }else StunBomb_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_quatermasterzigris(Creature *_Creature) +{ + return new boss_quatermasterzigrisAI (_Creature); +} + +void AddSC_boss_quatermasterzigris() +{ + Script *newscript; + newscript = new Script; + newscript->Name="quartermaster_zigris"; + newscript->GetAI = GetAI_boss_quatermasterzigris; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_rend_blackhand.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_rend_blackhand.cpp index 679f92a06b6..f16f883761a 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_rend_blackhand.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_rend_blackhand.cpp @@ -1,91 +1,91 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_WHIRLWIND 26038 -#define SPELL_CLEAVE 20691 -#define SPELL_THUNDERCLAP 23931 //Not sure if he cast this spell - -struct MANGOS_DLL_DECL boss_rend_blackhandAI : public ScriptedAI -{ - boss_rend_blackhandAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 WhirlWind_Timer; - uint32 Cleave_Timer; - uint32 Thunderclap_Timer; - - void Reset() - { - WhirlWind_Timer = 20000; - Cleave_Timer = 5000; - Thunderclap_Timer = 9000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //WhirlWind_Timer - if (WhirlWind_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_WHIRLWIND); - WhirlWind_Timer = 18000; - }else WhirlWind_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 10000; - }else Cleave_Timer -= diff; - - //Thunderclap_Timer - if (Thunderclap_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); - Thunderclap_Timer = 16000; - }else Thunderclap_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_rend_blackhand(Creature *_Creature) -{ - return new boss_rend_blackhandAI (_Creature); -} - -void AddSC_boss_rend_blackhand() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_rend_blackhand"; - newscript->GetAI = GetAI_boss_rend_blackhand; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_WHIRLWIND 26038 +#define SPELL_CLEAVE 20691 +#define SPELL_THUNDERCLAP 23931 //Not sure if he cast this spell + +struct MANGOS_DLL_DECL boss_rend_blackhandAI : public ScriptedAI +{ + boss_rend_blackhandAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 WhirlWind_Timer; + uint32 Cleave_Timer; + uint32 Thunderclap_Timer; + + void Reset() + { + WhirlWind_Timer = 20000; + Cleave_Timer = 5000; + Thunderclap_Timer = 9000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //WhirlWind_Timer + if (WhirlWind_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_WHIRLWIND); + WhirlWind_Timer = 18000; + }else WhirlWind_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 10000; + }else Cleave_Timer -= diff; + + //Thunderclap_Timer + if (Thunderclap_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); + Thunderclap_Timer = 16000; + }else Thunderclap_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_rend_blackhand(Creature *_Creature) +{ + return new boss_rend_blackhandAI (_Creature); +} + +void AddSC_boss_rend_blackhand() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_rend_blackhand"; + newscript->GetAI = GetAI_boss_rend_blackhand; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_shadow_hunter_voshgajin.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_shadow_hunter_voshgajin.cpp index bc43f2e223a..da7ef479f1d 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_shadow_hunter_voshgajin.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_shadow_hunter_voshgajin.cpp @@ -1,95 +1,95 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_CURSEOFBLOOD 24673 -#define SPELL_HEX 16708 -#define SPELL_CLEAVE 20691 - -struct MANGOS_DLL_DECL boss_shadowvoshAI : public ScriptedAI -{ - boss_shadowvoshAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 CurseOfBlood_Timer; - uint32 Hex_Timer; - uint32 Cleave_Timer; - - void Reset() - { - CurseOfBlood_Timer = 2000; - Hex_Timer = 8000; - Cleave_Timer = 14000; - - //m_creature->CastSpell(m_creature,SPELL_ICEARMOR,true); - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //CurseOfBlood_Timer - if (CurseOfBlood_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CURSEOFBLOOD); - CurseOfBlood_Timer = 45000; - }else CurseOfBlood_Timer -= diff; - - //Hex_Timer - if (Hex_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_HEX); - Hex_Timer = 15000; - }else Hex_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_shadowvosh(Creature *_Creature) -{ - return new boss_shadowvoshAI (_Creature); -} - -void AddSC_boss_shadowvosh() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_shadow_hunter_voshgajin"; - newscript->GetAI = GetAI_boss_shadowvosh; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_CURSEOFBLOOD 24673 +#define SPELL_HEX 16708 +#define SPELL_CLEAVE 20691 + +struct MANGOS_DLL_DECL boss_shadowvoshAI : public ScriptedAI +{ + boss_shadowvoshAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 CurseOfBlood_Timer; + uint32 Hex_Timer; + uint32 Cleave_Timer; + + void Reset() + { + CurseOfBlood_Timer = 2000; + Hex_Timer = 8000; + Cleave_Timer = 14000; + + //m_creature->CastSpell(m_creature,SPELL_ICEARMOR,true); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //CurseOfBlood_Timer + if (CurseOfBlood_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CURSEOFBLOOD); + CurseOfBlood_Timer = 45000; + }else CurseOfBlood_Timer -= diff; + + //Hex_Timer + if (Hex_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_HEX); + Hex_Timer = 15000; + }else Hex_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 7000; + }else Cleave_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_shadowvosh(Creature *_Creature) +{ + return new boss_shadowvoshAI (_Creature); +} + +void AddSC_boss_shadowvosh() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_shadow_hunter_voshgajin"; + newscript->GetAI = GetAI_boss_shadowvosh; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_the_beast.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_the_beast.cpp index 93a30ecd204..25a44eab1bc 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_the_beast.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_the_beast.cpp @@ -1,93 +1,93 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_FLAMEBREAK 16785 -#define SPELL_IMMOLATE 20294 -#define SPELL_TERRIFYINGROAR 14100 - -struct MANGOS_DLL_DECL boss_thebeastAI : public ScriptedAI -{ - boss_thebeastAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Flamebreak_Timer; - uint32 Immolate_Timer; - uint32 TerrifyingRoar_Timer; - - void Reset() - { - Flamebreak_Timer = 12000; - Immolate_Timer = 3000; - TerrifyingRoar_Timer = 23000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Flamebreak_Timer - if (Flamebreak_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FLAMEBREAK); - Flamebreak_Timer = 10000; - }else Flamebreak_Timer -= diff; - - //Immolate_Timer - if (Immolate_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_IMMOLATE); - Immolate_Timer = 8000; - }else Immolate_Timer -= diff; - - //TerrifyingRoar_Timer - if (TerrifyingRoar_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_TERRIFYINGROAR); - TerrifyingRoar_Timer = 20000; - }else TerrifyingRoar_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_thebeast(Creature *_Creature) -{ - return new boss_thebeastAI (_Creature); -} - -void AddSC_boss_thebeast() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_the_beast"; - newscript->GetAI = GetAI_boss_thebeast; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_FLAMEBREAK 16785 +#define SPELL_IMMOLATE 20294 +#define SPELL_TERRIFYINGROAR 14100 + +struct MANGOS_DLL_DECL boss_thebeastAI : public ScriptedAI +{ + boss_thebeastAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Flamebreak_Timer; + uint32 Immolate_Timer; + uint32 TerrifyingRoar_Timer; + + void Reset() + { + Flamebreak_Timer = 12000; + Immolate_Timer = 3000; + TerrifyingRoar_Timer = 23000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Flamebreak_Timer + if (Flamebreak_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FLAMEBREAK); + Flamebreak_Timer = 10000; + }else Flamebreak_Timer -= diff; + + //Immolate_Timer + if (Immolate_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_IMMOLATE); + Immolate_Timer = 8000; + }else Immolate_Timer -= diff; + + //TerrifyingRoar_Timer + if (TerrifyingRoar_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_TERRIFYINGROAR); + TerrifyingRoar_Timer = 20000; + }else TerrifyingRoar_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_thebeast(Creature *_Creature) +{ + return new boss_thebeastAI (_Creature); +} + +void AddSC_boss_thebeast() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_the_beast"; + newscript->GetAI = GetAI_boss_thebeast; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_warmaster_voone.cpp b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_warmaster_voone.cpp index 6621c4672a1..d1385ee9b15 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_spire/boss_warmaster_voone.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_spire/boss_warmaster_voone.cpp @@ -1,121 +1,121 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 15579 -#define SPELL_UPPERCUT 10966 -#define SPELL_MORTALSTRIKE 16856 -#define SPELL_PUMMEL 15615 -#define SPELL_THROWAXE 16075 - -struct MANGOS_DLL_DECL boss_warmastervooneAI : public ScriptedAI -{ - boss_warmastervooneAI(Creature *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Snapkick_Timer - if (Snapkick_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SNAPKICK); - Snapkick_Timer = 6000; - }else Snapkick_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 12000; - }else Cleave_Timer -= diff; - - //Uppercut_Timer - if (Uppercut_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_UPPERCUT); - Uppercut_Timer = 14000; - }else Uppercut_Timer -= diff; - - //MortalStrike_Timer - if (MortalStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); - MortalStrike_Timer = 10000; - }else MortalStrike_Timer -= diff; - - //Pummel_Timer - if (Pummel_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_PUMMEL); - Pummel_Timer = 16000; - }else Pummel_Timer -= diff; - - //ThrowAxe_Timer - if (ThrowAxe_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_THROWAXE); - ThrowAxe_Timer = 8000; - }else ThrowAxe_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_warmastervoone(Creature *_Creature) -{ - return new boss_warmastervooneAI (_Creature); -} - -void AddSC_boss_warmastervoone() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_warmaster_voone"; - newscript->GetAI = GetAI_boss_warmastervoone; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 15579 +#define SPELL_UPPERCUT 10966 +#define SPELL_MORTALSTRIKE 16856 +#define SPELL_PUMMEL 15615 +#define SPELL_THROWAXE 16075 + +struct MANGOS_DLL_DECL boss_warmastervooneAI : public ScriptedAI +{ + boss_warmastervooneAI(Creature *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Snapkick_Timer + if (Snapkick_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SNAPKICK); + Snapkick_Timer = 6000; + }else Snapkick_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 12000; + }else Cleave_Timer -= diff; + + //Uppercut_Timer + if (Uppercut_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_UPPERCUT); + Uppercut_Timer = 14000; + }else Uppercut_Timer -= diff; + + //MortalStrike_Timer + if (MortalStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); + MortalStrike_Timer = 10000; + }else MortalStrike_Timer -= diff; + + //Pummel_Timer + if (Pummel_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_PUMMEL); + Pummel_Timer = 16000; + }else Pummel_Timer -= diff; + + //ThrowAxe_Timer + if (ThrowAxe_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_THROWAXE); + ThrowAxe_Timer = 8000; + }else ThrowAxe_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_warmastervoone(Creature *_Creature) +{ + return new boss_warmastervooneAI (_Creature); +} + +void AddSC_boss_warmastervoone() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_warmaster_voone"; + newscript->GetAI = GetAI_boss_warmastervoone; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_broodlord_lashlayer.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_broodlord_lashlayer.cpp index a1f3260550b..12ba8bedb7c 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_broodlord_lashlayer.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_broodlord_lashlayer.cpp @@ -1,130 +1,130 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 SPELL_CLEAVE 26350 -#define SPELL_BLASTWAVE 23331 -#define SPELL_MORTALSTRIKE 24573 -#define SPELL_KNOCKBACK 25778 - -#define SAY_AGGRO "None of your kind should be here! You've doomed only yourselves!" -#define SAY_LEASH "Clever Mortals but I am not so easily lured away from my sanctum!" -#define SOUND_AGGRO 8286 -#define SOUND_LEASH 8287 - -struct MANGOS_DLL_DECL boss_broodlordAI : public ScriptedAI -{ - boss_broodlordAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Cleave_Timer; - uint32 BlastWave_Timer; - uint32 MortalStrike_Timer; - uint32 KnockBack_Timer; - uint32 LeashCheck_Timer; - - void Reset() - { - Cleave_Timer = 8000; //These times are probably wrong - BlastWave_Timer = 12000; - MortalStrike_Timer = 20000; - KnockBack_Timer = 30000; - LeashCheck_Timer = 2000; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //LeashCheck_Timer - if (LeashCheck_Timer < diff) - { - float rx,ry,rz; - m_creature->GetRespawnCoord(rx, ry, rz); - float spawndist = m_creature->GetDistance(rx,ry,rz); - if ( spawndist > 250 ) - { - EnterEvadeMode(); - return; - } - LeashCheck_Timer = 2000; - }else LeashCheck_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - // BlastWave - if (BlastWave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_BLASTWAVE); - BlastWave_Timer = 8000 + rand()%8000; - }else BlastWave_Timer -= diff; - - //MortalStrike_Timer - if (MortalStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); - MortalStrike_Timer = 25000 + rand()%10000; - }else MortalStrike_Timer -= diff; - - if (KnockBack_Timer < diff) - { - DoCast(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 = 15000 + rand()%15000; - }else KnockBack_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_broodlord(Creature *_Creature) -{ - return new boss_broodlordAI (_Creature); -} - -void AddSC_boss_broodlord() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_broodlord"; - newscript->GetAI = GetAI_boss_broodlord; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 SPELL_CLEAVE 26350 +#define SPELL_BLASTWAVE 23331 +#define SPELL_MORTALSTRIKE 24573 +#define SPELL_KNOCKBACK 25778 + +#define SAY_AGGRO "None of your kind should be here! You've doomed only yourselves!" +#define SAY_LEASH "Clever Mortals but I am not so easily lured away from my sanctum!" +#define SOUND_AGGRO 8286 +#define SOUND_LEASH 8287 + +struct MANGOS_DLL_DECL boss_broodlordAI : public ScriptedAI +{ + boss_broodlordAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Cleave_Timer; + uint32 BlastWave_Timer; + uint32 MortalStrike_Timer; + uint32 KnockBack_Timer; + uint32 LeashCheck_Timer; + + void Reset() + { + Cleave_Timer = 8000; //These times are probably wrong + BlastWave_Timer = 12000; + MortalStrike_Timer = 20000; + KnockBack_Timer = 30000; + LeashCheck_Timer = 2000; + + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //LeashCheck_Timer + if (LeashCheck_Timer < diff) + { + float rx,ry,rz; + m_creature->GetRespawnCoord(rx, ry, rz); + float spawndist = m_creature->GetDistance(rx,ry,rz); + if ( spawndist > 250 ) + { + EnterEvadeMode(); + return; + } + LeashCheck_Timer = 2000; + }else LeashCheck_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 7000; + }else Cleave_Timer -= diff; + + // BlastWave + if (BlastWave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_BLASTWAVE); + BlastWave_Timer = 8000 + rand()%8000; + }else BlastWave_Timer -= diff; + + //MortalStrike_Timer + if (MortalStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); + MortalStrike_Timer = 25000 + rand()%10000; + }else MortalStrike_Timer -= diff; + + if (KnockBack_Timer < diff) + { + DoCast(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 = 15000 + rand()%15000; + }else KnockBack_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_broodlord(Creature *_Creature) +{ + return new boss_broodlordAI (_Creature); +} + +void AddSC_boss_broodlord() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_broodlord"; + newscript->GetAI = GetAI_boss_broodlord; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_chromaggus.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_chromaggus.cpp index db05dab31b6..c746e935aba 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_chromaggus.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_chromaggus.cpp @@ -1,320 +1,320 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -//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% -#define SPELL_FIRE_VURNALBILTY 22277 -#define SPELL_FROST_VURNALBILTY 22278 -#define SPELL_SHADOW_VURNALBILTY 22279 -#define SPELL_NATURE_VURNALBILTY 22280 -#define SPELL_ARCANE_VURNALBILTY 22281 - -#define EMOTE_FRENZY "goes into a killing frenzy!" -#define EMOTE_SHIMMER "flinches as its skin shimmers" - -#define SPELL_INCINERATE 23308 //Incinerate 23308,23309 -#define SPELL_TIMELAPSE 23310 //Time lapse 23310, 23311(old threat mod that was removed in 2.01) -#define SPELL_CORROSIVEACID 23313 //Corrosive Acid 23313, 23314 -#define SPELL_IGNITEFLESH 23315 //Ignite Flesh 23315,23316 -#define 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 - -#define SPELL_BROODAF_BLUE 23153 //Blue affliction 23153 -#define SPELL_BROODAF_BLACK 23154 //Black affliction 23154 -#define SPELL_BROODAF_RED 23155 //Red affliction 23155 (23168 on death) -#define SPELL_BROODAF_BRONZE 23170 //Bronze Affliction 23170 -#define SPELL_BROODAF_GREEN 23169 //Brood Affliction Green 23169 - -#define SPELL_CHROMATIC_MUT_1 23174 //Spell cast on player if they get all 5 debuffs - -#define SPELL_FRENZY 28371 //The frenzy spell may be wrong -#define SPELL_ENRAGE 28747 - -#define TEMP_MUTATE_WHISPER "[SD2 Debug] You would be mind controlled here!" - -struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI -{ - boss_chromaggusAI(Creature *c) : ScriptedAI(c) - { - //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 (rand()%20) - { - //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 player every 5 sconds - Frenzy_Timer = 15000; - - Enraged = false; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !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 (rand()%5) - { - 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; - } - - DoCast(m_creature,spell); - CurrentVurln_Spell = spell; - - DoTextEmote(EMOTE_SHIMMER, NULL); - Shimmer_Timer = 45000; - }else Shimmer_Timer -= diff; - - //Breath1_Timer - if (Breath1_Timer < diff) - { - DoCast(m_creature->getVictim(),Breath1_Spell); - Breath1_Timer = 60000; - }else Breath1_Timer -= diff; - - //Breath2_Timer - if (Breath2_Timer < diff) - { - DoCast(m_creature->getVictim(),Breath2_Spell); - Breath2_Timer = 60000; - }else Breath2_Timer -= diff; - - //Affliction_Timer - if (Affliction_Timer < diff) - { - uint32 SpellAfflict = 0; - - switch (rand()%5) - { - 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; - } - - std::list::iterator i; - - for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - Unit* pUnit = NULL; - pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - - if(pUnit) - { - //Cast affliction - DoCast(pUnit, SpellAfflict, true); - - //Chromatic mutation if target is effected by all afflictions - if (pUnit->HasAura(SPELL_BROODAF_BLUE,0) - && pUnit->HasAura(SPELL_BROODAF_BLACK,0) - && pUnit->HasAura(SPELL_BROODAF_RED,0) - && pUnit->HasAura(SPELL_BROODAF_BRONZE,0) - && pUnit->HasAura(SPELL_BROODAF_GREEN,0)) - { - //target->RemoveAllAuras(); - //DoCast(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) - { - DoWhisper(TEMP_MUTATE_WHISPER, pUnit); - pUnit->CastSpell(pUnit, 5, false); - } - } - } - } - - Affliction_Timer = 10000; - }else Affliction_Timer -= diff; - - //Frenzy_Timer - if (Frenzy_Timer < diff) - { - DoCast(m_creature,SPELL_FRENZY); - DoTextEmote(EMOTE_FRENZY,NULL); - Frenzy_Timer = 10000 + (rand() % 5000); - }else Frenzy_Timer -= diff; - - //Enrage if not already enraged and below 20% - if (!Enraged && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) - { - DoCast(m_creature,SPELL_ENRAGE); - Enraged = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_chromaggus(Creature *_Creature) -{ - return new boss_chromaggusAI (_Creature); -} - -void AddSC_boss_chromaggus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_chromaggus"; - newscript->GetAI = GetAI_boss_chromaggus; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +//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% +#define SPELL_FIRE_VURNALBILTY 22277 +#define SPELL_FROST_VURNALBILTY 22278 +#define SPELL_SHADOW_VURNALBILTY 22279 +#define SPELL_NATURE_VURNALBILTY 22280 +#define SPELL_ARCANE_VURNALBILTY 22281 + +#define EMOTE_FRENZY "goes into a killing frenzy!" +#define EMOTE_SHIMMER "flinches as its skin shimmers" + +#define SPELL_INCINERATE 23308 //Incinerate 23308,23309 +#define SPELL_TIMELAPSE 23310 //Time lapse 23310, 23311(old threat mod that was removed in 2.01) +#define SPELL_CORROSIVEACID 23313 //Corrosive Acid 23313, 23314 +#define SPELL_IGNITEFLESH 23315 //Ignite Flesh 23315,23316 +#define 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 + +#define SPELL_BROODAF_BLUE 23153 //Blue affliction 23153 +#define SPELL_BROODAF_BLACK 23154 //Black affliction 23154 +#define SPELL_BROODAF_RED 23155 //Red affliction 23155 (23168 on death) +#define SPELL_BROODAF_BRONZE 23170 //Bronze Affliction 23170 +#define SPELL_BROODAF_GREEN 23169 //Brood Affliction Green 23169 + +#define SPELL_CHROMATIC_MUT_1 23174 //Spell cast on player if they get all 5 debuffs + +#define SPELL_FRENZY 28371 //The frenzy spell may be wrong +#define SPELL_ENRAGE 28747 + +#define TEMP_MUTATE_WHISPER "[SD2 Debug] You would be mind controlled here!" + +struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI +{ + boss_chromaggusAI(Creature *c) : ScriptedAI(c) + { + //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 (rand()%20) + { + //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 player every 5 sconds + Frenzy_Timer = 15000; + + Enraged = false; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !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 (rand()%5) + { + 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; + } + + DoCast(m_creature,spell); + CurrentVurln_Spell = spell; + + DoTextEmote(EMOTE_SHIMMER, NULL); + Shimmer_Timer = 45000; + }else Shimmer_Timer -= diff; + + //Breath1_Timer + if (Breath1_Timer < diff) + { + DoCast(m_creature->getVictim(),Breath1_Spell); + Breath1_Timer = 60000; + }else Breath1_Timer -= diff; + + //Breath2_Timer + if (Breath2_Timer < diff) + { + DoCast(m_creature->getVictim(),Breath2_Spell); + Breath2_Timer = 60000; + }else Breath2_Timer -= diff; + + //Affliction_Timer + if (Affliction_Timer < diff) + { + uint32 SpellAfflict = 0; + + switch (rand()%5) + { + 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; + } + + std::list::iterator i; + + for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Unit* pUnit = NULL; + pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + + if(pUnit) + { + //Cast affliction + DoCast(pUnit, SpellAfflict, true); + + //Chromatic mutation if target is effected by all afflictions + if (pUnit->HasAura(SPELL_BROODAF_BLUE,0) + && pUnit->HasAura(SPELL_BROODAF_BLACK,0) + && pUnit->HasAura(SPELL_BROODAF_RED,0) + && pUnit->HasAura(SPELL_BROODAF_BRONZE,0) + && pUnit->HasAura(SPELL_BROODAF_GREEN,0)) + { + //target->RemoveAllAuras(); + //DoCast(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) + { + DoWhisper(TEMP_MUTATE_WHISPER, pUnit); + pUnit->CastSpell(pUnit, 5, false); + } + } + } + } + + Affliction_Timer = 10000; + }else Affliction_Timer -= diff; + + //Frenzy_Timer + if (Frenzy_Timer < diff) + { + DoCast(m_creature,SPELL_FRENZY); + DoTextEmote(EMOTE_FRENZY,NULL); + Frenzy_Timer = 10000 + (rand() % 5000); + }else Frenzy_Timer -= diff; + + //Enrage if not already enraged and below 20% + if (!Enraged && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) + { + DoCast(m_creature,SPELL_ENRAGE); + Enraged = true; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_chromaggus(Creature *_Creature) +{ + return new boss_chromaggusAI (_Creature); +} + +void AddSC_boss_chromaggus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_chromaggus"; + newscript->GetAI = GetAI_boss_chromaggus; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_ebonroc.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_ebonroc.cpp index 91d57238f01..6f98580d64f 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_ebonroc.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_ebonroc.cpp @@ -1,103 +1,103 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 *who) - { - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Shadowflame Timer - if (ShadowFlame_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWFLAME); - ShadowFlame_Timer = 12000 + rand()%3000; - }else ShadowFlame_Timer -= diff; - - //Wing Buffet Timer - if (WingBuffet_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_WINGBUFFET); - WingBuffet_Timer = 25000; - }else WingBuffet_Timer -= diff; - - //Shadow of Ebonroc Timer - if (ShadowOfEbonroc_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWOFEBONROC); - ShadowOfEbonroc_Timer = 25000 + rand()%10000; - }else ShadowOfEbonroc_Timer -= diff; - - if (m_creature->getVictim()->HasAura(SPELL_SHADOWOFEBONROC,0)) - { - if (Heal_Timer < diff) - { - DoCast(m_creature, SPELL_HEAL); - Heal_Timer = 1000 + rand()%2000; - }else Heal_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ebonroc(Creature *_Creature) -{ - return new boss_ebonrocAI (_Creature); -} - -void AddSC_boss_ebonroc() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ebonroc"; - newscript->GetAI = GetAI_boss_ebonroc; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 *who) + { + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Shadowflame Timer + if (ShadowFlame_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWFLAME); + ShadowFlame_Timer = 12000 + rand()%3000; + }else ShadowFlame_Timer -= diff; + + //Wing Buffet Timer + if (WingBuffet_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_WINGBUFFET); + WingBuffet_Timer = 25000; + }else WingBuffet_Timer -= diff; + + //Shadow of Ebonroc Timer + if (ShadowOfEbonroc_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWOFEBONROC); + ShadowOfEbonroc_Timer = 25000 + rand()%10000; + }else ShadowOfEbonroc_Timer -= diff; + + if (m_creature->getVictim()->HasAura(SPELL_SHADOWOFEBONROC,0)) + { + if (Heal_Timer < diff) + { + DoCast(m_creature, SPELL_HEAL); + Heal_Timer = 1000 + rand()%2000; + }else Heal_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_ebonroc(Creature *_Creature) +{ + return new boss_ebonrocAI (_Creature); +} + +void AddSC_boss_ebonroc() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ebonroc"; + newscript->GetAI = GetAI_boss_ebonroc; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_firemaw.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_firemaw.cpp index f4b7848a3bb..22ed8fd5ea6 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_firemaw.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_firemaw.cpp @@ -1,94 +1,94 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 *who) - { - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowFlame_Timer - if (ShadowFlame_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWFLAME); - ShadowFlame_Timer = 15000 + rand()%3000; - }else ShadowFlame_Timer -= diff; - - //WingBuffet_Timer - if (WingBuffet_Timer < diff) - { - DoCast(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) - { - DoCast(m_creature->getVictim(),SPELL_FLAMEBUFFET); - FlameBuffet_Timer = 5000; - }else FlameBuffet_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_firemaw(Creature *_Creature) -{ - return new boss_firemawAI (_Creature); -} - -void AddSC_boss_firemaw() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_firemaw"; - newscript->GetAI = GetAI_boss_firemaw; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 *who) + { + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowFlame_Timer + if (ShadowFlame_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWFLAME); + ShadowFlame_Timer = 15000 + rand()%3000; + }else ShadowFlame_Timer -= diff; + + //WingBuffet_Timer + if (WingBuffet_Timer < diff) + { + DoCast(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) + { + DoCast(m_creature->getVictim(),SPELL_FLAMEBUFFET); + FlameBuffet_Timer = 5000; + }else FlameBuffet_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_firemaw(Creature *_Creature) +{ + return new boss_firemawAI (_Creature); +} + +void AddSC_boss_firemaw() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_firemaw"; + newscript->GetAI = GetAI_boss_firemaw; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_flamegor.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_flamegor.cpp index 5bc6531c45a..514f10651a7 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_flamegor.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_flamegor.cpp @@ -1,94 +1,94 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_SHADOWFLAME 22539 -#define SPELL_WINGBUFFET 23339 -#define SPELL_FRENZY 23342 //This spell periodically triggers fire nova - -struct MANGOS_DLL_DECL boss_flamegorAI : public ScriptedAI -{ - boss_flamegorAI(Creature *c) : ScriptedAI(c) {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 *who) - { - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowFlame_Timer - if (ShadowFlame_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWFLAME); - ShadowFlame_Timer = 15000 + rand()%7000; - }else ShadowFlame_Timer -= diff; - - //WingBuffet_Timer - if (WingBuffet_Timer < diff) - { - DoCast(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) - { - DoCast(m_creature,SPELL_FRENZY); - Frenzy_Timer = 8000 + (rand()%2000); - }else Frenzy_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_flamegor(Creature *_Creature) -{ - return new boss_flamegorAI (_Creature); -} - -void AddSC_boss_flamegor() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_flamegor"; - newscript->GetAI = GetAI_boss_flamegor; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_SHADOWFLAME 22539 +#define SPELL_WINGBUFFET 23339 +#define SPELL_FRENZY 23342 //This spell periodically triggers fire nova + +struct MANGOS_DLL_DECL boss_flamegorAI : public ScriptedAI +{ + boss_flamegorAI(Creature *c) : ScriptedAI(c) {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 *who) + { + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowFlame_Timer + if (ShadowFlame_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWFLAME); + ShadowFlame_Timer = 15000 + rand()%7000; + }else ShadowFlame_Timer -= diff; + + //WingBuffet_Timer + if (WingBuffet_Timer < diff) + { + DoCast(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) + { + DoCast(m_creature,SPELL_FRENZY); + Frenzy_Timer = 8000 + (rand()%2000); + }else Frenzy_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_flamegor(Creature *_Creature) +{ + return new boss_flamegorAI (_Creature); +} + +void AddSC_boss_flamegor() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_flamegor"; + newscript->GetAI = GetAI_boss_flamegor; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_nefarian.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_nefarian.cpp index 31495b35d9d..c534b213e8d 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_nefarian.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_nefarian.cpp @@ -1,250 +1,250 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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: 100 -SDComment: Some issues with class calls effecting more than one class -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO "Well done, my minions. The mortals' courage begins to wane! Now, let's see how they contend with the true Lord of Blackrock Spire!" -#define SAY_DEATH "This cannot be! I am the Master here! You mortals are nothing to my kind! DO YOU HEAR? NOTHING!" -#define SAY_RAISE_SKELETONS "Impossible! Rise my minions! Serve your master once more!" -#define SAY_SHADOWFLAME "Burn, you wretches! Burn!" -#define SAY_SLAY "Worthless $N! Your friends will join you soon enough!" -#define SAY_XHEALTH "Enough! Now you vermin shall feel the force of my birthright, the fury of the earth itself." -#define SAY_GAMESBEGIN "Let the games begin!" -#define SAY_START "" - -#define SOUND_AGGRO 8288 -#define SOUND_DEATH 8292 -#define SOUND_RAISE_SKELETONS 8291 -#define SOUND_SHADOWFLAME 8290 -#define SOUND_SLAY 8293 -#define SOUND_XHEALTH 8289 -#define SOUND_GAMESBEGIN 8279 -#define SOUND_START 8280 - -#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 - -#define SAY_MAGE "Mages too? You should be more careful when you play with magic..." -#define SAY_WARRIOR "Warriors, I know you can hit harder than that! Let's see it!" -#define SAY_DRUID "Druids and your silly shapeshifting. Let's see it in action!" -#define SAY_PRIEST "Priests! If you're going to keep healing like that, we might as well make it a little more interesting!" -#define SAY_PALADIN "Paladins, I've heard you have many lives. Show me." -#define SAY_SHAMAN "Shamans, show me what your totems can do!" -#define SAY_WARLOCK "Warlocks, you shouldn't be playing with magic you don't understand. See what happens?" -#define SAY_HUNTER "Hunters and your annoying pea-shooters!" -#define SAY_ROGUE "Rogues? Stop hiding and face me!" - -struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI -{ - boss_nefarianAI(Creature *c) : ScriptedAI(c) {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; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - } - - void KilledUnit(Unit* Victim) - { - if (rand()%5) - return; - - DoYell(SAY_SLAY,LANG_UNIVERSAL,Victim); - DoPlaySoundToSet(m_creature, SOUND_SLAY); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - switch (rand()%3) - { - case 0: - DoYell(SAY_XHEALTH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_XHEALTH); - break; - case 1: - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - break; - case 2: - DoYell(SAY_SHADOWFLAME,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SHADOWFLAME); - break; - } - - DoCast(who,SPELL_SHADOWFLAME_INITIAL); - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowFlame_Timer - if (ShadowFlame_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWFLAME); - ShadowFlame_Timer = 12000; - }else ShadowFlame_Timer -= diff; - - //BellowingRoar_Timer - if (BellowingRoar_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_BELLOWINGROAR); - BellowingRoar_Timer = 30000; - }else BellowingRoar_Timer -= diff; - - //VeilOfShadow_Timer - if (VeilOfShadow_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_VEILOFSHADOW); - VeilOfShadow_Timer = 15000; - }else VeilOfShadow_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(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 - //DoCast(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 (rand()%9) - { - case 0: - DoYell(SAY_MAGE,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_MAGE); - break; - case 1: - DoYell(SAY_WARRIOR,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_WARRIOR); - break; - case 2: - DoYell(SAY_DRUID,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_DRUID); - break; - case 3: - DoYell(SAY_PRIEST,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_PRIEST); - break; - case 4: - DoYell(SAY_PALADIN,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_PALADIN); - break; - case 5: - DoYell(SAY_SHAMAN,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_SHAMAN); - break; - case 6: - DoYell(SAY_WARLOCK,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_WARLOCK); - break; - case 7: - DoYell(SAY_HUNTER,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_HUNTER); - break; - case 8: - DoYell(SAY_ROGUE,LANG_UNIVERSAL,NULL); - DoCast(m_creature,SPELL_ROGUE); - break; - } - - ClassCall_Timer = 35000 + (rand() % 5000); - }else ClassCall_Timer -= diff; - - //Phase3 begins when we are below X health - if (!Phase3 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) - { - Phase3 = true; - DoYell(SAY_RAISE_SKELETONS,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RAISE_SKELETONS); - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_nefarian(Creature *_Creature) -{ - return new boss_nefarianAI (_Creature); -} - -void AddSC_boss_nefarian() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_nefarian"; - newscript->GetAI = GetAI_boss_nefarian; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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: 100 +SDComment: Some issues with class calls effecting more than one class +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO "Well done, my minions. The mortals' courage begins to wane! Now, let's see how they contend with the true Lord of Blackrock Spire!" +#define SAY_DEATH "This cannot be! I am the Master here! You mortals are nothing to my kind! DO YOU HEAR? NOTHING!" +#define SAY_RAISE_SKELETONS "Impossible! Rise my minions! Serve your master once more!" +#define SAY_SHADOWFLAME "Burn, you wretches! Burn!" +#define SAY_SLAY "Worthless $N! Your friends will join you soon enough!" +#define SAY_XHEALTH "Enough! Now you vermin shall feel the force of my birthright, the fury of the earth itself." +#define SAY_GAMESBEGIN "Let the games begin!" +#define SAY_START "" + +#define SOUND_AGGRO 8288 +#define SOUND_DEATH 8292 +#define SOUND_RAISE_SKELETONS 8291 +#define SOUND_SHADOWFLAME 8290 +#define SOUND_SLAY 8293 +#define SOUND_XHEALTH 8289 +#define SOUND_GAMESBEGIN 8279 +#define SOUND_START 8280 + +#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 + +#define SAY_MAGE "Mages too? You should be more careful when you play with magic..." +#define SAY_WARRIOR "Warriors, I know you can hit harder than that! Let's see it!" +#define SAY_DRUID "Druids and your silly shapeshifting. Let's see it in action!" +#define SAY_PRIEST "Priests! If you're going to keep healing like that, we might as well make it a little more interesting!" +#define SAY_PALADIN "Paladins, I've heard you have many lives. Show me." +#define SAY_SHAMAN "Shamans, show me what your totems can do!" +#define SAY_WARLOCK "Warlocks, you shouldn't be playing with magic you don't understand. See what happens?" +#define SAY_HUNTER "Hunters and your annoying pea-shooters!" +#define SAY_ROGUE "Rogues? Stop hiding and face me!" + +struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI +{ + boss_nefarianAI(Creature *c) : ScriptedAI(c) {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; + + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + } + + void KilledUnit(Unit* Victim) + { + if (rand()%5) + return; + + DoYell(SAY_SLAY,LANG_UNIVERSAL,Victim); + DoPlaySoundToSet(m_creature, SOUND_SLAY); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + switch (rand()%3) + { + case 0: + DoYell(SAY_XHEALTH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_XHEALTH); + break; + case 1: + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + break; + case 2: + DoYell(SAY_SHADOWFLAME,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SHADOWFLAME); + break; + } + + DoCast(who,SPELL_SHADOWFLAME_INITIAL); + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowFlame_Timer + if (ShadowFlame_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWFLAME); + ShadowFlame_Timer = 12000; + }else ShadowFlame_Timer -= diff; + + //BellowingRoar_Timer + if (BellowingRoar_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_BELLOWINGROAR); + BellowingRoar_Timer = 30000; + }else BellowingRoar_Timer -= diff; + + //VeilOfShadow_Timer + if (VeilOfShadow_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_VEILOFSHADOW); + VeilOfShadow_Timer = 15000; + }else VeilOfShadow_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(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 + //DoCast(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 (rand()%9) + { + case 0: + DoYell(SAY_MAGE,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_MAGE); + break; + case 1: + DoYell(SAY_WARRIOR,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_WARRIOR); + break; + case 2: + DoYell(SAY_DRUID,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_DRUID); + break; + case 3: + DoYell(SAY_PRIEST,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_PRIEST); + break; + case 4: + DoYell(SAY_PALADIN,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_PALADIN); + break; + case 5: + DoYell(SAY_SHAMAN,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_SHAMAN); + break; + case 6: + DoYell(SAY_WARLOCK,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_WARLOCK); + break; + case 7: + DoYell(SAY_HUNTER,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_HUNTER); + break; + case 8: + DoYell(SAY_ROGUE,LANG_UNIVERSAL,NULL); + DoCast(m_creature,SPELL_ROGUE); + break; + } + + ClassCall_Timer = 35000 + (rand() % 5000); + }else ClassCall_Timer -= diff; + + //Phase3 begins when we are below X health + if (!Phase3 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) + { + Phase3 = true; + DoYell(SAY_RAISE_SKELETONS,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RAISE_SKELETONS); + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_nefarian(Creature *_Creature) +{ + return new boss_nefarianAI (_Creature); +} + +void AddSC_boss_nefarian() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_nefarian"; + newscript->GetAI = GetAI_boss_nefarian; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_razorgore.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_razorgore.cpp index 78441b63888..203cf33491a 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_razorgore.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_razorgore.cpp @@ -1,126 +1,126 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -//Razorgore Phase 2 Script - -#define SAY_NPC_DEATH "If I fall into the abyss I'll take all of you mortals with me..." -#define SOUND_NPC_DEATH 8278 -#define SAY_EGGS_BREAK3 "No! Not another one! I'll have your heads for this atrocity." -#define SOUND_EGGS_BREAK3 8277 - -#define SPELL_CLEAVE 22540 -#define SPELL_WARSTOMP 24375 -#define SPELL_FIREBALLVOLLEY 22425 -#define SPELL_CONFLAGRATION 23023 - -struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI -{ - boss_razorgoreAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Cleave_Timer; - uint32 WarStomp_Timer; - uint32 FireballVolley_Timer; - uint32 Conflagration_Timer; - - void Reset() - { - Cleave_Timer = 15000; //These times are probably wrong - WarStomp_Timer = 35000; - FireballVolley_Timer = 7000; - Conflagration_Timer = 12000; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000 + rand()%3000; - }else Cleave_Timer -= diff; - - //WarStomp_Timer - if (WarStomp_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_WARSTOMP); - WarStomp_Timer = 15000 + rand()%10000; - }else WarStomp_Timer -= diff; - - //FireballVolley_Timer - if (FireballVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIREBALLVOLLEY); - FireballVolley_Timer = 12000 + rand()%3000; - }else FireballVolley_Timer -= diff; - - //Conflagration_Timer - if (Conflagration_Timer < diff) - { - DoCast(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); - - Conflagration_Timer = 12000; - }else Conflagration_Timer -= diff; - - // Aura Check. If the gamer is affected by confliguration we attack a random gamer. - if (m_creature->getVictim()->HasAura(SPELL_CONFLAGRATION,0)) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,1); - if (target) - m_creature->TauntApply(target); - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_razorgore(Creature *_Creature) -{ - return new boss_razorgoreAI (_Creature); -} - -void AddSC_boss_razorgore() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_razorgore"; - newscript->GetAI = GetAI_boss_razorgore; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" + +//Razorgore Phase 2 Script + +#define SAY_NPC_DEATH "If I fall into the abyss I'll take all of you mortals with me..." +#define SOUND_NPC_DEATH 8278 +#define SAY_EGGS_BREAK3 "No! Not another one! I'll have your heads for this atrocity." +#define SOUND_EGGS_BREAK3 8277 + +#define SPELL_CLEAVE 22540 +#define SPELL_WARSTOMP 24375 +#define SPELL_FIREBALLVOLLEY 22425 +#define SPELL_CONFLAGRATION 23023 + +struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI +{ + boss_razorgoreAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Cleave_Timer; + uint32 WarStomp_Timer; + uint32 FireballVolley_Timer; + uint32 Conflagration_Timer; + + void Reset() + { + Cleave_Timer = 15000; //These times are probably wrong + WarStomp_Timer = 35000; + FireballVolley_Timer = 7000; + Conflagration_Timer = 12000; + + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 7000 + rand()%3000; + }else Cleave_Timer -= diff; + + //WarStomp_Timer + if (WarStomp_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_WARSTOMP); + WarStomp_Timer = 15000 + rand()%10000; + }else WarStomp_Timer -= diff; + + //FireballVolley_Timer + if (FireballVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIREBALLVOLLEY); + FireballVolley_Timer = 12000 + rand()%3000; + }else FireballVolley_Timer -= diff; + + //Conflagration_Timer + if (Conflagration_Timer < diff) + { + DoCast(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); + + Conflagration_Timer = 12000; + }else Conflagration_Timer -= diff; + + // Aura Check. If the gamer is affected by confliguration we attack a random gamer. + if (m_creature->getVictim()->HasAura(SPELL_CONFLAGRATION,0)) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,1); + if (target) + m_creature->TauntApply(target); + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_razorgore(Creature *_Creature) +{ + return new boss_razorgoreAI (_Creature); +} + +void AddSC_boss_razorgore() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_razorgore"; + newscript->GetAI = GetAI_boss_razorgore; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_vaelastrasz.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_vaelastrasz.cpp index 217eebfb852..f11de6487be 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_vaelastrasz.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_vaelastrasz.cpp @@ -1,278 +1,278 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 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 - -#define SAY_LINE1 "Too late...friends. Nefarius' corruption has taken hold. I cannot...control myself. " -#define SOUND_LINE1 8281 - -#define SAY_LINE2 "I beg you Mortals, flee! Flee before I lose all control. The Black Fire rages within my heart. I must release it!" -#define SOUND_LINE2 8282 - -#define SAY_LINE3 "FLAME! DEATH! DESTRUCTION! COWER MORTALS BEFORE THE WRATH OF LORD....NO! I MUST FIGHT THIS!" -#define SOUND_LINE3 8283 - -#define SAY_HALFLIFE "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! " -#define SOUND_HALFLIFE 8285 - -#define SAY_KILLTARGET "Forgive me $N, your death only adds to my failure." -#define SOUND_KILLTARGET 8284 - -#define GOSSIP_ITEM "Start Event " - -struct MANGOS_DLL_DECL boss_vaelAI : public ScriptedAI -{ - boss_vaelAI(Creature *c) : ScriptedAI(c) - { - c->SetUInt32Value(UNIT_NPC_FLAGS,1); - c->setFaction(35); - c->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; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - } - - void BeginSpeach(Unit* target) - { - //Stand up and begin speach - PlayerGUID = target->GetGUID(); - - //10 seconds - DoYell(SAY_LINE1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_LINE1); - SpeachTimer = 10000; - SpeachNum = 0; - DoingSpeach = true; - } - - void KilledUnit(Unit *victim) - { - if (rand()%5) - return; - - DoYell(SAY_KILLTARGET,LANG_UNIVERSAL,victim); - DoPlaySoundToSet(m_creature,SOUND_KILLTARGET); - } - - void Aggro(Unit *who) - { - DoCast(m_creature,SPELL_ESSENCEOFTHERED); - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - //Speach - if (DoingSpeach) - if (SpeachTimer < diff) - { - switch (SpeachNum) - { - case 0: - //16 seconds till next line - DoYell(SAY_LINE2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_LINE2); - 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!" - DoYell(SAY_LINE3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_LINE3); - SpeachTimer = 10000; - SpeachNum++; - break; - - case 2: - default: - m_creature->setFaction(103); - m_creature->SetHealth(int(m_creature->GetMaxHealth()*.3)); - if (PlayerGUID && Unit::GetUnit((*m_creature),PlayerGUID)) - { - DoStartAttackAndMovement(Unit::GetUnit((*m_creature),PlayerGUID)); - DoCast(m_creature,SPELL_ESSENCEOFTHERED); - } - - SpeachTimer = 0; - DoingSpeach = false; - break; - } - }else SpeachTimer -= diff; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - // Yell if hp lower than 15% - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 15 && !HasYelled) - { - //Say our dialog - DoYell(SAY_HALFLIFE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_HALFLIFE); - HasYelled = true; - } - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 15000; - }else Cleave_Timer -= diff; - - //FlameBreath_Timer - if (FlameBreath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FLAMEBREATH); - FlameBreath_Timer = 4000 + rand()%4000; - }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 = SelectUnit(SELECT_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) - { - DoCast(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())) - { - DoCast(m_creature->getVictim(),SPELL_TAILSWIPE); - }*/ - - TailSwipe_Timer = 20000; - }else TailSwipe_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -void SendDefaultMenu_boss_vael(Player *player, Creature *_Creature, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) //Fight time - { - player->CLOSE_GOSSIP_MENU(); - ((boss_vaelAI*)_Creature->AI())->BeginSpeach((Unit*)player); - } -} - -bool GossipSelect_boss_vael(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (sender == GOSSIP_SENDER_MAIN) - SendDefaultMenu_boss_vael(player, _Creature, action); - - return true; -} - -bool GossipHello_boss_vael(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(907,_Creature->GetGUID()); - - return true; -} - -CreatureAI* GetAI_boss_vael(Creature *_Creature) -{ - return new boss_vaelAI (_Creature); -} - -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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 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 + +#define SAY_LINE1 "Too late...friends. Nefarius' corruption has taken hold. I cannot...control myself. " +#define SOUND_LINE1 8281 + +#define SAY_LINE2 "I beg you Mortals, flee! Flee before I lose all control. The Black Fire rages within my heart. I must release it!" +#define SOUND_LINE2 8282 + +#define SAY_LINE3 "FLAME! DEATH! DESTRUCTION! COWER MORTALS BEFORE THE WRATH OF LORD....NO! I MUST FIGHT THIS!" +#define SOUND_LINE3 8283 + +#define SAY_HALFLIFE "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! " +#define SOUND_HALFLIFE 8285 + +#define SAY_KILLTARGET "Forgive me $N, your death only adds to my failure." +#define SOUND_KILLTARGET 8284 + +#define GOSSIP_ITEM "Start Event " + +struct MANGOS_DLL_DECL boss_vaelAI : public ScriptedAI +{ + boss_vaelAI(Creature *c) : ScriptedAI(c) + { + c->SetUInt32Value(UNIT_NPC_FLAGS,1); + c->setFaction(35); + c->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; + + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + } + + void BeginSpeach(Unit* target) + { + //Stand up and begin speach + PlayerGUID = target->GetGUID(); + + //10 seconds + DoYell(SAY_LINE1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_LINE1); + SpeachTimer = 10000; + SpeachNum = 0; + DoingSpeach = true; + } + + void KilledUnit(Unit *victim) + { + if (rand()%5) + return; + + DoYell(SAY_KILLTARGET,LANG_UNIVERSAL,victim); + DoPlaySoundToSet(m_creature,SOUND_KILLTARGET); + } + + void Aggro(Unit *who) + { + DoCast(m_creature,SPELL_ESSENCEOFTHERED); + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + //Speach + if (DoingSpeach) + if (SpeachTimer < diff) + { + switch (SpeachNum) + { + case 0: + //16 seconds till next line + DoYell(SAY_LINE2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_LINE2); + 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!" + DoYell(SAY_LINE3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_LINE3); + SpeachTimer = 10000; + SpeachNum++; + break; + + case 2: + default: + m_creature->setFaction(103); + m_creature->SetHealth(int(m_creature->GetMaxHealth()*.3)); + if (PlayerGUID && Unit::GetUnit((*m_creature),PlayerGUID)) + { + DoStartAttackAndMovement(Unit::GetUnit((*m_creature),PlayerGUID)); + DoCast(m_creature,SPELL_ESSENCEOFTHERED); + } + + SpeachTimer = 0; + DoingSpeach = false; + break; + } + }else SpeachTimer -= diff; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + // Yell if hp lower than 15% + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 15 && !HasYelled) + { + //Say our dialog + DoYell(SAY_HALFLIFE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_HALFLIFE); + HasYelled = true; + } + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 15000; + }else Cleave_Timer -= diff; + + //FlameBreath_Timer + if (FlameBreath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FLAMEBREATH); + FlameBreath_Timer = 4000 + rand()%4000; + }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 = SelectUnit(SELECT_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) + { + DoCast(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())) + { + DoCast(m_creature->getVictim(),SPELL_TAILSWIPE); + }*/ + + TailSwipe_Timer = 20000; + }else TailSwipe_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +void SendDefaultMenu_boss_vael(Player *player, Creature *_Creature, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) //Fight time + { + player->CLOSE_GOSSIP_MENU(); + ((boss_vaelAI*)_Creature->AI())->BeginSpeach((Unit*)player); + } +} + +bool GossipSelect_boss_vael(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (sender == GOSSIP_SENDER_MAIN) + SendDefaultMenu_boss_vael(player, _Creature, action); + + return true; +} + +bool GossipHello_boss_vael(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(907,_Creature->GetGUID()); + + return true; +} + +CreatureAI* GetAI_boss_vael(Creature *_Creature) +{ + return new boss_vaelAI (_Creature); +} + +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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_victor_nefarius.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_victor_nefarius.cpp index 3870a247fa0..37bf475361b 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_victor_nefarius.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_victor_nefarius.cpp @@ -1,399 +1,399 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "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..." -#define SAY_GAMESBEGIN_2 "Let the games begin!" -#define SAY_VAEL_INTRO "" - -#define SOUND_GAMESBEGIN 8280 -#define SOUND_VAEL_INTRO 8279 - -#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.151855 -#define ADD_X2 -7514.598633 -#define ADD_Y1 -1204.051880 -#define ADD_Y2 -1150.448853 -#define ADD_Z1 476.800476 -#define ADD_Z2 476.796570 - -#define NEF_X -7445 -#define NEF_Y -1332 -#define NEF_Z 536 - -#define HIDE_X -7592 -#define HIDE_Y -1264 -#define HIDE_Z 481 - -#define 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 *c) : ScriptedAI(c) - { - NefarianGUID = 0; - Reset(); - srand(time(NULL)); - switch (rand()%20) - { - 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) - { - DoYell(SAY_GAMESBEGIN_2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_GAMESBEGIN); - - //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 Aggro(Unit *who) - { - } - - 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,0.0f); - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !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 = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - DoCast(target,SPELL_SHADOWBOLT); - - ShadowBoltTimer = 3000 + (rand()%7000); - }else ShadowBoltTimer -= diff; - - //FearTimer - if (FearTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - DoCast(target,SPELL_FEAR); - - FearTimer = 10000 + (rand()%10000); - }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 (rand()%3 == 0) - 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.000,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target && Spawned) - { - Spawned->AI()->AttackStart(target); - Spawned->setFaction(103); - } - - //1 in 3 chance it will be a chromatic - if (rand()%3 == 0) - 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 = SelectUnit(SELECT_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 - DoCast(m_creature,33356); - - //Make super invis - DoCast(m_creature,8149); - - //Teleport self to a hiding spot (this causes errors in the mangos log but no real issues) - m_creature->Relocate(HIDE_X,HIDE_Y,HIDE_Z,0); - m_creature->SendMonsterMove(HIDE_X,HIDE_Y,HIDE_Z,0,true,0); - m_creature->addUnitState(UNIT_STAT_FLEEING); - - //Spawn nef and have him attack a random target - Creature* Nefarian = NULL; - Nefarian = m_creature->SummonCreature(CREATURE_NEFARIAN,NEF_X,NEF_Y,NEF_Z,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,120000); - target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target && Nefarian) - { - Nefarian->AI()->AttackStart(target); - Nefarian->setFaction(103); - NefarianGUID = Nefarian->GetGUID(); - } - else DoYell("UNABLE TO SPAWN NEF PROPERLY",LANG_UNIVERSAL,NULL); - } - - AddSpawnTimer = 4000; - }else AddSpawnTimer -= diff; - } - else if (NefarianGUID) - { - if (NefCheckTime < diff) - { - Unit* Nefarian = NULL; - Nefarian = Unit::GetUnit((*m_creature),NefarianGUID); - - //If nef is dead then we die to so the players get out of combat - //and cannot repeat the event - if (!Nefarian || !Nefarian->isAlive()) - { - NefarianGUID = 0; - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - - NefCheckTime = 2000; - }else NefCheckTime -= diff; - } - } -}; - -CreatureAI* GetAI_boss_victor_nefarius(Creature *_Creature) -{ - return new boss_victor_nefariusAI (_Creature); -} - -bool GossipHello_boss_victor_nefarius(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_1 , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(7134,_Creature->GetGUID()); - return true; -} - -bool GossipSelect_boss_victor_nefarius(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(7198, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(7199, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->CLOSE_GOSSIP_MENU(); - _Creature->MonsterSay(SAY_GAMESBEGIN_1,LANG_UNIVERSAL,0); - ((boss_victor_nefariusAI*)_Creature->AI())->BeginEvent(player); - 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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "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..." +#define SAY_GAMESBEGIN_2 "Let the games begin!" +#define SAY_VAEL_INTRO "" + +#define SOUND_GAMESBEGIN 8280 +#define SOUND_VAEL_INTRO 8279 + +#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.151855 +#define ADD_X2 -7514.598633 +#define ADD_Y1 -1204.051880 +#define ADD_Y2 -1150.448853 +#define ADD_Z1 476.800476 +#define ADD_Z2 476.796570 + +#define NEF_X -7445 +#define NEF_Y -1332 +#define NEF_Z 536 + +#define HIDE_X -7592 +#define HIDE_Y -1264 +#define HIDE_Z 481 + +#define 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 *c) : ScriptedAI(c) + { + NefarianGUID = 0; + Reset(); + srand(time(NULL)); + switch (rand()%20) + { + 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) + { + DoYell(SAY_GAMESBEGIN_2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_GAMESBEGIN); + + //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 Aggro(Unit *who) + { + } + + 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,0.0f); + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !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 = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + DoCast(target,SPELL_SHADOWBOLT); + + ShadowBoltTimer = 3000 + (rand()%7000); + }else ShadowBoltTimer -= diff; + + //FearTimer + if (FearTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + DoCast(target,SPELL_FEAR); + + FearTimer = 10000 + (rand()%10000); + }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 (rand()%3 == 0) + 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.000,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target && Spawned) + { + Spawned->AI()->AttackStart(target); + Spawned->setFaction(103); + } + + //1 in 3 chance it will be a chromatic + if (rand()%3 == 0) + 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 = SelectUnit(SELECT_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 + DoCast(m_creature,33356); + + //Make super invis + DoCast(m_creature,8149); + + //Teleport self to a hiding spot (this causes errors in the mangos log but no real issues) + m_creature->Relocate(HIDE_X,HIDE_Y,HIDE_Z,0); + m_creature->SendMonsterMove(HIDE_X,HIDE_Y,HIDE_Z,0,true,0); + m_creature->addUnitState(UNIT_STAT_FLEEING); + + //Spawn nef and have him attack a random target + Creature* Nefarian = NULL; + Nefarian = m_creature->SummonCreature(CREATURE_NEFARIAN,NEF_X,NEF_Y,NEF_Z,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,120000); + target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target && Nefarian) + { + Nefarian->AI()->AttackStart(target); + Nefarian->setFaction(103); + NefarianGUID = Nefarian->GetGUID(); + } + else DoYell("UNABLE TO SPAWN NEF PROPERLY",LANG_UNIVERSAL,NULL); + } + + AddSpawnTimer = 4000; + }else AddSpawnTimer -= diff; + } + else if (NefarianGUID) + { + if (NefCheckTime < diff) + { + Unit* Nefarian = NULL; + Nefarian = Unit::GetUnit((*m_creature),NefarianGUID); + + //If nef is dead then we die to so the players get out of combat + //and cannot repeat the event + if (!Nefarian || !Nefarian->isAlive()) + { + NefarianGUID = 0; + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + NefCheckTime = 2000; + }else NefCheckTime -= diff; + } + } +}; + +CreatureAI* GetAI_boss_victor_nefarius(Creature *_Creature) +{ + return new boss_victor_nefariusAI (_Creature); +} + +bool GossipHello_boss_victor_nefarius(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_1 , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(7134,_Creature->GetGUID()); + return true; +} + +bool GossipSelect_boss_victor_nefarius(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(7198, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(7199, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay(SAY_GAMESBEGIN_1,LANG_UNIVERSAL,0); + ((boss_victor_nefariusAI*)_Creature->AI())->BeginEvent(player); + 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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/instance_blackwing_lair.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/instance_blackwing_lair.cpp index 7bdd3250442..e6c06bc739c 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/instance_blackwing_lair.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/instance_blackwing_lair.cpp @@ -1,8 +1,8 @@ -/* ScriptData -SDName: Instance_Blackwing_Lair -SD%Complete: 0 -SDComment: -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" +/* ScriptData +SDName: Instance_Blackwing_Lair +SD%Complete: 0 +SDComment: +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp b/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp index c7cb250eab7..a2e66c9bf0f 100644 --- a/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp +++ b/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp @@ -1,441 +1,441 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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) -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 -EndContentData */ - -#include "precompiled.h" - -/*###### -## mobs_bladespire_ogre -######*/ - -//TODO: add support for quest 10512 + creature abilities -struct MANGOS_DLL_DECL mobs_bladespire_ogreAI : public ScriptedAI -{ - mobs_bladespire_ogreAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - } - - void Aggro(Unit* who) - { - } - - void JustDied(Unit* Killer) - { - if (Killer->GetTypeId() == TYPEID_PLAYER) - ((Player*)Killer)->KilledMonster(19995, m_creature->GetGUID()); - } -}; -CreatureAI* GetAI_mobs_bladespire_ogre(Creature *_Creature) -{ - return new mobs_bladespire_ogreAI (_Creature); -} - -/*###### -## mobs_nether_drake -######*/ - -#define SAY_NIHIL_1 "Muahahahaha! You fool! You've released me from my banishment in the interstices between space and time!" -#define SAY_NIHIL_2 "All of Draenor shall quick beneath my feet! I will destroy this world and reshape it in my image!" -#define SAY_NIHIL_3 "Where shall I begin? I cannot bother myself with a worm such as yourself. There is a world to be conquered!" -#define SAY_NIHIL_4 "No doubt the fools that banished me are long dead. I shall take wing survey my demense. Pray to whatever gods you hold dear that we do not meet again." -#define SAY_NIHIL_INTERRUPT "NOOOOooooooo!" - -#define ENTRY_WHELP 20021 -#define ENTRY_PROTO 21821 -#define ENTRY_ADOLE 21817 -#define ENTRY_MATUR 21820 -#define ENTRY_NIHIL 21823 - -#define SPELL_T_PHASE_MODULATOR 37573 - -#define SPELL_ARCANE_BLAST 38881 -#define SPELL_MANA_BURN 38884 -#define SPELL_INTANGIBLE_PRESENCE 36513 - -struct MANGOS_DLL_DECL mobs_nether_drakeAI : public ScriptedAI -{ - mobs_nether_drakeAI(Creature *c) : ScriptedAI(c) {Reset();} - - bool IsNihil; - uint32 NihilSpeech_Timer; - uint32 NihilSpeech_Phase; - - uint32 ArcaneBlast_Timer; - uint32 ManaBurn_Timer; - uint32 IntangiblePresence_Timer; - - void Reset() - { - NihilSpeech_Timer = 2000; - IsNihil = false; - if( m_creature->GetEntry() == ENTRY_NIHIL ) - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - IsNihil = true; - } - NihilSpeech_Phase = 1; - - ArcaneBlast_Timer = 7500; - ManaBurn_Timer = 10000; - IntangiblePresence_Timer = 15000; - } - - void Aggro(Unit* who) { } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if( spell->Id == SPELL_T_PHASE_MODULATOR && caster->GetTypeId() == TYPEID_PLAYER ) - { - uint32 cEntry = 0; - - switch( m_creature->GetEntry() ) - { - case ENTRY_WHELP: - switch(rand()%4) - { - case 0: cEntry = ENTRY_PROTO; break; - case 1: cEntry = ENTRY_ADOLE; break; - case 2: cEntry = ENTRY_MATUR; break; - case 3: cEntry = ENTRY_NIHIL; break; - } - break; - case ENTRY_PROTO: - switch(rand()%3) - { - case 0: cEntry = ENTRY_ADOLE; break; - case 1: cEntry = ENTRY_MATUR; break; - case 2: cEntry = ENTRY_NIHIL; break; - } - break; - case ENTRY_ADOLE: - switch(rand()%3) - { - case 0: cEntry = ENTRY_PROTO; break; - case 1: cEntry = ENTRY_MATUR; break; - case 2: cEntry = ENTRY_NIHIL; break; - } - break; - case ENTRY_MATUR: - switch(rand()%3) - { - case 0: cEntry = ENTRY_PROTO; break; - case 1: cEntry = ENTRY_ADOLE; break; - case 2: cEntry = ENTRY_NIHIL; break; - } - break; - case ENTRY_NIHIL: - if( NihilSpeech_Phase ) - { - DoYell(SAY_NIHIL_INTERRUPT,LANG_UNIVERSAL,NULL); - IsNihil = false; - switch(rand()%3) - { - case 0: cEntry = ENTRY_PROTO; break; - case 1: cEntry = ENTRY_ADOLE; break; - case 2: cEntry = ENTRY_MATUR; break; - } - } - break; - } - - if( cEntry ) - { - m_creature->UpdateEntry(cEntry); - - if( cEntry == ENTRY_NIHIL ) - { - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - InCombat = false; - Reset(); - } - } - } - } - - void UpdateAI(const uint32 diff) - { - if( IsNihil ) - { - if( NihilSpeech_Phase ) - { - if(NihilSpeech_Timer <= diff) - { - switch( NihilSpeech_Phase ) - { - case 1: - DoSay(SAY_NIHIL_1,LANG_UNIVERSAL,NULL); - ++NihilSpeech_Phase; - break; - case 2: - DoSay(SAY_NIHIL_2,LANG_UNIVERSAL,NULL); - ++NihilSpeech_Phase; - break; - case 3: - DoSay(SAY_NIHIL_3,LANG_UNIVERSAL,NULL); - ++NihilSpeech_Phase; - break; - case 4: - DoSay(SAY_NIHIL_4,LANG_UNIVERSAL,NULL); - ++NihilSpeech_Phase; - break; - case 5: - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // + MOVEMENTFLAG_LEVITATING - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - //then take off to random location. creature is initially summoned, so don't bother do anything else. - m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX()+100, m_creature->GetPositionY(), m_creature->GetPositionZ()+100); - NihilSpeech_Phase = 0; - break; - } - NihilSpeech_Timer = 5000; - }else NihilSpeech_Timer -=diff; - } - return; //anything below here is not interesting for Nihil, so skip it - } - - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( IntangiblePresence_Timer <= diff ) - { - DoCast(m_creature->getVictim(),SPELL_INTANGIBLE_PRESENCE); - IntangiblePresence_Timer = 15000+rand()%15000; - }else IntangiblePresence_Timer -= diff; - - if( ManaBurn_Timer <= diff ) - { - Unit* target = m_creature->getVictim(); - if( target && target->getPowerType() == POWER_MANA ) - DoCast(target,SPELL_MANA_BURN); - ManaBurn_Timer = 8000+rand()%8000; - }else ManaBurn_Timer -= diff; - - if( ArcaneBlast_Timer <= diff ) - { - DoCast(m_creature->getVictim(),SPELL_ARCANE_BLAST); - ArcaneBlast_Timer = 2500+rand()%5000; - }else ArcaneBlast_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_mobs_nether_drake(Creature *_Creature) -{ - return new mobs_nether_drakeAI (_Creature); -} - -/*###### -## npc_daranelle -######*/ - -struct MANGOS_DLL_DECL npc_daranelleAI : public ScriptedAI -{ - npc_daranelleAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - } - - void Aggro(Unit* who) - { - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || m_creature->getVictim()) - return; - - if (who->GetTypeId() == TYPEID_PLAYER) - { - if(who->HasAura(36904,0)) - { - DoSay("Good $N, you are under the spell's influence. I must analyze it quickly, then we can talk.",LANG_COMMON,who); - //TODO: Move the below to updateAI and run if this statement == true - ((Player*)who)->KilledMonster(21511, m_creature->GetGUID()); - ((Player*)who)->RemoveAurasDueToSpell(36904); - } - } - - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - //Begin melee attack if we are within range - DoStartAttackAndMovement(who); - } - } - } -}; - -CreatureAI* GetAI_npc_daranelle(Creature *_Creature) -{ - return new npc_daranelleAI (_Creature); -} - -/*###### -## npc_overseer_nuaar -######*/ - -bool GossipHello_npc_overseer_nuaar(Player *player, Creature *_Creature) -{ - if (player->GetQuestStatus(10682) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Overseer, I am here to negotiate on behalf of the Cenarion Expedition.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(10532, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_overseer_nuaar(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->SEND_GOSSIP_MENU(10533, _Creature->GetGUID()); - player->AreaExploredOrEventHappens(10682); - } - return true; -} - -/*###### -## npc_saikkal_the_elder -######*/ - -bool GossipHello_npc_saikkal_the_elder(Player *player, Creature *_Creature) -{ - if (player->GetQuestStatus(10980) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Yes... yes, it's me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(10794, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_saikkal_the_elder(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "Yes elder. Tell me more of the book.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(10795, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); - player->SEND_GOSSIP_MENU(10796, _Creature->GetGUID()); - break; - } - return true; -} - -/*###### -## npc_skyguard_handler_irena -######*/ - -#define GOSSIP_SKYGUARD "Fly me to Skettis please" - -bool GossipHello_npc_skyguard_handler_irena(Player *player, Creature *_Creature ) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetReputationRank(1031) >= REP_HONORED) - player->ADD_GOSSIP_ITEM( 2, GOSSIP_SKYGUARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_skyguard_handler_irena(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - - std::vector nodes; - - nodes.resize(2); - nodes[0] = 172; //from ogri'la - nodes[1] = 171; //end at skettis - player->ActivateTaxiPathTo(nodes); //TaxiPath 706 - } - return true; -} - -/*###### -## AddSC -######*/ - -void AddSC_blades_edge_mountains() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mobs_bladespire_ogre"; - newscript->GetAI = GetAI_mobs_bladespire_ogre; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mobs_nether_drake"; - newscript->GetAI = GetAI_mobs_nether_drake; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_daranelle"; - newscript->GetAI = GetAI_npc_daranelle; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_overseer_nuaar"; - newscript->pGossipHello = &GossipHello_npc_overseer_nuaar; - newscript->pGossipSelect = &GossipSelect_npc_overseer_nuaar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_saikkal_the_elder"; - newscript->pGossipHello = &GossipHello_npc_saikkal_the_elder; - newscript->pGossipSelect = &GossipSelect_npc_saikkal_the_elder; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_skyguard_handler_irena"; - newscript->pGossipHello = &GossipHello_npc_skyguard_handler_irena; - newscript->pGossipSelect = &GossipSelect_npc_skyguard_handler_irena; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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) +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 +EndContentData */ + +#include "precompiled.h" + +/*###### +## mobs_bladespire_ogre +######*/ + +//TODO: add support for quest 10512 + creature abilities +struct MANGOS_DLL_DECL mobs_bladespire_ogreAI : public ScriptedAI +{ + mobs_bladespire_ogreAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + } + + void Aggro(Unit* who) + { + } + + void JustDied(Unit* Killer) + { + if (Killer->GetTypeId() == TYPEID_PLAYER) + ((Player*)Killer)->KilledMonster(19995, m_creature->GetGUID()); + } +}; +CreatureAI* GetAI_mobs_bladespire_ogre(Creature *_Creature) +{ + return new mobs_bladespire_ogreAI (_Creature); +} + +/*###### +## mobs_nether_drake +######*/ + +#define SAY_NIHIL_1 "Muahahahaha! You fool! You've released me from my banishment in the interstices between space and time!" +#define SAY_NIHIL_2 "All of Draenor shall quick beneath my feet! I will destroy this world and reshape it in my image!" +#define SAY_NIHIL_3 "Where shall I begin? I cannot bother myself with a worm such as yourself. There is a world to be conquered!" +#define SAY_NIHIL_4 "No doubt the fools that banished me are long dead. I shall take wing survey my demense. Pray to whatever gods you hold dear that we do not meet again." +#define SAY_NIHIL_INTERRUPT "NOOOOooooooo!" + +#define ENTRY_WHELP 20021 +#define ENTRY_PROTO 21821 +#define ENTRY_ADOLE 21817 +#define ENTRY_MATUR 21820 +#define ENTRY_NIHIL 21823 + +#define SPELL_T_PHASE_MODULATOR 37573 + +#define SPELL_ARCANE_BLAST 38881 +#define SPELL_MANA_BURN 38884 +#define SPELL_INTANGIBLE_PRESENCE 36513 + +struct MANGOS_DLL_DECL mobs_nether_drakeAI : public ScriptedAI +{ + mobs_nether_drakeAI(Creature *c) : ScriptedAI(c) {Reset();} + + bool IsNihil; + uint32 NihilSpeech_Timer; + uint32 NihilSpeech_Phase; + + uint32 ArcaneBlast_Timer; + uint32 ManaBurn_Timer; + uint32 IntangiblePresence_Timer; + + void Reset() + { + NihilSpeech_Timer = 2000; + IsNihil = false; + if( m_creature->GetEntry() == ENTRY_NIHIL ) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + IsNihil = true; + } + NihilSpeech_Phase = 1; + + ArcaneBlast_Timer = 7500; + ManaBurn_Timer = 10000; + IntangiblePresence_Timer = 15000; + } + + void Aggro(Unit* who) { } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if( spell->Id == SPELL_T_PHASE_MODULATOR && caster->GetTypeId() == TYPEID_PLAYER ) + { + uint32 cEntry = 0; + + switch( m_creature->GetEntry() ) + { + case ENTRY_WHELP: + switch(rand()%4) + { + case 0: cEntry = ENTRY_PROTO; break; + case 1: cEntry = ENTRY_ADOLE; break; + case 2: cEntry = ENTRY_MATUR; break; + case 3: cEntry = ENTRY_NIHIL; break; + } + break; + case ENTRY_PROTO: + switch(rand()%3) + { + case 0: cEntry = ENTRY_ADOLE; break; + case 1: cEntry = ENTRY_MATUR; break; + case 2: cEntry = ENTRY_NIHIL; break; + } + break; + case ENTRY_ADOLE: + switch(rand()%3) + { + case 0: cEntry = ENTRY_PROTO; break; + case 1: cEntry = ENTRY_MATUR; break; + case 2: cEntry = ENTRY_NIHIL; break; + } + break; + case ENTRY_MATUR: + switch(rand()%3) + { + case 0: cEntry = ENTRY_PROTO; break; + case 1: cEntry = ENTRY_ADOLE; break; + case 2: cEntry = ENTRY_NIHIL; break; + } + break; + case ENTRY_NIHIL: + if( NihilSpeech_Phase ) + { + DoYell(SAY_NIHIL_INTERRUPT,LANG_UNIVERSAL,NULL); + IsNihil = false; + switch(rand()%3) + { + case 0: cEntry = ENTRY_PROTO; break; + case 1: cEntry = ENTRY_ADOLE; break; + case 2: cEntry = ENTRY_MATUR; break; + } + } + break; + } + + if( cEntry ) + { + m_creature->UpdateEntry(cEntry); + + if( cEntry == ENTRY_NIHIL ) + { + m_creature->InterruptNonMeleeSpells(true); + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + InCombat = false; + Reset(); + } + } + } + } + + void UpdateAI(const uint32 diff) + { + if( IsNihil ) + { + if( NihilSpeech_Phase ) + { + if(NihilSpeech_Timer <= diff) + { + switch( NihilSpeech_Phase ) + { + case 1: + DoSay(SAY_NIHIL_1,LANG_UNIVERSAL,NULL); + ++NihilSpeech_Phase; + break; + case 2: + DoSay(SAY_NIHIL_2,LANG_UNIVERSAL,NULL); + ++NihilSpeech_Phase; + break; + case 3: + DoSay(SAY_NIHIL_3,LANG_UNIVERSAL,NULL); + ++NihilSpeech_Phase; + break; + case 4: + DoSay(SAY_NIHIL_4,LANG_UNIVERSAL,NULL); + ++NihilSpeech_Phase; + break; + case 5: + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // + MOVEMENTFLAG_LEVITATING + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + //then take off to random location. creature is initially summoned, so don't bother do anything else. + m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX()+100, m_creature->GetPositionY(), m_creature->GetPositionZ()+100); + NihilSpeech_Phase = 0; + break; + } + NihilSpeech_Timer = 5000; + }else NihilSpeech_Timer -=diff; + } + return; //anything below here is not interesting for Nihil, so skip it + } + + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( IntangiblePresence_Timer <= diff ) + { + DoCast(m_creature->getVictim(),SPELL_INTANGIBLE_PRESENCE); + IntangiblePresence_Timer = 15000+rand()%15000; + }else IntangiblePresence_Timer -= diff; + + if( ManaBurn_Timer <= diff ) + { + Unit* target = m_creature->getVictim(); + if( target && target->getPowerType() == POWER_MANA ) + DoCast(target,SPELL_MANA_BURN); + ManaBurn_Timer = 8000+rand()%8000; + }else ManaBurn_Timer -= diff; + + if( ArcaneBlast_Timer <= diff ) + { + DoCast(m_creature->getVictim(),SPELL_ARCANE_BLAST); + ArcaneBlast_Timer = 2500+rand()%5000; + }else ArcaneBlast_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_mobs_nether_drake(Creature *_Creature) +{ + return new mobs_nether_drakeAI (_Creature); +} + +/*###### +## npc_daranelle +######*/ + +struct MANGOS_DLL_DECL npc_daranelleAI : public ScriptedAI +{ + npc_daranelleAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + } + + void Aggro(Unit* who) + { + } + + void MoveInLineOfSight(Unit *who) + { + if (who->GetTypeId() == TYPEID_PLAYER) + { + if(who->HasAura(36904,0)) + { + DoSay("Good $N, you are under the spell's influence. I must analyze it quickly, then we can talk.",LANG_COMMON,who); + //TODO: Move the below to updateAI and run if this statement == true + ((Player*)who)->KilledMonster(21511, m_creature->GetGUID()); + ((Player*)who)->RemoveAurasDueToSpell(36904); + } + } + + if (!m_creature->getVictim() && 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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + //Begin melee attack if we are within range + DoStartAttackAndMovement(who); + } + } + } +}; + +CreatureAI* GetAI_npc_daranelle(Creature *_Creature) +{ + return new npc_daranelleAI (_Creature); +} + +/*###### +## npc_overseer_nuaar +######*/ + +bool GossipHello_npc_overseer_nuaar(Player *player, Creature *_Creature) +{ + if (player->GetQuestStatus(10682) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Overseer, I am here to negotiate on behalf of the Cenarion Expedition.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(10532, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_overseer_nuaar(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->SEND_GOSSIP_MENU(10533, _Creature->GetGUID()); + player->AreaExploredOrEventHappens(10682); + } + return true; +} + +/*###### +## npc_saikkal_the_elder +######*/ + +bool GossipHello_npc_saikkal_the_elder(Player *player, Creature *_Creature) +{ + if (player->GetQuestStatus(10980) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Yes... yes, it's me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(10794, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_saikkal_the_elder(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "Yes elder. Tell me more of the book.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(10795, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); + player->SEND_GOSSIP_MENU(10796, _Creature->GetGUID()); + break; + } + return true; +} + +/*###### +## npc_skyguard_handler_irena +######*/ + +#define GOSSIP_SKYGUARD "Fly me to Skettis please" + +bool GossipHello_npc_skyguard_handler_irena(Player *player, Creature *_Creature ) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetReputationRank(1031) >= REP_HONORED) + player->ADD_GOSSIP_ITEM( 2, GOSSIP_SKYGUARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_skyguard_handler_irena(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + + std::vector nodes; + + nodes.resize(2); + nodes[0] = 172; //from ogri'la + nodes[1] = 171; //end at skettis + player->ActivateTaxiPathTo(nodes); //TaxiPath 706 + } + return true; +} + +/*###### +## AddSC +######*/ + +void AddSC_blades_edge_mountains() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mobs_bladespire_ogre"; + newscript->GetAI = GetAI_mobs_bladespire_ogre; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mobs_nether_drake"; + newscript->GetAI = GetAI_mobs_nether_drake; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_daranelle"; + newscript->GetAI = GetAI_npc_daranelle; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_overseer_nuaar"; + newscript->pGossipHello = &GossipHello_npc_overseer_nuaar; + newscript->pGossipSelect = &GossipSelect_npc_overseer_nuaar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_saikkal_the_elder"; + newscript->pGossipHello = &GossipHello_npc_saikkal_the_elder; + newscript->pGossipSelect = &GossipSelect_npc_saikkal_the_elder; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_skyguard_handler_irena"; + newscript->pGossipHello = &GossipHello_npc_skyguard_handler_irena; + newscript->pGossipSelect = &GossipSelect_npc_skyguard_handler_irena; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blasted_lands/blasted_lands.cpp b/src/bindings/scripts/scripts/zone/blasted_lands/blasted_lands.cpp index 4c84994c5b6..84cd2aeb3c9 100644 --- a/src/bindings/scripts/scripts/zone/blasted_lands/blasted_lands.cpp +++ b/src/bindings/scripts/scripts/zone/blasted_lands/blasted_lands.cpp @@ -1,159 +1,159 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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. -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 *player, Creature *_Creature) -{ - if(player->GetQuestStatus(3628) == QUEST_STATUS_INCOMPLETE && player->HasItemCount(10757, 1)) - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_USHER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_deathly_usher(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if(action = GOSSIP_ACTION_INFO_DEF) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player, SPELL_TELEPORT_SINGLE, true); - } - - return true; -} - -/*###### -## npc_fallen_hero_of_horde -######*/ - -#define GOSSIP_ITEM_FALLEN "Continue..." - -#define GOSSIP_ITEM_FALLEN1 "What could be worse than death?" -#define GOSSIP_ITEM_FALLEN2 "Subordinates?" -#define GOSSIP_ITEM_FALLEN3 "What are the stones of binding?" -#define GOSSIP_ITEM_FALLEN4 "You can count on me, Hero" -#define GOSSIP_ITEM_FALLEN5 "I shall" - -bool GossipHello_npc_fallen_hero_of_horde(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(2784) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Why are you here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - if (player->GetQuestStatus(2801) == QUEST_STATUS_INCOMPLETE && player->GetTeam() == HORDE) - player->ADD_GOSSIP_ITEM( 0, "Continue story...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - if (player->GetQuestStatus(2801) == QUEST_STATUS_INCOMPLETE && player->GetTeam() == ALLIANCE) - player->ADD_GOSSIP_ITEM( 0, "Why are you here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_fallen_hero_of_horde(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(1392, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - player->SEND_GOSSIP_MENU(1411, _Creature->GetGUID()); - if (player->GetQuestStatus(2784) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(2784); - if (player->GetTeam() == ALLIANCE) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(1411, _Creature->GetGUID()); - } - break; - - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); - player->SEND_GOSSIP_MENU(1451, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+21: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); - player->SEND_GOSSIP_MENU(1452, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+22: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 23); - player->SEND_GOSSIP_MENU(1453, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+23: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 24); - player->SEND_GOSSIP_MENU(1454, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+24: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 25); - player->SEND_GOSSIP_MENU(1455, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+25: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 26); - player->SEND_GOSSIP_MENU(1456, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+26: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(2801); - break; - } - return true; -} - -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; - m_scripts[nrscripts++] = newscript; - - 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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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. +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 *player, Creature *_Creature) +{ + if(player->GetQuestStatus(3628) == QUEST_STATUS_INCOMPLETE && player->HasItemCount(10757, 1)) + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_USHER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_deathly_usher(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if(action = GOSSIP_ACTION_INFO_DEF) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player, SPELL_TELEPORT_SINGLE, true); + } + + return true; +} + +/*###### +## npc_fallen_hero_of_horde +######*/ + +#define GOSSIP_ITEM_FALLEN "Continue..." + +#define GOSSIP_ITEM_FALLEN1 "What could be worse than death?" +#define GOSSIP_ITEM_FALLEN2 "Subordinates?" +#define GOSSIP_ITEM_FALLEN3 "What are the stones of binding?" +#define GOSSIP_ITEM_FALLEN4 "You can count on me, Hero" +#define GOSSIP_ITEM_FALLEN5 "I shall" + +bool GossipHello_npc_fallen_hero_of_horde(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(2784) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Why are you here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + if (player->GetQuestStatus(2801) == QUEST_STATUS_INCOMPLETE && player->GetTeam() == HORDE) + player->ADD_GOSSIP_ITEM( 0, "Continue story...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + + if (player->GetQuestStatus(2801) == QUEST_STATUS_INCOMPLETE && player->GetTeam() == ALLIANCE) + player->ADD_GOSSIP_ITEM( 0, "Why are you here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_fallen_hero_of_horde(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(1392, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+11: + player->SEND_GOSSIP_MENU(1411, _Creature->GetGUID()); + if (player->GetQuestStatus(2784) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(2784); + if (player->GetTeam() == ALLIANCE) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(1411, _Creature->GetGUID()); + } + break; + + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); + player->SEND_GOSSIP_MENU(1451, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+21: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); + player->SEND_GOSSIP_MENU(1452, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+22: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 23); + player->SEND_GOSSIP_MENU(1453, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+23: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 24); + player->SEND_GOSSIP_MENU(1454, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+24: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 25); + player->SEND_GOSSIP_MENU(1455, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+25: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_FALLEN5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 26); + player->SEND_GOSSIP_MENU(1456, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+26: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(2801); + break; + } + return true; +} + +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; + m_scripts[nrscripts++] = newscript; + + 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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/blasted_lands/boss_kruul.cpp b/src/bindings/scripts/scripts/zone/blasted_lands/boss_kruul.cpp index fd8eb90ddf0..7843fb884e4 100644 --- a/src/bindings/scripts/scripts/zone/blasted_lands/boss_kruul.cpp +++ b/src/bindings/scripts/scripts/zone/blasted_lands/boss_kruul.cpp @@ -1,182 +1,182 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void KilledUnit() - { - // When a player, pet or totem gets killed, Lord Kazzak casts this spell to instantly regenerate 70,000 health. - DoCast(m_creature,SPELL_CAPTURESOUL); - - } - - void SummonHounds(Unit* victim) - { - Rand = rand()%10; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%10; - switch (rand()%2) - { - 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) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowVolley_Timer - if (ShadowVolley_Timer < diff) - { - if (rand()%100 < 46) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWVOLLEY); - } - - ShadowVolley_Timer = 5000; - }else ShadowVolley_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - if (rand()%100 < 50) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - } - - Cleave_Timer = 10000; - }else Cleave_Timer -= diff; - - //ThunderClap_Timer - if (ThunderClap_Timer < diff) - { - if (rand()%100 < 20) - { - DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); - } - - ThunderClap_Timer = 12000; - }else ThunderClap_Timer -= diff; - - //TwistedReflection_Timer - if (TwistedReflection_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_TWISTEDREFLECTION); - TwistedReflection_Timer = 30000; - }else TwistedReflection_Timer -= diff; - - //VoidBolt_Timer - if (VoidBolt_Timer < diff) - { - if (rand()%100 < 40) - { - DoCast(m_creature->getVictim(),SPELL_VOIDBOLT); - } - - VoidBolt_Timer = 18000; - }else VoidBolt_Timer -= diff; - - //Rage_Timer - if (Rage_Timer < diff) - { - DoCast(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 *_Creature) -{ - return new boss_kruulAI (_Creature); -} - -void AddSC_boss_kruul() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_kruul"; - newscript->GetAI = GetAI_boss_kruul; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void KilledUnit() + { + // When a player, pet or totem gets killed, Lord Kazzak casts this spell to instantly regenerate 70,000 health. + DoCast(m_creature,SPELL_CAPTURESOUL); + + } + + void SummonHounds(Unit* victim) + { + Rand = rand()%10; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%10; + switch (rand()%2) + { + 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) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowVolley_Timer + if (ShadowVolley_Timer < diff) + { + if (rand()%100 < 46) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWVOLLEY); + } + + ShadowVolley_Timer = 5000; + }else ShadowVolley_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + if (rand()%100 < 50) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + } + + Cleave_Timer = 10000; + }else Cleave_Timer -= diff; + + //ThunderClap_Timer + if (ThunderClap_Timer < diff) + { + if (rand()%100 < 20) + { + DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); + } + + ThunderClap_Timer = 12000; + }else ThunderClap_Timer -= diff; + + //TwistedReflection_Timer + if (TwistedReflection_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_TWISTEDREFLECTION); + TwistedReflection_Timer = 30000; + }else TwistedReflection_Timer -= diff; + + //VoidBolt_Timer + if (VoidBolt_Timer < diff) + { + if (rand()%100 < 40) + { + DoCast(m_creature->getVictim(),SPELL_VOIDBOLT); + } + + VoidBolt_Timer = 18000; + }else VoidBolt_Timer -= diff; + + //Rage_Timer + if (Rage_Timer < diff) + { + DoCast(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 *_Creature) +{ + return new boss_kruulAI (_Creature); +} + +void AddSC_boss_kruul() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_kruul"; + newscript->GetAI = GetAI_boss_kruul; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp b/src/bindings/scripts/scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp index 254d5082797..a12c8995e5d 100644 --- a/src/bindings/scripts/scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp +++ b/src/bindings/scripts/scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp @@ -1,141 +1,141 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Bloodmyst_Isle -SD%Complete: 80 -SDComment: Quest support: 9670, 9756(gossip items text needed). -SDCategory: Bloodmyst Isle -EndScriptData */ - -/* ContentData -mob_webbed_creature -npc_captured_sunhawk_agent -EndContentData */ - -#include "precompiled.h" - -/*###### -## 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}; - -struct MANGOS_DLL_DECL mob_webbed_creatureAI : public ScriptedAI -{ - mob_webbed_creatureAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - } - - void Aggro(Unit* who) - { - } - - void JustDied(Unit* Killer) - { - uint32 spawnCreatureID; - - switch(rand()%3) - { - case 0: - spawnCreatureID = 17681; - if (Killer->GetTypeId() == TYPEID_PLAYER) - ((Player*)Killer)->KilledMonster(spawnCreatureID, m_creature->GetGUID()); - break; - case 1: - case 2: - spawnCreatureID = possibleSpawns[rand()%31]; - break; - } - - if(spawnCreatureID) - DoSpawnCreature(spawnCreatureID,0,0,0,m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - } -}; -CreatureAI* GetAI_mob_webbed_creature(Creature *_Creature) -{ - return new mob_webbed_creatureAI (_Creature); -} - -/*###### -## npc_captured_sunhawk_agent -######*/ - -#define C_SUNHAWK_TRIGGER 17974 - -bool GossipHello_npc_captured_sunhawk_agent(Player *player, Creature *_Creature) -{ - if (player->HasAura(31609,1) && player->GetQuestStatus(9756) == QUEST_STATUS_INCOMPLETE) - { - player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(9136, _Creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(9134, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_captured_sunhawk_agent(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(9137, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(9138, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(9139, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(9140, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - player->SEND_GOSSIP_MENU(9141, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->CLOSE_GOSSIP_MENU(); - player->TalkedToCreature(C_SUNHAWK_TRIGGER, _Creature->GetGUID()); - break; - } - return true; -} - -void AddSC_bloodmyst_isle() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_webbed_creature"; - newscript->GetAI = GetAI_mob_webbed_creature; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_captured_sunhawk_agent"; - newscript->pGossipHello = &GossipHello_npc_captured_sunhawk_agent; - newscript->pGossipSelect = &GossipSelect_npc_captured_sunhawk_agent; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Bloodmyst_Isle +SD%Complete: 80 +SDComment: Quest support: 9670, 9756(gossip items text needed). +SDCategory: Bloodmyst Isle +EndScriptData */ + +/* ContentData +mob_webbed_creature +npc_captured_sunhawk_agent +EndContentData */ + +#include "precompiled.h" + +/*###### +## 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}; + +struct MANGOS_DLL_DECL mob_webbed_creatureAI : public ScriptedAI +{ + mob_webbed_creatureAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + } + + void Aggro(Unit* who) + { + } + + void JustDied(Unit* Killer) + { + uint32 spawnCreatureID; + + switch(rand()%3) + { + case 0: + spawnCreatureID = 17681; + if (Killer->GetTypeId() == TYPEID_PLAYER) + ((Player*)Killer)->KilledMonster(spawnCreatureID, m_creature->GetGUID()); + break; + case 1: + case 2: + spawnCreatureID = possibleSpawns[rand()%31]; + break; + } + + if(spawnCreatureID) + DoSpawnCreature(spawnCreatureID,0,0,0,m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + } +}; +CreatureAI* GetAI_mob_webbed_creature(Creature *_Creature) +{ + return new mob_webbed_creatureAI (_Creature); +} + +/*###### +## npc_captured_sunhawk_agent +######*/ + +#define C_SUNHAWK_TRIGGER 17974 + +bool GossipHello_npc_captured_sunhawk_agent(Player *player, Creature *_Creature) +{ + if (player->HasAura(31609,1) && player->GetQuestStatus(9756) == QUEST_STATUS_INCOMPLETE) + { + player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(9136, _Creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(9134, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_captured_sunhawk_agent(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(9137, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(9138, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(9139, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(9140, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM( 0, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + player->SEND_GOSSIP_MENU(9141, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + player->CLOSE_GOSSIP_MENU(); + player->TalkedToCreature(C_SUNHAWK_TRIGGER, _Creature->GetGUID()); + break; + } + return true; +} + +void AddSC_bloodmyst_isle() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_webbed_creature"; + newscript->GetAI = GetAI_mob_webbed_creature; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_captured_sunhawk_agent"; + newscript->pGossipHello = &GossipHello_npc_captured_sunhawk_agent; + newscript->pGossipSelect = &GossipSelect_npc_captured_sunhawk_agent; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp b/src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp index 0526163be56..42e33c67abc 100644 --- a/src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp +++ b/src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp @@ -1,157 +1,157 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Burning_Steppes -SD%Complete: 100 -SDComment: Quest support: 4224, 4866 -SDCategory: Burning Steppes -EndScriptData */ - -/* ContentData -npc_ragged_john -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_ragged_john -######*/ - -struct MANGOS_DLL_DECL npc_ragged_johnAI : public ScriptedAI -{ - npc_ragged_johnAI(Creature *c) : ScriptedAI(c) { Reset(); } - - void Reset() {} - - void MoveInLineOfSight(Unit *who) - { - if( who->HasAura(16468,0) ) - { - if( who->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(who, 15) && who->isInAccessablePlaceFor(m_creature) ) - { - DoCast(who,16472); - ((Player*)who)->AreaExploredOrEventHappens(4866); - } - } - - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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) ) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void Aggro(Unit *who) {} -}; - -CreatureAI* GetAI_npc_ragged_john(Creature *_Creature) -{ - return new npc_ragged_johnAI (_Creature); -} - -bool GossipHello_npc_ragged_john(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(4224) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "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); - - player->SEND_GOSSIP_MENU(2713, _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_ragged_john(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, "So what did you do?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(2714, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(2715, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "Ironfoe?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(2716, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "Interesting... continue John.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(2717, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM( 0, "So that's how Windsor died...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(2718, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM( 0, "So how did he die?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(2719, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM( 0, "Ok so where the hell is he? Wait a minute! Are you drunk?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(2720, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - player->ADD_GOSSIP_ITEM( 0, "WHY is he in Blackrock Depths?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(2721, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+8: - player->ADD_GOSSIP_ITEM( 0, "300? So the Dark Irons killed him and dragged him into the Depths?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->SEND_GOSSIP_MENU(2722, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+9: - player->ADD_GOSSIP_ITEM( 0, "Ahh... Ironfoe", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->SEND_GOSSIP_MENU(2723, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+10: - player->ADD_GOSSIP_ITEM( 0, "Thanks, Ragged John. Your story was very uplifting and informative", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(2725, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(4224); - break; - } - return true; -} - -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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Burning_Steppes +SD%Complete: 100 +SDComment: Quest support: 4224, 4866 +SDCategory: Burning Steppes +EndScriptData */ + +/* ContentData +npc_ragged_john +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_ragged_john +######*/ + +struct MANGOS_DLL_DECL npc_ragged_johnAI : public ScriptedAI +{ + npc_ragged_johnAI(Creature *c) : ScriptedAI(c) { Reset(); } + + void Reset() {} + + void MoveInLineOfSight(Unit *who) + { + if( who->HasAura(16468,0) ) + { + if( who->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(who, 15) && who->isInAccessablePlaceFor(m_creature) ) + { + DoCast(who,16472); + ((Player*)who)->AreaExploredOrEventHappens(4866); + } + } + + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void Aggro(Unit *who) {} +}; + +CreatureAI* GetAI_npc_ragged_john(Creature *_Creature) +{ + return new npc_ragged_johnAI (_Creature); +} + +bool GossipHello_npc_ragged_john(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(4224) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "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); + + player->SEND_GOSSIP_MENU(2713, _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_ragged_john(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, "So what did you do?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(2714, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(2715, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "Ironfoe?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(2716, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "Interesting... continue John.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(2717, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM( 0, "So that's how Windsor died...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(2718, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM( 0, "So how did he die?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(2719, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + player->ADD_GOSSIP_ITEM( 0, "Ok so where the hell is he? Wait a minute! Are you drunk?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(2720, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+7: + player->ADD_GOSSIP_ITEM( 0, "WHY is he in Blackrock Depths?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + player->SEND_GOSSIP_MENU(2721, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+8: + player->ADD_GOSSIP_ITEM( 0, "300? So the Dark Irons killed him and dragged him into the Depths?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->SEND_GOSSIP_MENU(2722, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+9: + player->ADD_GOSSIP_ITEM( 0, "Ahh... Ironfoe", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + player->SEND_GOSSIP_MENU(2723, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+10: + player->ADD_GOSSIP_ITEM( 0, "Thanks, Ragged John. Your story was very uplifting and informative", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(2725, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+11: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(4224); + break; + } + return true; +} + +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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_aeonus.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_aeonus.cpp index 89e9ee31dfe..330fe6b8e08 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_aeonus.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_aeonus.cpp @@ -1,137 +1,137 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Aeonus -SD%Complete: 100 -SDComment: -SDCategory: Caverns of Time, The Dark Portal -EndScriptData */ - -#include "precompiled.h" - -#define SAND_BREATH 31478 -#define TIME_STOP 31422 -#define FRENZY 19812 - -#define SAY_ENTER "The time has come to shatter this clockwork universe forever! Let us no longer be slaves of the hourglass! I warn you: those who do not embrace the greater path shall become victims of its passing!" -#define SAY_AGGRO "Let us see what fate lays in store..." -#define SAY_BANISH "Your time is up, slave of the past!" -#define SAY_SLAY1 "One less obstacle in our way!" -#define SAY_SLAY2 "No one can stop us! No one!" -#define SAY_DEATH "It is only a matter...of time." - -#define SOUND_ENTER 10400 -#define SOUND_AGGRO 10402 -#define SOUND_BANISH 10401 -#define SOUND_SLAY1 10403 -#define SOUND_SLAY2 10404 -#define SOUND_DEATH 10405 - -struct MANGOS_DLL_DECL boss_aeonusAI : public ScriptedAI -{ - boss_aeonusAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 SandBreath_Timer; - uint32 TimeStop_Timer; - uint32 Frenzy_Timer; - - void Reset() - { - SandBreath_Timer = 30000; - TimeStop_Timer = 40000; - Frenzy_Timer = 120000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void JustDied(Unit *victim) - { - //Just Died - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void KilledUnit(Unit *victim) - { - //Killed Unit - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Sand Breath - if (SandBreath_Timer < diff) - { - Unit* target = NULL; - target = m_creature->getVictim(); - if (target) - DoCast(target, SAND_BREATH); - SandBreath_Timer = 30000; - }else SandBreath_Timer -= diff; - - //Time Stop - if (TimeStop_Timer < diff) - { - DoYell(SAY_BANISH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_BANISH); - - DoCast(m_creature->getVictim(), TIME_STOP); - TimeStop_Timer = 40000; - }else TimeStop_Timer -= diff; - - //Frenzy - if (Frenzy_Timer < diff) - { - DoCast(m_creature, FRENZY); - Frenzy_Timer = 120000; - }else Frenzy_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_aeonus(Creature *_Creature) -{ - return new boss_aeonusAI (_Creature); -} - -void AddSC_boss_aeonus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_aeonus"; - newscript->GetAI = GetAI_boss_aeonus; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Aeonus +SD%Complete: 100 +SDComment: +SDCategory: Caverns of Time, The Dark Portal +EndScriptData */ + +#include "precompiled.h" + +#define SAND_BREATH 31478 +#define TIME_STOP 31422 +#define FRENZY 19812 + +#define SAY_ENTER "The time has come to shatter this clockwork universe forever! Let us no longer be slaves of the hourglass! I warn you: those who do not embrace the greater path shall become victims of its passing!" +#define SAY_AGGRO "Let us see what fate lays in store..." +#define SAY_BANISH "Your time is up, slave of the past!" +#define SAY_SLAY1 "One less obstacle in our way!" +#define SAY_SLAY2 "No one can stop us! No one!" +#define SAY_DEATH "It is only a matter...of time." + +#define SOUND_ENTER 10400 +#define SOUND_AGGRO 10402 +#define SOUND_BANISH 10401 +#define SOUND_SLAY1 10403 +#define SOUND_SLAY2 10404 +#define SOUND_DEATH 10405 + +struct MANGOS_DLL_DECL boss_aeonusAI : public ScriptedAI +{ + boss_aeonusAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 SandBreath_Timer; + uint32 TimeStop_Timer; + uint32 Frenzy_Timer; + + void Reset() + { + SandBreath_Timer = 30000; + TimeStop_Timer = 40000; + Frenzy_Timer = 120000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void JustDied(Unit *victim) + { + //Just Died + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void KilledUnit(Unit *victim) + { + //Killed Unit + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Sand Breath + if (SandBreath_Timer < diff) + { + Unit* target = NULL; + target = m_creature->getVictim(); + if (target) + DoCast(target, SAND_BREATH); + SandBreath_Timer = 30000; + }else SandBreath_Timer -= diff; + + //Time Stop + if (TimeStop_Timer < diff) + { + DoYell(SAY_BANISH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_BANISH); + + DoCast(m_creature->getVictim(), TIME_STOP); + TimeStop_Timer = 40000; + }else TimeStop_Timer -= diff; + + //Frenzy + if (Frenzy_Timer < diff) + { + DoCast(m_creature, FRENZY); + Frenzy_Timer = 120000; + }else Frenzy_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_aeonus(Creature *_Creature) +{ + return new boss_aeonusAI (_Creature); +} + +void AddSC_boss_aeonus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_aeonus"; + newscript->GetAI = GetAI_boss_aeonus; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp index 1dcc7fcc5ee..4d958332bb8 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp @@ -1,124 +1,124 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Chrono_Lord_Deja -SD%Complete: 100 -SDComment: -SDCategory: Caverns of Time, The Dark Portal -EndScriptData */ - -#include "precompiled.h" - -#define ARCANE_BLAST 24857 -#define TIME_LAPSE 31467 -#define MAGNETIC_PULL 28337 //Not Implemented (Heroic mod) - -#define SAY_ENTER "Why do you aid the Magus? Just think of how many lives could be saved if the portal is never opened, if the resulting wars could be erased ..." -#define SAY_AGGRO "If you will not cease this foolish quest, then you will die!" -#define SAY_BANISH "You have outstayed your welcome, Timekeeper. Begone!" -#define SAY_SLAY1 "I told you it was a fool's quest!" -#define SAY_SLAY2 "Leaving so soon?" -#define SAY_DEATH "Time ... is on our side." - -#define SOUND_ENTER 10412 -#define SOUND_AGGRO 10414 -#define SOUND_BANISH 10413 -#define SOUND_SLAY1 10415 -#define SOUND_SLAY2 10416 -#define SOUND_DEATH 10417 - -struct MANGOS_DLL_DECL boss_chrono_lord_dejaAI : public ScriptedAI -{ - boss_chrono_lord_dejaAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ArcaneBlast_Timer; - uint32 TimeLapse_Timer; - - void Reset() - { - ArcaneBlast_Timer = 20000; - TimeLapse_Timer = 15000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Arcane Blast - if (ArcaneBlast_Timer < diff) - { - DoCast(m_creature->getVictim(), ARCANE_BLAST); - ArcaneBlast_Timer = 20000+rand()%5000; - }else ArcaneBlast_Timer -= diff; - - //Time Lapse - if (TimeLapse_Timer < diff) - { - DoYell(SAY_BANISH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_BANISH); - DoCast(m_creature, TIME_LAPSE); - TimeLapse_Timer = 15000+rand()%10000; - }else TimeLapse_Timer -= diff; - - DoMeleeAttackIfReady(); - - } -}; - -CreatureAI* GetAI_boss_chrono_lord_deja(Creature *_Creature) -{ - return new boss_chrono_lord_dejaAI (_Creature); -} - -void AddSC_boss_chrono_lord_deja() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_chrono_lord_deja"; - newscript->GetAI = GetAI_boss_chrono_lord_deja; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Chrono_Lord_Deja +SD%Complete: 100 +SDComment: +SDCategory: Caverns of Time, The Dark Portal +EndScriptData */ + +#include "precompiled.h" + +#define ARCANE_BLAST 24857 +#define TIME_LAPSE 31467 +#define MAGNETIC_PULL 28337 //Not Implemented (Heroic mod) + +#define SAY_ENTER "Why do you aid the Magus? Just think of how many lives could be saved if the portal is never opened, if the resulting wars could be erased ..." +#define SAY_AGGRO "If you will not cease this foolish quest, then you will die!" +#define SAY_BANISH "You have outstayed your welcome, Timekeeper. Begone!" +#define SAY_SLAY1 "I told you it was a fool's quest!" +#define SAY_SLAY2 "Leaving so soon?" +#define SAY_DEATH "Time ... is on our side." + +#define SOUND_ENTER 10412 +#define SOUND_AGGRO 10414 +#define SOUND_BANISH 10413 +#define SOUND_SLAY1 10415 +#define SOUND_SLAY2 10416 +#define SOUND_DEATH 10417 + +struct MANGOS_DLL_DECL boss_chrono_lord_dejaAI : public ScriptedAI +{ + boss_chrono_lord_dejaAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ArcaneBlast_Timer; + uint32 TimeLapse_Timer; + + void Reset() + { + ArcaneBlast_Timer = 20000; + TimeLapse_Timer = 15000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Arcane Blast + if (ArcaneBlast_Timer < diff) + { + DoCast(m_creature->getVictim(), ARCANE_BLAST); + ArcaneBlast_Timer = 20000+rand()%5000; + }else ArcaneBlast_Timer -= diff; + + //Time Lapse + if (TimeLapse_Timer < diff) + { + DoYell(SAY_BANISH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_BANISH); + DoCast(m_creature, TIME_LAPSE); + TimeLapse_Timer = 15000+rand()%10000; + }else TimeLapse_Timer -= diff; + + DoMeleeAttackIfReady(); + + } +}; + +CreatureAI* GetAI_boss_chrono_lord_deja(Creature *_Creature) +{ + return new boss_chrono_lord_dejaAI (_Creature); +} + +void AddSC_boss_chrono_lord_deja() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_chrono_lord_deja"; + newscript->GetAI = GetAI_boss_chrono_lord_deja; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp index c95657634cf..958e1c33de6 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp @@ -1,166 +1,169 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Temporus -SD%Complete: 100 -SDComment: -SDCategory: Caverns of Time, The Dark Portal -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_TAUNT 355 -#define SPELL_HASTE 31458 -#define SPELL_MORTAL_WOUND 28467 -#define SPELL_REFLECT 23920 //Not Implemented (Heroic mod) - -#define SAY_ENTER "Why do you persist? Surely you can see the futility of it all. It is not too late! You may still leave with your lives ..." -#define SAY_AGGRO "So be it ... you have been warned." -#define SAY_BANISH "Time... sands of time is run out for you." -#define SAY_SLAY1 "You should have left when you had the chance." -#define SAY_SLAY2 "Your days are done." -#define SAY_DEATH "My death means ... little." - -#define SOUND_ENTER 10442 -#define SOUND_AGGRO 10444 -#define SOUND_BANISH 10443 -#define SOUND_SLAY1 10445 -#define SOUND_SLAY2 10446 -#define SOUND_DEATH 10447 - -struct MANGOS_DLL_DECL boss_temporusAI : public ScriptedAI -{ - boss_temporusAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Haste_Timer; - uint32 SpellReflection_Timer; - - void Reset() - { - Haste_Timer = 20000; - SpellReflection_Timer = 40000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || m_creature->getVictim()) - return; - - //Despawn Time Keeper - if (who->GetTypeId() == TYPEID_UNIT) - { - if(((Creature*)who)->GetEntry() == 17918 && m_creature->IsWithinDistInMap(who,20)) - { - //This is the wrong yell & sound for despawning time keepers! - DoYell(SAY_ENTER, LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_ENTER); - - m_creature->DealDamage(who, who->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - } - - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - if (!InCombat) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Check if we have a current target - if( m_creature->getVictim() && m_creature->isAlive()) - { - - //Attack Haste - if (Haste_Timer < diff) - { - DoCast(m_creature, SPELL_HASTE); - Haste_Timer = 20000+rand()%5000; - }else Haste_Timer -= diff; - - //Spell Reflection - if (SpellReflection_Timer < diff) - { - DoYell(SAY_BANISH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_BANISH); - - DoCast(m_creature, SPELL_REFLECT); - SpellReflection_Timer = 40000+rand()%10000; - }else SpellReflection_Timer -= diff; - - DoMeleeAttackIfReady(); - - } - } -}; - -CreatureAI* GetAI_boss_temporus(Creature *_Creature) -{ - return new boss_temporusAI (_Creature); -} - -void AddSC_boss_temporus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_temporus"; - newscript->GetAI = GetAI_boss_temporus; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Temporus +SD%Complete: 100 +SDComment: +SDCategory: Caverns of Time, The Dark Portal +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_TAUNT 355 +#define SPELL_HASTE 31458 +#define SPELL_MORTAL_WOUND 28467 +#define SPELL_REFLECT 23920 //Not Implemented (Heroic mod) + +#define SAY_ENTER "Why do you persist? Surely you can see the futility of it all. It is not too late! You may still leave with your lives ..." +#define SAY_AGGRO "So be it ... you have been warned." +#define SAY_BANISH "Time... sands of time is run out for you." +#define SAY_SLAY1 "You should have left when you had the chance." +#define SAY_SLAY2 "Your days are done." +#define SAY_DEATH "My death means ... little." + +#define SOUND_ENTER 10442 +#define SOUND_AGGRO 10444 +#define SOUND_BANISH 10443 +#define SOUND_SLAY1 10445 +#define SOUND_SLAY2 10446 +#define SOUND_DEATH 10447 + +struct MANGOS_DLL_DECL boss_temporusAI : public ScriptedAI +{ + boss_temporusAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Haste_Timer; + uint32 SpellReflection_Timer; + + void Reset() + { + Haste_Timer = 20000; + SpellReflection_Timer = 40000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void MoveInLineOfSight(Unit *who) + { + if (!who || m_creature->getVictim()) + return; + + //Despawn Time Keeper + if (who->GetTypeId() == TYPEID_UNIT) + { + if(((Creature*)who)->GetEntry() == 17918 && m_creature->IsWithinDistInMap(who,20)) + { + //This is the wrong yell & sound for despawning time keepers! + DoYell(SAY_ENTER, LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_ENTER); + + m_creature->DealDamage(who, who->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + if (!m_creature->getVictim() && 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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + DoStartAttackAndMovement(who); + if (!InCombat) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + } + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Check if we have a current target + if( m_creature->getVictim() && m_creature->isAlive()) + { + + //Attack Haste + if (Haste_Timer < diff) + { + DoCast(m_creature, SPELL_HASTE); + Haste_Timer = 20000+rand()%5000; + }else Haste_Timer -= diff; + + //Spell Reflection + if (SpellReflection_Timer < diff) + { + DoYell(SAY_BANISH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_BANISH); + + DoCast(m_creature, SPELL_REFLECT); + SpellReflection_Timer = 40000+rand()%10000; + }else SpellReflection_Timer -= diff; + + DoMeleeAttackIfReady(); + + } + } +}; + +CreatureAI* GetAI_boss_temporus(Creature *_Creature) +{ + return new boss_temporusAI (_Creature); +} + +void AddSC_boss_temporus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_temporus"; + newscript->GetAI = GetAI_boss_temporus; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_archimonde.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_archimonde.cpp index d6e24a30a9a..686c4557768 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_archimonde.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_archimonde.cpp @@ -1,788 +1,788 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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: 95 -SDComment: Doomfires not completely offlike due to core limitations for random moving. -SDCategory: Caverns of Time, Mount Hyjal -EndScriptData */ - -#include "precompiled.h" -#include "def_hyjal.h" -#include "SpellAuras.h" - -#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_SPAWN 32074 -#define SPELL_DOOMFIRE_VISUAL 42344 // This is actually a Zul'Aman spell, but the proper Doomfire spell sometimes freezes the server if a player stands in it for too long -#define SPELL_DOOMFIRE_DAMAGE 31944 -#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 SAY_AGGRO "Your resistance is insignificant!" -#define SOUND_AGGRO 10987 - -#define SAY_DOOMFIRE1 "This world will burn!" -#define SOUND_DOOMFIRE1 10990 - -#define SAY_DOOMFIRE2 "Manach sheek-thrish!" -#define SOUND_DOOMFIRE2 11041 - -#define SAY_AIR_BURST "A-kreesh!" -#define SOUND_AIR_BURST 10989 - -#define SAY_AIR_BURST2 "Away vermin!" -#define SOUND_AIR_BURST2 11043 - -#define SAY_SLAY1 "All creation will be devoured!" -#define SOUND_SLAY1 11044 - -#define SAY_SLAY2 "Your soul will languish for eternity." -#define SOUND_SLAY2 10991 - -#define SAY_SLAY3 "I am the coming of the end!" -#define SOUND_SLAY3 11045 - -#define SAY_UNK1 "You are mine now." -#define SOUND_UNK1 10988 - -#define SAY_UNK2 "Bow to my will." -#define SOUND_UNK2 11042 - -#define SAY_ENRAGE "At last it is here. Mourn and lament the passing of all you have ever known and all that would have been! Akmin-kurai!" -#define SOUND_ENRAGE 10993 - -#define SAY_DEATH "No, it cannot be! Nooo!" -#define SOUND_DEATH 10992 - -#define CREATURE_ARCHIMONDE 17968 -#define CREATURE_DOOMFIRE 18095 -#define CREATURE_DOOMFIRE_TARGETING 18104 -#define CREATURE_ANCIENT_WISP 17946 -#define CREATURE_CHANNEL_TARGET 22418 - -#define NORDRASSIL_X 5503.713 -#define NORDRASSIL_Y -3523.436 -#define NORDRASSIL_Z 1608.781 - -struct mob_ancient_wispAI : public ScriptedAI -{ - mob_ancient_wispAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - uint64 ArchimondeGUID; - uint32 CheckTimer; - - void Reset() - { - ArchimondeGUID = 0; - CheckTimer = 1000; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - void Aggro(Unit* who) {} - - void DamageTaken(Unit* done_by, uint32 &damage) { damage = 0; } - - void UpdateAI(const uint32 diff) - { - if(!ArchimondeGUID) - { - if(pInstance) - ArchimondeGUID = pInstance->GetData64(DATA_ARCHIMONDE); - } - - if(CheckTimer < diff) - { - if(ArchimondeGUID) - { - Unit* Archimonde = Unit::GetUnit((*m_creature), ArchimondeGUID); - if(Archimonde) - { - if((((Archimonde->GetHealth()*100) / Archimonde->GetMaxHealth()) < 2) || !Archimonde->isAlive()) - DoCast(m_creature, SPELL_DENOUEMENT_WISP); - else - DoCast(Archimonde, SPELL_ANCIENT_SPARK); - } - } - CheckTimer = 1000; - }else CheckTimer -= diff; - } -}; - -/* This script controls the Doomfire mob. Unlike the other Doomfire mob, this one does not stalk players. - Instead, this doomfire will simply stand in one place after spawning and deal damage to any players that - are within 3 yards. Another creature called Doomfire Targetting spawns this creature as well as stalks. */ -struct MANGOS_DLL_DECL mob_doomfireAI : public ScriptedAI -{ - mob_doomfireAI(Creature* c) : ScriptedAI(c) - { - Reset(); - } - - uint32 CheckTimer; - uint32 RefreshTimer; - - bool TargetSelected; - - uint64 ArchimondeGUID; - uint64 TargetGUID; - - void Reset() - { - CheckTimer = 5000; - RefreshTimer = 0; - - TargetSelected = false; - - ArchimondeGUID = 0; - TargetGUID = 0; - } - - void DamageTaken(Unit *done_by, uint32 &damage) { damage = 0; } - - void Aggro(Unit* who) { } - - void MoveInLineOfSight(Unit* who) - { - // Do not do anything if who does not exist, or we are refreshing our timer, or who is Doomfire, Archimonde or Doomfire targetting - if(!who || who == m_creature || RefreshTimer || who->GetEntry() == CREATURE_ANCIENT_WISP || - who->GetEntry() == CREATURE_ARCHIMONDE || who->GetEntry() == CREATURE_DOOMFIRE || - who->GetEntry() == CREATURE_DOOMFIRE_TARGETING || !who->isTargetableForAttack()) - return; - - if(m_creature->IsWithinDistInMap(who, 3)) - { - TargetSelected = true; - TargetGUID = who->GetGUID(); - RefreshTimer = 2000; - } - } - - void KilledUnit(Unit* victim) - { - bool suicide = true; - if(ArchimondeGUID) - { - Creature* Archimonde = ((Creature*)Unit::GetUnit((*m_creature), ArchimondeGUID)); - if(Archimonde && Archimonde->isAlive()) - { - suicide = false; - Archimonde->AI()->KilledUnit(victim); - } - } - - if(suicide) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - - void UpdateAI(const uint32 diff) - { - if(RefreshTimer < diff) - RefreshTimer = 0; - else RefreshTimer -= diff; - - if(TargetSelected && TargetGUID) - { - Unit* target = Unit::GetUnit((*m_creature), TargetGUID); - if(target && target->isAlive()) - { - target->CastSpell(target, SPELL_DOOMFIRE_DAMAGE, true); - TargetGUID = 0; - TargetSelected = false; - } - } - - if(CheckTimer < diff) - { - if(ArchimondeGUID) - { - Unit* Archimonde = Unit::GetUnit((*m_creature), ArchimondeGUID); - if(!Archimonde || !Archimonde->isAlive()) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - CheckTimer = 5000; - } - else m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - }else CheckTimer -= diff; - } -}; - -/* This is the script for the Doomfire Targetting Mob. This mob simply follows players and/or travels in random directions and spawns the actual Doomfire which does damage to anyone that moves close. */ -struct MANGOS_DLL_DECL mob_doomfire_targettingAI : public ScriptedAI -{ - mob_doomfire_targettingAI(Creature* c) : ScriptedAI(c) - { - Reset(); - } - - uint32 ChangeTargetTimer; - uint32 SummonTimer; // This timer will serve as both a summon timer for the doomfire that does damage as well as to check on Archionde - - uint64 ArchimondeGUID; - - void Reset() - { - ChangeTargetTimer = 5000; - SummonTimer = 1000; - - ArchimondeGUID = 0; - } - - void Aggro(Unit* who) {} - - void MoveInLineOfSight(Unit* who) - { - // Do not do anything if who does not exist, or who is Doomfire, Archimonde or Doomfire targetting - if(!who || who == m_creature || who->GetEntry() == CREATURE_ARCHIMONDE - || who->GetEntry() == CREATURE_DOOMFIRE || who->GetEntry() == CREATURE_DOOMFIRE_TARGETING || !who->isTargetableForAttack()) - return; - - m_creature->AddThreat(who, 1.0f); - } - - void DamageTaken(Unit *done_by, uint32 &damage) { damage = 0; } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(SummonTimer < diff) - { - if(ArchimondeGUID) - { - Unit* Archimonde = Unit::GetUnit((*m_creature), ArchimondeGUID); - if(Archimonde && Archimonde->isAlive()) - { - Creature* Doomfire = DoSpawnCreature(CREATURE_DOOMFIRE, 0, 0, 2, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); - if(Doomfire) - { - Doomfire->CastSpell(Doomfire, SPELL_DOOMFIRE_VISUAL, true); - ((mob_doomfireAI*)Doomfire->AI())->ArchimondeGUID = ArchimondeGUID; - Doomfire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - SummonTimer = 500; - } - else - 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); - }else SummonTimer -= diff; - - if(ChangeTargetTimer < diff) - { - Unit* target = NULL; - switch(rand()%2) - { - case 0: // stalk player - target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(target && target->isAlive()) - { - m_creature->AddThreat(target, m_creature->getThreatManager().getThreat(m_creature->getVictim())); - m_creature->GetMotionMaster()->MoveChase(target); - } - break; - - case 1: // random location - float x = 0; - float y = 0; - float z = 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); - break; - } - 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 Targetting) that summons another mob (Doomfire every second) - Doomfire Targetting 'stalks' players whilst Doomfire damages player that are within range. */ - -// This is used to sort by distance in order to see who is the closest target, when checking for Finger of Death -struct TargetDistanceOrder : public std::binary_function -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator "<" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); - } -}; - -struct MANGOS_DLL_DECL boss_archimondeAI : public ScriptedAI -{ - boss_archimondeAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 DrainNordrassilTimer; - uint32 FearTimer; - uint32 AirBurstTimer; - uint32 GripOfTheLegionTimer; - uint32 DoomfireTimer; - uint32 SoulChargeTimer; - uint32 SoulChargeCount; - uint32 MeleeRangeCheckTimer; - uint32 HandOfDeathTimer; - uint32 SummonWispTimer; - uint32 WispCount; - uint32 EnrageTimer; - uint32 CheckDistanceTimer; - - bool Enraged; - bool BelowTenPercent; - bool HasProtected; - bool IsChanneling; - - void Reset() - { - if(pInstance) - pInstance->SetData(DATA_ARCHIMONDEEVENT, NOT_STARTED); - - DrainNordrassilTimer = 0; - FearTimer = 40000; - AirBurstTimer = 30000; - GripOfTheLegionTimer = 5000 + rand()%20000; - DoomfireTimer = 20000; - SoulChargeTimer = 2000 + rand()%27000; - SoulChargeCount = 0; - 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 *who) - { - m_creature->InterruptSpell(CURRENT_CHANNELED_SPELL); - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - DoZoneInCombat(); - - if(pInstance) - pInstance->SetData(DATA_ARCHIMONDEEVENT, IN_PROGRESS); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - case 2: - DoYell(SAY_SLAY3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY3); - break; - } - - if(victim && (victim->GetTypeId() == TYPEID_PLAYER)) - GainSoulCharge(((Player*)victim)); - } - - void GainSoulCharge(Player* victim) - { - switch(victim->getClass()) - { - case CLASS_PRIEST: - case CLASS_PALADIN: - case CLASS_WARLOCK: - victim->CastSpell(m_creature, SPELL_SOUL_CHARGE_RED, true); - break; - case CLASS_MAGE: - case CLASS_ROGUE: - case CLASS_WARRIOR: - victim->CastSpell(m_creature, SPELL_SOUL_CHARGE_YELLOW, true); - break; - case CLASS_DRUID: - case CLASS_SHAMAN: - case CLASS_HUNTER: - victim->CastSpell(m_creature, SPELL_SOUL_CHARGE_GREEN, true); - break; - } - - SoulChargeTimer = 2000 + rand()%28000; - ++SoulChargeCount; - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - - if(pInstance) - pInstance->SetData(DATA_ARCHIMONDEEVENT, 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; - - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - if(m_threatlist.empty()) - return false; - - std::list targets; - std::list::iterator itr = m_threatlist.begin(); - for( ; itr != m_threatlist.end(); ++itr) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); - if(pUnit && pUnit->isAlive()) - targets.push_back(pUnit); - } - - if(targets.empty()) - return false; - - targets.sort(TargetDistanceOrder(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 SummonDoomfire(Unit* target) - { - Creature* Doomfire = DoSpawnCreature(CREATURE_DOOMFIRE_TARGETING, rand()%30, rand()%30, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); - if(Doomfire) - { - ((mob_doomfire_targettingAI*)Doomfire->AI())->ArchimondeGUID = m_creature->GetGUID(); - Doomfire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // Give Doomfire a taste of everyone in the threatlist = more targets to chase. - std::list::iterator itr; - for(itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr) - Doomfire->AddThreat(Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()), 1.0f); - Doomfire->setFaction(m_creature->getFaction()); - DoCast(Doomfire, SPELL_DOOMFIRE_SPAWN); - Doomfire->CastSpell(Doomfire, SPELL_DOOMFIRE_VISUAL, true); - if(target) - Doomfire->AI()->AttackStart(target); - - if(rand()%2 == 0) - { - DoYell(SAY_DOOMFIRE1, LANG_UNIVERSAL, m_creature); - DoPlaySoundToSet(m_creature, SOUND_DOOMFIRE1); - }else - { - DoYell(SAY_DOOMFIRE2, LANG_UNIVERSAL, m_creature); - DoPlaySoundToSet(m_creature, SOUND_DOOMFIRE2); - } - } - } - - void UnleashSoulCharge() - { - m_creature->InterruptNonMeleeSpells(false); - bool HasCast = false; - uint32 chargeSpell = 0; - uint32 unleashSpell = 0; - switch(rand()%3) - { - case 0: - chargeSpell = SPELL_SOUL_CHARGE_RED; - unleashSpell = SPELL_UNLEASH_SOUL_RED; - break; - case 1: - chargeSpell = SPELL_SOUL_CHARGE_YELLOW; - unleashSpell = SPELL_UNLEASH_SOUL_YELLOW; - break; - case 2: - chargeSpell = SPELL_SOUL_CHARGE_GREEN; - unleashSpell = SPELL_UNLEASH_SOUL_GREEN; - break; - } - if(m_creature->HasAura(chargeSpell, 0)) - { - m_creature->RemoveSingleAuraFromStack(chargeSpell, 0); - DoCast(m_creature->getVictim(), unleashSpell); - HasCast = true; - SoulChargeCount--; - } - if(HasCast) - SoulChargeTimer = 2000 + rand()%28000; - } - - void UpdateAI(const uint32 diff) - { - if(!InCombat) - { - if(pInstance) - { - // Do not let the raid skip straight to Archimonde. Visible and hostile ONLY if Azagalor is finished. - if((pInstance->GetData(DATA_AZGALOREVENT) < DONE) && ((m_creature->GetVisibility() != VISIBILITY_OFF) || (m_creature->getFaction() != 35))) - { - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->setFaction(35); - } - else if((pInstance->GetData(DATA_AZGALOREVENT) >= 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* Nordrassil = m_creature->SummonCreature(CREATURE_CHANNEL_TARGET, NORDRASSIL_X, NORDRASSIL_Y, NORDRASSIL_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 1200000); - if(Nordrassil) - { - Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Nordrassil->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); - DoCast(Nordrassil, SPELL_DRAIN_WORLD_TREE); - IsChanneling = true; - } - } - Creature* Nordrassil = m_creature->SummonCreature(CREATURE_CHANNEL_TARGET, NORDRASSIL_X, NORDRASSIL_Y, NORDRASSIL_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 5000); - if(Nordrassil) - { - Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Nordrassil->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); - Nordrassil->CastSpell(m_creature, SPELL_DRAIN_WORLD_TREE_2, true); - DrainNordrassilTimer = 1000; - } - }else DrainNordrassilTimer -= diff; - } - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !BelowTenPercent && !Enraged) - BelowTenPercent = true; - - if(!Enraged) - { - if(EnrageTimer < diff) - { - if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) > 10) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - Enraged = true; - DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - } - }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; - DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - } - } - CheckDistanceTimer = 5000; - }else CheckDistanceTimer -= diff; - } - - if(BelowTenPercent) - { - if(!HasProtected) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - DoCast(m_creature->getVictim(), SPELL_PROTECTION_OF_ELUNE); - HasProtected = true; - Enraged = true; - } - - if(SummonWispTimer < diff) - { - Creature* Wisp = DoSpawnCreature(CREATURE_ANCIENT_WISP, rand()%40, rand()%40, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(Wisp) - { - Wisp->AI()->AttackStart(m_creature); - ((mob_ancient_wispAI*)Wisp->AI())->ArchimondeGUID = m_creature->GetGUID(); - } - 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) - { - DoCast(m_creature->getVictim(), SPELL_HAND_OF_DEATH); - HandOfDeathTimer = 2000; - }else HandOfDeathTimer -= diff; - return; // Don't do anything after this point. - } - - if(SoulChargeCount) - { - if(SoulChargeTimer < diff) - UnleashSoulCharge(); - else SoulChargeTimer -= diff; - } - - if(GripOfTheLegionTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_GRIP_OF_THE_LEGION); - GripOfTheLegionTimer = 5000 + rand()%20000; - }else GripOfTheLegionTimer -= diff; - - if(AirBurstTimer < diff) - { - if(rand()%2 == 0) - { - DoYell(SAY_AIR_BURST, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AIR_BURST); - }else - { - DoYell(SAY_AIR_BURST2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AIR_BURST2); - } - - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_AIR_BURST); - AirBurstTimer = 25000 + rand()%15000; - }else AirBurstTimer -= diff; - - if(FearTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FEAR); - FearTimer = 40000; - }else FearTimer -= diff; - - if(DoomfireTimer < diff) - { - SummonDoomfire(SelectUnit(SELECT_TARGET_RANDOM, 1)); - DoomfireTimer = 40000; - }else DoomfireTimer -= diff; - - if(MeleeRangeCheckTimer < diff) - { - if(CanUseFingerOfDeath()) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FINGER_OF_DEATH); - MeleeRangeCheckTimer = 1000; - } - - MeleeRangeCheckTimer = 5000; - }else MeleeRangeCheckTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_archimonde(Creature *_Creature) -{ - return new boss_archimondeAI (_Creature); -} - -CreatureAI* GetAI_mob_doomfire(Creature* _Creature) -{ - return new mob_doomfireAI(_Creature); -} - -CreatureAI* GetAI_mob_doomfire_targetting(Creature* _Creature) -{ - return new mob_doomfire_targettingAI(_Creature); -} - -CreatureAI* GetAI_mob_ancient_wisp(Creature* _Creature) -{ - return new mob_ancient_wispAI(_Creature); -} - -void AddSC_boss_archimonde() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_archimonde"; - newscript->GetAI = GetAI_boss_archimonde; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_doomfire"; - newscript->GetAI = GetAI_mob_doomfire; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_doomfire_targetting"; - newscript->GetAI = GetAI_mob_doomfire_targetting; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_ancient_wisp"; - newscript->GetAI = GetAI_mob_ancient_wisp; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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: 95 +SDComment: Doomfires not completely offlike due to core limitations for random moving. +SDCategory: Caverns of Time, Mount Hyjal +EndScriptData */ + +#include "precompiled.h" +#include "def_hyjal.h" +#include "SpellAuras.h" + +#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_SPAWN 32074 +#define SPELL_DOOMFIRE_VISUAL 42344 // This is actually a Zul'Aman spell, but the proper Doomfire spell sometimes freezes the server if a player stands in it for too long +#define SPELL_DOOMFIRE_DAMAGE 31944 +#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 SAY_AGGRO "Your resistance is insignificant!" +#define SOUND_AGGRO 10987 + +#define SAY_DOOMFIRE1 "This world will burn!" +#define SOUND_DOOMFIRE1 10990 + +#define SAY_DOOMFIRE2 "Manach sheek-thrish!" +#define SOUND_DOOMFIRE2 11041 + +#define SAY_AIR_BURST "A-kreesh!" +#define SOUND_AIR_BURST 10989 + +#define SAY_AIR_BURST2 "Away vermin!" +#define SOUND_AIR_BURST2 11043 + +#define SAY_SLAY1 "All creation will be devoured!" +#define SOUND_SLAY1 11044 + +#define SAY_SLAY2 "Your soul will languish for eternity." +#define SOUND_SLAY2 10991 + +#define SAY_SLAY3 "I am the coming of the end!" +#define SOUND_SLAY3 11045 + +#define SAY_UNK1 "You are mine now." +#define SOUND_UNK1 10988 + +#define SAY_UNK2 "Bow to my will." +#define SOUND_UNK2 11042 + +#define SAY_ENRAGE "At last it is here. Mourn and lament the passing of all you have ever known and all that would have been! Akmin-kurai!" +#define SOUND_ENRAGE 10993 + +#define SAY_DEATH "No, it cannot be! Nooo!" +#define SOUND_DEATH 10992 + +#define CREATURE_ARCHIMONDE 17968 +#define CREATURE_DOOMFIRE 18095 +#define CREATURE_DOOMFIRE_TARGETING 18104 +#define CREATURE_ANCIENT_WISP 17946 +#define CREATURE_CHANNEL_TARGET 22418 + +#define NORDRASSIL_X 5503.713 +#define NORDRASSIL_Y -3523.436 +#define NORDRASSIL_Z 1608.781 + +struct mob_ancient_wispAI : public ScriptedAI +{ + mob_ancient_wispAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + uint64 ArchimondeGUID; + uint32 CheckTimer; + + void Reset() + { + ArchimondeGUID = 0; + CheckTimer = 1000; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void Aggro(Unit* who) {} + + void DamageTaken(Unit* done_by, uint32 &damage) { damage = 0; } + + void UpdateAI(const uint32 diff) + { + if(!ArchimondeGUID) + { + if(pInstance) + ArchimondeGUID = pInstance->GetData64(DATA_ARCHIMONDE); + } + + if(CheckTimer < diff) + { + if(ArchimondeGUID) + { + Unit* Archimonde = Unit::GetUnit((*m_creature), ArchimondeGUID); + if(Archimonde) + { + if((((Archimonde->GetHealth()*100) / Archimonde->GetMaxHealth()) < 2) || !Archimonde->isAlive()) + DoCast(m_creature, SPELL_DENOUEMENT_WISP); + else + DoCast(Archimonde, SPELL_ANCIENT_SPARK); + } + } + CheckTimer = 1000; + }else CheckTimer -= diff; + } +}; + +/* This script controls the Doomfire mob. Unlike the other Doomfire mob, this one does not stalk players. + Instead, this doomfire will simply stand in one place after spawning and deal damage to any players that + are within 3 yards. Another creature called Doomfire Targetting spawns this creature as well as stalks. */ +struct MANGOS_DLL_DECL mob_doomfireAI : public ScriptedAI +{ + mob_doomfireAI(Creature* c) : ScriptedAI(c) + { + Reset(); + } + + uint32 CheckTimer; + uint32 RefreshTimer; + + bool TargetSelected; + + uint64 ArchimondeGUID; + uint64 TargetGUID; + + void Reset() + { + CheckTimer = 5000; + RefreshTimer = 0; + + TargetSelected = false; + + ArchimondeGUID = 0; + TargetGUID = 0; + } + + void DamageTaken(Unit *done_by, uint32 &damage) { damage = 0; } + + void Aggro(Unit* who) { } + + void MoveInLineOfSight(Unit* who) + { + // Do not do anything if who does not exist, or we are refreshing our timer, or who is Doomfire, Archimonde or Doomfire targetting + if(!who || who == m_creature || RefreshTimer || who->GetEntry() == CREATURE_ANCIENT_WISP || + who->GetEntry() == CREATURE_ARCHIMONDE || who->GetEntry() == CREATURE_DOOMFIRE || + who->GetEntry() == CREATURE_DOOMFIRE_TARGETING || !who->isTargetableForAttack()) + return; + + if(m_creature->IsWithinDistInMap(who, 3)) + { + TargetSelected = true; + TargetGUID = who->GetGUID(); + RefreshTimer = 2000; + } + } + + void KilledUnit(Unit* victim) + { + bool suicide = true; + if(ArchimondeGUID) + { + Creature* Archimonde = ((Creature*)Unit::GetUnit((*m_creature), ArchimondeGUID)); + if(Archimonde && Archimonde->isAlive()) + { + suicide = false; + Archimonde->AI()->KilledUnit(victim); + } + } + + if(suicide) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + void UpdateAI(const uint32 diff) + { + if(RefreshTimer < diff) + RefreshTimer = 0; + else RefreshTimer -= diff; + + if(TargetSelected && TargetGUID) + { + Unit* target = Unit::GetUnit((*m_creature), TargetGUID); + if(target && target->isAlive()) + { + target->CastSpell(target, SPELL_DOOMFIRE_DAMAGE, true); + TargetGUID = 0; + TargetSelected = false; + } + } + + if(CheckTimer < diff) + { + if(ArchimondeGUID) + { + Unit* Archimonde = Unit::GetUnit((*m_creature), ArchimondeGUID); + if(!Archimonde || !Archimonde->isAlive()) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + CheckTimer = 5000; + } + else m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + }else CheckTimer -= diff; + } +}; + +/* This is the script for the Doomfire Targetting Mob. This mob simply follows players and/or travels in random directions and spawns the actual Doomfire which does damage to anyone that moves close. */ +struct MANGOS_DLL_DECL mob_doomfire_targettingAI : public ScriptedAI +{ + mob_doomfire_targettingAI(Creature* c) : ScriptedAI(c) + { + Reset(); + } + + uint32 ChangeTargetTimer; + uint32 SummonTimer; // This timer will serve as both a summon timer for the doomfire that does damage as well as to check on Archionde + + uint64 ArchimondeGUID; + + void Reset() + { + ChangeTargetTimer = 5000; + SummonTimer = 1000; + + ArchimondeGUID = 0; + } + + void Aggro(Unit* who) {} + + void MoveInLineOfSight(Unit* who) + { + // Do not do anything if who does not exist, or who is Doomfire, Archimonde or Doomfire targetting + if(!who || who == m_creature || who->GetEntry() == CREATURE_ARCHIMONDE + || who->GetEntry() == CREATURE_DOOMFIRE || who->GetEntry() == CREATURE_DOOMFIRE_TARGETING || !who->isTargetableForAttack()) + return; + + m_creature->AddThreat(who, 1.0f); + } + + void DamageTaken(Unit *done_by, uint32 &damage) { damage = 0; } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(SummonTimer < diff) + { + if(ArchimondeGUID) + { + Unit* Archimonde = Unit::GetUnit((*m_creature), ArchimondeGUID); + if(Archimonde && Archimonde->isAlive()) + { + Creature* Doomfire = DoSpawnCreature(CREATURE_DOOMFIRE, 0, 0, 2, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); + if(Doomfire) + { + Doomfire->CastSpell(Doomfire, SPELL_DOOMFIRE_VISUAL, true); + ((mob_doomfireAI*)Doomfire->AI())->ArchimondeGUID = ArchimondeGUID; + Doomfire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + SummonTimer = 500; + } + else + 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); + }else SummonTimer -= diff; + + if(ChangeTargetTimer < diff) + { + Unit* target = NULL; + switch(rand()%2) + { + case 0: // stalk player + target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(target && target->isAlive()) + { + m_creature->AddThreat(target, m_creature->getThreatManager().getThreat(m_creature->getVictim())); + m_creature->GetMotionMaster()->MoveChase(target); + } + break; + + case 1: // random location + float x = 0; + float y = 0; + float z = 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); + break; + } + 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 Targetting) that summons another mob (Doomfire every second) + Doomfire Targetting 'stalks' players whilst Doomfire damages player that are within range. */ + +// This is used to sort by distance in order to see who is the closest target, when checking for Finger of Death +struct TargetDistanceOrder : public std::binary_function +{ + const Unit* MainTarget; + TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; + // functor for operator "<" + bool operator()(const Unit* _Left, const Unit* _Right) const + { + return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); + } +}; + +struct MANGOS_DLL_DECL boss_archimondeAI : public ScriptedAI +{ + boss_archimondeAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 DrainNordrassilTimer; + uint32 FearTimer; + uint32 AirBurstTimer; + uint32 GripOfTheLegionTimer; + uint32 DoomfireTimer; + uint32 SoulChargeTimer; + uint32 SoulChargeCount; + uint32 MeleeRangeCheckTimer; + uint32 HandOfDeathTimer; + uint32 SummonWispTimer; + uint32 WispCount; + uint32 EnrageTimer; + uint32 CheckDistanceTimer; + + bool Enraged; + bool BelowTenPercent; + bool HasProtected; + bool IsChanneling; + + void Reset() + { + if(pInstance) + pInstance->SetData(DATA_ARCHIMONDEEVENT, NOT_STARTED); + + DrainNordrassilTimer = 0; + FearTimer = 40000; + AirBurstTimer = 30000; + GripOfTheLegionTimer = 5000 + rand()%20000; + DoomfireTimer = 20000; + SoulChargeTimer = 2000 + rand()%27000; + SoulChargeCount = 0; + 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 *who) + { + m_creature->InterruptSpell(CURRENT_CHANNELED_SPELL); + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + DoZoneInCombat(); + + if(pInstance) + pInstance->SetData(DATA_ARCHIMONDEEVENT, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + case 2: + DoYell(SAY_SLAY3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY3); + break; + } + + if(victim && (victim->GetTypeId() == TYPEID_PLAYER)) + GainSoulCharge(((Player*)victim)); + } + + void GainSoulCharge(Player* victim) + { + switch(victim->getClass()) + { + case CLASS_PRIEST: + case CLASS_PALADIN: + case CLASS_WARLOCK: + victim->CastSpell(m_creature, SPELL_SOUL_CHARGE_RED, true); + break; + case CLASS_MAGE: + case CLASS_ROGUE: + case CLASS_WARRIOR: + victim->CastSpell(m_creature, SPELL_SOUL_CHARGE_YELLOW, true); + break; + case CLASS_DRUID: + case CLASS_SHAMAN: + case CLASS_HUNTER: + victim->CastSpell(m_creature, SPELL_SOUL_CHARGE_GREEN, true); + break; + } + + SoulChargeTimer = 2000 + rand()%28000; + ++SoulChargeCount; + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + + if(pInstance) + pInstance->SetData(DATA_ARCHIMONDEEVENT, 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; + + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + if(m_threatlist.empty()) + return false; + + std::list targets; + std::list::iterator itr = m_threatlist.begin(); + for( ; itr != m_threatlist.end(); ++itr) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if(pUnit && pUnit->isAlive()) + targets.push_back(pUnit); + } + + if(targets.empty()) + return false; + + targets.sort(TargetDistanceOrder(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 SummonDoomfire(Unit* target) + { + Creature* Doomfire = DoSpawnCreature(CREATURE_DOOMFIRE_TARGETING, rand()%30, rand()%30, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); + if(Doomfire) + { + ((mob_doomfire_targettingAI*)Doomfire->AI())->ArchimondeGUID = m_creature->GetGUID(); + Doomfire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // Give Doomfire a taste of everyone in the threatlist = more targets to chase. + std::list::iterator itr; + for(itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr) + Doomfire->AddThreat(Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()), 1.0f); + Doomfire->setFaction(m_creature->getFaction()); + DoCast(Doomfire, SPELL_DOOMFIRE_SPAWN); + Doomfire->CastSpell(Doomfire, SPELL_DOOMFIRE_VISUAL, true); + if(target) + Doomfire->AI()->AttackStart(target); + + if(rand()%2 == 0) + { + DoYell(SAY_DOOMFIRE1, LANG_UNIVERSAL, m_creature); + DoPlaySoundToSet(m_creature, SOUND_DOOMFIRE1); + }else + { + DoYell(SAY_DOOMFIRE2, LANG_UNIVERSAL, m_creature); + DoPlaySoundToSet(m_creature, SOUND_DOOMFIRE2); + } + } + } + + void UnleashSoulCharge() + { + m_creature->InterruptNonMeleeSpells(false); + bool HasCast = false; + uint32 chargeSpell = 0; + uint32 unleashSpell = 0; + switch(rand()%3) + { + case 0: + chargeSpell = SPELL_SOUL_CHARGE_RED; + unleashSpell = SPELL_UNLEASH_SOUL_RED; + break; + case 1: + chargeSpell = SPELL_SOUL_CHARGE_YELLOW; + unleashSpell = SPELL_UNLEASH_SOUL_YELLOW; + break; + case 2: + chargeSpell = SPELL_SOUL_CHARGE_GREEN; + unleashSpell = SPELL_UNLEASH_SOUL_GREEN; + break; + } + if(m_creature->HasAura(chargeSpell, 0)) + { + m_creature->RemoveSingleAuraFromStack(chargeSpell, 0); + DoCast(m_creature->getVictim(), unleashSpell); + HasCast = true; + SoulChargeCount--; + } + if(HasCast) + SoulChargeTimer = 2000 + rand()%28000; + } + + void UpdateAI(const uint32 diff) + { + if(!InCombat) + { + if(pInstance) + { + // Do not let the raid skip straight to Archimonde. Visible and hostile ONLY if Azagalor is finished. + if((pInstance->GetData(DATA_AZGALOREVENT) < DONE) && ((m_creature->GetVisibility() != VISIBILITY_OFF) || (m_creature->getFaction() != 35))) + { + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->setFaction(35); + } + else if((pInstance->GetData(DATA_AZGALOREVENT) >= 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* Nordrassil = m_creature->SummonCreature(CREATURE_CHANNEL_TARGET, NORDRASSIL_X, NORDRASSIL_Y, NORDRASSIL_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 1200000); + if(Nordrassil) + { + Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Nordrassil->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); + DoCast(Nordrassil, SPELL_DRAIN_WORLD_TREE); + IsChanneling = true; + } + } + Creature* Nordrassil = m_creature->SummonCreature(CREATURE_CHANNEL_TARGET, NORDRASSIL_X, NORDRASSIL_Y, NORDRASSIL_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 5000); + if(Nordrassil) + { + Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Nordrassil->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); + Nordrassil->CastSpell(m_creature, SPELL_DRAIN_WORLD_TREE_2, true); + DrainNordrassilTimer = 1000; + } + }else DrainNordrassilTimer -= diff; + } + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !BelowTenPercent && !Enraged) + BelowTenPercent = true; + + if(!Enraged) + { + if(EnrageTimer < diff) + { + if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) > 10) + { + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + Enraged = true; + DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + } + }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; + DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + } + } + CheckDistanceTimer = 5000; + }else CheckDistanceTimer -= diff; + } + + if(BelowTenPercent) + { + if(!HasProtected) + { + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + DoCast(m_creature->getVictim(), SPELL_PROTECTION_OF_ELUNE); + HasProtected = true; + Enraged = true; + } + + if(SummonWispTimer < diff) + { + Creature* Wisp = DoSpawnCreature(CREATURE_ANCIENT_WISP, rand()%40, rand()%40, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(Wisp) + { + Wisp->AI()->AttackStart(m_creature); + ((mob_ancient_wispAI*)Wisp->AI())->ArchimondeGUID = m_creature->GetGUID(); + } + 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) + { + DoCast(m_creature->getVictim(), SPELL_HAND_OF_DEATH); + HandOfDeathTimer = 2000; + }else HandOfDeathTimer -= diff; + return; // Don't do anything after this point. + } + + if(SoulChargeCount) + { + if(SoulChargeTimer < diff) + UnleashSoulCharge(); + else SoulChargeTimer -= diff; + } + + if(GripOfTheLegionTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_GRIP_OF_THE_LEGION); + GripOfTheLegionTimer = 5000 + rand()%20000; + }else GripOfTheLegionTimer -= diff; + + if(AirBurstTimer < diff) + { + if(rand()%2 == 0) + { + DoYell(SAY_AIR_BURST, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AIR_BURST); + }else + { + DoYell(SAY_AIR_BURST2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AIR_BURST2); + } + + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_AIR_BURST); + AirBurstTimer = 25000 + rand()%15000; + }else AirBurstTimer -= diff; + + if(FearTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FEAR); + FearTimer = 40000; + }else FearTimer -= diff; + + if(DoomfireTimer < diff) + { + SummonDoomfire(SelectUnit(SELECT_TARGET_RANDOM, 1)); + DoomfireTimer = 40000; + }else DoomfireTimer -= diff; + + if(MeleeRangeCheckTimer < diff) + { + if(CanUseFingerOfDeath()) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FINGER_OF_DEATH); + MeleeRangeCheckTimer = 1000; + } + + MeleeRangeCheckTimer = 5000; + }else MeleeRangeCheckTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_archimonde(Creature *_Creature) +{ + return new boss_archimondeAI (_Creature); +} + +CreatureAI* GetAI_mob_doomfire(Creature* _Creature) +{ + return new mob_doomfireAI(_Creature); +} + +CreatureAI* GetAI_mob_doomfire_targetting(Creature* _Creature) +{ + return new mob_doomfire_targettingAI(_Creature); +} + +CreatureAI* GetAI_mob_ancient_wisp(Creature* _Creature) +{ + return new mob_ancient_wispAI(_Creature); +} + +void AddSC_boss_archimonde() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_archimonde"; + newscript->GetAI = GetAI_boss_archimonde; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_doomfire"; + newscript->GetAI = GetAI_mob_doomfire; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_doomfire_targetting"; + newscript->GetAI = GetAI_mob_doomfire_targetting; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_ancient_wisp"; + newscript->GetAI = GetAI_mob_ancient_wisp; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/def_hyjal.h b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/def_hyjal.h index 1e28156857f..ff8e3dd3eed 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/def_hyjal.h +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/def_hyjal.h @@ -1,25 +1,25 @@ -/* Copyright (C) 2006 - 2008 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 DATA_ANETHERON 1 -#define DATA_ANETHERONEVENT 2 -#define DATA_ARCHIMONDE 3 -#define DATA_ARCHIMONDEEVENT 4 -#define DATA_AZGALOR 5 -#define DATA_AZGALOREVENT 6 -#define DATA_JAINAPROUDMOORE 7 -#define DATA_KAZROGAL 8 -#define DATA_KAZROGALEVENT 9 -#define DATA_RAGEWINTERCHILL 10 -#define DATA_RAGEWINTERCHILLEVENT 11 -#define DATA_THRALL 12 -#define DATA_TYRANDEWHISPERWIND 13 -#define DATA_TRASH 14 -#define DATA_RESET_TRASH_COUNT 15 - -#define ERROR_INST_DATA "SD2: Instance data not set properly for Mount Hyjal. Encounters will be buggy" -#endif +/* Copyright (C) 2006 - 2008 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 DATA_ANETHERON 1 +#define DATA_ANETHERONEVENT 2 +#define DATA_ARCHIMONDE 3 +#define DATA_ARCHIMONDEEVENT 4 +#define DATA_AZGALOR 5 +#define DATA_AZGALOREVENT 6 +#define DATA_JAINAPROUDMOORE 7 +#define DATA_KAZROGAL 8 +#define DATA_KAZROGALEVENT 9 +#define DATA_RAGEWINTERCHILL 10 +#define DATA_RAGEWINTERCHILLEVENT 11 +#define DATA_THRALL 12 +#define DATA_TYRANDEWHISPERWIND 13 +#define DATA_TRASH 14 +#define DATA_RESET_TRASH_COUNT 15 + +#define ERROR_INST_DATA "SD2: Instance data not set properly for Mount Hyjal. Encounters will be buggy" +#endif diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp index 14dbdf62736..63410206531 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp @@ -1,217 +1,217 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Hyjal -SD%Complete: 100 -SDComment: -SDCategory: Caverns of Time, Mount Hyjal -EndScriptData */ - -/* ContentData -npc_jaina_proudmoore -npc_thrall -npc_tyrande_whisperwind -EndContentData */ - -#include "precompiled.h" -#include "hyjalAI.h" - -#define GOSSIP_ITEM_BEGIN_ALLY "We are ready to defend the Alliance base." -#define GOSSIP_ITEM_ANETHERON "The defenses are holding up; we can continue." -#define GOSSIP_ITEM_RETREAT "We can't keep this up. Let's retreat!" - -#define GOSSIP_ITEM_BEGIN_HORDE "We're here to help! The Alliance are overrun." -#define GOSSIP_ITEM_AZGALOR "We're okay so far. Let's do this!" - -CreatureAI* GetAI_npc_jaina_proudmoore(Creature *_Creature) -{ - hyjalAI* ai = new hyjalAI(_Creature); - - ai->Reset(); - ai->EnterEvadeMode(); - - ai->Spell[0].SpellId = SPELL_BLIZZARD; - ai->Spell[0].Cooldown = 15000 + rand()%20000; - ai->Spell[0].TargetType = TARGETTYPE_RANDOM; - - ai->Spell[1].SpellId = SPELL_PYROBLAST; - ai->Spell[1].Cooldown = 2000 + rand()%7000; - ai->Spell[1].TargetType = TARGETTYPE_RANDOM; - - ai->Spell[2].SpellId = SPELL_SUMMON_ELEMENTALS; - ai->Spell[2].Cooldown = 15000 + rand()%30000; - ai->Spell[2].TargetType = TARGETTYPE_SELF; - - return ai; -} - -bool GossipHello_npc_jaina_proudmoore(Player *player, Creature *_Creature) -{ - hyjalAI* ai = ((hyjalAI*)_Creature->AI()); - if(ai->EventBegun) - return false; - - uint32 RageEncounter = ai->GetInstanceData(DATA_RAGEWINTERCHILLEVENT); - uint32 AnetheronEncounter = ai->GetInstanceData(DATA_ANETHERONEVENT); - if(RageEncounter == NOT_STARTED) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_BEGIN_ALLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - else if(RageEncounter == DONE && AnetheronEncounter == NOT_STARTED) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ANETHERON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - else if(RageEncounter == DONE && AnetheronEncounter == DONE) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_RETREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - - if(player->isGameMaster()) - player->ADD_GOSSIP_ITEM(2, "[GM] Toggle Debug Timers", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - - player->SEND_GOSSIP_MENU(907, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_jaina_proudmoore(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - player->PlayerTalkClass->GetGossipMenu(); - hyjalAI* ai = ((hyjalAI*)_Creature->AI()); - switch(action) - { - case GOSSIP_ACTION_INFO_DEF + 1: - ai->StartEvent(player); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - ai->FirstBossDead = true; - ai->WaveCount = 9; - ai->StartEvent(player); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - ai->Retreat(); - break; - case GOSSIP_ACTION_INFO_DEF + 4: - ai->Debug = !ai->Debug; - outstring_log("SD2 : HyjalAI - Debug mode has been toggled"); - break; - } - - return true; -} - -CreatureAI* GetAI_npc_thrall(Creature *_Creature) -{ - hyjalAI* ai = new hyjalAI(_Creature); - - ai->Reset(); - ai->EnterEvadeMode(); - - ai->Spell[0].SpellId = SPELL_CHAIN_LIGHTNING; - ai->Spell[0].Cooldown = 2000 + rand()%5000; - ai->Spell[0].TargetType = TARGETTYPE_VICTIM; - - ai->Spell[1].SpellId = SPELL_SUMMON_DIRE_WOLF; - ai->Spell[1].Cooldown = 6000 + rand()%35000; - ai->Spell[1].TargetType = TARGETTYPE_RANDOM; - - return ai; -} - -bool GossipHello_npc_thrall(Player *player, Creature *_Creature) -{ - hyjalAI* ai = ((hyjalAI*)_Creature->AI()); - uint32 AnetheronEvent = ai->GetInstanceData(DATA_ANETHERONEVENT); - if(AnetheronEvent >= DONE && !ai->EventBegun) // Only let them start the Horde phase if Anetheron is dead. - { - uint32 KazrogalEvent = ai->GetInstanceData(DATA_KAZROGALEVENT); - uint32 AzgalorEvent = ai->GetInstanceData(DATA_AZGALOREVENT); - if(KazrogalEvent == NOT_STARTED) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_BEGIN_HORDE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - else if(KazrogalEvent == DONE && AzgalorEvent == NOT_STARTED) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_AZGALOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - else if(AzgalorEvent == DONE) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_RETREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - } - - if(player->isGameMaster()) - player->ADD_GOSSIP_ITEM(2, "[GM] Toggle Debug Timers", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - - player->SEND_GOSSIP_MENU(907, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_thrall(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - player->PlayerTalkClass->GetGossipMenu(); - hyjalAI* ai = ((hyjalAI*)_Creature->AI()); - switch(action) - { - case GOSSIP_ACTION_INFO_DEF + 1: - ai->StartEvent(player); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - ai->FirstBossDead = true; - ai->WaveCount = 9; - ai->StartEvent(player); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - ai->Retreat(); - break; - case GOSSIP_ACTION_INFO_DEF + 4: - ai->Debug = !ai->Debug; - outstring_log("SD2 : HyjalAI - Debug mode has been toggled"); - break; - } - - return true; -} - -bool GossipHello_npc_tyrande_whisperwind(Player* player, Creature* _Creature) -{ - player->ADD_GOSSIP_ITEM(1, "Aid us in defending Nordrassil", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU(907, _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_tyrande_whisperwind(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if(action == GOSSIP_ACTION_TRADE) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - - return true; -} - -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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "npc_thrall"; - newscript->GetAI = GetAI_npc_thrall; - newscript->pGossipHello = &GossipHello_npc_thrall; - newscript->pGossipSelect = &GossipSelect_npc_thrall; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "npc_tyrande_whisperwind"; - newscript->pGossipHello = &GossipHello_npc_tyrande_whisperwind; - newscript->pGossipSelect = &GossipSelect_npc_tyrande_whisperwind; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Hyjal +SD%Complete: 100 +SDComment: +SDCategory: Caverns of Time, Mount Hyjal +EndScriptData */ + +/* ContentData +npc_jaina_proudmoore +npc_thrall +npc_tyrande_whisperwind +EndContentData */ + +#include "precompiled.h" +#include "hyjalAI.h" + +#define GOSSIP_ITEM_BEGIN_ALLY "We are ready to defend the Alliance base." +#define GOSSIP_ITEM_ANETHERON "The defenses are holding up; we can continue." +#define GOSSIP_ITEM_RETREAT "We can't keep this up. Let's retreat!" + +#define GOSSIP_ITEM_BEGIN_HORDE "We're here to help! The Alliance are overrun." +#define GOSSIP_ITEM_AZGALOR "We're okay so far. Let's do this!" + +CreatureAI* GetAI_npc_jaina_proudmoore(Creature *_Creature) +{ + hyjalAI* ai = new hyjalAI(_Creature); + + ai->Reset(); + ai->EnterEvadeMode(); + + ai->Spell[0].SpellId = SPELL_BLIZZARD; + ai->Spell[0].Cooldown = 15000 + rand()%20000; + ai->Spell[0].TargetType = TARGETTYPE_RANDOM; + + ai->Spell[1].SpellId = SPELL_PYROBLAST; + ai->Spell[1].Cooldown = 2000 + rand()%7000; + ai->Spell[1].TargetType = TARGETTYPE_RANDOM; + + ai->Spell[2].SpellId = SPELL_SUMMON_ELEMENTALS; + ai->Spell[2].Cooldown = 15000 + rand()%30000; + ai->Spell[2].TargetType = TARGETTYPE_SELF; + + return ai; +} + +bool GossipHello_npc_jaina_proudmoore(Player *player, Creature *_Creature) +{ + hyjalAI* ai = ((hyjalAI*)_Creature->AI()); + if(ai->EventBegun) + return false; + + uint32 RageEncounter = ai->GetInstanceData(DATA_RAGEWINTERCHILLEVENT); + uint32 AnetheronEncounter = ai->GetInstanceData(DATA_ANETHERONEVENT); + if(RageEncounter == NOT_STARTED) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_BEGIN_ALLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + else if(RageEncounter == DONE && AnetheronEncounter == NOT_STARTED) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ANETHERON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + else if(RageEncounter == DONE && AnetheronEncounter == DONE) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_RETREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + + if(player->isGameMaster()) + player->ADD_GOSSIP_ITEM(2, "[GM] Toggle Debug Timers", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + + player->SEND_GOSSIP_MENU(907, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_jaina_proudmoore(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + player->PlayerTalkClass->GetGossipMenu(); + hyjalAI* ai = ((hyjalAI*)_Creature->AI()); + switch(action) + { + case GOSSIP_ACTION_INFO_DEF + 1: + ai->StartEvent(player); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + ai->FirstBossDead = true; + ai->WaveCount = 9; + ai->StartEvent(player); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + ai->Retreat(); + break; + case GOSSIP_ACTION_INFO_DEF + 4: + ai->Debug = !ai->Debug; + outstring_log("SD2 : HyjalAI - Debug mode has been toggled"); + break; + } + + return true; +} + +CreatureAI* GetAI_npc_thrall(Creature *_Creature) +{ + hyjalAI* ai = new hyjalAI(_Creature); + + ai->Reset(); + ai->EnterEvadeMode(); + + ai->Spell[0].SpellId = SPELL_CHAIN_LIGHTNING; + ai->Spell[0].Cooldown = 2000 + rand()%5000; + ai->Spell[0].TargetType = TARGETTYPE_VICTIM; + + ai->Spell[1].SpellId = SPELL_SUMMON_DIRE_WOLF; + ai->Spell[1].Cooldown = 6000 + rand()%35000; + ai->Spell[1].TargetType = TARGETTYPE_RANDOM; + + return ai; +} + +bool GossipHello_npc_thrall(Player *player, Creature *_Creature) +{ + hyjalAI* ai = ((hyjalAI*)_Creature->AI()); + uint32 AnetheronEvent = ai->GetInstanceData(DATA_ANETHERONEVENT); + if(AnetheronEvent >= DONE && !ai->EventBegun) // Only let them start the Horde phase if Anetheron is dead. + { + uint32 KazrogalEvent = ai->GetInstanceData(DATA_KAZROGALEVENT); + uint32 AzgalorEvent = ai->GetInstanceData(DATA_AZGALOREVENT); + if(KazrogalEvent == NOT_STARTED) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_BEGIN_HORDE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + else if(KazrogalEvent == DONE && AzgalorEvent == NOT_STARTED) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_AZGALOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + else if(AzgalorEvent == DONE) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_RETREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + } + + if(player->isGameMaster()) + player->ADD_GOSSIP_ITEM(2, "[GM] Toggle Debug Timers", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + + player->SEND_GOSSIP_MENU(907, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_thrall(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + player->PlayerTalkClass->GetGossipMenu(); + hyjalAI* ai = ((hyjalAI*)_Creature->AI()); + switch(action) + { + case GOSSIP_ACTION_INFO_DEF + 1: + ai->StartEvent(player); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + ai->FirstBossDead = true; + ai->WaveCount = 9; + ai->StartEvent(player); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + ai->Retreat(); + break; + case GOSSIP_ACTION_INFO_DEF + 4: + ai->Debug = !ai->Debug; + outstring_log("SD2 : HyjalAI - Debug mode has been toggled"); + break; + } + + return true; +} + +bool GossipHello_npc_tyrande_whisperwind(Player* player, Creature* _Creature) +{ + player->ADD_GOSSIP_ITEM(1, "Aid us in defending Nordrassil", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + player->SEND_GOSSIP_MENU(907, _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_tyrande_whisperwind(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if(action == GOSSIP_ACTION_TRADE) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + + return true; +} + +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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "npc_thrall"; + newscript->GetAI = GetAI_npc_thrall; + newscript->pGossipHello = &GossipHello_npc_thrall; + newscript->pGossipSelect = &GossipSelect_npc_thrall; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "npc_tyrande_whisperwind"; + newscript->pGossipHello = &GossipHello_npc_tyrande_whisperwind; + newscript->pGossipSelect = &GossipSelect_npc_tyrande_whisperwind; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp index 0d18f0d9244..d1db61148e1 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp @@ -1,458 +1,458 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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: 99 -SDComment: World Packet workaround for World States -SDCategory: Caverns of Time, Mount Hyjal -EndScriptData */ - -#include "precompiled.h" -#include "hyjalAI.h" -#include "WorldPacket.h" - -float AllianceBase[4][3]= // Locations for summoning waves in Alliance base -{ - {4979.010, -1709.134, 1339.674}, - {4969.123, -1705.904, 1341.363}, - {4970.260, -1698.546, 1341.200}, - {4975.262, -1698.239, 1341.427} -}; - -float HordeBase[4][3]= // Locations for summoning waves in Horde base -{ - {5554.399, -2581.419, 1480.820}, - {5538.996, -2577.742, 1479.790}, - {5565.642, -2565.666, 1481.635}, - {5547.218, -2574.589, 1479.194} -}; - -float AttackArea[2][3]= // used to inform the wave where to move and attack to -{ - { // Alliance - 5042.9189, -1776.2562, 1323.0621 - }, - { // Horde - 5510.4815, -2676.7112, 1480.4314 - } -}; - -hyjalAI::hyjalAI(Creature *c) : ScriptedAI(c) -{ - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); -} - -void hyjalAI::Reset() -{ - /** GUIDs **/ - PlayerGUID = 0; - BossGUID[0] = 0; - BossGUID[1] = 0; - - /** Timers **/ - NextWaveTimer = 10000; - CheckTimer = 0; - RetreatTimer = 1000; - - /** Misc **/ - WaveCount = 0; - - /** Set faction properly based on creature entry**/ - switch(m_creature->GetEntry()) - { - case 17772: - Faction = 0; - DoCast(m_creature, SPELL_BRILLIANCE_AURA, true); - break; - - case 17852: Faction = 1; break; - } - - /** Bools **/ - EventBegun = false; - FirstBossDead = false; - SecondBossDead = false; - Summon = false; - bRetreat = false; - - /** Flags **/ - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - /** Initialize spells **/ - memset(Spell, 0, sizeof(Spell)); - - /** Reset World States **/ - UpdateWorldState(WORLDSTATE_WAVES, 0); - UpdateWorldState(WORLDSTATE_ENEMY, 0); - UpdateWorldState(WORLDSTATE_ENEMYCOUNT, 0); - - /** Reset Instance Data for trash count **/ - if(pInstance) - pInstance->SetData(DATA_RESET_TRASH_COUNT, 0); - else error_log(ERROR_INST_DATA); - - /*** Visibility ***/ - m_creature->SetVisibility(VISIBILITY_ON); - - /** If Jaina evades, reset the visibility of all other creatures in the grid. **/ - if(CreatureList.empty()) - return; - - for(std::list::iterator itr = CreatureList.begin(); itr != CreatureList.end(); ++itr) - if(Creature* cr = ((Creature*)Unit::GetUnit(*m_creature, *itr))) - cr->SetVisibility(VISIBILITY_ON); - - CreatureList.clear(); -} - -void hyjalAI::EnterEvadeMode() -{ - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - m_creature->LoadCreaturesAddon(); - - if(m_creature->isAlive()) - m_creature->GetMotionMaster()->MoveTargetedHome(); - - InCombat = false; -} - -void hyjalAI::Aggro(Unit *who) -{ - for(uint8 i = 0; i < 2; ++i) - if(Spell[i].Cooldown) - SpellTimer[i] = Spell[i].Cooldown; - - Talk(ATTACKED); -} - -void hyjalAI::SummonCreature(uint32 entry, float Base[4][3]) -{ - uint32 random = rand()%4; - float SpawnLoc[3]; - float AttackLoc[3]; - - for(uint8 i = 0; i < 3; ++i) - { - SpawnLoc[i] = Base[random][i]; - AttackLoc[i] = AttackArea[Faction][i]; - } - - Creature* pCreature = m_creature->SummonCreature(entry, SpawnLoc[0], SpawnLoc[1], SpawnLoc[2], 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); - if(pCreature) - { - ++EnemyCount; // Increment Enemy Count to be used in World States and instance script - - pCreature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - pCreature->GetMotionMaster()->MovePoint(0, AttackLoc[0],AttackLoc[1],AttackLoc[2]); - pCreature->AddThreat(m_creature, 1.0f); - DoZoneInCombat(pCreature); - - // Check if creature is a boss. - if(pCreature->GetCreatureInfo()->rank == 3) - { - if(!FirstBossDead) BossGUID[0] = pCreature->GetGUID(); - else BossGUID[1] = pCreature->GetGUID(); - CheckTimer = 5000; - } - } -} - -void hyjalAI::SummonNextWave(Wave wave[18], uint32 Count, float Base[4][3]) -{ - if(rand()%4 == 0) // 1 in 4 chance we give a rally yell. Not sure if the chance is Blizzlike. - Talk(RALLY); - - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - EnemyCount = pInstance->GetData(DATA_TRASH); - for(uint8 i = 0; i < 18; ++i) - { - if(wave[Count].Mob[i]) - SummonCreature(wave[Count].Mob[i], Base); - } - - if(!wave[Count].IsBoss) - { - uint32 stateValue = Count+1; - if(FirstBossDead) - stateValue -= 9; // Subtract 9 from it to give the proper wave number if we are greater than 8 - UpdateWorldState(WORLDSTATE_WAVES, stateValue); // Set world state to our current wave number - UpdateWorldState(WORLDSTATE_ENEMY, 1); - //UpdateWorldState(WORLDSTATE_ENEMYCOUNT, EnemyCount); // Let Instance Script handle this - pInstance->SetData(DATA_TRASH, EnemyCount); - if(!Debug) - NextWaveTimer = wave[Count].WaveTimer; - else - { - NextWaveTimer = 15000; - DoTextEmote(": Debug Mode is enabled. Next Wave in 15 seconds", NULL); - } - } - else - { - UpdateWorldState(WORLDSTATE_WAVES, 0); // Set world state for waves to 0 to disable it. - UpdateWorldState(WORLDSTATE_ENEMYCOUNT, 1); // Set World State for enemies invading to 1. - Summon = false; - } - CheckTimer = 5000; -} - -void hyjalAI::StartEvent(Player* player) -{ - if(!player) - return; - - Talk(BEGIN); - - EventBegun = true; - Summon = true; - - NextWaveTimer = 15000; - CheckTimer = 5000; - PlayerGUID = player->GetGUID(); - - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - UpdateWorldState(WORLDSTATE_WAVES, 0); - UpdateWorldState(WORLDSTATE_ENEMY, 0); - UpdateWorldState(WORLDSTATE_ENEMYCOUNT, 0); -} - -uint32 hyjalAI::GetInstanceData(uint32 Event) -{ - if(pInstance) - return pInstance->GetData(Event); - else error_log(ERROR_INST_DATA); - - return 0; -} - -void hyjalAI::Talk(uint32 id) -{ - std::list index; - for(uint8 i = 0; i < 10; i++) - { - if(Faction == 0) // Alliance - { - if(JainaQuotes[i].id == id) - index.push_back(i); - } - else if(Faction == 1) // Horde - { - if(ThrallQuotes[i].id == id) - index.push_back(i); - } - } - - if(index.empty()) - return; // No quotes found, no use to continue - - uint8 ind = *(index.begin()) + rand()%index.size(); - - char* Yell = NULL; - uint32 Sound = 0; - if(Faction == 0) // Alliance - { - Yell = JainaQuotes[ind].text; - Sound = JainaQuotes[ind].sound; - } - else if(Faction == 1) // Horde - { - Yell = ThrallQuotes[ind].text; - Sound = ThrallQuotes[ind].sound; - } - - if(Yell) - DoYell(Yell, LANG_UNIVERSAL, NULL); - if(Sound) - DoPlaySoundToSet(m_creature, Sound); -} - -// Slight workaround for now -void hyjalAI::UpdateWorldState(uint32 field, uint32 value) -{ - Map * map = m_creature->GetMap(); - if(!map->IsDungeon()) return; - - WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); - - data << field; - data << value; - - ((InstanceMap*)map)->SendToPlayers(&data); - - // TODO: Uncomment and remove everything above this line only when the core patch for this is accepted - //m_creature->GetMap()->UpdateWorldState(field, value); -} - -void hyjalAI::Retreat() -{ - CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - // First get all creatures. - std::list creatures; - AllFriendlyCreaturesInGrid creature_check(m_creature); - MaNGOS::CreatureListSearcher creature_searcher(creatures, creature_check); - TypeContainerVisitor - , - GridTypeMapContainer> creature_visitor(creature_searcher); - - // Then get all Ancient Gem Veins. NOTE: Grid Search will only be able to find those in the grid. - std::list goList; - AllGameObjectsWithEntryInGrid go_check(185557); - MaNGOS::GameObjectListSearcher go_search(goList, go_check); - TypeContainerVisitor - , GridTypeMapContainer> go_visit(go_search); - - CellLock cell_lock(cell, pair); - // Get Creatures - cell_lock->Visit(cell_lock, creature_visitor, *(m_creature->GetMap())); - // Get GOs - cell_lock->Visit(cell_lock, go_visit, *(m_creature->GetMap())); - - CreatureList.clear(); - if(!creatures.empty()) - { - for(std::list::iterator itr = creatures.begin(); itr != creatures.end(); ++itr) - { - (*itr)->CastSpell(*itr, SPELL_TELEPORT_VISUAL, true); - CreatureList.push_back((*itr)->GetGUID()); - } - - DoCast(m_creature, SPELL_TELEPORT_VISUAL); - bRetreat = true; - RetreatTimer = 1000; - } - - if(!goList.empty()) - { - for(std::list::iterator itr = goList.begin(); itr != goList.end(); ++itr) - (*itr)->SetRespawnTime(5000); - } -} - -void hyjalAI::UpdateAI(const uint32 diff) -{ - if(bRetreat) - if(RetreatTimer < diff) - { - bRetreat = false; - if(CreatureList.empty()) - return; - - for(std::list::iterator itr = CreatureList.begin(); itr != CreatureList.end(); ++itr) - if(Unit* pUnit = Unit::GetUnit(*m_creature, *itr)) - pUnit->SetVisibility(VISIBILITY_OFF); - - m_creature->SetVisibility(VISIBILITY_OFF); - }else RetreatTimer -= diff; - - if(!EventBegun) - return; - - if(Summon) - { - if(pInstance && EnemyCount) - { - EnemyCount = pInstance->GetData(DATA_TRASH); - if(!EnemyCount) - NextWaveTimer = 5000; - } - - if(NextWaveTimer < diff) - { - if(Faction == 0) - SummonNextWave(AllianceWaves, WaveCount, AllianceBase); - else if(Faction == 1) - SummonNextWave(HordeWaves, WaveCount, HordeBase); - ++WaveCount; - }else NextWaveTimer -= diff; - } - - if(CheckTimer < diff) - { - for(uint8 i = 0; i < 2; ++i) - { - if(BossGUID[i]) - { - Unit* pUnit = Unit::GetUnit((*m_creature), BossGUID[i]); - if(pUnit && (!pUnit->isAlive())) - { - if(BossGUID[i] == BossGUID[0]) - { - Talk(INCOMING); - FirstBossDead = true; - } - else if(BossGUID[i] == BossGUID[1]) - { - Talk(SUCCESS); - SecondBossDead = true; - } - EventBegun = false; - CheckTimer = 0; - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - BossGUID[i] = 0; - UpdateWorldState(WORLDSTATE_ENEMY, 0); // Reset world state for enemies to disable it - } - } - } - CheckTimer = 5000; - }else CheckTimer -= diff; - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - for(uint8 i = 0; i < 3; ++i) - { - if(Spell[i].SpellId) - { - if(SpellTimer[i] < diff) - { - if(m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - Unit* target = NULL; - - switch(Spell[i].TargetType) - { - case TARGETTYPE_SELF: target = m_creature; break; - case TARGETTYPE_RANDOM: target = SelectUnit(SELECT_TARGET_RANDOM, 0); break; - case TARGETTYPE_VICTIM: target = m_creature->getVictim(); break; - } - - if(target && target->isAlive()) - { - DoCast(target, Spell[i].SpellId); - SpellTimer[i] = Spell[i].Cooldown; - } - }else SpellTimer[i] -= diff; - } - } - - DoMeleeAttackIfReady(); -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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: 99 +SDComment: World Packet workaround for World States +SDCategory: Caverns of Time, Mount Hyjal +EndScriptData */ + +#include "precompiled.h" +#include "hyjalAI.h" +#include "WorldPacket.h" + +float AllianceBase[4][3]= // Locations for summoning waves in Alliance base +{ + {4979.010, -1709.134, 1339.674}, + {4969.123, -1705.904, 1341.363}, + {4970.260, -1698.546, 1341.200}, + {4975.262, -1698.239, 1341.427} +}; + +float HordeBase[4][3]= // Locations for summoning waves in Horde base +{ + {5554.399, -2581.419, 1480.820}, + {5538.996, -2577.742, 1479.790}, + {5565.642, -2565.666, 1481.635}, + {5547.218, -2574.589, 1479.194} +}; + +float AttackArea[2][3]= // used to inform the wave where to move and attack to +{ + { // Alliance + 5042.9189, -1776.2562, 1323.0621 + }, + { // Horde + 5510.4815, -2676.7112, 1480.4314 + } +}; + +hyjalAI::hyjalAI(Creature *c) : ScriptedAI(c) +{ + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); +} + +void hyjalAI::Reset() +{ + /** GUIDs **/ + PlayerGUID = 0; + BossGUID[0] = 0; + BossGUID[1] = 0; + + /** Timers **/ + NextWaveTimer = 10000; + CheckTimer = 0; + RetreatTimer = 1000; + + /** Misc **/ + WaveCount = 0; + + /** Set faction properly based on creature entry**/ + switch(m_creature->GetEntry()) + { + case 17772: + Faction = 0; + DoCast(m_creature, SPELL_BRILLIANCE_AURA, true); + break; + + case 17852: Faction = 1; break; + } + + /** Bools **/ + EventBegun = false; + FirstBossDead = false; + SecondBossDead = false; + Summon = false; + bRetreat = false; + + /** Flags **/ + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + /** Initialize spells **/ + memset(Spell, 0, sizeof(Spell)); + + /** Reset World States **/ + UpdateWorldState(WORLDSTATE_WAVES, 0); + UpdateWorldState(WORLDSTATE_ENEMY, 0); + UpdateWorldState(WORLDSTATE_ENEMYCOUNT, 0); + + /** Reset Instance Data for trash count **/ + if(pInstance) + pInstance->SetData(DATA_RESET_TRASH_COUNT, 0); + else error_log(ERROR_INST_DATA); + + /*** Visibility ***/ + m_creature->SetVisibility(VISIBILITY_ON); + + /** If Jaina evades, reset the visibility of all other creatures in the grid. **/ + if(CreatureList.empty()) + return; + + for(std::list::iterator itr = CreatureList.begin(); itr != CreatureList.end(); ++itr) + if(Creature* cr = ((Creature*)Unit::GetUnit(*m_creature, *itr))) + cr->SetVisibility(VISIBILITY_ON); + + CreatureList.clear(); +} + +void hyjalAI::EnterEvadeMode() +{ + m_creature->InterruptNonMeleeSpells(true); + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + m_creature->LoadCreaturesAddon(); + + if(m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + InCombat = false; +} + +void hyjalAI::Aggro(Unit *who) +{ + for(uint8 i = 0; i < 2; ++i) + if(Spell[i].Cooldown) + SpellTimer[i] = Spell[i].Cooldown; + + Talk(ATTACKED); +} + +void hyjalAI::SummonCreature(uint32 entry, float Base[4][3]) +{ + uint32 random = rand()%4; + float SpawnLoc[3]; + float AttackLoc[3]; + + for(uint8 i = 0; i < 3; ++i) + { + SpawnLoc[i] = Base[random][i]; + AttackLoc[i] = AttackArea[Faction][i]; + } + + Creature* pCreature = m_creature->SummonCreature(entry, SpawnLoc[0], SpawnLoc[1], SpawnLoc[2], 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); + if(pCreature) + { + ++EnemyCount; // Increment Enemy Count to be used in World States and instance script + + pCreature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + pCreature->GetMotionMaster()->MovePoint(0, AttackLoc[0],AttackLoc[1],AttackLoc[2]); + pCreature->AddThreat(m_creature, 1.0f); + DoZoneInCombat(pCreature); + + // Check if creature is a boss. + if(pCreature->GetCreatureInfo()->rank == 3) + { + if(!FirstBossDead) BossGUID[0] = pCreature->GetGUID(); + else BossGUID[1] = pCreature->GetGUID(); + CheckTimer = 5000; + } + } +} + +void hyjalAI::SummonNextWave(Wave wave[18], uint32 Count, float Base[4][3]) +{ + if(rand()%4 == 0) // 1 in 4 chance we give a rally yell. Not sure if the chance is Blizzlike. + Talk(RALLY); + + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + EnemyCount = pInstance->GetData(DATA_TRASH); + for(uint8 i = 0; i < 18; ++i) + { + if(wave[Count].Mob[i]) + SummonCreature(wave[Count].Mob[i], Base); + } + + if(!wave[Count].IsBoss) + { + uint32 stateValue = Count+1; + if(FirstBossDead) + stateValue -= 9; // Subtract 9 from it to give the proper wave number if we are greater than 8 + UpdateWorldState(WORLDSTATE_WAVES, stateValue); // Set world state to our current wave number + UpdateWorldState(WORLDSTATE_ENEMY, 1); + //UpdateWorldState(WORLDSTATE_ENEMYCOUNT, EnemyCount); // Let Instance Script handle this + pInstance->SetData(DATA_TRASH, EnemyCount); + if(!Debug) + NextWaveTimer = wave[Count].WaveTimer; + else + { + NextWaveTimer = 15000; + DoTextEmote(": Debug Mode is enabled. Next Wave in 15 seconds", NULL); + } + } + else + { + UpdateWorldState(WORLDSTATE_WAVES, 0); // Set world state for waves to 0 to disable it. + UpdateWorldState(WORLDSTATE_ENEMYCOUNT, 1); // Set World State for enemies invading to 1. + Summon = false; + } + CheckTimer = 5000; +} + +void hyjalAI::StartEvent(Player* player) +{ + if(!player) + return; + + Talk(BEGIN); + + EventBegun = true; + Summon = true; + + NextWaveTimer = 15000; + CheckTimer = 5000; + PlayerGUID = player->GetGUID(); + + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + UpdateWorldState(WORLDSTATE_WAVES, 0); + UpdateWorldState(WORLDSTATE_ENEMY, 0); + UpdateWorldState(WORLDSTATE_ENEMYCOUNT, 0); +} + +uint32 hyjalAI::GetInstanceData(uint32 Event) +{ + if(pInstance) + return pInstance->GetData(Event); + else error_log(ERROR_INST_DATA); + + return 0; +} + +void hyjalAI::Talk(uint32 id) +{ + std::list index; + for(uint8 i = 0; i < 10; i++) + { + if(Faction == 0) // Alliance + { + if(JainaQuotes[i].id == id) + index.push_back(i); + } + else if(Faction == 1) // Horde + { + if(ThrallQuotes[i].id == id) + index.push_back(i); + } + } + + if(index.empty()) + return; // No quotes found, no use to continue + + uint8 ind = *(index.begin()) + rand()%index.size(); + + char* Yell = NULL; + uint32 Sound = 0; + if(Faction == 0) // Alliance + { + Yell = JainaQuotes[ind].text; + Sound = JainaQuotes[ind].sound; + } + else if(Faction == 1) // Horde + { + Yell = ThrallQuotes[ind].text; + Sound = ThrallQuotes[ind].sound; + } + + if(Yell) + DoYell(Yell, LANG_UNIVERSAL, NULL); + if(Sound) + DoPlaySoundToSet(m_creature, Sound); +} + +// Slight workaround for now +void hyjalAI::UpdateWorldState(uint32 field, uint32 value) +{ + Map * map = m_creature->GetMap(); + if(!map->IsDungeon()) return; + + WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); + + data << field; + data << value; + + ((InstanceMap*)map)->SendToPlayers(&data); + + // TODO: Uncomment and remove everything above this line only when the core patch for this is accepted + //m_creature->GetMap()->UpdateWorldState(field, value); +} + +void hyjalAI::Retreat() +{ + CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + // First get all creatures. + std::list creatures; + AllFriendlyCreaturesInGrid creature_check(m_creature); + MaNGOS::CreatureListSearcher creature_searcher(creatures, creature_check); + TypeContainerVisitor + , + GridTypeMapContainer> creature_visitor(creature_searcher); + + // Then get all Ancient Gem Veins. NOTE: Grid Search will only be able to find those in the grid. + std::list goList; + AllGameObjectsWithEntryInGrid go_check(185557); + MaNGOS::GameObjectListSearcher go_search(goList, go_check); + TypeContainerVisitor + , GridTypeMapContainer> go_visit(go_search); + + CellLock cell_lock(cell, pair); + // Get Creatures + cell_lock->Visit(cell_lock, creature_visitor, *(m_creature->GetMap())); + // Get GOs + cell_lock->Visit(cell_lock, go_visit, *(m_creature->GetMap())); + + CreatureList.clear(); + if(!creatures.empty()) + { + for(std::list::iterator itr = creatures.begin(); itr != creatures.end(); ++itr) + { + (*itr)->CastSpell(*itr, SPELL_TELEPORT_VISUAL, true); + CreatureList.push_back((*itr)->GetGUID()); + } + + DoCast(m_creature, SPELL_TELEPORT_VISUAL); + bRetreat = true; + RetreatTimer = 1000; + } + + if(!goList.empty()) + { + for(std::list::iterator itr = goList.begin(); itr != goList.end(); ++itr) + (*itr)->SetRespawnTime(5000); + } +} + +void hyjalAI::UpdateAI(const uint32 diff) +{ + if(bRetreat) + if(RetreatTimer < diff) + { + bRetreat = false; + if(CreatureList.empty()) + return; + + for(std::list::iterator itr = CreatureList.begin(); itr != CreatureList.end(); ++itr) + if(Unit* pUnit = Unit::GetUnit(*m_creature, *itr)) + pUnit->SetVisibility(VISIBILITY_OFF); + + m_creature->SetVisibility(VISIBILITY_OFF); + }else RetreatTimer -= diff; + + if(!EventBegun) + return; + + if(Summon) + { + if(pInstance && EnemyCount) + { + EnemyCount = pInstance->GetData(DATA_TRASH); + if(!EnemyCount) + NextWaveTimer = 5000; + } + + if(NextWaveTimer < diff) + { + if(Faction == 0) + SummonNextWave(AllianceWaves, WaveCount, AllianceBase); + else if(Faction == 1) + SummonNextWave(HordeWaves, WaveCount, HordeBase); + ++WaveCount; + }else NextWaveTimer -= diff; + } + + if(CheckTimer < diff) + { + for(uint8 i = 0; i < 2; ++i) + { + if(BossGUID[i]) + { + Unit* pUnit = Unit::GetUnit((*m_creature), BossGUID[i]); + if(pUnit && (!pUnit->isAlive())) + { + if(BossGUID[i] == BossGUID[0]) + { + Talk(INCOMING); + FirstBossDead = true; + } + else if(BossGUID[i] == BossGUID[1]) + { + Talk(SUCCESS); + SecondBossDead = true; + } + EventBegun = false; + CheckTimer = 0; + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + BossGUID[i] = 0; + UpdateWorldState(WORLDSTATE_ENEMY, 0); // Reset world state for enemies to disable it + } + } + } + CheckTimer = 5000; + }else CheckTimer -= diff; + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + for(uint8 i = 0; i < 3; ++i) + { + if(Spell[i].SpellId) + { + if(SpellTimer[i] < diff) + { + if(m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + + Unit* target = NULL; + + switch(Spell[i].TargetType) + { + case TARGETTYPE_SELF: target = m_creature; break; + case TARGETTYPE_RANDOM: target = SelectUnit(SELECT_TARGET_RANDOM, 0); break; + case TARGETTYPE_VICTIM: target = m_creature->getVictim(); break; + } + + if(target && target->isAlive()) + { + DoCast(target, Spell[i].SpellId); + SpellTimer[i] = Spell[i].Cooldown; + } + }else SpellTimer[i] -= diff; + } + } + + DoMeleeAttackIfReady(); +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.h b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.h index 46be6a83879..83ca6c82ce4 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.h +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.h @@ -1,286 +1,286 @@ -/* Copyright (C) 2006 - 2008 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 "def_hyjal.h" - -// Trash Mobs summoned in waves -#define NECROMANCER 17899 -#define ABOMINATION 17898 -#define GHOUL 17895 -#define BANSHEE 17905 -#define CRYPT_FIEND 17897 -#define GARGOYLE 17906 -#define FROST_WYRM 17907 -#define GIANT_INFERNAL 17908 -#define FEL_STALKER 17916 - -// Bosses summoned after every 8 waves -#define RAGE_WINTERCHILL 17767 -#define ANETHERON 17808 -#define KAZROGAL 17888 -#define AZGALOR 17842 -#define ARCHIMONDE 17968 - -#define SPELL_TELEPORT_VISUAL 41232 - -#define WORLDSTATE_WAVES 2842 -#define WORLDSTATE_ENEMY 2453 -#define WORLDSTATE_ENEMYCOUNT 2454 - -/*** Spells for Jaina ***/ -#define SPELL_BRILLIANCE_AURA 31260 // The database must handle this spell via creature_addon -#define SPELL_BLIZZARD 31266 -#define SPELL_PYROBLAST 31263 -#define SPELL_SUMMON_ELEMENTALS 31264 - -/** Thrall spells **/ -#define SPELL_CHAIN_LIGHTNING 31330 -#define SPELL_SUMMON_DIRE_WOLF 31331 - -struct Wave -{ - uint32 Mob[18]; // Stores Creature Entries to be summoned in Waves - uint32 WaveTimer; // The timer before the next wave is summoned - bool IsBoss; // Simply used to inform the wave summoner that the next wave contains a boss to halt all waves after that -}; - -static Wave AllianceWaves[]= // Waves that will be summoned in the Alliance Base -{ - { // Wave 1 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, 0, 0, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 2 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 3 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 4 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 5 - GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 6 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 7 - GHOUL, GHOUL, GHOUL, GHOUL, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 8 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 180000, false - }, - { // All 8 Waves are summoned, summon Rage Winterchill, next few waves are for Anetheron - RAGE_WINTERCHILL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true - }, - { // Wave 1 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, 0, 0, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 2 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 3 - GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 4 - GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, BANSHEE, BANSHEE, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 5 - CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, BANSHEE, BANSHEE, BANSHEE, BANSHEE, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 6 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 7 - CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, BANSHEE, BANSHEE, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 8 - GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 180000, false - }, - { // All 8 Waves are summoned, summon Anatheron - ANETHERON, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true - } -}; - -static Wave HordeWaves[]= // Waves that are summoned in the Horde base -{ - { // Wave 1 - GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 2 - GHOUL, GHOUL, GHOUL, GHOUL, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, 0, 0, 0, 0, 120000, false - }, - { // Wave 3 - GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 120000, false - }, - { // Wave 4 - CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, NECROMANCER, NECROMANCER , 0, 0, 0, 0, 120000, false - }, - { // Wave 5 - GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 6 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, FROST_WYRM, 0, 0, 120000, false - }, - { // Wave 7 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, FROST_WYRM, 0, 0, 120000, false - }, - { // Wave 8 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, BANSHEE, BANSHEE, 180000, false - }, - { // All 8 Waves are summoned, summon Kaz'Rogal, next few waves are for Azgalor - KAZROGAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true - }, - { // Wave 1 - ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 2 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, FROST_WYRM, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, 0, 0, 0, 0, 120000, false - }, - { // Wave 3 - GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, 0, 0, 0, 0, 120000, false - }, - { // Wave 4 - GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, 0, 0, 0, 0, 120000, false - }, - { // Wave 5 - FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 120000, false - }, - { // Wave 6 - NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, BANSHEE, BANSHEE, BANSHEE, BANSHEE, BANSHEE, BANSHEE, 0, 0, 0, 0, 120000, false - }, - { // Wave 7 - GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, FEL_STALKER, FEL_STALKER, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, 0, 0, 0, 0, 0, 0, 120000, false - }, - { // Wave 8 - CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, FEL_STALKER, FEL_STALKER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, BANSHEE, BANSHEE, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0, 180000, false - }, - { // All 8 Waves are summoned, summon Azgalor - 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, -}; - -struct Yells -{ - uint32 id; // Used to determine the type of yell (attack, rally, etc) - char* text; // The text to be yelled - uint32 sound; // Sound that corresponds to the text -}; - -enum YellId -{ - 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 -}; - -static Yells JainaQuotes[]= -{ - {ATTACKED, "I'm in jeopardy, help me if you can!", 11007}, - {ATTACKED, "They've broken through!", 11049}, - {INCOMING, "Stay alert! Another wave approaches.", 11008}, - {BEGIN, "Hold them back as long as possible", 11050}, - {RALLY, "Don't give up! We must prevail!", 11006}, - {RALLY, "We must hold strong!", 11051}, - {FAILURE, "We are lost. Fall back!", 11009}, - {SUCCESS, "We have won valuable time. Now we must pull back!", 11011}, - {DEATH, "I did... my best.", 11010}, -}; - -static Yells ThrallQuotes[]= -{ - {ATTACKED, "I will lie down for no one!", 11031}, - {ATTACKED, "Bring the fight to me and pay with your lives!", 11061}, - {INCOMING, "Make ready for another wave! LOK-TAR OGAR!", 11032}, - {BEGIN, "Do not give an inch of ground!", 11060}, - {RALLY, "Hold them back! Do not falter!", 11030}, - {RALLY, "Victory or death!", 11059}, - {RALLY, "Do not give an inch of ground!", 11060}, - {FAILURE, "It is over. Withdraw! We have failed.", 11033}, - {SUCCESS, "We have played our part and done well. It is up to the others now.", 11035}, - {DEATH, "Uraaa...", 11034}, -}; - -struct MANGOS_DLL_DECL hyjalAI : public ScriptedAI -{ - hyjalAI(Creature *c); - - void Reset(); // Generically used to reset our variables. Do *not* call in EnterEvadeMode as this may make problems if the raid is still in combat - - void EnterEvadeMode(); // Send creature back to spawn location and evade. - - void Aggro(Unit *who); // Used to reset cooldowns for our spells and to inform the raid that we're under attack - - void UpdateAI(const uint32 diff); // Called to summon waves, check for boss deaths and to cast our spells. - - void JustDied(Unit* killer) // Called on death, informs the raid that they have failed. - { - Talk(DEATH); - } - - void SetFaction(uint32 _faction) // Set the faction to either Alliance or Horde in Hyjal - { - Faction = _faction; - } - - void Retreat(); // "Teleport" (teleport visual + set invisible) all friendly creatures away from the base. - - void SummonCreature(uint32 entry, float Base[4][3]); // Summons a creature for that wave in that base - - // Summons the next wave, calls SummonCreature - void SummonNextWave(Wave wave[18], uint32 Count, float Base[4][3]); - - void StartEvent(Player* player); // Begins the event by gossip click - - uint32 GetInstanceData(uint32 Event); // Gets instance data for this instance, used to check if raid has gotten past a certain point and can access the next phase - - void Talk(uint32 id); // Searches for the appropriate yell and sound and uses it to inform the raid of various things - - void UpdateWorldState(uint32 field, uint32 value); // NYI: Requires core support. Updates the world state counter at the top of the UI. - public: - ScriptedInstance* pInstance; - - uint64 PlayerGUID; - uint64 BossGUID[2]; - - uint32 NextWaveTimer; - uint32 WaveCount; - uint32 CheckTimer; - uint32 Faction; - uint32 EnemyCount; - uint32 RetreatTimer; - - bool EventBegun; - bool FirstBossDead; - bool SecondBossDead; - bool Summon; - bool bRetreat; - bool Debug; - - struct Spell - { - uint32 SpellId; - uint32 Cooldown; - uint32 TargetType; - }Spell[3]; - - private: - uint32 SpellTimer[3]; - std::list CreatureList; -}; -#endif +/* Copyright (C) 2006 - 2008 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 "def_hyjal.h" + +// Trash Mobs summoned in waves +#define NECROMANCER 17899 +#define ABOMINATION 17898 +#define GHOUL 17895 +#define BANSHEE 17905 +#define CRYPT_FIEND 17897 +#define GARGOYLE 17906 +#define FROST_WYRM 17907 +#define GIANT_INFERNAL 17908 +#define FEL_STALKER 17916 + +// Bosses summoned after every 8 waves +#define RAGE_WINTERCHILL 17767 +#define ANETHERON 17808 +#define KAZROGAL 17888 +#define AZGALOR 17842 +#define ARCHIMONDE 17968 + +#define SPELL_TELEPORT_VISUAL 41232 + +#define WORLDSTATE_WAVES 2842 +#define WORLDSTATE_ENEMY 2453 +#define WORLDSTATE_ENEMYCOUNT 2454 + +/*** Spells for Jaina ***/ +#define SPELL_BRILLIANCE_AURA 31260 // The database must handle this spell via creature_addon +#define SPELL_BLIZZARD 31266 +#define SPELL_PYROBLAST 31263 +#define SPELL_SUMMON_ELEMENTALS 31264 + +/** Thrall spells **/ +#define SPELL_CHAIN_LIGHTNING 31330 +#define SPELL_SUMMON_DIRE_WOLF 31331 + +struct Wave +{ + uint32 Mob[18]; // Stores Creature Entries to be summoned in Waves + uint32 WaveTimer; // The timer before the next wave is summoned + bool IsBoss; // Simply used to inform the wave summoner that the next wave contains a boss to halt all waves after that +}; + +static Wave AllianceWaves[]= // Waves that will be summoned in the Alliance Base +{ + { // Wave 1 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, 0, 0, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 2 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 3 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 4 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 5 + GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 6 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 7 + GHOUL, GHOUL, GHOUL, GHOUL, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 8 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 180000, false + }, + { // All 8 Waves are summoned, summon Rage Winterchill, next few waves are for Anetheron + RAGE_WINTERCHILL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true + }, + { // Wave 1 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, 0, 0, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 2 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 3 + GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 4 + GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, BANSHEE, BANSHEE, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 5 + CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, BANSHEE, BANSHEE, BANSHEE, BANSHEE, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 6 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 7 + CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, BANSHEE, BANSHEE, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 8 + GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 180000, false + }, + { // All 8 Waves are summoned, summon Anatheron + ANETHERON, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true + } +}; + +static Wave HordeWaves[]= // Waves that are summoned in the Horde base +{ + { // Wave 1 + GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 2 + GHOUL, GHOUL, GHOUL, GHOUL, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, 0, 0, 0, 0, 120000, false + }, + { // Wave 3 + GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 120000, false + }, + { // Wave 4 + CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, NECROMANCER, NECROMANCER , 0, 0, 0, 0, 120000, false + }, + { // Wave 5 + GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 6 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, FROST_WYRM, 0, 0, 120000, false + }, + { // Wave 7 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, FROST_WYRM, 0, 0, 120000, false + }, + { // Wave 8 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, BANSHEE, BANSHEE, 180000, false + }, + { // All 8 Waves are summoned, summon Kaz'Rogal, next few waves are for Azgalor + KAZROGAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true + }, + { // Wave 1 + ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 2 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, FROST_WYRM, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, 0, 0, 0, 0, 120000, false + }, + { // Wave 3 + GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, 0, 0, 0, 0, 120000, false + }, + { // Wave 4 + GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, 0, 0, 0, 0, 120000, false + }, + { // Wave 5 + FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 120000, false + }, + { // Wave 6 + NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, BANSHEE, BANSHEE, BANSHEE, BANSHEE, BANSHEE, BANSHEE, 0, 0, 0, 0, 120000, false + }, + { // Wave 7 + GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, FEL_STALKER, FEL_STALKER, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, 0, 0, 0, 0, 0, 0, 120000, false + }, + { // Wave 8 + CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, FEL_STALKER, FEL_STALKER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, BANSHEE, BANSHEE, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0, 180000, false + }, + { // All 8 Waves are summoned, summon Azgalor + 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, +}; + +struct Yells +{ + uint32 id; // Used to determine the type of yell (attack, rally, etc) + char* text; // The text to be yelled + uint32 sound; // Sound that corresponds to the text +}; + +enum YellId +{ + 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 +}; + +static Yells JainaQuotes[]= +{ + {ATTACKED, "I'm in jeopardy, help me if you can!", 11007}, + {ATTACKED, "They've broken through!", 11049}, + {INCOMING, "Stay alert! Another wave approaches.", 11008}, + {BEGIN, "Hold them back as long as possible", 11050}, + {RALLY, "Don't give up! We must prevail!", 11006}, + {RALLY, "We must hold strong!", 11051}, + {FAILURE, "We are lost. Fall back!", 11009}, + {SUCCESS, "We have won valuable time. Now we must pull back!", 11011}, + {DEATH, "I did... my best.", 11010}, +}; + +static Yells ThrallQuotes[]= +{ + {ATTACKED, "I will lie down for no one!", 11031}, + {ATTACKED, "Bring the fight to me and pay with your lives!", 11061}, + {INCOMING, "Make ready for another wave! LOK-TAR OGAR!", 11032}, + {BEGIN, "Do not give an inch of ground!", 11060}, + {RALLY, "Hold them back! Do not falter!", 11030}, + {RALLY, "Victory or death!", 11059}, + {RALLY, "Do not give an inch of ground!", 11060}, + {FAILURE, "It is over. Withdraw! We have failed.", 11033}, + {SUCCESS, "We have played our part and done well. It is up to the others now.", 11035}, + {DEATH, "Uraaa...", 11034}, +}; + +struct MANGOS_DLL_DECL hyjalAI : public ScriptedAI +{ + hyjalAI(Creature *c); + + void Reset(); // Generically used to reset our variables. Do *not* call in EnterEvadeMode as this may make problems if the raid is still in combat + + void EnterEvadeMode(); // Send creature back to spawn location and evade. + + void Aggro(Unit *who); // Used to reset cooldowns for our spells and to inform the raid that we're under attack + + void UpdateAI(const uint32 diff); // Called to summon waves, check for boss deaths and to cast our spells. + + void JustDied(Unit* killer) // Called on death, informs the raid that they have failed. + { + Talk(DEATH); + } + + void SetFaction(uint32 _faction) // Set the faction to either Alliance or Horde in Hyjal + { + Faction = _faction; + } + + void Retreat(); // "Teleport" (teleport visual + set invisible) all friendly creatures away from the base. + + void SummonCreature(uint32 entry, float Base[4][3]); // Summons a creature for that wave in that base + + // Summons the next wave, calls SummonCreature + void SummonNextWave(Wave wave[18], uint32 Count, float Base[4][3]); + + void StartEvent(Player* player); // Begins the event by gossip click + + uint32 GetInstanceData(uint32 Event); // Gets instance data for this instance, used to check if raid has gotten past a certain point and can access the next phase + + void Talk(uint32 id); // Searches for the appropriate yell and sound and uses it to inform the raid of various things + + void UpdateWorldState(uint32 field, uint32 value); // NYI: Requires core support. Updates the world state counter at the top of the UI. + public: + ScriptedInstance* pInstance; + + uint64 PlayerGUID; + uint64 BossGUID[2]; + + uint32 NextWaveTimer; + uint32 WaveCount; + uint32 CheckTimer; + uint32 Faction; + uint32 EnemyCount; + uint32 RetreatTimer; + + bool EventBegun; + bool FirstBossDead; + bool SecondBossDead; + bool Summon; + bool bRetreat; + bool Debug; + + struct Spell + { + uint32 SpellId; + uint32 Cooldown; + uint32 TargetType; + }Spell[3]; + + private: + uint32 SpellTimer[3]; + std::list CreatureList; +}; +#endif diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp index 796069ba81f..349a1e6efff 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp @@ -1,203 +1,203 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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 "def_hyjal.h" -#include "WorldPacket.h" - -#define ENCOUNTERS 5 - -/* 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 *Map) : ScriptedInstance(Map) {Initialize();}; - - uint64 RageWinterchill; - uint64 Anetheron; - uint64 Kazrogal; - uint64 Azgalor; - uint64 Archimonde; - uint64 JainaProudmoore; - uint64 Thrall; - uint64 TyrandeWhisperwind; - - uint32 Trash; - uint32 Encounters[ENCOUNTERS]; - - void Initialize() - { - RageWinterchill = 0; - Anetheron = 0; - Kazrogal = 0; - Azgalor = 0; - Archimonde = 0; - JainaProudmoore = 0; - Thrall = 0; - TyrandeWhisperwind = 0; - - Trash = 0; - for(uint8 i = 0; i < ENCOUNTERS; ++i) - Encounters[i] = NOT_STARTED; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; ++i) - if(Encounters[i] == IN_PROGRESS) return true; - - return false; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case 17767: RageWinterchill = creature->GetGUID(); break; - case 17808: Anetheron = creature->GetGUID(); break; - case 17888: Kazrogal = creature->GetGUID(); break; - case 17842: Azgalor = creature->GetGUID(); break; - case 17968: Archimonde = creature->GetGUID(); break; - case 17772: JainaProudmoore = creature->GetGUID(); break; - case 17852: Thrall = creature->GetGUID(); break; - case 17948: TyrandeWhisperwind = creature->GetGUID(); break; - } - } - - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_RAGEWINTERCHILL: return RageWinterchill; - case DATA_ANETHERON: return Anetheron; - case DATA_KAZROGAL: return Kazrogal; - case DATA_AZGALOR: return Azgalor; - case DATA_ARCHIMONDE: return Archimonde; - case DATA_JAINAPROUDMOORE: return JainaProudmoore; - case DATA_THRALL: return Thrall; - case DATA_TYRANDEWHISPERWIND: return TyrandeWhisperwind; - } - - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_RAGEWINTERCHILLEVENT: Encounters[0] = data; break; - case DATA_ANETHERONEVENT: Encounters[1] = data; break; - case DATA_KAZROGALEVENT: Encounters[2] = data; break; - case DATA_AZGALOREVENT: Encounters[3] = data; break; - case DATA_ARCHIMONDEEVENT: Encounters[4] = data; break; - case DATA_RESET_TRASH_COUNT: Trash = 0; break; - - case DATA_TRASH: - if(data) Trash = data; - else Trash--; - UpdateWorldState(2453, data); - break; - } - - if(data == DONE) - SaveToDB(); - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_RAGEWINTERCHILLEVENT: return Encounters[0]; - case DATA_ANETHERONEVENT: return Encounters[1]; - case DATA_KAZROGALEVENT: return Encounters[2]; - case DATA_AZGALOREVENT: return Encounters[3]; - case DATA_ARCHIMONDEEVENT: return Encounters[4]; - case DATA_TRASH: return Trash; - } - return 0; - } - - void UpdateWorldState(uint32 field, uint32 value) - { - WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); - data << field; - data << value; - - ((InstanceMap*)instance)->SendToPlayers(&data); - } - - const char* Save() - { - OUT_SAVE_INST_DATA; - std::ostringstream stream; - stream << Encounters[0] << " " << Encounters[1] << " " - << Encounters[2] << " " << Encounters[3] << " " - << Encounters[4]; - char* out = new char[stream.str().length() + 1]; - strcpy(out, stream.str().c_str()); - if(out) - { - OUT_SAVE_INST_DATA_COMPLETE; - return out; - } - - return NULL; - } - - void Load(const char* load) - { - if(!load) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(load); - std::istringstream stream; - stream >> Encounters[1] >> Encounters[2] >> Encounters[3] >> Encounters[4]; - for(uint8 i = 0; i < ENCOUNTERS; ++i) - if(Encounters[i] == IN_PROGRESS) // Do not load an encounter as IN_PROGRESS - reset it instead. - Encounters[i] = NOT_STARTED; - OUT_LOAD_INST_DATA_COMPLETE; - } -}; - -InstanceData* GetInstanceData_instance_mount_hyjal(Map* map) -{ - return new instance_mount_hyjal(map); -} - -void AddSC_instance_mount_hyjal() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_hyjal"; - newscript->GetInstanceData = GetInstanceData_instance_mount_hyjal; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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 "def_hyjal.h" +#include "WorldPacket.h" + +#define ENCOUNTERS 5 + +/* 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 *Map) : ScriptedInstance(Map) {Initialize();}; + + uint64 RageWinterchill; + uint64 Anetheron; + uint64 Kazrogal; + uint64 Azgalor; + uint64 Archimonde; + uint64 JainaProudmoore; + uint64 Thrall; + uint64 TyrandeWhisperwind; + + uint32 Trash; + uint32 Encounters[ENCOUNTERS]; + + void Initialize() + { + RageWinterchill = 0; + Anetheron = 0; + Kazrogal = 0; + Azgalor = 0; + Archimonde = 0; + JainaProudmoore = 0; + Thrall = 0; + TyrandeWhisperwind = 0; + + Trash = 0; + for(uint8 i = 0; i < ENCOUNTERS; ++i) + Encounters[i] = NOT_STARTED; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; ++i) + if(Encounters[i] == IN_PROGRESS) return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case 17767: RageWinterchill = creature->GetGUID(); break; + case 17808: Anetheron = creature->GetGUID(); break; + case 17888: Kazrogal = creature->GetGUID(); break; + case 17842: Azgalor = creature->GetGUID(); break; + case 17968: Archimonde = creature->GetGUID(); break; + case 17772: JainaProudmoore = creature->GetGUID(); break; + case 17852: Thrall = creature->GetGUID(); break; + case 17948: TyrandeWhisperwind = creature->GetGUID(); break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_RAGEWINTERCHILL: return RageWinterchill; + case DATA_ANETHERON: return Anetheron; + case DATA_KAZROGAL: return Kazrogal; + case DATA_AZGALOR: return Azgalor; + case DATA_ARCHIMONDE: return Archimonde; + case DATA_JAINAPROUDMOORE: return JainaProudmoore; + case DATA_THRALL: return Thrall; + case DATA_TYRANDEWHISPERWIND: return TyrandeWhisperwind; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_RAGEWINTERCHILLEVENT: Encounters[0] = data; break; + case DATA_ANETHERONEVENT: Encounters[1] = data; break; + case DATA_KAZROGALEVENT: Encounters[2] = data; break; + case DATA_AZGALOREVENT: Encounters[3] = data; break; + case DATA_ARCHIMONDEEVENT: Encounters[4] = data; break; + case DATA_RESET_TRASH_COUNT: Trash = 0; break; + + case DATA_TRASH: + if(data) Trash = data; + else Trash--; + UpdateWorldState(2453, data); + break; + } + + if(data == DONE) + SaveToDB(); + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_RAGEWINTERCHILLEVENT: return Encounters[0]; + case DATA_ANETHERONEVENT: return Encounters[1]; + case DATA_KAZROGALEVENT: return Encounters[2]; + case DATA_AZGALOREVENT: return Encounters[3]; + case DATA_ARCHIMONDEEVENT: return Encounters[4]; + case DATA_TRASH: return Trash; + } + return 0; + } + + void UpdateWorldState(uint32 field, uint32 value) + { + WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); + data << field; + data << value; + + ((InstanceMap*)instance)->SendToPlayers(&data); + } + + const char* Save() + { + OUT_SAVE_INST_DATA; + std::ostringstream stream; + stream << Encounters[0] << " " << Encounters[1] << " " + << Encounters[2] << " " << Encounters[3] << " " + << Encounters[4]; + char* out = new char[stream.str().length() + 1]; + strcpy(out, stream.str().c_str()); + if(out) + { + OUT_SAVE_INST_DATA_COMPLETE; + return out; + } + + return NULL; + } + + void Load(const char* load) + { + if(!load) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(load); + std::istringstream stream; + stream >> Encounters[1] >> Encounters[2] >> Encounters[3] >> Encounters[4]; + for(uint8 i = 0; i < ENCOUNTERS; ++i) + if(Encounters[i] == IN_PROGRESS) // Do not load an encounter as IN_PROGRESS - reset it instead. + Encounters[i] = NOT_STARTED; + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_mount_hyjal(Map* map) +{ + return new instance_mount_hyjal(map); +} + +void AddSC_instance_mount_hyjal() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_hyjal"; + newscript->GetInstanceData = GetInstanceData_instance_mount_hyjal; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp index 2dbb79b02a1..9882368a735 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp @@ -1,177 +1,177 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_old_hillsbrad.h" - -#define HOLY_LIGHT 29562 -#define CLEANSE 39078 -#define HAMMER_OF_JUSTICE 13005 -#define HOLY_SHIELD 31904 -#define DEVOTION_AURA 41452 -#define CONSECRATION 41541 - -#define SAY_ENTER "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!" -#define SAY_AGGRO1 "You're a slave. That's all you'll ever be.'" -#define SAY_AGGRO2 "I don't know what Blackmoore sees in you. For my money, you're just another ignorant savage!" -#define SAY_SLAY1 "Thrall will never be free!" -#define SAY_SLAY2 "Did you really think you would leave here alive?" -#define SAY_DEATH "Guards! Urgh..Guards..!'" - -#define SOUND_ENTER 10406 -#define SOUND_AGGRO1 10407 -#define SOUND_AGGRO2 10408 -#define SOUND_SLAY1 10409 -#define SOUND_SLAY2 10410 -#define SOUND_DEATH 10411 - -struct MANGOS_DLL_DECL boss_captain_skarlocAI : public ScriptedAI -{ - boss_captain_skarlocAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *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 = 60000; - Consecration_Timer = 8000; - } - - void Aggro(Unit *who) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - } - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - if( pInstance && pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS ) - pInstance->SetData(TYPE_THRALL_PART1, DONE); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Holy_Light - if (Holy_Light_Timer < diff) - { - DoCast(m_creature, HOLY_LIGHT); - Holy_Light_Timer = 30000; - }else Holy_Light_Timer -= diff; - - //Cleanse - if(Cleanse_Timer < diff) - { - DoCast(m_creature, CLEANSE); - Cleanse_Timer = 10000 ; - } else Cleanse_Timer -= diff; - - //Hammer of Justice - if (HammerOfJustice_Timer < diff) - { - DoCast(m_creature->getVictim(), HAMMER_OF_JUSTICE); - HammerOfJustice_Timer = 60000; - }else HammerOfJustice_Timer -= diff; - - //Holy Shield - if (HolyShield_Timer < diff) - { - DoCast(m_creature,HOLY_SHIELD); - HolyShield_Timer = 240000; - }else HolyShield_Timer -= diff; - - //Devotion_Aura - if (DevotionAura_Timer < diff) - { - DoCast(m_creature,DEVOTION_AURA); - DevotionAura_Timer = 60000; - }else DevotionAura_Timer -= diff; - - //Consecration - if (Consecration_Timer < diff) - { - //DoCast(m_creature->getVictim(),CONSECRATION); - Consecration_Timer = 8000; - }else Consecration_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_captain_skarloc(Creature *_Creature) -{ - return new boss_captain_skarlocAI (_Creature); -} - -void AddSC_boss_captain_skarloc() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_captain_skarloc"; - newscript->GetAI = GetAI_boss_captain_skarloc; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_old_hillsbrad.h" + +#define HOLY_LIGHT 29562 +#define CLEANSE 39078 +#define HAMMER_OF_JUSTICE 13005 +#define HOLY_SHIELD 31904 +#define DEVOTION_AURA 41452 +#define CONSECRATION 41541 + +#define SAY_ENTER "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!" +#define SAY_AGGRO1 "You're a slave. That's all you'll ever be.'" +#define SAY_AGGRO2 "I don't know what Blackmoore sees in you. For my money, you're just another ignorant savage!" +#define SAY_SLAY1 "Thrall will never be free!" +#define SAY_SLAY2 "Did you really think you would leave here alive?" +#define SAY_DEATH "Guards! Urgh..Guards..!'" + +#define SOUND_ENTER 10406 +#define SOUND_AGGRO1 10407 +#define SOUND_AGGRO2 10408 +#define SOUND_SLAY1 10409 +#define SOUND_SLAY2 10410 +#define SOUND_DEATH 10411 + +struct MANGOS_DLL_DECL boss_captain_skarlocAI : public ScriptedAI +{ + boss_captain_skarlocAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *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 = 60000; + Consecration_Timer = 8000; + } + + void Aggro(Unit *who) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + } + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + if( pInstance && pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS ) + pInstance->SetData(TYPE_THRALL_PART1, DONE); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Holy_Light + if (Holy_Light_Timer < diff) + { + DoCast(m_creature, HOLY_LIGHT); + Holy_Light_Timer = 30000; + }else Holy_Light_Timer -= diff; + + //Cleanse + if(Cleanse_Timer < diff) + { + DoCast(m_creature, CLEANSE); + Cleanse_Timer = 10000 ; + } else Cleanse_Timer -= diff; + + //Hammer of Justice + if (HammerOfJustice_Timer < diff) + { + DoCast(m_creature->getVictim(), HAMMER_OF_JUSTICE); + HammerOfJustice_Timer = 60000; + }else HammerOfJustice_Timer -= diff; + + //Holy Shield + if (HolyShield_Timer < diff) + { + DoCast(m_creature,HOLY_SHIELD); + HolyShield_Timer = 240000; + }else HolyShield_Timer -= diff; + + //Devotion_Aura + if (DevotionAura_Timer < diff) + { + DoCast(m_creature,DEVOTION_AURA); + DevotionAura_Timer = 60000; + }else DevotionAura_Timer -= diff; + + //Consecration + if (Consecration_Timer < diff) + { + //DoCast(m_creature->getVictim(),CONSECRATION); + Consecration_Timer = 8000; + }else Consecration_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_captain_skarloc(Creature *_Creature) +{ + return new boss_captain_skarlocAI (_Creature); +} + +void AddSC_boss_captain_skarloc() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_captain_skarloc"; + newscript->GetAI = GetAI_boss_captain_skarloc; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp index bbcaec53407..0222a6c2955 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp @@ -1,183 +1,183 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_old_hillsbrad.h" - -#define SAY_ENTER1 "Thrall! Come outside and face your fate!" -#define SOUND_ENTER1 10418 -#define SAY_ENTER2 "Taretha's life hangs in the balance. Surely you care for her. Surely you wish to save her..." -#define SOUND_ENTER2 10419 -#define SAY_ENTER3 "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!" -#define SOUND_ENTER3 10420 - -#define SAY_AGGRO1 "Enough! I will erase your very existence!" -#define SOUND_AGGRO1 10421 -#define SAY_AGGRO2 "You cannot fight fate!" -#define SOUND_AGGRO2 10422 - -#define SAY_SLAY1 "You are...irrelevant." -#define SOUND_SLAY1 10425 -#define SAY_SLAY2 "Thrall will remain a slave. Taretha will die. You have failed." -#define SOUND_SLAY2 10426 - -#define SAY_BREATH1 "Not so fast!" -#define SOUND_BREATH1 10423 -#define SAY_BREATH2 "Struggle as much as you like!" -#define SOUND_BREATH2 10424 - -#define SAY_DEATH "No!...The master... will not... be pleased." -#define SOUND_DEATH 10427 - -#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 *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 SandBreath_Timer; - uint32 ImpendingDeath_Timer; - uint32 WingBuffet_Timer; - uint32 Mda_Timer; - - void Reset() - { - SandBreath_Timer = 25000; - ImpendingDeath_Timer = 30000; - WingBuffet_Timer = 35000; - Mda_Timer = 40000; - } - - void Aggro(Unit *who) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - } - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if( pInstance && pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS ) - pInstance->SetData(TYPE_THRALL_PART4, DONE); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Sand Breath - if( SandBreath_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(false); - - DoCast(m_creature->getVictim(),SPELL_SAND_BREATH); - - switch(rand()%2) - { - case 0: - DoYell(SAY_BREATH1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_BREATH1); - break; - case 1: - DoYell(SAY_BREATH2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_BREATH2); - break; - } - - SandBreath_Timer = 25000+rand()%5000; - }else SandBreath_Timer -= diff; - - if( ImpendingDeath_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_IMPENDING_DEATH); - ImpendingDeath_Timer = 30000+rand()%5000; - }else ImpendingDeath_Timer -= diff; - - if( WingBuffet_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_WING_BUFFET); - WingBuffet_Timer = 25000+rand()%10000; - }else WingBuffet_Timer -= diff; - - if( Mda_Timer < diff ) - { - DoCast(m_creature,SPELL_MAGIC_DISRUPTION_AURA); - Mda_Timer = 15000; - }else Mda_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_epoch_hunter(Creature *_Creature) -{ - return new boss_epoch_hunterAI (_Creature); -} - -void AddSC_boss_epoch_hunter() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_epoch_hunter"; - newscript->GetAI = GetAI_boss_epoch_hunter; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_old_hillsbrad.h" + +#define SAY_ENTER1 "Thrall! Come outside and face your fate!" +#define SOUND_ENTER1 10418 +#define SAY_ENTER2 "Taretha's life hangs in the balance. Surely you care for her. Surely you wish to save her..." +#define SOUND_ENTER2 10419 +#define SAY_ENTER3 "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!" +#define SOUND_ENTER3 10420 + +#define SAY_AGGRO1 "Enough! I will erase your very existence!" +#define SOUND_AGGRO1 10421 +#define SAY_AGGRO2 "You cannot fight fate!" +#define SOUND_AGGRO2 10422 + +#define SAY_SLAY1 "You are...irrelevant." +#define SOUND_SLAY1 10425 +#define SAY_SLAY2 "Thrall will remain a slave. Taretha will die. You have failed." +#define SOUND_SLAY2 10426 + +#define SAY_BREATH1 "Not so fast!" +#define SOUND_BREATH1 10423 +#define SAY_BREATH2 "Struggle as much as you like!" +#define SOUND_BREATH2 10424 + +#define SAY_DEATH "No!...The master... will not... be pleased." +#define SOUND_DEATH 10427 + +#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 *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 SandBreath_Timer; + uint32 ImpendingDeath_Timer; + uint32 WingBuffet_Timer; + uint32 Mda_Timer; + + void Reset() + { + SandBreath_Timer = 25000; + ImpendingDeath_Timer = 30000; + WingBuffet_Timer = 35000; + Mda_Timer = 40000; + } + + void Aggro(Unit *who) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + } + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if( pInstance && pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS ) + pInstance->SetData(TYPE_THRALL_PART4, DONE); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Sand Breath + if( SandBreath_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(false); + + DoCast(m_creature->getVictim(),SPELL_SAND_BREATH); + + switch(rand()%2) + { + case 0: + DoYell(SAY_BREATH1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_BREATH1); + break; + case 1: + DoYell(SAY_BREATH2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_BREATH2); + break; + } + + SandBreath_Timer = 25000+rand()%5000; + }else SandBreath_Timer -= diff; + + if( ImpendingDeath_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_IMPENDING_DEATH); + ImpendingDeath_Timer = 30000+rand()%5000; + }else ImpendingDeath_Timer -= diff; + + if( WingBuffet_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_WING_BUFFET); + WingBuffet_Timer = 25000+rand()%10000; + }else WingBuffet_Timer -= diff; + + if( Mda_Timer < diff ) + { + DoCast(m_creature,SPELL_MAGIC_DISRUPTION_AURA); + Mda_Timer = 15000; + }else Mda_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_epoch_hunter(Creature *_Creature) +{ + return new boss_epoch_hunterAI (_Creature); +} + +void AddSC_boss_epoch_hunter() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_epoch_hunter"; + newscript->GetAI = GetAI_boss_epoch_hunter; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp index 5a6ccb7dc97..e70b52dfa43 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp @@ -1,246 +1,246 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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. Also script for GO (barrels)(missing mangos support) -SDCategory: Caverns of Time, Old Hillsbrad Foothills -EndScriptData */ - -#include "precompiled.h" -#include "def_old_hillsbrad.h" -#include "../../../npc/npc_escortAI.h" - -/*###### -## go_barrel_old_hillsbrad -######*/ - -#define QUEST_ENTRY_DIVERSION 10283 -#define LODGE_QUEST_TRIGGER 20155 - -bool GOHello_go_barrel_old_hillsbrad(Player *player, GameObject* _GO) -{ - ScriptedInstance* pInstance = ((ScriptedInstance*)_GO->GetInstanceData()); - - if( pInstance ) - { - if( pInstance->GetData(TYPE_BARREL_DIVERSION) != DONE ) - { - pInstance->SetData(TYPE_BARREL_DIVERSION, IN_PROGRESS); - } - else if( pInstance->GetData(TYPE_BARREL_DIVERSION) == DONE ) - { - player->SummonCreature(17848,2128.43,71.01,64.42,1.74,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1200000); - if( player->GetQuestStatus(QUEST_ENTRY_DIVERSION) == QUEST_STATUS_INCOMPLETE ) - player->KilledMonster(LODGE_QUEST_TRIGGER,0); - } - } - return false; -} - -/*###### -## boss_lieutenant_drake -######*/ - -#define WHIRLWIND 40236 -#define FEAR 33789 -#define MORTAL_STRIKE 40220 -#define EXPLODIG_SHOUT 33792 - -#define SAY_ENTER1 "You there, fetch water quickly!" -#define SAY_ENTER2 "Get these flames out before they spread to the rest of the keep!" -#define SAY_ENTER3 "Hurry, damn you!" -#define SAY_AGGRO "I know what you're up to, and I mean to put an end to it, permanently!" -#define SAY_SLAY1 "No more middling for you." -#define SAY_SLAY2 "You will not interfere!" -#define SAY_MORTAL "Time to bleed!" -#define SAY_SHOUT "Run, you blasted cowards!" -#define SAY_DEATH "Thrall... must not... go free." - -#define SOUND_ENTER 10428 -#define SOUND_AGGRO 10429 -#define SOUND_SLAY1 10432 -#define SOUND_SLAY2 10433 -#define SOUND_MORTAL 10430 -#define SOUND_SHOUT 10431 -#define SOUND_DEATH 10434 - -struct Location -{ - uint32 wpId; - float x; - float y; - float z; -}; - -static Location DrakeWP[]= -{ - {0, 2125.84, 88.2535, 54.8830}, - {1, 2111.01, 93.8022, 52.6356}, - {2, 2106.70, 114.753, 53.1965}, - {3, 2107.76, 138.746, 52.5109}, - {4, 2114.83, 160.142, 52.4738}, - {5, 2125.24, 178.909, 52.7283}, - {6, 2151.02, 208.901, 53.1551}, - {7, 2177.00, 233.069, 52.4409}, - {8, 2190.71, 227.831, 53.2742}, - {9, 2178.14, 214.219, 53.0779}, - {10, 2154.99, 202.795, 52.6446}, - {11, 2132.00, 191.834, 52.5709}, - {12, 2117.59, 166.708, 52.7686}, - {13, 2093.61, 139.441, 52.7616}, - {14, 2086.29, 104.950, 52.9246}, - {15, 2094.23, 81.2788, 52.6946}, - {16, 2108.70, 85.3075, 53.3294}, - {17, 2125.50, 88.9481, 54.7953}, - {18, 2128.20, 70.9763, 64.4221} -}; - -struct MANGOS_DLL_DECL boss_lieutenant_drakeAI : public ScriptedAI -{ - boss_lieutenant_drakeAI(Creature *c) : ScriptedAI(c) {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) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - 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->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Whirlwind - if (Whirlwind_Timer < diff) - { - DoCast(m_creature->getVictim(), WHIRLWIND); - - Whirlwind_Timer = 20000+rand()%5000; - }else Whirlwind_Timer -= diff; - - //Fear - if (Fear_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (target) - DoCast(target, FEAR); - - Fear_Timer = 30000+rand()%10000; - }else Fear_Timer -= diff; - - //Mortal Strike - if (MortalStrike_Timer < diff) - { - DoYell(SAY_MORTAL, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_MORTAL); - - DoCast(m_creature->getVictim(), MORTAL_STRIKE); - - MortalStrike_Timer = 45000+rand()%5000; - }else MortalStrike_Timer -= diff; - - /* - //This only enabled on heroic? - //Exploding Shout - if (m_creature->IsHeroicCreature()) - { - if (ExplodingShout_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - DoYell(SAY_SHOUT, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SHOUT); - DoCast(target,EXPLODING_SHOUT); - ExplodingShout_Timer = 25000+rand()%5000; - }else ExplodingShout_Timer -= diff; - } - */ - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_lieutenant_drake(Creature *_Creature) -{ - return new boss_lieutenant_drakeAI (_Creature); -} - -void AddSC_boss_lieutenant_drake() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="go_barrel_old_hillsbrad"; - newscript->pGOHello = GOHello_go_barrel_old_hillsbrad; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_lieutenant_drake"; - newscript->GetAI = GetAI_boss_lieutenant_drake; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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. Also script for GO (barrels)(missing mangos support) +SDCategory: Caverns of Time, Old Hillsbrad Foothills +EndScriptData */ + +#include "precompiled.h" +#include "def_old_hillsbrad.h" +#include "../../../npc/npc_escortAI.h" + +/*###### +## go_barrel_old_hillsbrad +######*/ + +#define QUEST_ENTRY_DIVERSION 10283 +#define LODGE_QUEST_TRIGGER 20155 + +bool GOHello_go_barrel_old_hillsbrad(Player *player, GameObject* _GO) +{ + ScriptedInstance* pInstance = ((ScriptedInstance*)_GO->GetInstanceData()); + + if( pInstance ) + { + if( pInstance->GetData(TYPE_BARREL_DIVERSION) != DONE ) + { + pInstance->SetData(TYPE_BARREL_DIVERSION, IN_PROGRESS); + } + else if( pInstance->GetData(TYPE_BARREL_DIVERSION) == DONE ) + { + player->SummonCreature(17848,2128.43,71.01,64.42,1.74,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1200000); + if( player->GetQuestStatus(QUEST_ENTRY_DIVERSION) == QUEST_STATUS_INCOMPLETE ) + player->KilledMonster(LODGE_QUEST_TRIGGER,0); + } + } + return false; +} + +/*###### +## boss_lieutenant_drake +######*/ + +#define WHIRLWIND 40236 +#define FEAR 33789 +#define MORTAL_STRIKE 40220 +#define EXPLODIG_SHOUT 33792 + +#define SAY_ENTER1 "You there, fetch water quickly!" +#define SAY_ENTER2 "Get these flames out before they spread to the rest of the keep!" +#define SAY_ENTER3 "Hurry, damn you!" +#define SAY_AGGRO "I know what you're up to, and I mean to put an end to it, permanently!" +#define SAY_SLAY1 "No more middling for you." +#define SAY_SLAY2 "You will not interfere!" +#define SAY_MORTAL "Time to bleed!" +#define SAY_SHOUT "Run, you blasted cowards!" +#define SAY_DEATH "Thrall... must not... go free." + +#define SOUND_ENTER 10428 +#define SOUND_AGGRO 10429 +#define SOUND_SLAY1 10432 +#define SOUND_SLAY2 10433 +#define SOUND_MORTAL 10430 +#define SOUND_SHOUT 10431 +#define SOUND_DEATH 10434 + +struct Location +{ + uint32 wpId; + float x; + float y; + float z; +}; + +static Location DrakeWP[]= +{ + {0, 2125.84, 88.2535, 54.8830}, + {1, 2111.01, 93.8022, 52.6356}, + {2, 2106.70, 114.753, 53.1965}, + {3, 2107.76, 138.746, 52.5109}, + {4, 2114.83, 160.142, 52.4738}, + {5, 2125.24, 178.909, 52.7283}, + {6, 2151.02, 208.901, 53.1551}, + {7, 2177.00, 233.069, 52.4409}, + {8, 2190.71, 227.831, 53.2742}, + {9, 2178.14, 214.219, 53.0779}, + {10, 2154.99, 202.795, 52.6446}, + {11, 2132.00, 191.834, 52.5709}, + {12, 2117.59, 166.708, 52.7686}, + {13, 2093.61, 139.441, 52.7616}, + {14, 2086.29, 104.950, 52.9246}, + {15, 2094.23, 81.2788, 52.6946}, + {16, 2108.70, 85.3075, 53.3294}, + {17, 2125.50, 88.9481, 54.7953}, + {18, 2128.20, 70.9763, 64.4221} +}; + +struct MANGOS_DLL_DECL boss_lieutenant_drakeAI : public ScriptedAI +{ + boss_lieutenant_drakeAI(Creature *c) : ScriptedAI(c) {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) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + 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->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Whirlwind + if (Whirlwind_Timer < diff) + { + DoCast(m_creature->getVictim(), WHIRLWIND); + + Whirlwind_Timer = 20000+rand()%5000; + }else Whirlwind_Timer -= diff; + + //Fear + if (Fear_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (target) + DoCast(target, FEAR); + + Fear_Timer = 30000+rand()%10000; + }else Fear_Timer -= diff; + + //Mortal Strike + if (MortalStrike_Timer < diff) + { + DoYell(SAY_MORTAL, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_MORTAL); + + DoCast(m_creature->getVictim(), MORTAL_STRIKE); + + MortalStrike_Timer = 45000+rand()%5000; + }else MortalStrike_Timer -= diff; + + /* + //This only enabled on heroic? + //Exploding Shout + if (m_creature->IsHeroicCreature()) + { + if (ExplodingShout_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + DoYell(SAY_SHOUT, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SHOUT); + DoCast(target,EXPLODING_SHOUT); + ExplodingShout_Timer = 25000+rand()%5000; + }else ExplodingShout_Timer -= diff; + } + */ + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_lieutenant_drake(Creature *_Creature) +{ + return new boss_lieutenant_drakeAI (_Creature); +} + +void AddSC_boss_lieutenant_drake() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="go_barrel_old_hillsbrad"; + newscript->pGOHello = GOHello_go_barrel_old_hillsbrad; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_lieutenant_drake"; + newscript->GetAI = GetAI_boss_lieutenant_drake; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/def_old_hillsbrad.h b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/def_old_hillsbrad.h index 8a230919bbc..4d82a179a93 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/def_old_hillsbrad.h +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/def_old_hillsbrad.h @@ -1,16 +1,16 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_OLD_HILLSBRAD_H -#define DEF_OLD_HILLSBRAD_H - -#define TYPE_BARREL_DIVERSION 1 -#define TYPE_THRALL_EVENT 2 -#define TYPE_THRALL_PART1 3 -#define TYPE_THRALL_PART2 4 -#define TYPE_THRALL_PART3 5 -#define TYPE_THRALL_PART4 6 -#define DATA_THRALL 7 -#define DATA_TARETHA 8 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_OLD_HILLSBRAD_H +#define DEF_OLD_HILLSBRAD_H + +#define TYPE_BARREL_DIVERSION 1 +#define TYPE_THRALL_EVENT 2 +#define TYPE_THRALL_PART1 3 +#define TYPE_THRALL_PART2 4 +#define TYPE_THRALL_PART3 5 +#define TYPE_THRALL_PART4 6 +#define DATA_THRALL 7 +#define DATA_TARETHA 8 +#endif diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp index 57d78f5d98f..1ac0d03a3bb 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp @@ -1,178 +1,178 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Old_Hillsbrad -SD%Complete: 60 -SDComment: If thrall escort fail, all parts will reset. In future, save sub-parts and continue from last known. -SDCategory: Caverns of Time, Old Hillsbrad Foothills -EndScriptData */ - -/* --- UPDATE `gameobject_template` SET `ScriptName`='go_barrel_old_hillsbrad' WHERE `entry`=182589; -*/ - -#include "precompiled.h" -#include "def_old_hillsbrad.h" - -#define ENCOUNTERS 6 - -#define THRALL_ENTRY 17876 -#define TARETHA_ENTRY 18887 - -struct MANGOS_DLL_DECL instance_old_hillsbrad : public ScriptedInstance -{ - instance_old_hillsbrad(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint32 Encounter[ENCOUNTERS]; - uint32 mBarrelCount; - uint32 mThrallEventCount; - - uint64 ThrallGUID; - uint64 TarethaGUID; - - void Initialize() - { - mBarrelCount = 0; - mThrallEventCount = 0; - ThrallGUID = 0; - TarethaGUID = 0; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounter[i] = NOT_STARTED; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case THRALL_ENTRY: - ThrallGUID = creature->GetGUID(); - break; - case TARETHA_ENTRY: - TarethaGUID = creature->GetGUID(); - break; - } - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case TYPE_BARREL_DIVERSION: - { - if( mBarrelCount < 5 ) - { - mBarrelCount++; - debug_log("SD2: go_barrel_old_hillsbrad count %u",mBarrelCount); - } - else if( mBarrelCount >= 5 ) - Encounter[0] = DONE; - break; - } - case TYPE_THRALL_EVENT: - { - if( data == FAIL ) - { - if( mThrallEventCount <= 20 ) - { - mThrallEventCount++; - Encounter[1] = NOT_STARTED; - debug_log("SD2: Thrall event failed %u times. Resetting all sub-events.",mThrallEventCount); - Encounter[2] = NOT_STARTED; - Encounter[3] = NOT_STARTED; - Encounter[4] = NOT_STARTED; - Encounter[5] = NOT_STARTED; - } - else if( mThrallEventCount > 20 ) - { - Encounter[1] = data; - Encounter[2] = data; - Encounter[3] = data; - Encounter[4] = data; - Encounter[5] = data; - debug_log("SD2: Thrall event failed %u times. Reset instance required.",mThrallEventCount); - } - } - else - Encounter[1] = data; - debug_log("SD2: Thrall escort event adjusted to data %u.",data); - break; - } - case TYPE_THRALL_PART1: - Encounter[2] = data; - debug_log("SD2: Thrall event part I adjusted to data %u.",data); - break; - case TYPE_THRALL_PART2: - Encounter[3] = data; - debug_log("SD2: Thrall event part II adjusted to data %u.",data); - break; - case TYPE_THRALL_PART3: - Encounter[4] = data; - debug_log("SD2: Thrall event part III adjusted to data %u.",data); - break; - case TYPE_THRALL_PART4: - Encounter[5] = data; - debug_log("SD2: Thrall event part IV adjusted to data %u.",data); - break; - } - } - - uint32 GetData(uint32 data) - { - switch(data) - { - case TYPE_BARREL_DIVERSION: - return Encounter[0]; - case TYPE_THRALL_EVENT: - return Encounter[1]; - case TYPE_THRALL_PART1: - return Encounter[2]; - case TYPE_THRALL_PART2: - return Encounter[3]; - case TYPE_THRALL_PART3: - return Encounter[4]; - case TYPE_THRALL_PART4: - return Encounter[5]; - } - return 0; - } - - uint64 GetData64(uint32 data) - { - switch(data) - { - case DATA_THRALL: - return ThrallGUID; - case DATA_TARETHA: - return TarethaGUID; - } - return 0; - } -}; -InstanceData* GetInstanceData_instance_old_hillsbrad(Map* map) -{ - return new instance_old_hillsbrad(map); -} - -void AddSC_instance_old_hillsbrad() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_old_hillsbrad"; - newscript->GetInstanceData = GetInstanceData_instance_old_hillsbrad; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Old_Hillsbrad +SD%Complete: 60 +SDComment: If thrall escort fail, all parts will reset. In future, save sub-parts and continue from last known. +SDCategory: Caverns of Time, Old Hillsbrad Foothills +EndScriptData */ + +/* +-- UPDATE `gameobject_template` SET `ScriptName`='go_barrel_old_hillsbrad' WHERE `entry`=182589; +*/ + +#include "precompiled.h" +#include "def_old_hillsbrad.h" + +#define ENCOUNTERS 6 + +#define THRALL_ENTRY 17876 +#define TARETHA_ENTRY 18887 + +struct MANGOS_DLL_DECL instance_old_hillsbrad : public ScriptedInstance +{ + instance_old_hillsbrad(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 Encounter[ENCOUNTERS]; + uint32 mBarrelCount; + uint32 mThrallEventCount; + + uint64 ThrallGUID; + uint64 TarethaGUID; + + void Initialize() + { + mBarrelCount = 0; + mThrallEventCount = 0; + ThrallGUID = 0; + TarethaGUID = 0; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounter[i] = NOT_STARTED; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case THRALL_ENTRY: + ThrallGUID = creature->GetGUID(); + break; + case TARETHA_ENTRY: + TarethaGUID = creature->GetGUID(); + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case TYPE_BARREL_DIVERSION: + { + if( mBarrelCount < 5 ) + { + mBarrelCount++; + debug_log("SD2: go_barrel_old_hillsbrad count %u",mBarrelCount); + } + else if( mBarrelCount >= 5 ) + Encounter[0] = DONE; + break; + } + case TYPE_THRALL_EVENT: + { + if( data == FAIL ) + { + if( mThrallEventCount <= 20 ) + { + mThrallEventCount++; + Encounter[1] = NOT_STARTED; + debug_log("SD2: Thrall event failed %u times. Resetting all sub-events.",mThrallEventCount); + Encounter[2] = NOT_STARTED; + Encounter[3] = NOT_STARTED; + Encounter[4] = NOT_STARTED; + Encounter[5] = NOT_STARTED; + } + else if( mThrallEventCount > 20 ) + { + Encounter[1] = data; + Encounter[2] = data; + Encounter[3] = data; + Encounter[4] = data; + Encounter[5] = data; + debug_log("SD2: Thrall event failed %u times. Reset instance required.",mThrallEventCount); + } + } + else + Encounter[1] = data; + debug_log("SD2: Thrall escort event adjusted to data %u.",data); + break; + } + case TYPE_THRALL_PART1: + Encounter[2] = data; + debug_log("SD2: Thrall event part I adjusted to data %u.",data); + break; + case TYPE_THRALL_PART2: + Encounter[3] = data; + debug_log("SD2: Thrall event part II adjusted to data %u.",data); + break; + case TYPE_THRALL_PART3: + Encounter[4] = data; + debug_log("SD2: Thrall event part III adjusted to data %u.",data); + break; + case TYPE_THRALL_PART4: + Encounter[5] = data; + debug_log("SD2: Thrall event part IV adjusted to data %u.",data); + break; + } + } + + uint32 GetData(uint32 data) + { + switch(data) + { + case TYPE_BARREL_DIVERSION: + return Encounter[0]; + case TYPE_THRALL_EVENT: + return Encounter[1]; + case TYPE_THRALL_PART1: + return Encounter[2]; + case TYPE_THRALL_PART2: + return Encounter[3]; + case TYPE_THRALL_PART3: + return Encounter[4]; + case TYPE_THRALL_PART4: + return Encounter[5]; + } + return 0; + } + + uint64 GetData64(uint32 data) + { + switch(data) + { + case DATA_THRALL: + return ThrallGUID; + case DATA_TARETHA: + return TarethaGUID; + } + return 0; + } +}; +InstanceData* GetInstanceData_instance_old_hillsbrad(Map* map) +{ + return new instance_old_hillsbrad(map); +} + +void AddSC_instance_old_hillsbrad() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_old_hillsbrad"; + newscript->GetInstanceData = GetInstanceData_instance_old_hillsbrad; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp index a02715785fe..9a7c039b5d6 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp @@ -1,916 +1,916 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Old_Hillsbrad -SD%Complete: 40 -SDComment: All friendly NPC's. Thrall waypoints fairly complete, missing many details, but possible to complete escort. -SDCategory: Caverns of Time, Old Hillsbrad Foothills -EndScriptData */ - -/* ContentData -npc_brazen -npc_erozion -npc_thrall_old_hillsbrad -npc_taretha -EndContentData */ - -#include "precompiled.h" -#include "../../../npc/npc_escortAI.h" -#include "def_old_hillsbrad.h" - -#define QUEST_ENTRY_HILLSBRAD 10282 -#define QUEST_ENTRY_DIVERSION 10283 -#define QUEST_ENTRY_ESCAPE 10284 -#define QUEST_ENTRY_RETURN 10285 -#define ITEM_ENTRY_BOMBS 25853 - -/*###### -## npc_brazen -######*/ - -bool GossipHello_npc_brazen(Player *player, Creature *_Creature) -{ - player->ADD_GOSSIP_ITEM(0, "I am ready to go to Durnholde Keep.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_brazen(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - if( !player->HasItemCount(ITEM_ENTRY_BOMBS,1) ) - player->SEND_GOSSIP_MENU(9780, _Creature->GetGUID()); - else - { - player->CLOSE_GOSSIP_MENU(); - - std::vector nodes; - - nodes.resize(2); - nodes[0] = 115; //from brazen - nodes[1] = 116; //end outside durnholde - player->ActivateTaxiPathTo(nodes); //TaxiPath 534 - } - } - return true; -} - -/*###### -## npc_erozion -######*/ - -bool GossipHello_npc_erozion(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - if( pInstance && pInstance->GetData(TYPE_BARREL_DIVERSION) != DONE && !player->HasItemCount(ITEM_ENTRY_BOMBS,1) ) - player->ADD_GOSSIP_ITEM( 0, "I need a pack of Incendiary Bombs.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - if( !player->GetQuestRewardStatus(QUEST_ENTRY_RETURN) && player->GetQuestStatus(QUEST_ENTRY_RETURN) == QUEST_STATUS_COMPLETE ) - player->ADD_GOSSIP_ITEM( 0, "[PH] Teleport please, i'm tired.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - player->SEND_GOSSIP_MENU(9778, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_erozion(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if( action == GOSSIP_ACTION_INFO_DEF+1 ) - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, ITEM_ENTRY_BOMBS, 1, false); - if( msg == EQUIP_ERR_OK ) - { - player->StoreNewItem( dest, ITEM_ENTRY_BOMBS, 1, true); - } - player->SEND_GOSSIP_MENU(9515, _Creature->GetGUID()); - } - if( action == GOSSIP_ACTION_INFO_DEF+2 ) - { - player->CLOSE_GOSSIP_MENU(); - } - return true; -} - -/*###### -## npc_thrall_old_hillsbrad -######*/ - -#define SPEED_WALK (0.5f) -#define SPEED_RUN (1.0f) -#define SPEED_MOUNT (1.6f) - -#define THRALL_WEAPON_MODEL 22106 -#define THRALL_WEAPON_INFO 218169346 -#define THRALL_SHIELD_MODEL 18662 -#define THRALL_SHIELD_INFO 234948100 -#define THRALL_MODEL_UNEQUIPPED 17292 -#define THRALL_MODEL_EQUIPPED 18165 - -#define MOB_ENTRY_RIFLE 17820 -#define MOB_ENTRY_WARDEN 17833 -#define MOB_ENTRY_VETERAN 17860 -#define MOB_ENTRY_WATCHMAN 17814 -#define MOB_ENTRY_SENTRY 17815 - -#define MOB_ENTRY_BARN_GUARDSMAN 18092 -#define MOB_ENTRY_BARN_PROTECTOR 18093 -#define MOB_ENTRY_BARN_LOOKOUT 18094 - -#define MOB_ENTRY_CHURCH_GUARDSMAN 23175 -#define MOB_ENTRY_CHURCH_PROTECTOR 23179 -#define MOB_ENTRY_CHURCH_LOOKOUT 23177 - -#define MOB_ENTRY_INN_GUARDSMAN 23176 -#define MOB_ENTRY_INN_PROTECTOR 23180 -#define MOB_ENTRY_INN_LOOKOUT 23178 - -#define SKARLOC_MOUNT 18798 -#define SKARLOC_MOUNT_MODEL 18223 -#define EROZION_ENTRY 18723 - -#define GOSSIP_ID_START 9568 -#define GOSSIP_ID_SKARLOC1 9614 //I'm glad Taretha is alive. We now must find a way to free her... -#define GOSSIP_ITEM_SKARLOC1 "Taretha cannot see you, Thrall." -#define GOSSIP_ID_SKARLOC2 9579 //What do you mean by this? Is Taretha in danger? -#define GOSSIP_ITEM_SKARLOC2 "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." -#define GOSSIP_ID_SKARLOC3 9580 - -#define GOSSIP_ID_TARREN 9597 //tarren mill is beyond these trees -#define GOSSIP_ITEM_TARREN "We're ready, Thrall." - -#define GOSSIP_ID_COMPLETE 9578 //Thank you friends, I owe my freedom to you. Where is Taretha? I hoped to see her - -#define THRALL_START_EVENT_PART1 "Very well then. Let's go!" -#define SOUND_START_EVENT 10465 - -#define THRALL_SAY_ARMOR "As long as we're going with a new plan, I may aswell pick up a weapon and some armor." - -#define THRALL_SKARLOC_MEET "A rider approaches!" -#define SOUND_SKARLOC_MEET 10466 -#define THRALL_SKARLOC_TAUNT "I'll never be chained again!" -#define SOUND_SKARLOC_TAUNT 10467 - -#define THRALL_START_EVENT_PART2 "Very well. Tarren Mill lies just west of here. Since time is of the essence..." -#define SOUND_START_EVENT_PART2 10468 -#define THRALL_MOUNTS_UP "Let's ride!" -#define SOUND_MOUNTS_UP 10469 - -#define THRALL_CHURCH_END "Taretha must be in the inn. Let's go." -#define THRALL_MEET_TARETHA "Taretha! What foul magic is this?" - -#define THRALL_EPOCH_WONDER "Who or what was that?" -#define SOUND_EPOCH_WONDER 10470 -#define THRALL_EPOCH_KILL_TARETHA "No!" -#define SOUND_EPOCH_KILL_TARETHA 10471 - -#define THRALL_EVENT_COMPLETE "Goodbye, Taretha. I will never forget your kindness." -#define SOUND_EVENT_COMPLETE 10472 - -#define THRALL_RANDOM_LOW_HP1 "Things are looking grim..." -#define SOUND_RANDOM_LOW_HP1 10458 -#define THRALL_RANDOM_LOW_HP2 "I will fight to the last!" -#define SOUND_RANDOM_LOW_HP2 10459 - -#define THRALL_RANDOM_DIE1 "Taretha..." -#define SOUND_RANDOM_DIE1 10460 -#define THRALL_RANDOM_DIE2 "A good day...to die..." -#define SOUND_RANDOM_DIE2 10461 - -#define THRALL_RANDOM_AGGRO1 "I have earned my freedom!" -#define SOUND_RANDOM_AGGRO1 10448 -#define THRALL_RANDOM_AGGRO2 "This day is long overdue. Out of my way!" -#define SOUND_RANDOM_AGGRO2 10449 -#define THRALL_RANDOM_AGGRO3 "I am a slave no longer!" -#define SOUND_RANDOM_AGGRO3 10450 -#define THRALL_RANDOM_AGGRO4 "Blackmoore has much to answer for!" -#define SOUND_RANDOM_AGGRO4 10451 - -#define THRALL_RANDOM_KILL1 "You have forced my hand!" -#define SOUND_RANDOM_KILL1 10452 -#define THRALL_RANDOM_KILL2 "It should not have come to this!" -#define SOUND_RANDOM_KILL2 10453 -#define THRALL_RANDOM_KILL3 "I did not ask for this!" -#define SOUND_RANDOM_KILL3 10454 - -#define THRALL_LEAVE_COMBAT1 "I am truly in your debt, strangers." -#define SOUND_LEAVE_COMBAT1 10455 -#define THRALL_LEAVE_COMBAT2 "Thank you, strangers. You have given me hope." -#define SOUND_LEAVE_COMBAT2 10456 -#define THRALL_LEAVE_COMBAT3 "I will not waste this chance. I will seek out my destiny." -#define SOUND_LEAVE_COMBAT3 10457 - -struct MANGOS_DLL_DECL npc_thrall_old_hillsbradAI : public npc_escortAI -{ - npc_thrall_old_hillsbradAI(Creature *c) : npc_escortAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - Creature* sum; - uint64 TarethaGUID; - bool LowHp; - bool HadMount; - - void WaypointReached(uint32 i) - { - switch( i ) - { - case 8: - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - sum = m_creature->SummonCreature(18764,2181.87,112.46,89.45,0.26,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - break; - case 9: - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - DoSay(THRALL_SAY_ARMOR, LANG_UNIVERSAL, NULL); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, THRALL_WEAPON_MODEL); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, THRALL_WEAPON_INFO); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+1, 781); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, THRALL_SHIELD_MODEL); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+2, THRALL_SHIELD_INFO); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+3, 1038); - break; - case 10: - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, THRALL_MODEL_EQUIPPED); - break; - case 11: - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - break; - case 15: - sum = m_creature->SummonCreature(MOB_ENTRY_RIFLE,2200.28,137.37,87.93,5.07,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_WARDEN,2197.44,131.83,87.93,0.78,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2203.62,135.40,87.93,3.70,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2200.75,130.13,87.93,1.48,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - break; - case 21: - sum = m_creature->SummonCreature(MOB_ENTRY_RIFLE,2135.80,154.01,67.45,4.98,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_WARDEN,2144.36,151.87,67.74,4.46,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2142.12,154.41,67.12,4.56,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2138.08,155.38,67.24,4.60,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - break; - case 25: - sum = m_creature->SummonCreature(MOB_ENTRY_RIFLE,2102.98,192.17,65.24,6.02,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_WARDEN,2108.48,198.75,65.18,5.15,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2106.11,197.29,65.18,5.63,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2104.18,194.82,65.18,5.75,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - break; - case 29: - DoSay(THRALL_SKARLOC_MEET, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SKARLOC_MEET); - sum = m_creature->SummonCreature(17862,2036.48,271.22,63.43,5.27,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); - //temporary,skarloc should rather be triggered to walk up to thrall - if( sum ) sum->AI()->AttackStart(m_creature); - break; - case 30: - IsOnHold = true; - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - break; - case 31: - DoSay(THRALL_MOUNTS_UP, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_MOUNTS_UP); - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - DoMount(); - break; - case 37: - //possibly regular patrollers? If so, remove this and let database handle them - sum = m_creature->SummonCreature(MOB_ENTRY_WATCHMAN,2124.26,522.16,56.87,3.99,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_WATCHMAN,2121.69,525.37,57.11,4.01,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_SENTRY,2124.65,524.55,56.63,3.98,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - break; - case 59: - m_creature->SummonCreature(SKARLOC_MOUNT,2488.64,625.77,58.26,4.71,TEMPSUMMON_TIMED_DESPAWN,10000); - DoUnmount(); - HadMount = false; - break; - case 60: - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); - //make horsie run off - IsOnHold = true; - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - if( pInstance ) - pInstance->SetData(TYPE_THRALL_PART2, DONE); - break; - case 64: - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - break; - case 68: - m_creature->SummonCreature(MOB_ENTRY_BARN_PROTECTOR,2500.22,692.60,55.50,2.84,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - m_creature->SummonCreature(MOB_ENTRY_BARN_LOOKOUT,2500.13,696.55,55.51,3.38,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - m_creature->SummonCreature(MOB_ENTRY_BARN_GUARDSMAN,2500.55,693.64,55.50,3.14,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - m_creature->SummonCreature(MOB_ENTRY_BARN_GUARDSMAN,2500.94,695.81,55.50,3.14,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - break; - case 71: - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - break; - case 81: - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - break; - case 83: - sum = m_creature->SummonCreature(MOB_ENTRY_CHURCH_PROTECTOR,2627.33,646.82,56.03,4.28,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_CHURCH_LOOKOUT,2624.14,648.03,56.03,4.50,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_CHURCH_GUARDSMAN,2625.32,649.60,56.03,4.38,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_CHURCH_GUARDSMAN,2627.22,649.00,56.03,4.34,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - break; - case 84: - DoSay(THRALL_CHURCH_END, LANG_UNIVERSAL, NULL); - break; - case 91: - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - case 93: - sum = m_creature->SummonCreature(MOB_ENTRY_INN_PROTECTOR,2652.71,660.31,61.93,1.67,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_INN_LOOKOUT,2648.96,662.59,61.93,0.79,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_INN_GUARDSMAN,2657.36,662.34,61.93,2.68,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - sum = m_creature->SummonCreature(MOB_ENTRY_INN_GUARDSMAN,2656.39,659.77,61.93,2.61,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - if( sum ) sum->AI()->AttackStart(m_creature); - break; - case 94: - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - //trigger taretha Say("Thrall, you escaped!") - break; - case 95: - DoSay(THRALL_MEET_TARETHA, LANG_UNIVERSAL, NULL); - if( pInstance ) - pInstance->SetData(TYPE_THRALL_PART3,DONE); - IsOnHold = true; - break; - case 96: - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - DoYell(THRALL_EPOCH_WONDER, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_EPOCH_WONDER); - break; - case 97: - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); - DoYell(THRALL_EPOCH_KILL_TARETHA, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_EPOCH_KILL_TARETHA); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - break; - case 98: - //trigger epoch Yell("Thrall! Come outside and face your fate! ....") - break; - case 106: - { - //trigger taretha to run down outside - /*if( pInstance ) - uint64 TarethaGUID = pInstance->GetData64(DATA_TARETHA); - if( TarethaGUID ) - { - Creature* Taretha = ((Creature*)Unit::GetUnit((*m_creature), TarethaGUID)); - if( Taretha ) - ((npc_escortAI*)(Taretha->AI()))->Start(false, false, true, 0); - }*/ - - if( PlayerGUID ) - { - Unit* player = ((Creature*)Unit::GetUnit((*m_creature), PlayerGUID)); - if( player && player->GetTypeId() == TYPEID_PLAYER ) - ((Player*)player)->KilledMonster(20156,m_creature->GetGUID()); - } - - //alot will happen here, thrall and taretha talk, erozion appear at spot to explain - m_creature->SummonCreature(EROZION_ENTRY,2646.47,680.416,55.38,4.16,TEMPSUMMON_TIMED_DESPAWN,120000); - } - break; - } - } - - void Reset() - { - sum = NULL; - LowHp = false; - - if( HadMount ) - DoMount(); - - if( !IsBeingEscorted ) - { - DoUnmount(); - HadMount = false; - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+1, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+2, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+3, 0); - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, THRALL_MODEL_UNEQUIPPED); - } - if( IsBeingEscorted ) - { - switch(rand()%3) - { - case 0: - DoYell(THRALL_LEAVE_COMBAT1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_LEAVE_COMBAT1); - break; - case 1: - DoYell(THRALL_LEAVE_COMBAT2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_LEAVE_COMBAT2); - break; - case 2: - DoYell(THRALL_LEAVE_COMBAT3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_LEAVE_COMBAT3); - break; - } - } - } - void StartWP() - { - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - IsOnHold = false; - } - void DoMount() - { - m_creature->Mount(SKARLOC_MOUNT_MODEL); - m_creature->SetSpeed(MOVE_RUN,SPEED_MOUNT); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - } - void DoUnmount() - { - m_creature->Unmount(); - m_creature->SetSpeed(MOVE_RUN,SPEED_RUN); - } - void Aggro(Unit* who) - { - switch(rand()%4) - { - case 0: - DoYell(THRALL_RANDOM_AGGRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_AGGRO1); - break; - case 1: - DoYell(THRALL_RANDOM_AGGRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_AGGRO2); - break; - case 2: - DoYell(THRALL_RANDOM_AGGRO3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_AGGRO3); - break; - case 3: - DoYell(THRALL_RANDOM_AGGRO4,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_AGGRO4); - break; - } - if( m_creature->IsMounted() ) - { - DoUnmount(); - HadMount = true; - } - } - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoYell(THRALL_RANDOM_KILL1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_KILL1); - break; - case 1: - DoYell(THRALL_RANDOM_KILL2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_KILL2); - break; - case 2: - DoYell(THRALL_RANDOM_KILL3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_KILL3); - break; - } - } - void JustDied(Unit *slayer) - { - if(slayer == m_creature) // Don't do a yell if he kills self (if player goes too far or at the end). - return; - - switch(rand()%2) - { - case 0: - DoYell(THRALL_RANDOM_DIE1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_DIE1); - break; - case 1: - DoYell(THRALL_RANDOM_DIE2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_DIE2); - break; - } - if( pInstance ) - pInstance->SetData(TYPE_THRALL_EVENT,FAIL); - } - void UpdateAI(const uint32 diff) - { - npc_escortAI::UpdateAI(diff); - - if( InCombat && m_creature->getVictim() ) - { - //add his abilities'n-crap here - - if( !LowHp && ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) ) - { - switch(rand()%2) - { - case 0: - DoYell(THRALL_RANDOM_LOW_HP1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_LOW_HP1); - break; - case 1: - DoYell(THRALL_RANDOM_LOW_HP2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RANDOM_LOW_HP2); - break; - } - LowHp = true; - } - } - } -}; - -CreatureAI* GetAI_npc_thrall_old_hillsbrad(Creature *_Creature) -{ - npc_thrall_old_hillsbradAI* thrall_walkAI = new npc_thrall_old_hillsbradAI(_Creature); - - thrall_walkAI->AddWaypoint(0, 2230.91, 118.765, 82.2947,5000); - thrall_walkAI->AddWaypoint(1, 2230.33, 114.980, 82.2946); - thrall_walkAI->AddWaypoint(2, 2233.36, 111.057, 82.2996); - thrall_walkAI->AddWaypoint(3, 2231.17, 108.486, 82.6624); - thrall_walkAI->AddWaypoint(4, 2220.22, 114.605, 89.4264); - thrall_walkAI->AddWaypoint(5, 2215.23, 115.990, 89.4549); - thrall_walkAI->AddWaypoint(6, 2210.00, 106.849, 89.4549); - thrall_walkAI->AddWaypoint(7, 2205.66, 105.234, 89.4549); - //spawn armorer - thrall_walkAI->AddWaypoint(8, 2192.26, 112.618, 89.4549); - - //get weapon - thrall_walkAI->AddWaypoint(9, 2181.28, 118.612, 89.4549,8000); - //get armor - thrall_walkAI->AddWaypoint(10, 2181.62, 120.385, 89.4549,5000); - - thrall_walkAI->AddWaypoint(11, 2189.44, 113.922, 89.4549); - thrall_walkAI->AddWaypoint(12, 2195.63, 110.584, 89.4549); - thrall_walkAI->AddWaypoint(13, 2201.09, 115.115, 89.4549); - thrall_walkAI->AddWaypoint(14, 2204.34, 121.036, 89.4355); - //first ambush - thrall_walkAI->AddWaypoint(15, 2208.66, 129.127, 87.9560); - thrall_walkAI->AddWaypoint(16, 2193.09, 137.940, 88.2164); - thrall_walkAI->AddWaypoint(17, 2173.39, 149.064, 87.9227); - thrall_walkAI->AddWaypoint(18, 2164.25, 137.965, 85.0595); - thrall_walkAI->AddWaypoint(19, 2149.31, 125.645, 77.0858); - thrall_walkAI->AddWaypoint(20, 2142.78, 127.173, 75.5954); - //second ambush - thrall_walkAI->AddWaypoint(21, 2139.28, 133.952, 73.6386); - thrall_walkAI->AddWaypoint(22, 2139.54, 155.235, 67.1269); - thrall_walkAI->AddWaypoint(23, 2145.38, 167.551, 64.8974); - thrall_walkAI->AddWaypoint(24, 2134.28, 175.304, 67.9446); - thrall_walkAI->AddWaypoint(25, 2118.08, 187.387, 68.8141); - //third ambush - thrall_walkAI->AddWaypoint(26, 2105.88, 195.461, 65.1854); - thrall_walkAI->AddWaypoint(27, 2096.77, 196.939, 65.2117); - thrall_walkAI->AddWaypoint(28, 2083.90, 209.395, 64.8736); - //in front of keeps gate, meeting scarloc - thrall_walkAI->AddWaypoint(29, 2067.84, 224.376, 64.8022,30000); - - //ref point after skarloc fight - thrall_walkAI->AddWaypoint(30, 2055.40, 242.90, 63.3418); - - //mount up! - thrall_walkAI->AddWaypoint(31, 2039.20, 266.460, 63.0182,10000); - thrall_walkAI->AddWaypoint(32, 2011.77, 278.478, 65.3388); - thrall_walkAI->AddWaypoint(33, 2005.08, 289.676, 66.1179); - thrall_walkAI->AddWaypoint(34, 2033.11, 337.450, 66.0948); - thrall_walkAI->AddWaypoint(35, 2070.30, 416.208, 66.0893); - thrall_walkAI->AddWaypoint(36, 2086.76, 469.768, 65.9182); - //possible road ambush - thrall_walkAI->AddWaypoint(37, 2101.70, 497.955, 61.7881); - - thrall_walkAI->AddWaypoint(38, 2133.39, 530.933, 55.3700,5000); - thrall_walkAI->AddWaypoint(39, 2157.91, 559.635, 48.5157); - thrall_walkAI->AddWaypoint(40, 2167.34, 586.191, 42.4394); - thrall_walkAI->AddWaypoint(41, 2174.17, 637.643, 33.9002); - thrall_walkAI->AddWaypoint(42, 2179.31, 656.053, 34.723); - thrall_walkAI->AddWaypoint(43, 2183.65, 670.941, 34.0318); - thrall_walkAI->AddWaypoint(44, 2201.50, 668.616, 36.1236); - thrall_walkAI->AddWaypoint(45, 2221.56, 652.747, 36.6153); - thrall_walkAI->AddWaypoint(46, 2238.97, 640.125, 37.2214); - thrall_walkAI->AddWaypoint(47, 2251.17, 620.574, 40.1473); - thrall_walkAI->AddWaypoint(48, 2261.98, 595.303, 41.4117); - thrall_walkAI->AddWaypoint(49, 2278.67, 560.172, 38.9090); - thrall_walkAI->AddWaypoint(50, 2336.72, 528.327, 40.9369); - thrall_walkAI->AddWaypoint(51, 2381.04, 519.612, 37.7312); - thrall_walkAI->AddWaypoint(52, 2412.20, 515.425, 39.2068); - thrall_walkAI->AddWaypoint(53, 2452.39, 516.174, 42.9387); - thrall_walkAI->AddWaypoint(54, 2467.38, 539.389, 47.4992); - thrall_walkAI->AddWaypoint(55, 2470.70, 554.333, 46.6668); - thrall_walkAI->AddWaypoint(56, 2478.07, 575.321, 55.4549); - thrall_walkAI->AddWaypoint(57, 2480.00, 585.408, 56.6921); - thrall_walkAI->AddWaypoint(58, 2482.67, 608.817, 55.6643); - //demount - thrall_walkAI->AddWaypoint(59, 2485.62, 626.061, 58.0132,2000); - //scare the shit out of horse, so it'll run off - thrall_walkAI->AddWaypoint(60, 2486.91, 626.356, 58.0761); - - thrall_walkAI->AddWaypoint(61, 2488.58, 660.940, 57.3913); - thrall_walkAI->AddWaypoint(62, 2502.56, 686.059, 55.6252); - thrall_walkAI->AddWaypoint(63, 2502.08, 694.360, 55.5083); - thrall_walkAI->AddWaypoint(64, 2491.46, 694.321, 55.7163); - thrall_walkAI->AddWaypoint(65, 2491.10, 703.300, 55.7630); - thrall_walkAI->AddWaypoint(66, 2485.64, 702.992, 55.7917); - - thrall_walkAI->AddWaypoint(67, 2479.10, 695.291, 55.7901,10000); - //spawn mobs - thrall_walkAI->AddWaypoint(68, 2476.75, 693.689, 55.7960); - thrall_walkAI->AddWaypoint(69, 2475.39, 695.983, 55.8146); - thrall_walkAI->AddWaypoint(70, 2477.75, 694.473, 55.7945); - //meet mobs in doorway - thrall_walkAI->AddWaypoint(71, 2481.27, 697.747, 55.7910); - - thrall_walkAI->AddWaypoint(72, 2486.31, 703.131, 55.7861,5000); - thrall_walkAI->AddWaypoint(73, 2490.76, 703.511, 55.7662); - thrall_walkAI->AddWaypoint(74, 2491.30, 694.792, 55.7195); - thrall_walkAI->AddWaypoint(75, 2518.69, 693.876, 55.1383); - thrall_walkAI->AddWaypoint(76, 2531.33, 681.914, 55.1383); - thrall_walkAI->AddWaypoint(77, 2568.25, 682.654, 55.1778); - thrall_walkAI->AddWaypoint(78, 2589.61, 689.981, 55.1421); - thrall_walkAI->AddWaypoint(79, 2634.74, 679.833, 54.6613); - thrall_walkAI->AddWaypoint(80, 2630.41, 661.464, 54.2761); - thrall_walkAI->AddWaypoint(81, 2629.00, 656.982, 56.0651); - //stop in church - thrall_walkAI->AddWaypoint(82, 2620.84, 633.007, 56.0300,3000); - //summon - thrall_walkAI->AddWaypoint(83, 2622.99, 639.178, 56.0300); - - thrall_walkAI->AddWaypoint(84, 2628.73, 656.693, 56.0610,5000); - thrall_walkAI->AddWaypoint(85, 2630.34, 661.135, 54.2738); - thrall_walkAI->AddWaypoint(86, 2635.38, 672.243, 54.4508); - thrall_walkAI->AddWaypoint(87, 2644.13, 668.158, 55.3797); - thrall_walkAI->AddWaypoint(88, 2646.82, 666.740, 56.9898); - thrall_walkAI->AddWaypoint(89, 2658.22, 665.432, 57.1725); - thrall_walkAI->AddWaypoint(90, 2661.88, 674.849, 57.1725); - thrall_walkAI->AddWaypoint(91, 2656.23, 677.208, 57.1725); - - thrall_walkAI->AddWaypoint(92, 2652.28, 670.270, 61.9353); - //summon inn - thrall_walkAI->AddWaypoint(93, 2650.79, 664.290, 61.9302); - thrall_walkAI->AddWaypoint(94, 2658.19, 660.454, 61.9320,5000); - //speak with Taretha - thrall_walkAI->AddWaypoint(95, 2660.57, 659.173, 61.9370); - - //epoch calls - thrall_walkAI->AddWaypoint(96, 2658.19, 660.454, 61.9320,5000); - //taretha "dies" - thrall_walkAI->AddWaypoint(97, 2659.84, 659.482, 61.9361,5000); - - thrall_walkAI->AddWaypoint(98, 2654.28, 662.722, 61.9313); - thrall_walkAI->AddWaypoint(99, 2652.37, 670.561, 61.9368); - thrall_walkAI->AddWaypoint(100, 2656.05, 676.761, 57.1727); - thrall_walkAI->AddWaypoint(101, 2658.49, 677.166, 57.1727); - thrall_walkAI->AddWaypoint(102, 2659.28, 667.117, 57.1727); - thrall_walkAI->AddWaypoint(103, 2649.71, 665.387, 57.1727); - //he's outside inn here - thrall_walkAI->AddWaypoint(104, 2634.79, 672.964, 54.4577); - - //getting ready here, must start attack before 30secs up - thrall_walkAI->AddWaypoint(105, 2635.06, 673.892, 54.4713,30000); - - //ref point, will move here when all dead and meet Taretha - thrall_walkAI->AddWaypoint(106, 2634.79, 672.964, 54.4577,60000); - - //run off - thrall_walkAI->AddWaypoint(107, 2631.72, 665.629, 54.2923); - thrall_walkAI->AddWaypoint(108, 2647.40, 640.530, 55.7634); - - return (CreatureAI*)thrall_walkAI; -} - -bool GossipHello_npc_thrall_old_hillsbrad(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - if( pInstance ) - { - //if( pInstance->GetData(TYPE_BARREL_DIVERSION) == DONE && pInstance->GetData(TYPE_THRALL_EVENT) == NOT_STARTED ) - if( pInstance->GetData(TYPE_THRALL_EVENT) == NOT_STARTED ) - { - player->ADD_GOSSIP_ITEM( 0, "[PH] Start walking.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(GOSSIP_ID_START, _Creature->GetGUID()); - } - if( pInstance->GetData(TYPE_THRALL_PART1) == DONE && !pInstance->GetData(TYPE_THRALL_PART2) ) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_SKARLOC1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(GOSSIP_ID_SKARLOC1, _Creature->GetGUID()); - } - if( pInstance->GetData(TYPE_THRALL_PART2) == DONE && !pInstance->GetData(TYPE_THRALL_PART3) ) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_TARREN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(GOSSIP_ID_TARREN, _Creature->GetGUID()); - } - } - return true; -} - -bool GossipSelect_npc_thrall_old_hillsbrad(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - switch( action ) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->CLOSE_GOSSIP_MENU(); - pInstance->SetData(TYPE_THRALL_EVENT,IN_PROGRESS); - pInstance->SetData(TYPE_THRALL_PART1,IN_PROGRESS); - - _Creature->Say(THRALL_START_EVENT_PART1, LANG_UNIVERSAL, 0); - ((npc_thrall_old_hillsbradAI*)_Creature->AI())->DoPlaySoundToSet(_Creature,SOUND_START_EVENT); - - ((npc_escortAI*)(_Creature->AI()))->Start(true, true, true, player->GetGUID()); - break; - - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_SKARLOC2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+20); - player->SEND_GOSSIP_MENU(GOSSIP_ID_SKARLOC2, _Creature->GetGUID()); - break; - - case GOSSIP_ACTION_INFO_DEF+20: - player->SEND_GOSSIP_MENU(GOSSIP_ID_SKARLOC3, _Creature->GetGUID()); - _Creature->SummonCreature(SKARLOC_MOUNT,2038.81,270.26,63.20,5.41,TEMPSUMMON_TIMED_DESPAWN,12000); - pInstance->SetData(TYPE_THRALL_PART2,IN_PROGRESS); - - _Creature->Say(THRALL_START_EVENT_PART2, LANG_UNIVERSAL, 0); - ((npc_thrall_old_hillsbradAI*)_Creature->AI())->DoPlaySoundToSet(_Creature,SOUND_START_EVENT_PART2); - - ((npc_thrall_old_hillsbradAI*)_Creature->AI())->StartWP(); - break; - - case GOSSIP_ACTION_INFO_DEF+3: - player->CLOSE_GOSSIP_MENU(); - pInstance->SetData(TYPE_THRALL_PART3,IN_PROGRESS); - ((npc_thrall_old_hillsbradAI*)_Creature->AI())->StartWP(); - break; - } - return true; -} - -/*###### -## npc_taretha -######*/ - -#define GOSSIP_ID_EPOCH1 9610 //Thank you for helping Thrall escape, friends. Now I only hope -#define GOSSIP_ITEM_EPOCH1 "Strange wizard?" -#define GOSSIP_ID_EPOCH2 9613 //Yes, friends. This man was no wizard of -#define GOSSIP_ITEM_EPOCH2 "We'll get you out. Taretha. Don't worry. I doubt the wizard would wander too far away." - -#define TARETHA_FREE "I'm free! Thank you all!" - -struct MANGOS_DLL_DECL npc_tarethaAI : public npc_escortAI -{ - npc_tarethaAI(Creature *c) : npc_escortAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - void WaypointReached(uint32 i) - { - switch( i ) - { - case 6: - m_creature->Say(TARETHA_FREE, LANG_UNIVERSAL, 0); - break; - case 7: - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_CHEER); - break; - } - } - void Reset() {} - void Aggro(Unit* who) {} - -}; -CreatureAI* GetAI_npc_taretha(Creature *_Creature) -{ - npc_tarethaAI* taretha_walkAI = new npc_tarethaAI(_Creature); - - taretha_walkAI->AddWaypoint(0, 2650.06, 665.473, 61.9305); - taretha_walkAI->AddWaypoint(1, 2652.44, 670.761, 61.9370); - taretha_walkAI->AddWaypoint(2, 2655.96, 676.913, 57.1725); - taretha_walkAI->AddWaypoint(3, 2659.40, 677.317, 57.1725); - taretha_walkAI->AddWaypoint(4, 2651.75, 664.482, 57.1725); - taretha_walkAI->AddWaypoint(5, 2647.49, 666.595, 57.0824); - taretha_walkAI->AddWaypoint(6, 2644.37, 668.167, 55.4182); - taretha_walkAI->AddWaypoint(7, 2640.96, 669.890, 54.7567,60000); - - return (CreatureAI*)taretha_walkAI; -} - -bool GossipHello_npc_taretha(Player *player, Creature *_Creature) -{ - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - if( pInstance && pInstance->GetData(TYPE_THRALL_PART3) == DONE && pInstance->GetData(TYPE_THRALL_PART4) == NOT_STARTED) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_EPOCH1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(GOSSIP_ID_EPOCH1, _Creature->GetGUID()); - } - return true; -} - -bool GossipSelect_npc_taretha(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - if( action == GOSSIP_ACTION_INFO_DEF+1 ) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_EPOCH2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(GOSSIP_ID_EPOCH2, _Creature->GetGUID()); - } - if( action == GOSSIP_ACTION_INFO_DEF+2 ) - { - player->CLOSE_GOSSIP_MENU(); - - if( pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS ) - { - pInstance->SetData(TYPE_THRALL_PART4,IN_PROGRESS); - _Creature->SummonCreature(18096,2639.13,698.55,65.43,4.59,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,120000); - - uint64 ThrallGUID = pInstance->GetData64(DATA_THRALL); - if(ThrallGUID) - { - Creature* Thrall = ((Creature*)Unit::GetUnit((*_Creature), ThrallGUID)); - if(Thrall) - ((npc_thrall_old_hillsbradAI*)Thrall->AI())->StartWP(); - } - } - } - return true; -} - -/*###### -## AddSC -######*/ - -void AddSC_old_hillsbrad() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_brazen"; - newscript->pGossipHello = &GossipHello_npc_brazen; - newscript->pGossipSelect = &GossipSelect_npc_brazen; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_erozion"; - newscript->pGossipHello = &GossipHello_npc_erozion; - newscript->pGossipSelect = &GossipSelect_npc_erozion; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_thrall_old_hillsbrad"; - newscript->pGossipHello = &GossipHello_npc_thrall_old_hillsbrad; - newscript->pGossipSelect = &GossipSelect_npc_thrall_old_hillsbrad; - newscript->GetAI = GetAI_npc_thrall_old_hillsbrad; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_taretha"; - newscript->pGossipHello = &GossipHello_npc_taretha; - newscript->pGossipSelect = &GossipSelect_npc_taretha; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Old_Hillsbrad +SD%Complete: 40 +SDComment: All friendly NPC's. Thrall waypoints fairly complete, missing many details, but possible to complete escort. +SDCategory: Caverns of Time, Old Hillsbrad Foothills +EndScriptData */ + +/* ContentData +npc_brazen +npc_erozion +npc_thrall_old_hillsbrad +npc_taretha +EndContentData */ + +#include "precompiled.h" +#include "../../../npc/npc_escortAI.h" +#include "def_old_hillsbrad.h" + +#define QUEST_ENTRY_HILLSBRAD 10282 +#define QUEST_ENTRY_DIVERSION 10283 +#define QUEST_ENTRY_ESCAPE 10284 +#define QUEST_ENTRY_RETURN 10285 +#define ITEM_ENTRY_BOMBS 25853 + +/*###### +## npc_brazen +######*/ + +bool GossipHello_npc_brazen(Player *player, Creature *_Creature) +{ + player->ADD_GOSSIP_ITEM(0, "I am ready to go to Durnholde Keep.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_brazen(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + if( !player->HasItemCount(ITEM_ENTRY_BOMBS,1) ) + player->SEND_GOSSIP_MENU(9780, _Creature->GetGUID()); + else + { + player->CLOSE_GOSSIP_MENU(); + + std::vector nodes; + + nodes.resize(2); + nodes[0] = 115; //from brazen + nodes[1] = 116; //end outside durnholde + player->ActivateTaxiPathTo(nodes); //TaxiPath 534 + } + } + return true; +} + +/*###### +## npc_erozion +######*/ + +bool GossipHello_npc_erozion(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + if( pInstance && pInstance->GetData(TYPE_BARREL_DIVERSION) != DONE && !player->HasItemCount(ITEM_ENTRY_BOMBS,1) ) + player->ADD_GOSSIP_ITEM( 0, "I need a pack of Incendiary Bombs.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + if( !player->GetQuestRewardStatus(QUEST_ENTRY_RETURN) && player->GetQuestStatus(QUEST_ENTRY_RETURN) == QUEST_STATUS_COMPLETE ) + player->ADD_GOSSIP_ITEM( 0, "[PH] Teleport please, i'm tired.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + + player->SEND_GOSSIP_MENU(9778, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_erozion(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, ITEM_ENTRY_BOMBS, 1, false); + if( msg == EQUIP_ERR_OK ) + { + player->StoreNewItem( dest, ITEM_ENTRY_BOMBS, 1, true); + } + player->SEND_GOSSIP_MENU(9515, _Creature->GetGUID()); + } + if( action == GOSSIP_ACTION_INFO_DEF+2 ) + { + player->CLOSE_GOSSIP_MENU(); + } + return true; +} + +/*###### +## npc_thrall_old_hillsbrad +######*/ + +#define SPEED_WALK (0.5f) +#define SPEED_RUN (1.0f) +#define SPEED_MOUNT (1.6f) + +#define THRALL_WEAPON_MODEL 22106 +#define THRALL_WEAPON_INFO 218169346 +#define THRALL_SHIELD_MODEL 18662 +#define THRALL_SHIELD_INFO 234948100 +#define THRALL_MODEL_UNEQUIPPED 17292 +#define THRALL_MODEL_EQUIPPED 18165 + +#define MOB_ENTRY_RIFLE 17820 +#define MOB_ENTRY_WARDEN 17833 +#define MOB_ENTRY_VETERAN 17860 +#define MOB_ENTRY_WATCHMAN 17814 +#define MOB_ENTRY_SENTRY 17815 + +#define MOB_ENTRY_BARN_GUARDSMAN 18092 +#define MOB_ENTRY_BARN_PROTECTOR 18093 +#define MOB_ENTRY_BARN_LOOKOUT 18094 + +#define MOB_ENTRY_CHURCH_GUARDSMAN 23175 +#define MOB_ENTRY_CHURCH_PROTECTOR 23179 +#define MOB_ENTRY_CHURCH_LOOKOUT 23177 + +#define MOB_ENTRY_INN_GUARDSMAN 23176 +#define MOB_ENTRY_INN_PROTECTOR 23180 +#define MOB_ENTRY_INN_LOOKOUT 23178 + +#define SKARLOC_MOUNT 18798 +#define SKARLOC_MOUNT_MODEL 18223 +#define EROZION_ENTRY 18723 + +#define GOSSIP_ID_START 9568 +#define GOSSIP_ID_SKARLOC1 9614 //I'm glad Taretha is alive. We now must find a way to free her... +#define GOSSIP_ITEM_SKARLOC1 "Taretha cannot see you, Thrall." +#define GOSSIP_ID_SKARLOC2 9579 //What do you mean by this? Is Taretha in danger? +#define GOSSIP_ITEM_SKARLOC2 "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." +#define GOSSIP_ID_SKARLOC3 9580 + +#define GOSSIP_ID_TARREN 9597 //tarren mill is beyond these trees +#define GOSSIP_ITEM_TARREN "We're ready, Thrall." + +#define GOSSIP_ID_COMPLETE 9578 //Thank you friends, I owe my freedom to you. Where is Taretha? I hoped to see her + +#define THRALL_START_EVENT_PART1 "Very well then. Let's go!" +#define SOUND_START_EVENT 10465 + +#define THRALL_SAY_ARMOR "As long as we're going with a new plan, I may aswell pick up a weapon and some armor." + +#define THRALL_SKARLOC_MEET "A rider approaches!" +#define SOUND_SKARLOC_MEET 10466 +#define THRALL_SKARLOC_TAUNT "I'll never be chained again!" +#define SOUND_SKARLOC_TAUNT 10467 + +#define THRALL_START_EVENT_PART2 "Very well. Tarren Mill lies just west of here. Since time is of the essence..." +#define SOUND_START_EVENT_PART2 10468 +#define THRALL_MOUNTS_UP "Let's ride!" +#define SOUND_MOUNTS_UP 10469 + +#define THRALL_CHURCH_END "Taretha must be in the inn. Let's go." +#define THRALL_MEET_TARETHA "Taretha! What foul magic is this?" + +#define THRALL_EPOCH_WONDER "Who or what was that?" +#define SOUND_EPOCH_WONDER 10470 +#define THRALL_EPOCH_KILL_TARETHA "No!" +#define SOUND_EPOCH_KILL_TARETHA 10471 + +#define THRALL_EVENT_COMPLETE "Goodbye, Taretha. I will never forget your kindness." +#define SOUND_EVENT_COMPLETE 10472 + +#define THRALL_RANDOM_LOW_HP1 "Things are looking grim..." +#define SOUND_RANDOM_LOW_HP1 10458 +#define THRALL_RANDOM_LOW_HP2 "I will fight to the last!" +#define SOUND_RANDOM_LOW_HP2 10459 + +#define THRALL_RANDOM_DIE1 "Taretha..." +#define SOUND_RANDOM_DIE1 10460 +#define THRALL_RANDOM_DIE2 "A good day...to die..." +#define SOUND_RANDOM_DIE2 10461 + +#define THRALL_RANDOM_AGGRO1 "I have earned my freedom!" +#define SOUND_RANDOM_AGGRO1 10448 +#define THRALL_RANDOM_AGGRO2 "This day is long overdue. Out of my way!" +#define SOUND_RANDOM_AGGRO2 10449 +#define THRALL_RANDOM_AGGRO3 "I am a slave no longer!" +#define SOUND_RANDOM_AGGRO3 10450 +#define THRALL_RANDOM_AGGRO4 "Blackmoore has much to answer for!" +#define SOUND_RANDOM_AGGRO4 10451 + +#define THRALL_RANDOM_KILL1 "You have forced my hand!" +#define SOUND_RANDOM_KILL1 10452 +#define THRALL_RANDOM_KILL2 "It should not have come to this!" +#define SOUND_RANDOM_KILL2 10453 +#define THRALL_RANDOM_KILL3 "I did not ask for this!" +#define SOUND_RANDOM_KILL3 10454 + +#define THRALL_LEAVE_COMBAT1 "I am truly in your debt, strangers." +#define SOUND_LEAVE_COMBAT1 10455 +#define THRALL_LEAVE_COMBAT2 "Thank you, strangers. You have given me hope." +#define SOUND_LEAVE_COMBAT2 10456 +#define THRALL_LEAVE_COMBAT3 "I will not waste this chance. I will seek out my destiny." +#define SOUND_LEAVE_COMBAT3 10457 + +struct MANGOS_DLL_DECL npc_thrall_old_hillsbradAI : public npc_escortAI +{ + npc_thrall_old_hillsbradAI(Creature *c) : npc_escortAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + Creature* sum; + uint64 TarethaGUID; + bool LowHp; + bool HadMount; + + void WaypointReached(uint32 i) + { + switch( i ) + { + case 8: + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + sum = m_creature->SummonCreature(18764,2181.87,112.46,89.45,0.26,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + break; + case 9: + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + DoSay(THRALL_SAY_ARMOR, LANG_UNIVERSAL, NULL); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, THRALL_WEAPON_MODEL); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, THRALL_WEAPON_INFO); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+1, 781); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, THRALL_SHIELD_MODEL); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+2, THRALL_SHIELD_INFO); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+3, 1038); + break; + case 10: + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, THRALL_MODEL_EQUIPPED); + break; + case 11: + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + break; + case 15: + sum = m_creature->SummonCreature(MOB_ENTRY_RIFLE,2200.28,137.37,87.93,5.07,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_WARDEN,2197.44,131.83,87.93,0.78,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2203.62,135.40,87.93,3.70,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2200.75,130.13,87.93,1.48,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + break; + case 21: + sum = m_creature->SummonCreature(MOB_ENTRY_RIFLE,2135.80,154.01,67.45,4.98,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_WARDEN,2144.36,151.87,67.74,4.46,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2142.12,154.41,67.12,4.56,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2138.08,155.38,67.24,4.60,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + break; + case 25: + sum = m_creature->SummonCreature(MOB_ENTRY_RIFLE,2102.98,192.17,65.24,6.02,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_WARDEN,2108.48,198.75,65.18,5.15,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2106.11,197.29,65.18,5.63,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_VETERAN,2104.18,194.82,65.18,5.75,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + break; + case 29: + DoSay(THRALL_SKARLOC_MEET, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SKARLOC_MEET); + sum = m_creature->SummonCreature(17862,2036.48,271.22,63.43,5.27,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); + //temporary,skarloc should rather be triggered to walk up to thrall + if( sum ) sum->AI()->AttackStart(m_creature); + break; + case 30: + IsOnHold = true; + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + break; + case 31: + DoSay(THRALL_MOUNTS_UP, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_MOUNTS_UP); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + DoMount(); + break; + case 37: + //possibly regular patrollers? If so, remove this and let database handle them + sum = m_creature->SummonCreature(MOB_ENTRY_WATCHMAN,2124.26,522.16,56.87,3.99,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_WATCHMAN,2121.69,525.37,57.11,4.01,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_SENTRY,2124.65,524.55,56.63,3.98,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + break; + case 59: + m_creature->SummonCreature(SKARLOC_MOUNT,2488.64,625.77,58.26,4.71,TEMPSUMMON_TIMED_DESPAWN,10000); + DoUnmount(); + HadMount = false; + break; + case 60: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + //make horsie run off + IsOnHold = true; + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + if( pInstance ) + pInstance->SetData(TYPE_THRALL_PART2, DONE); + break; + case 64: + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + break; + case 68: + m_creature->SummonCreature(MOB_ENTRY_BARN_PROTECTOR,2500.22,692.60,55.50,2.84,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + m_creature->SummonCreature(MOB_ENTRY_BARN_LOOKOUT,2500.13,696.55,55.51,3.38,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + m_creature->SummonCreature(MOB_ENTRY_BARN_GUARDSMAN,2500.55,693.64,55.50,3.14,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + m_creature->SummonCreature(MOB_ENTRY_BARN_GUARDSMAN,2500.94,695.81,55.50,3.14,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + break; + case 71: + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + break; + case 81: + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + break; + case 83: + sum = m_creature->SummonCreature(MOB_ENTRY_CHURCH_PROTECTOR,2627.33,646.82,56.03,4.28,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_CHURCH_LOOKOUT,2624.14,648.03,56.03,4.50,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_CHURCH_GUARDSMAN,2625.32,649.60,56.03,4.38,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_CHURCH_GUARDSMAN,2627.22,649.00,56.03,4.34,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + break; + case 84: + DoSay(THRALL_CHURCH_END, LANG_UNIVERSAL, NULL); + break; + case 91: + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + case 93: + sum = m_creature->SummonCreature(MOB_ENTRY_INN_PROTECTOR,2652.71,660.31,61.93,1.67,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_INN_LOOKOUT,2648.96,662.59,61.93,0.79,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_INN_GUARDSMAN,2657.36,662.34,61.93,2.68,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + sum = m_creature->SummonCreature(MOB_ENTRY_INN_GUARDSMAN,2656.39,659.77,61.93,2.61,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if( sum ) sum->AI()->AttackStart(m_creature); + break; + case 94: + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + //trigger taretha Say("Thrall, you escaped!") + break; + case 95: + DoSay(THRALL_MEET_TARETHA, LANG_UNIVERSAL, NULL); + if( pInstance ) + pInstance->SetData(TYPE_THRALL_PART3,DONE); + IsOnHold = true; + break; + case 96: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + DoYell(THRALL_EPOCH_WONDER, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_EPOCH_WONDER); + break; + case 97: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + DoYell(THRALL_EPOCH_KILL_TARETHA, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_EPOCH_KILL_TARETHA); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + break; + case 98: + //trigger epoch Yell("Thrall! Come outside and face your fate! ....") + break; + case 106: + { + //trigger taretha to run down outside + /*if( pInstance ) + uint64 TarethaGUID = pInstance->GetData64(DATA_TARETHA); + if( TarethaGUID ) + { + Creature* Taretha = ((Creature*)Unit::GetUnit((*m_creature), TarethaGUID)); + if( Taretha ) + ((npc_escortAI*)(Taretha->AI()))->Start(false, false, true, 0); + }*/ + + if( PlayerGUID ) + { + Unit* player = ((Creature*)Unit::GetUnit((*m_creature), PlayerGUID)); + if( player && player->GetTypeId() == TYPEID_PLAYER ) + ((Player*)player)->KilledMonster(20156,m_creature->GetGUID()); + } + + //alot will happen here, thrall and taretha talk, erozion appear at spot to explain + m_creature->SummonCreature(EROZION_ENTRY,2646.47,680.416,55.38,4.16,TEMPSUMMON_TIMED_DESPAWN,120000); + } + break; + } + } + + void Reset() + { + sum = NULL; + LowHp = false; + + if( HadMount ) + DoMount(); + + if( !IsBeingEscorted ) + { + DoUnmount(); + HadMount = false; + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+1, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+2, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+3, 0); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, THRALL_MODEL_UNEQUIPPED); + } + if( IsBeingEscorted ) + { + switch(rand()%3) + { + case 0: + DoYell(THRALL_LEAVE_COMBAT1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_LEAVE_COMBAT1); + break; + case 1: + DoYell(THRALL_LEAVE_COMBAT2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_LEAVE_COMBAT2); + break; + case 2: + DoYell(THRALL_LEAVE_COMBAT3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_LEAVE_COMBAT3); + break; + } + } + } + void StartWP() + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + IsOnHold = false; + } + void DoMount() + { + m_creature->Mount(SKARLOC_MOUNT_MODEL); + m_creature->SetSpeed(MOVE_RUN,SPEED_MOUNT); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + } + void DoUnmount() + { + m_creature->Unmount(); + m_creature->SetSpeed(MOVE_RUN,SPEED_RUN); + } + void Aggro(Unit* who) + { + switch(rand()%4) + { + case 0: + DoYell(THRALL_RANDOM_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_AGGRO1); + break; + case 1: + DoYell(THRALL_RANDOM_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_AGGRO2); + break; + case 2: + DoYell(THRALL_RANDOM_AGGRO3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_AGGRO3); + break; + case 3: + DoYell(THRALL_RANDOM_AGGRO4,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_AGGRO4); + break; + } + if( m_creature->IsMounted() ) + { + DoUnmount(); + HadMount = true; + } + } + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoYell(THRALL_RANDOM_KILL1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_KILL1); + break; + case 1: + DoYell(THRALL_RANDOM_KILL2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_KILL2); + break; + case 2: + DoYell(THRALL_RANDOM_KILL3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_KILL3); + break; + } + } + void JustDied(Unit *slayer) + { + if(slayer == m_creature) // Don't do a yell if he kills self (if player goes too far or at the end). + return; + + switch(rand()%2) + { + case 0: + DoYell(THRALL_RANDOM_DIE1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_DIE1); + break; + case 1: + DoYell(THRALL_RANDOM_DIE2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_DIE2); + break; + } + if( pInstance ) + pInstance->SetData(TYPE_THRALL_EVENT,FAIL); + } + void UpdateAI(const uint32 diff) + { + npc_escortAI::UpdateAI(diff); + + if( InCombat && m_creature->getVictim() ) + { + //add his abilities'n-crap here + + if( !LowHp && ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) ) + { + switch(rand()%2) + { + case 0: + DoYell(THRALL_RANDOM_LOW_HP1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_LOW_HP1); + break; + case 1: + DoYell(THRALL_RANDOM_LOW_HP2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RANDOM_LOW_HP2); + break; + } + LowHp = true; + } + } + } +}; + +CreatureAI* GetAI_npc_thrall_old_hillsbrad(Creature *_Creature) +{ + npc_thrall_old_hillsbradAI* thrall_walkAI = new npc_thrall_old_hillsbradAI(_Creature); + + thrall_walkAI->AddWaypoint(0, 2230.91, 118.765, 82.2947,5000); + thrall_walkAI->AddWaypoint(1, 2230.33, 114.980, 82.2946); + thrall_walkAI->AddWaypoint(2, 2233.36, 111.057, 82.2996); + thrall_walkAI->AddWaypoint(3, 2231.17, 108.486, 82.6624); + thrall_walkAI->AddWaypoint(4, 2220.22, 114.605, 89.4264); + thrall_walkAI->AddWaypoint(5, 2215.23, 115.990, 89.4549); + thrall_walkAI->AddWaypoint(6, 2210.00, 106.849, 89.4549); + thrall_walkAI->AddWaypoint(7, 2205.66, 105.234, 89.4549); + //spawn armorer + thrall_walkAI->AddWaypoint(8, 2192.26, 112.618, 89.4549); + + //get weapon + thrall_walkAI->AddWaypoint(9, 2181.28, 118.612, 89.4549,8000); + //get armor + thrall_walkAI->AddWaypoint(10, 2181.62, 120.385, 89.4549,5000); + + thrall_walkAI->AddWaypoint(11, 2189.44, 113.922, 89.4549); + thrall_walkAI->AddWaypoint(12, 2195.63, 110.584, 89.4549); + thrall_walkAI->AddWaypoint(13, 2201.09, 115.115, 89.4549); + thrall_walkAI->AddWaypoint(14, 2204.34, 121.036, 89.4355); + //first ambush + thrall_walkAI->AddWaypoint(15, 2208.66, 129.127, 87.9560); + thrall_walkAI->AddWaypoint(16, 2193.09, 137.940, 88.2164); + thrall_walkAI->AddWaypoint(17, 2173.39, 149.064, 87.9227); + thrall_walkAI->AddWaypoint(18, 2164.25, 137.965, 85.0595); + thrall_walkAI->AddWaypoint(19, 2149.31, 125.645, 77.0858); + thrall_walkAI->AddWaypoint(20, 2142.78, 127.173, 75.5954); + //second ambush + thrall_walkAI->AddWaypoint(21, 2139.28, 133.952, 73.6386); + thrall_walkAI->AddWaypoint(22, 2139.54, 155.235, 67.1269); + thrall_walkAI->AddWaypoint(23, 2145.38, 167.551, 64.8974); + thrall_walkAI->AddWaypoint(24, 2134.28, 175.304, 67.9446); + thrall_walkAI->AddWaypoint(25, 2118.08, 187.387, 68.8141); + //third ambush + thrall_walkAI->AddWaypoint(26, 2105.88, 195.461, 65.1854); + thrall_walkAI->AddWaypoint(27, 2096.77, 196.939, 65.2117); + thrall_walkAI->AddWaypoint(28, 2083.90, 209.395, 64.8736); + //in front of keeps gate, meeting scarloc + thrall_walkAI->AddWaypoint(29, 2067.84, 224.376, 64.8022,30000); + + //ref point after skarloc fight + thrall_walkAI->AddWaypoint(30, 2055.40, 242.90, 63.3418); + + //mount up! + thrall_walkAI->AddWaypoint(31, 2039.20, 266.460, 63.0182,10000); + thrall_walkAI->AddWaypoint(32, 2011.77, 278.478, 65.3388); + thrall_walkAI->AddWaypoint(33, 2005.08, 289.676, 66.1179); + thrall_walkAI->AddWaypoint(34, 2033.11, 337.450, 66.0948); + thrall_walkAI->AddWaypoint(35, 2070.30, 416.208, 66.0893); + thrall_walkAI->AddWaypoint(36, 2086.76, 469.768, 65.9182); + //possible road ambush + thrall_walkAI->AddWaypoint(37, 2101.70, 497.955, 61.7881); + + thrall_walkAI->AddWaypoint(38, 2133.39, 530.933, 55.3700,5000); + thrall_walkAI->AddWaypoint(39, 2157.91, 559.635, 48.5157); + thrall_walkAI->AddWaypoint(40, 2167.34, 586.191, 42.4394); + thrall_walkAI->AddWaypoint(41, 2174.17, 637.643, 33.9002); + thrall_walkAI->AddWaypoint(42, 2179.31, 656.053, 34.723); + thrall_walkAI->AddWaypoint(43, 2183.65, 670.941, 34.0318); + thrall_walkAI->AddWaypoint(44, 2201.50, 668.616, 36.1236); + thrall_walkAI->AddWaypoint(45, 2221.56, 652.747, 36.6153); + thrall_walkAI->AddWaypoint(46, 2238.97, 640.125, 37.2214); + thrall_walkAI->AddWaypoint(47, 2251.17, 620.574, 40.1473); + thrall_walkAI->AddWaypoint(48, 2261.98, 595.303, 41.4117); + thrall_walkAI->AddWaypoint(49, 2278.67, 560.172, 38.9090); + thrall_walkAI->AddWaypoint(50, 2336.72, 528.327, 40.9369); + thrall_walkAI->AddWaypoint(51, 2381.04, 519.612, 37.7312); + thrall_walkAI->AddWaypoint(52, 2412.20, 515.425, 39.2068); + thrall_walkAI->AddWaypoint(53, 2452.39, 516.174, 42.9387); + thrall_walkAI->AddWaypoint(54, 2467.38, 539.389, 47.4992); + thrall_walkAI->AddWaypoint(55, 2470.70, 554.333, 46.6668); + thrall_walkAI->AddWaypoint(56, 2478.07, 575.321, 55.4549); + thrall_walkAI->AddWaypoint(57, 2480.00, 585.408, 56.6921); + thrall_walkAI->AddWaypoint(58, 2482.67, 608.817, 55.6643); + //demount + thrall_walkAI->AddWaypoint(59, 2485.62, 626.061, 58.0132,2000); + //scare the shit out of horse, so it'll run off + thrall_walkAI->AddWaypoint(60, 2486.91, 626.356, 58.0761); + + thrall_walkAI->AddWaypoint(61, 2488.58, 660.940, 57.3913); + thrall_walkAI->AddWaypoint(62, 2502.56, 686.059, 55.6252); + thrall_walkAI->AddWaypoint(63, 2502.08, 694.360, 55.5083); + thrall_walkAI->AddWaypoint(64, 2491.46, 694.321, 55.7163); + thrall_walkAI->AddWaypoint(65, 2491.10, 703.300, 55.7630); + thrall_walkAI->AddWaypoint(66, 2485.64, 702.992, 55.7917); + + thrall_walkAI->AddWaypoint(67, 2479.10, 695.291, 55.7901,10000); + //spawn mobs + thrall_walkAI->AddWaypoint(68, 2476.75, 693.689, 55.7960); + thrall_walkAI->AddWaypoint(69, 2475.39, 695.983, 55.8146); + thrall_walkAI->AddWaypoint(70, 2477.75, 694.473, 55.7945); + //meet mobs in doorway + thrall_walkAI->AddWaypoint(71, 2481.27, 697.747, 55.7910); + + thrall_walkAI->AddWaypoint(72, 2486.31, 703.131, 55.7861,5000); + thrall_walkAI->AddWaypoint(73, 2490.76, 703.511, 55.7662); + thrall_walkAI->AddWaypoint(74, 2491.30, 694.792, 55.7195); + thrall_walkAI->AddWaypoint(75, 2518.69, 693.876, 55.1383); + thrall_walkAI->AddWaypoint(76, 2531.33, 681.914, 55.1383); + thrall_walkAI->AddWaypoint(77, 2568.25, 682.654, 55.1778); + thrall_walkAI->AddWaypoint(78, 2589.61, 689.981, 55.1421); + thrall_walkAI->AddWaypoint(79, 2634.74, 679.833, 54.6613); + thrall_walkAI->AddWaypoint(80, 2630.41, 661.464, 54.2761); + thrall_walkAI->AddWaypoint(81, 2629.00, 656.982, 56.0651); + //stop in church + thrall_walkAI->AddWaypoint(82, 2620.84, 633.007, 56.0300,3000); + //summon + thrall_walkAI->AddWaypoint(83, 2622.99, 639.178, 56.0300); + + thrall_walkAI->AddWaypoint(84, 2628.73, 656.693, 56.0610,5000); + thrall_walkAI->AddWaypoint(85, 2630.34, 661.135, 54.2738); + thrall_walkAI->AddWaypoint(86, 2635.38, 672.243, 54.4508); + thrall_walkAI->AddWaypoint(87, 2644.13, 668.158, 55.3797); + thrall_walkAI->AddWaypoint(88, 2646.82, 666.740, 56.9898); + thrall_walkAI->AddWaypoint(89, 2658.22, 665.432, 57.1725); + thrall_walkAI->AddWaypoint(90, 2661.88, 674.849, 57.1725); + thrall_walkAI->AddWaypoint(91, 2656.23, 677.208, 57.1725); + + thrall_walkAI->AddWaypoint(92, 2652.28, 670.270, 61.9353); + //summon inn + thrall_walkAI->AddWaypoint(93, 2650.79, 664.290, 61.9302); + thrall_walkAI->AddWaypoint(94, 2658.19, 660.454, 61.9320,5000); + //speak with Taretha + thrall_walkAI->AddWaypoint(95, 2660.57, 659.173, 61.9370); + + //epoch calls + thrall_walkAI->AddWaypoint(96, 2658.19, 660.454, 61.9320,5000); + //taretha "dies" + thrall_walkAI->AddWaypoint(97, 2659.84, 659.482, 61.9361,5000); + + thrall_walkAI->AddWaypoint(98, 2654.28, 662.722, 61.9313); + thrall_walkAI->AddWaypoint(99, 2652.37, 670.561, 61.9368); + thrall_walkAI->AddWaypoint(100, 2656.05, 676.761, 57.1727); + thrall_walkAI->AddWaypoint(101, 2658.49, 677.166, 57.1727); + thrall_walkAI->AddWaypoint(102, 2659.28, 667.117, 57.1727); + thrall_walkAI->AddWaypoint(103, 2649.71, 665.387, 57.1727); + //he's outside inn here + thrall_walkAI->AddWaypoint(104, 2634.79, 672.964, 54.4577); + + //getting ready here, must start attack before 30secs up + thrall_walkAI->AddWaypoint(105, 2635.06, 673.892, 54.4713,30000); + + //ref point, will move here when all dead and meet Taretha + thrall_walkAI->AddWaypoint(106, 2634.79, 672.964, 54.4577,60000); + + //run off + thrall_walkAI->AddWaypoint(107, 2631.72, 665.629, 54.2923); + thrall_walkAI->AddWaypoint(108, 2647.40, 640.530, 55.7634); + + return (CreatureAI*)thrall_walkAI; +} + +bool GossipHello_npc_thrall_old_hillsbrad(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + if( pInstance ) + { + //if( pInstance->GetData(TYPE_BARREL_DIVERSION) == DONE && pInstance->GetData(TYPE_THRALL_EVENT) == NOT_STARTED ) + if( pInstance->GetData(TYPE_THRALL_EVENT) == NOT_STARTED ) + { + player->ADD_GOSSIP_ITEM( 0, "[PH] Start walking.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(GOSSIP_ID_START, _Creature->GetGUID()); + } + if( pInstance->GetData(TYPE_THRALL_PART1) == DONE && !pInstance->GetData(TYPE_THRALL_PART2) ) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_SKARLOC1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(GOSSIP_ID_SKARLOC1, _Creature->GetGUID()); + } + if( pInstance->GetData(TYPE_THRALL_PART2) == DONE && !pInstance->GetData(TYPE_THRALL_PART3) ) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_TARREN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(GOSSIP_ID_TARREN, _Creature->GetGUID()); + } + } + return true; +} + +bool GossipSelect_npc_thrall_old_hillsbrad(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + switch( action ) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->CLOSE_GOSSIP_MENU(); + pInstance->SetData(TYPE_THRALL_EVENT,IN_PROGRESS); + pInstance->SetData(TYPE_THRALL_PART1,IN_PROGRESS); + + _Creature->Say(THRALL_START_EVENT_PART1, LANG_UNIVERSAL, 0); + ((npc_thrall_old_hillsbradAI*)_Creature->AI())->DoPlaySoundToSet(_Creature,SOUND_START_EVENT); + + ((npc_escortAI*)(_Creature->AI()))->Start(true, true, true, player->GetGUID()); + break; + + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_SKARLOC2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+20); + player->SEND_GOSSIP_MENU(GOSSIP_ID_SKARLOC2, _Creature->GetGUID()); + break; + + case GOSSIP_ACTION_INFO_DEF+20: + player->SEND_GOSSIP_MENU(GOSSIP_ID_SKARLOC3, _Creature->GetGUID()); + _Creature->SummonCreature(SKARLOC_MOUNT,2038.81,270.26,63.20,5.41,TEMPSUMMON_TIMED_DESPAWN,12000); + pInstance->SetData(TYPE_THRALL_PART2,IN_PROGRESS); + + _Creature->Say(THRALL_START_EVENT_PART2, LANG_UNIVERSAL, 0); + ((npc_thrall_old_hillsbradAI*)_Creature->AI())->DoPlaySoundToSet(_Creature,SOUND_START_EVENT_PART2); + + ((npc_thrall_old_hillsbradAI*)_Creature->AI())->StartWP(); + break; + + case GOSSIP_ACTION_INFO_DEF+3: + player->CLOSE_GOSSIP_MENU(); + pInstance->SetData(TYPE_THRALL_PART3,IN_PROGRESS); + ((npc_thrall_old_hillsbradAI*)_Creature->AI())->StartWP(); + break; + } + return true; +} + +/*###### +## npc_taretha +######*/ + +#define GOSSIP_ID_EPOCH1 9610 //Thank you for helping Thrall escape, friends. Now I only hope +#define GOSSIP_ITEM_EPOCH1 "Strange wizard?" +#define GOSSIP_ID_EPOCH2 9613 //Yes, friends. This man was no wizard of +#define GOSSIP_ITEM_EPOCH2 "We'll get you out. Taretha. Don't worry. I doubt the wizard would wander too far away." + +#define TARETHA_FREE "I'm free! Thank you all!" + +struct MANGOS_DLL_DECL npc_tarethaAI : public npc_escortAI +{ + npc_tarethaAI(Creature *c) : npc_escortAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + void WaypointReached(uint32 i) + { + switch( i ) + { + case 6: + m_creature->Say(TARETHA_FREE, LANG_UNIVERSAL, 0); + break; + case 7: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_CHEER); + break; + } + } + void Reset() {} + void Aggro(Unit* who) {} + +}; +CreatureAI* GetAI_npc_taretha(Creature *_Creature) +{ + npc_tarethaAI* taretha_walkAI = new npc_tarethaAI(_Creature); + + taretha_walkAI->AddWaypoint(0, 2650.06, 665.473, 61.9305); + taretha_walkAI->AddWaypoint(1, 2652.44, 670.761, 61.9370); + taretha_walkAI->AddWaypoint(2, 2655.96, 676.913, 57.1725); + taretha_walkAI->AddWaypoint(3, 2659.40, 677.317, 57.1725); + taretha_walkAI->AddWaypoint(4, 2651.75, 664.482, 57.1725); + taretha_walkAI->AddWaypoint(5, 2647.49, 666.595, 57.0824); + taretha_walkAI->AddWaypoint(6, 2644.37, 668.167, 55.4182); + taretha_walkAI->AddWaypoint(7, 2640.96, 669.890, 54.7567,60000); + + return (CreatureAI*)taretha_walkAI; +} + +bool GossipHello_npc_taretha(Player *player, Creature *_Creature) +{ + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + if( pInstance && pInstance->GetData(TYPE_THRALL_PART3) == DONE && pInstance->GetData(TYPE_THRALL_PART4) == NOT_STARTED) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_EPOCH1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(GOSSIP_ID_EPOCH1, _Creature->GetGUID()); + } + return true; +} + +bool GossipSelect_npc_taretha(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_EPOCH2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(GOSSIP_ID_EPOCH2, _Creature->GetGUID()); + } + if( action == GOSSIP_ACTION_INFO_DEF+2 ) + { + player->CLOSE_GOSSIP_MENU(); + + if( pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS ) + { + pInstance->SetData(TYPE_THRALL_PART4,IN_PROGRESS); + _Creature->SummonCreature(18096,2639.13,698.55,65.43,4.59,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,120000); + + uint64 ThrallGUID = pInstance->GetData64(DATA_THRALL); + if(ThrallGUID) + { + Creature* Thrall = ((Creature*)Unit::GetUnit((*_Creature), ThrallGUID)); + if(Thrall) + ((npc_thrall_old_hillsbradAI*)Thrall->AI())->StartWP(); + } + } + } + return true; +} + +/*###### +## AddSC +######*/ + +void AddSC_old_hillsbrad() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_brazen"; + newscript->pGossipHello = &GossipHello_npc_brazen; + newscript->pGossipSelect = &GossipSelect_npc_brazen; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_erozion"; + newscript->pGossipHello = &GossipHello_npc_erozion; + newscript->pGossipSelect = &GossipSelect_npc_erozion; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_thrall_old_hillsbrad"; + newscript->pGossipHello = &GossipHello_npc_thrall_old_hillsbrad; + newscript->pGossipSelect = &GossipSelect_npc_thrall_old_hillsbrad; + newscript->GetAI = GetAI_npc_thrall_old_hillsbrad; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_taretha"; + newscript->pGossipHello = &GossipHello_npc_taretha; + newscript->pGossipSelect = &GossipSelect_npc_taretha; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp index d21c3836d00..c36ffd251d7 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp @@ -1,559 +1,559 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Fathomlord_Karathress -SD%Complete: 50 -SDComment: Missing Multishot, pet, Totems, Windfury, Whirlwind -SDCategory: Coilfang Resevoir, Serpent Shrine Cavern -EndScriptData */ - -#include "precompiled.h" -#include "def_serpent_shrine.h" - -//Karathress spells -#define SPELL_CATACLYSMIC_BOLT 38441 -#define SPELL_POWER_OF_SHARKKIS 38455 -#define SPELL_POWER_OF_TIDALVESS 38452 -#define SPELL_POWER_OF_CARIBDIS 38451 -#define SPELL_ENRAGE 24318 -//Sharkkis spells -#define SPELL_LEECHING_THROW 29436 -#define SPELL_THE_BEAST_WITHIN 38373 -//Tidalvess spells -#define SPELL_FROST_SHOCK 38234 -//Caribdis Spells -#define SPELL_WATER_BOLT_VOLLEY 38335 -#define SPELL_TIDAL_SURGE 38353 -#define SPELL_HEAL 41386 - -#define SAY_AGGRO "Guards, attention! We have visitors..." -#define SAY_SLAY1 "I am rid of you." -#define SAY_GAIN_ABILITY1 "I am more powerful than ever!" -#define SAY_GAIN_ABILITY2 "Go on, kill them! I'll be the better for it!" -#define SAY_GAIN_ABILITY3 "More knowledge, more power!" -#define SAY_DEATH "Her ... excellency ... awaits!" - -#define SOUND_AGGRO 11277 -#define SOUND_PLYR_ATTACK 11278 -#define SOUND_GAIN_ABILITY1 11279 -#define SOUND_GAIN_ABILITY2 11280 -#define SOUND_GAIN_ABILITY3 11281 -#define SOUND_SLAY1 11282 -#define SOUND_SLAY2 11283 -#define SOUND_SLAY3 11284 -#define SOUND_DEATH 11285 - -//entry and position for Seer Olum -#define SEER_OLUM 22820 -#define OLUM_X 446.78f -#define OLUM_Y -542.76f -#define OLUM_Z -7.54773f -#define OLUM_O 0.401581f - -//Fathom-Lord Karathress AI -struct MANGOS_DLL_DECL boss_fathomlord_karathressAI : public ScriptedAI -{ - boss_fathomlord_karathressAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Advisors[0] = 0; - Advisors[1] = 0; - Advisors[2] = 0; - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 CataclysmicBolt_Timer; - uint32 Enrage_Timer; - - uint64 Advisors[3]; - - void Reset() - { - CataclysmicBolt_Timer = 10000; - Enrage_Timer = 600000; //10 minutes - - Creature* Advisor; - for(uint8 i = 0; i < 3; ++i) - if(Advisors[i]) - { - Advisor = ((Creature*)Unit::GetUnit(*m_creature, Advisors[i])); - if(Advisor) - { - if(Advisor->isAlive()) - { - Advisor->DealDamage(Advisor, Advisor->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - Advisor->RemoveCorpse(); - Advisor->Respawn(); - } - Advisor->AI()->EnterEvadeMode(); - } - } - - if( pInstance ) - pInstance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); - } - - void EventSharkkisDeath() - { - DoPlaySoundToSet(m_creature, SOUND_GAIN_ABILITY1); - DoYell(SAY_GAIN_ABILITY1, LANG_UNIVERSAL, NULL); - DoCast(m_creature, SPELL_POWER_OF_SHARKKIS); - } - - void EventTidalvessDeath() - { - DoPlaySoundToSet(m_creature, SOUND_GAIN_ABILITY2); - DoYell(SAY_GAIN_ABILITY2, LANG_UNIVERSAL, NULL); - DoCast(m_creature, SPELL_POWER_OF_TIDALVESS); - } - - void EventCaribdisDeath() - { - DoPlaySoundToSet(m_creature, SOUND_GAIN_ABILITY3); - DoYell(SAY_GAIN_ABILITY3, LANG_UNIVERSAL, NULL); - DoCast(m_creature, SPELL_POWER_OF_CARIBDIS); - } - - void GetAdvisors() - { - if(!pInstance) - return; - - Advisors[0] = pInstance->GetData64(DATA_SHARKKIS); - Advisors[1] = pInstance->GetData64(DATA_TIDALVESS); - Advisors[2] = pInstance->GetData64(DATA_CARIBDIS); - } - - void StartEvent(Unit *who) - { - if(!pInstance) - return; - - GetAdvisors(); - - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - - pInstance->SetData64(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); - pInstance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - case 2: - DoPlaySoundToSet(m_creature, SOUND_SLAY3); - break; - } - } - - void JustDied(Unit *killer) - { - DoPlaySoundToSet(m_creature, SOUND_DEATH); - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - - if( pInstance ) - pInstance->SetData(DATA_FATHOMLORDKARATHRESSEVENT, NOT_STARTED); - - //support for quest 10944 - m_creature->SummonCreature(SEER_OLUM, OLUM_X, OLUM_Y, OLUM_Z, OLUM_O, TEMPSUMMON_TIMED_DESPAWN, 3600000); - } - - void Aggro(Unit *who) - { - StartEvent(who); - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_KARATHRESSEVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if(target) - { - DoStartAttackAndMovement(target); - - GetAdvisors(); - - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_KARATHRESSEVENT)) - EnterEvadeMode(); - - //CataclysmicBolt_Timer - if(CataclysmicBolt_Timer < diff) - { - //select a random unit other than the main tank - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 1); - - //if there aren't other units, cast on the tank - if(!target) - target = m_creature->getVictim(); - - int32 dmg = target->GetMaxHealth() / 2; - m_creature->CastCustomSpell(target, SPELL_CATACLYSMIC_BOLT, &dmg, NULL, NULL, false, NULL, NULL, m_creature->GetGUID()); - - CataclysmicBolt_Timer = 10000; - }else CataclysmicBolt_Timer -= diff; - - //Enrage_Timer - if(Enrage_Timer < diff) - { - DoCast(m_creature, SPELL_ENRAGE); - Enrage_Timer = 90000; - }else Enrage_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Fathom-Guard Sharkkis AI -struct MANGOS_DLL_DECL boss_fathomguard_sharkkisAI : public ScriptedAI -{ - boss_fathomguard_sharkkisAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 LeechingThrow_Timer; - uint32 TheBeastWithin_Timer; - - void Reset() - { - LeechingThrow_Timer = 20000; - TheBeastWithin_Timer = 30000; - - if( pInstance ) - pInstance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); - } - - void JustDied(Unit *victim) - { - if(pInstance) - { - Creature *Karathress = NULL; - Karathress = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESS))); - - if(Karathress) - ((boss_fathomlord_karathressAI*)Karathress->AI())->EventSharkkisDeath(); - } - } - - void Aggro(Unit *who) - { - if(pInstance) - { - pInstance->SetData64(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); - pInstance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); - } - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_KARATHRESSEVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if(target) - { - DoStartAttackAndMovement(target); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_KARATHRESSEVENT)) - EnterEvadeMode(); - - //LeechingThrow_Timer - if(LeechingThrow_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_LEECHING_THROW); - LeechingThrow_Timer = 20000; - }else LeechingThrow_Timer -= diff; - - //TheBeastWithin_Timer - if(TheBeastWithin_Timer < diff) - { - DoCast(m_creature, SPELL_THE_BEAST_WITHIN); - TheBeastWithin_Timer = 30000; - }else TheBeastWithin_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Fathom-Guard Tidalvess AI -struct MANGOS_DLL_DECL boss_fathomguard_tidalvessAI : public ScriptedAI -{ - boss_fathomguard_tidalvessAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 FrostShock_Timer; - - void Reset() - { - FrostShock_Timer = 25000; - - if( pInstance ) - pInstance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); - } - - void JustDied(Unit *victim) - { - if(pInstance) - { - Creature *Karathress = NULL; - Karathress = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESS))); - - if(Karathress) - ((boss_fathomlord_karathressAI*)Karathress->AI())->EventTidalvessDeath(); - } - } - - void Aggro(Unit *who) - { - if(pInstance) - { - pInstance->SetData64(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); - pInstance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); - } - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_KARATHRESSEVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if(target) - { - DoStartAttackAndMovement(target); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_KARATHRESSEVENT)) - EnterEvadeMode(); - - //FrostShock_Timer - if(FrostShock_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FROST_SHOCK); - FrostShock_Timer = 25000+rand()%5000; - }else FrostShock_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Fathom-Guard Caribdis AI -struct MANGOS_DLL_DECL boss_fathomguard_caribdisAI : public ScriptedAI -{ - boss_fathomguard_caribdisAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 WaterBoltVolley_Timer; - uint32 TidalSurge_Timer; - uint32 Heal_Timer; - - void Reset() - { - WaterBoltVolley_Timer = 35000; - TidalSurge_Timer = 15000+rand()%5000; - Heal_Timer = 55000; - - if(pInstance) - pInstance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); - } - - void JustDied(Unit *victim) - { - if(pInstance) - { - Creature *Karathress = NULL; - Karathress = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESS))); - - if(Karathress) - ((boss_fathomlord_karathressAI*)Karathress->AI())->EventCaribdisDeath(); - } - } - - void Aggro(Unit *who) - { - if(pInstance) - { - pInstance->SetData64(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); - pInstance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); - } - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_KARATHRESSEVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if(target) - { - DoStartAttackAndMovement(target); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_KARATHRESSEVENT)) - EnterEvadeMode(); - - //WaterBoltVolley_Timer - if(WaterBoltVolley_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_WATER_BOLT_VOLLEY); - WaterBoltVolley_Timer = 30000; - }else WaterBoltVolley_Timer -= diff; - - //TidalSurge_Timer - if(TidalSurge_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_TIDAL_SURGE); - TidalSurge_Timer = 15000+rand()%5000; - }else TidalSurge_Timer -= diff; - - //Heal_Timer - if(Heal_Timer < diff) - { - // It can be cast on any of the mobs - Unit *pUnit = NULL; - - if(pInstance) - { - switch(rand()%4) - { - case 0: - pUnit = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESS)); - break; - case 1: - pUnit = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_SHARKKIS)); - break; - case 2: - pUnit = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_TIDALVESS)); - break; - case 3: - pUnit = m_creature; - break; - } - }else pUnit = m_creature; - - if(pUnit && pUnit->isAlive()) - DoCast(pUnit, SPELL_HEAL); - - Heal_Timer = 60000; - }else Heal_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_fathomlord_karathress(Creature *_Creature) -{ - return new boss_fathomlord_karathressAI (_Creature); -} - -CreatureAI* GetAI_boss_fathomguard_sharkkis(Creature *_Creature) -{ - return new boss_fathomguard_sharkkisAI (_Creature); -} - -CreatureAI* GetAI_boss_fathomguard_tidalvess(Creature *_Creature) -{ - return new boss_fathomguard_tidalvessAI (_Creature); -} - -CreatureAI* GetAI_boss_fathomguard_caribdis(Creature *_Creature) -{ - return new boss_fathomguard_caribdisAI (_Creature); -} - -void AddSC_boss_fathomlord_karathress() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_fathomlord_karathress"; - newscript->GetAI = GetAI_boss_fathomlord_karathress; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_fathomguard_sharkkis"; - newscript->GetAI = GetAI_boss_fathomguard_sharkkis; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_fathomguard_tidalvess"; - newscript->GetAI = GetAI_boss_fathomguard_tidalvess; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_fathomguard_caribdis"; - newscript->GetAI = GetAI_boss_fathomguard_caribdis; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Fathomlord_Karathress +SD%Complete: 50 +SDComment: Missing Multishot, pet, Totems, Windfury, Whirlwind +SDCategory: Coilfang Resevoir, Serpent Shrine Cavern +EndScriptData */ + +#include "precompiled.h" +#include "def_serpent_shrine.h" + +//Karathress spells +#define SPELL_CATACLYSMIC_BOLT 38441 +#define SPELL_POWER_OF_SHARKKIS 38455 +#define SPELL_POWER_OF_TIDALVESS 38452 +#define SPELL_POWER_OF_CARIBDIS 38451 +#define SPELL_ENRAGE 24318 +//Sharkkis spells +#define SPELL_LEECHING_THROW 29436 +#define SPELL_THE_BEAST_WITHIN 38373 +//Tidalvess spells +#define SPELL_FROST_SHOCK 38234 +//Caribdis Spells +#define SPELL_WATER_BOLT_VOLLEY 38335 +#define SPELL_TIDAL_SURGE 38353 +#define SPELL_HEAL 41386 + +#define SAY_AGGRO "Guards, attention! We have visitors..." +#define SAY_SLAY1 "I am rid of you." +#define SAY_GAIN_ABILITY1 "I am more powerful than ever!" +#define SAY_GAIN_ABILITY2 "Go on, kill them! I'll be the better for it!" +#define SAY_GAIN_ABILITY3 "More knowledge, more power!" +#define SAY_DEATH "Her ... excellency ... awaits!" + +#define SOUND_AGGRO 11277 +#define SOUND_PLYR_ATTACK 11278 +#define SOUND_GAIN_ABILITY1 11279 +#define SOUND_GAIN_ABILITY2 11280 +#define SOUND_GAIN_ABILITY3 11281 +#define SOUND_SLAY1 11282 +#define SOUND_SLAY2 11283 +#define SOUND_SLAY3 11284 +#define SOUND_DEATH 11285 + +//entry and position for Seer Olum +#define SEER_OLUM 22820 +#define OLUM_X 446.78f +#define OLUM_Y -542.76f +#define OLUM_Z -7.54773f +#define OLUM_O 0.401581f + +//Fathom-Lord Karathress AI +struct MANGOS_DLL_DECL boss_fathomlord_karathressAI : public ScriptedAI +{ + boss_fathomlord_karathressAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Advisors[0] = 0; + Advisors[1] = 0; + Advisors[2] = 0; + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 CataclysmicBolt_Timer; + uint32 Enrage_Timer; + + uint64 Advisors[3]; + + void Reset() + { + CataclysmicBolt_Timer = 10000; + Enrage_Timer = 600000; //10 minutes + + Creature* Advisor; + for(uint8 i = 0; i < 3; ++i) + if(Advisors[i]) + { + Advisor = ((Creature*)Unit::GetUnit(*m_creature, Advisors[i])); + if(Advisor) + { + if(Advisor->isAlive()) + { + Advisor->DealDamage(Advisor, Advisor->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + Advisor->RemoveCorpse(); + Advisor->Respawn(); + } + Advisor->AI()->EnterEvadeMode(); + } + } + + if( pInstance ) + pInstance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); + } + + void EventSharkkisDeath() + { + DoPlaySoundToSet(m_creature, SOUND_GAIN_ABILITY1); + DoYell(SAY_GAIN_ABILITY1, LANG_UNIVERSAL, NULL); + DoCast(m_creature, SPELL_POWER_OF_SHARKKIS); + } + + void EventTidalvessDeath() + { + DoPlaySoundToSet(m_creature, SOUND_GAIN_ABILITY2); + DoYell(SAY_GAIN_ABILITY2, LANG_UNIVERSAL, NULL); + DoCast(m_creature, SPELL_POWER_OF_TIDALVESS); + } + + void EventCaribdisDeath() + { + DoPlaySoundToSet(m_creature, SOUND_GAIN_ABILITY3); + DoYell(SAY_GAIN_ABILITY3, LANG_UNIVERSAL, NULL); + DoCast(m_creature, SPELL_POWER_OF_CARIBDIS); + } + + void GetAdvisors() + { + if(!pInstance) + return; + + Advisors[0] = pInstance->GetData64(DATA_SHARKKIS); + Advisors[1] = pInstance->GetData64(DATA_TIDALVESS); + Advisors[2] = pInstance->GetData64(DATA_CARIBDIS); + } + + void StartEvent(Unit *who) + { + if(!pInstance) + return; + + GetAdvisors(); + + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + + pInstance->SetData64(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); + pInstance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + break; + case 1: + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + case 2: + DoPlaySoundToSet(m_creature, SOUND_SLAY3); + break; + } + } + + void JustDied(Unit *killer) + { + DoPlaySoundToSet(m_creature, SOUND_DEATH); + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + + if( pInstance ) + pInstance->SetData(DATA_FATHOMLORDKARATHRESSEVENT, NOT_STARTED); + + //support for quest 10944 + m_creature->SummonCreature(SEER_OLUM, OLUM_X, OLUM_Y, OLUM_Z, OLUM_O, TEMPSUMMON_TIMED_DESPAWN, 3600000); + } + + void Aggro(Unit *who) + { + StartEvent(who); + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_KARATHRESSEVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESSEVENT_STARTER)); + + if(target) + { + DoStartAttackAndMovement(target); + + GetAdvisors(); + + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_KARATHRESSEVENT)) + EnterEvadeMode(); + + //CataclysmicBolt_Timer + if(CataclysmicBolt_Timer < diff) + { + //select a random unit other than the main tank + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 1); + + //if there aren't other units, cast on the tank + if(!target) + target = m_creature->getVictim(); + + int32 dmg = target->GetMaxHealth() / 2; + m_creature->CastCustomSpell(target, SPELL_CATACLYSMIC_BOLT, &dmg, NULL, NULL, false, NULL, NULL, m_creature->GetGUID()); + + CataclysmicBolt_Timer = 10000; + }else CataclysmicBolt_Timer -= diff; + + //Enrage_Timer + if(Enrage_Timer < diff) + { + DoCast(m_creature, SPELL_ENRAGE); + Enrage_Timer = 90000; + }else Enrage_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Fathom-Guard Sharkkis AI +struct MANGOS_DLL_DECL boss_fathomguard_sharkkisAI : public ScriptedAI +{ + boss_fathomguard_sharkkisAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 LeechingThrow_Timer; + uint32 TheBeastWithin_Timer; + + void Reset() + { + LeechingThrow_Timer = 20000; + TheBeastWithin_Timer = 30000; + + if( pInstance ) + pInstance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); + } + + void JustDied(Unit *victim) + { + if(pInstance) + { + Creature *Karathress = NULL; + Karathress = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESS))); + + if(Karathress) + ((boss_fathomlord_karathressAI*)Karathress->AI())->EventSharkkisDeath(); + } + } + + void Aggro(Unit *who) + { + if(pInstance) + { + pInstance->SetData64(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); + pInstance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); + } + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_KARATHRESSEVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESSEVENT_STARTER)); + + if(target) + { + DoStartAttackAndMovement(target); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_KARATHRESSEVENT)) + EnterEvadeMode(); + + //LeechingThrow_Timer + if(LeechingThrow_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_LEECHING_THROW); + LeechingThrow_Timer = 20000; + }else LeechingThrow_Timer -= diff; + + //TheBeastWithin_Timer + if(TheBeastWithin_Timer < diff) + { + DoCast(m_creature, SPELL_THE_BEAST_WITHIN); + TheBeastWithin_Timer = 30000; + }else TheBeastWithin_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Fathom-Guard Tidalvess AI +struct MANGOS_DLL_DECL boss_fathomguard_tidalvessAI : public ScriptedAI +{ + boss_fathomguard_tidalvessAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 FrostShock_Timer; + + void Reset() + { + FrostShock_Timer = 25000; + + if( pInstance ) + pInstance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); + } + + void JustDied(Unit *victim) + { + if(pInstance) + { + Creature *Karathress = NULL; + Karathress = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESS))); + + if(Karathress) + ((boss_fathomlord_karathressAI*)Karathress->AI())->EventTidalvessDeath(); + } + } + + void Aggro(Unit *who) + { + if(pInstance) + { + pInstance->SetData64(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); + pInstance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); + } + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_KARATHRESSEVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESSEVENT_STARTER)); + + if(target) + { + DoStartAttackAndMovement(target); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_KARATHRESSEVENT)) + EnterEvadeMode(); + + //FrostShock_Timer + if(FrostShock_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FROST_SHOCK); + FrostShock_Timer = 25000+rand()%5000; + }else FrostShock_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Fathom-Guard Caribdis AI +struct MANGOS_DLL_DECL boss_fathomguard_caribdisAI : public ScriptedAI +{ + boss_fathomguard_caribdisAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 WaterBoltVolley_Timer; + uint32 TidalSurge_Timer; + uint32 Heal_Timer; + + void Reset() + { + WaterBoltVolley_Timer = 35000; + TidalSurge_Timer = 15000+rand()%5000; + Heal_Timer = 55000; + + if(pInstance) + pInstance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); + } + + void JustDied(Unit *victim) + { + if(pInstance) + { + Creature *Karathress = NULL; + Karathress = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESS))); + + if(Karathress) + ((boss_fathomlord_karathressAI*)Karathress->AI())->EventCaribdisDeath(); + } + } + + void Aggro(Unit *who) + { + if(pInstance) + { + pInstance->SetData64(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); + pInstance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); + } + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_KARATHRESSEVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESSEVENT_STARTER)); + + if(target) + { + DoStartAttackAndMovement(target); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_KARATHRESSEVENT)) + EnterEvadeMode(); + + //WaterBoltVolley_Timer + if(WaterBoltVolley_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_WATER_BOLT_VOLLEY); + WaterBoltVolley_Timer = 30000; + }else WaterBoltVolley_Timer -= diff; + + //TidalSurge_Timer + if(TidalSurge_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_TIDAL_SURGE); + TidalSurge_Timer = 15000+rand()%5000; + }else TidalSurge_Timer -= diff; + + //Heal_Timer + if(Heal_Timer < diff) + { + // It can be cast on any of the mobs + Unit *pUnit = NULL; + + if(pInstance) + { + switch(rand()%4) + { + case 0: + pUnit = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KARATHRESS)); + break; + case 1: + pUnit = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_SHARKKIS)); + break; + case 2: + pUnit = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_TIDALVESS)); + break; + case 3: + pUnit = m_creature; + break; + } + }else pUnit = m_creature; + + if(pUnit && pUnit->isAlive()) + DoCast(pUnit, SPELL_HEAL); + + Heal_Timer = 60000; + }else Heal_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_fathomlord_karathress(Creature *_Creature) +{ + return new boss_fathomlord_karathressAI (_Creature); +} + +CreatureAI* GetAI_boss_fathomguard_sharkkis(Creature *_Creature) +{ + return new boss_fathomguard_sharkkisAI (_Creature); +} + +CreatureAI* GetAI_boss_fathomguard_tidalvess(Creature *_Creature) +{ + return new boss_fathomguard_tidalvessAI (_Creature); +} + +CreatureAI* GetAI_boss_fathomguard_caribdis(Creature *_Creature) +{ + return new boss_fathomguard_caribdisAI (_Creature); +} + +void AddSC_boss_fathomlord_karathress() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_fathomlord_karathress"; + newscript->GetAI = GetAI_boss_fathomlord_karathress; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_fathomguard_sharkkis"; + newscript->GetAI = GetAI_boss_fathomguard_sharkkis; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_fathomguard_tidalvess"; + newscript->GetAI = GetAI_boss_fathomguard_tidalvess; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_fathomguard_caribdis"; + newscript->GetAI = GetAI_boss_fathomguard_caribdis; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp index d9bc9429d14..c1d3086a2e6 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp @@ -1,357 +1,357 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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. -SDCategory: Coilfang Resevoir, Serpent Shrine Cavern -EndScriptData */ - -#include "precompiled.h" -#include "def_serpent_shrine.h" - -#define SWITCH_RADIUS 18 - -#define MODEL_CORRUPT 20609 -#define MODEL_CLEAN 20162 - -#define SPELL_WATER_TOMB 38235 -#define SPELL_MARK_OF_HYDROSS1 38215 -#define SPELL_MARK_OF_HYDROSS2 38216 -#define SPELL_MARK_OF_HYDROSS3 38217 -#define SPELL_MARK_OF_HYDROSS4 38218 -#define SPELL_MARK_OF_HYDROSS5 38231 -#define SPELL_MARK_OF_HYDROSS6 40584 -#define SPELL_MARK_OF_CORRUPTION1 38219 -#define SPELL_MARK_OF_CORRUPTION2 38220 -#define SPELL_MARK_OF_CORRUPTION3 38221 -#define SPELL_MARK_OF_CORRUPTION4 38222 -#define SPELL_MARK_OF_CORRUPTION5 38230 -#define SPELL_MARK_OF_CORRUPTION6 40583 -#define SPELL_VILE_SLUDGE 38246 -#define SPELL_ENRAGE 27680 //this spell need verification -#define SPELL_SUMMON_WATER_ELEMENT 36459 //not in use yet(in use ever?) -#define SPELL_ELEMENTAL_SPAWNIN 25035 -//#define SPELL_BLUE_BEAM 38015 //channeled Hydross Beam Helper (not in use yet) - -#define ENTRY_PURE_SPAWN 22035 -#define ENTRY_TAINTED_SPAWN 22036 - -#define SAY_AGGRO "I cannot allow you to interfere!" -#define SAY_SWITCH_TO_CLEAN "Better, much better." -#define SAY_CLEAN_SLAY1 "They have forced me to this..." -#define SAY_CLEAN_SLAY2 "I have no choice." -#define SAY_CLEAN_DEATH "I am... released..." -#define SAY_SWITCH_TO_CORRUPT "Aaghh, the poison..." -#define SAY_CORRUPT_SLAY1 "I will purge you from this place." -#define SAY_CORRUPT_SLAY2 "You are no better than they!" -#define SAY_CORRUPT_DEATH "You are the disease, not I" - -#define SOUND_AGGRO 11289 -#define SOUND_SWITCH_TO_CLEAN 11290 -#define SOUND_CLEAN_SLAY1 11291 -#define SOUND_CLEAN_SLAY2 11292 -#define SOUND_CLEAN_DEATH 11293 -#define SOUND_SWITCH_TO_CORRUPT 11297 -#define SOUND_CORRUPT_SLAY1 11298 -#define SOUND_CORRUPT_SLAY2 11299 -#define SOUND_CORRUPT_DEATH 11300 - -#define HYDROSS_X -239.439 -#define HYDROSS_Y -363.481 - -#define SPAWN_X_DIFF1 6.934003 -#define SPAWN_Y_DIFF1 -11.255012 -#define SPAWN_X_DIFF2 -6.934003 -#define SPAWN_Y_DIFF2 11.255012 -#define SPAWN_X_DIFF3 -12.577011 -#define SPAWN_Y_DIFF3 -4.72702 -#define SPAWN_X_DIFF4 12.577011 -#define SPAWN_Y_DIFF4 4.72702 - -struct MANGOS_DLL_DECL boss_hydross_the_unstableAI : public ScriptedAI -{ - boss_hydross_the_unstableAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 PosCheck_Timer; - uint32 MarkOfHydross_Timer; - uint32 MarkOfCorruption_Timer; - uint32 WaterTomb_Timer; - uint32 VileSludge_Timer; - uint32 MarkOfHydross_Count; - uint32 MarkOfCorruption_Count; - uint32 EnrageTimer; - bool CorruptedForm; - - void Reset() - { - PosCheck_Timer = 2500; - MarkOfHydross_Timer = 15000; - MarkOfCorruption_Timer = 15000; - WaterTomb_Timer = 7000; - VileSludge_Timer = 7000; - MarkOfHydross_Count = 0; - MarkOfCorruption_Count = 0; - EnrageTimer = 600000; - - CorruptedForm = 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->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_CLEAN); - - if( pInstance ) - pInstance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, NOT_STARTED); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - - if( pInstance ) - pInstance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, IN_PROGRESS); - } - - void KilledUnit(Unit *victim) - { - if(CorruptedForm) - switch(rand()%2) - { - case 0: - DoYell(SAY_CORRUPT_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CORRUPT_SLAY1); - break; - case 1: - DoYell(SAY_CORRUPT_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CORRUPT_SLAY2); - break; - } - else - { - switch(rand()%2) - { - case 0: - DoYell(SAY_CLEAN_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CLEAN_SLAY1); - break; - case 1: - DoYell(SAY_CLEAN_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CLEAN_SLAY2); - break; - } - } - } - - void JustSummoned(Creature* summoned) - { - if( summoned->GetEntry() == ENTRY_PURE_SPAWN ) - summoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); - if( summoned->GetEntry() == ENTRY_TAINTED_SPAWN ) - summoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); - - summoned->CastSpell(summoned,SPELL_ELEMENTAL_SPAWNIN,true); - } - - void JustDied(Unit *victim) - { - if( CorruptedForm ) - { - DoYell(SAY_CORRUPT_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CORRUPT_DEATH); - } - else - { - DoYell(SAY_CLEAN_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CLEAN_DEATH); - } - - if( pInstance ) - pInstance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, NOT_STARTED); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - // corrupted form - if( CorruptedForm ) - { - //MarkOfCorruption_Timer - if( MarkOfCorruption_Timer < diff ) - { - if( MarkOfCorruption_Count <= 5 ) - { - uint32 mark_spell; - - switch(MarkOfCorruption_Count) - { - case 0: mark_spell = SPELL_MARK_OF_CORRUPTION1; break; - case 1: mark_spell = SPELL_MARK_OF_CORRUPTION2; break; - case 2: mark_spell = SPELL_MARK_OF_CORRUPTION3; break; - case 3: mark_spell = SPELL_MARK_OF_CORRUPTION4; break; - case 4: mark_spell = SPELL_MARK_OF_CORRUPTION5; break; - case 5: mark_spell = SPELL_MARK_OF_CORRUPTION6; break; - } - - DoCast(m_creature->getVictim(), mark_spell); - - if( MarkOfCorruption_Count < 5 ) - MarkOfCorruption_Count++; - } - - MarkOfCorruption_Timer = 15000; - }else MarkOfCorruption_Timer -= diff; - - //VileSludge_Timer - if( VileSludge_Timer < diff ) - { - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if( target ) - DoCast(target, SPELL_VILE_SLUDGE); - - VileSludge_Timer = 15000; - }else VileSludge_Timer -= diff; - - //PosCheck_Timer - if( PosCheck_Timer < diff ) - { - if( m_creature->GetDistance2d(HYDROSS_X, HYDROSS_Y) < SWITCH_RADIUS ) - { - // switch to clean form - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_CLEAN); - CorruptedForm = false; - MarkOfHydross_Count = 0; - - DoYell(SAY_SWITCH_TO_CLEAN, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SWITCH_TO_CLEAN); - DoResetThreat(); - - // spawn 4 adds - DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - - 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); - } - - PosCheck_Timer = 2500; - }else PosCheck_Timer -=diff; - } - // clean form - else - { - //MarkOfHydross_Timer - if( MarkOfHydross_Timer < diff ) - { - if( MarkOfHydross_Count <= 5 ) - { - uint32 mark_spell; - - switch(MarkOfHydross_Count) - { - case 0: mark_spell = SPELL_MARK_OF_HYDROSS1; break; - case 1: mark_spell = SPELL_MARK_OF_HYDROSS2; break; - case 2: mark_spell = SPELL_MARK_OF_HYDROSS3; break; - case 3: mark_spell = SPELL_MARK_OF_HYDROSS4; break; - case 4: mark_spell = SPELL_MARK_OF_HYDROSS5; break; - case 5: mark_spell = SPELL_MARK_OF_HYDROSS6; break; - } - - DoCast(m_creature->getVictim(), mark_spell); - - if( MarkOfHydross_Count < 5 ) - MarkOfHydross_Count++; - } - - MarkOfHydross_Timer = 15000; - }else MarkOfHydross_Timer -= diff; - - //WaterTomb_Timer - if( WaterTomb_Timer < diff ) - { - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if( target ) - DoCast(target, SPELL_WATER_TOMB); - - WaterTomb_Timer = 7000; - }else WaterTomb_Timer -= diff; - - //PosCheck_Timer - if( PosCheck_Timer < diff ) - { - if( m_creature->GetDistance2d(HYDROSS_X, HYDROSS_Y) >= SWITCH_RADIUS ) - { - // switch to corrupted form - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_CORRUPT); - MarkOfCorruption_Count = 0; - CorruptedForm = true; - - DoYell(SAY_SWITCH_TO_CORRUPT, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SWITCH_TO_CORRUPT); - DoResetThreat(); - - // spawn 4 adds - DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - - 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); - } - - PosCheck_Timer = 2500; - }else PosCheck_Timer -=diff; - } - - //EnrageTimer - if( EnrageTimer < diff ) - { - DoCast(m_creature, SPELL_ENRAGE); - EnrageTimer = 60000; - }else EnrageTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_hydross_the_unstable(Creature *_Creature) -{ - return new boss_hydross_the_unstableAI (_Creature); -} - -void AddSC_boss_hydross_the_unstable() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_hydross_the_unstable"; - newscript->GetAI = GetAI_boss_hydross_the_unstable; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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. +SDCategory: Coilfang Resevoir, Serpent Shrine Cavern +EndScriptData */ + +#include "precompiled.h" +#include "def_serpent_shrine.h" + +#define SWITCH_RADIUS 18 + +#define MODEL_CORRUPT 20609 +#define MODEL_CLEAN 20162 + +#define SPELL_WATER_TOMB 38235 +#define SPELL_MARK_OF_HYDROSS1 38215 +#define SPELL_MARK_OF_HYDROSS2 38216 +#define SPELL_MARK_OF_HYDROSS3 38217 +#define SPELL_MARK_OF_HYDROSS4 38218 +#define SPELL_MARK_OF_HYDROSS5 38231 +#define SPELL_MARK_OF_HYDROSS6 40584 +#define SPELL_MARK_OF_CORRUPTION1 38219 +#define SPELL_MARK_OF_CORRUPTION2 38220 +#define SPELL_MARK_OF_CORRUPTION3 38221 +#define SPELL_MARK_OF_CORRUPTION4 38222 +#define SPELL_MARK_OF_CORRUPTION5 38230 +#define SPELL_MARK_OF_CORRUPTION6 40583 +#define SPELL_VILE_SLUDGE 38246 +#define SPELL_ENRAGE 27680 //this spell need verification +#define SPELL_SUMMON_WATER_ELEMENT 36459 //not in use yet(in use ever?) +#define SPELL_ELEMENTAL_SPAWNIN 25035 +//#define SPELL_BLUE_BEAM 38015 //channeled Hydross Beam Helper (not in use yet) + +#define ENTRY_PURE_SPAWN 22035 +#define ENTRY_TAINTED_SPAWN 22036 + +#define SAY_AGGRO "I cannot allow you to interfere!" +#define SAY_SWITCH_TO_CLEAN "Better, much better." +#define SAY_CLEAN_SLAY1 "They have forced me to this..." +#define SAY_CLEAN_SLAY2 "I have no choice." +#define SAY_CLEAN_DEATH "I am... released..." +#define SAY_SWITCH_TO_CORRUPT "Aaghh, the poison..." +#define SAY_CORRUPT_SLAY1 "I will purge you from this place." +#define SAY_CORRUPT_SLAY2 "You are no better than they!" +#define SAY_CORRUPT_DEATH "You are the disease, not I" + +#define SOUND_AGGRO 11289 +#define SOUND_SWITCH_TO_CLEAN 11290 +#define SOUND_CLEAN_SLAY1 11291 +#define SOUND_CLEAN_SLAY2 11292 +#define SOUND_CLEAN_DEATH 11293 +#define SOUND_SWITCH_TO_CORRUPT 11297 +#define SOUND_CORRUPT_SLAY1 11298 +#define SOUND_CORRUPT_SLAY2 11299 +#define SOUND_CORRUPT_DEATH 11300 + +#define HYDROSS_X -239.439 +#define HYDROSS_Y -363.481 + +#define SPAWN_X_DIFF1 6.934003 +#define SPAWN_Y_DIFF1 -11.255012 +#define SPAWN_X_DIFF2 -6.934003 +#define SPAWN_Y_DIFF2 11.255012 +#define SPAWN_X_DIFF3 -12.577011 +#define SPAWN_Y_DIFF3 -4.72702 +#define SPAWN_X_DIFF4 12.577011 +#define SPAWN_Y_DIFF4 4.72702 + +struct MANGOS_DLL_DECL boss_hydross_the_unstableAI : public ScriptedAI +{ + boss_hydross_the_unstableAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 PosCheck_Timer; + uint32 MarkOfHydross_Timer; + uint32 MarkOfCorruption_Timer; + uint32 WaterTomb_Timer; + uint32 VileSludge_Timer; + uint32 MarkOfHydross_Count; + uint32 MarkOfCorruption_Count; + uint32 EnrageTimer; + bool CorruptedForm; + + void Reset() + { + PosCheck_Timer = 2500; + MarkOfHydross_Timer = 15000; + MarkOfCorruption_Timer = 15000; + WaterTomb_Timer = 7000; + VileSludge_Timer = 7000; + MarkOfHydross_Count = 0; + MarkOfCorruption_Count = 0; + EnrageTimer = 600000; + + CorruptedForm = 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->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_CLEAN); + + if( pInstance ) + pInstance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, NOT_STARTED); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + + if( pInstance ) + pInstance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + if(CorruptedForm) + switch(rand()%2) + { + case 0: + DoYell(SAY_CORRUPT_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CORRUPT_SLAY1); + break; + case 1: + DoYell(SAY_CORRUPT_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CORRUPT_SLAY2); + break; + } + else + { + switch(rand()%2) + { + case 0: + DoYell(SAY_CLEAN_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CLEAN_SLAY1); + break; + case 1: + DoYell(SAY_CLEAN_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CLEAN_SLAY2); + break; + } + } + } + + void JustSummoned(Creature* summoned) + { + if( summoned->GetEntry() == ENTRY_PURE_SPAWN ) + summoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); + if( summoned->GetEntry() == ENTRY_TAINTED_SPAWN ) + summoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + + summoned->CastSpell(summoned,SPELL_ELEMENTAL_SPAWNIN,true); + } + + void JustDied(Unit *victim) + { + if( CorruptedForm ) + { + DoYell(SAY_CORRUPT_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CORRUPT_DEATH); + } + else + { + DoYell(SAY_CLEAN_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CLEAN_DEATH); + } + + if( pInstance ) + pInstance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, NOT_STARTED); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + // corrupted form + if( CorruptedForm ) + { + //MarkOfCorruption_Timer + if( MarkOfCorruption_Timer < diff ) + { + if( MarkOfCorruption_Count <= 5 ) + { + uint32 mark_spell; + + switch(MarkOfCorruption_Count) + { + case 0: mark_spell = SPELL_MARK_OF_CORRUPTION1; break; + case 1: mark_spell = SPELL_MARK_OF_CORRUPTION2; break; + case 2: mark_spell = SPELL_MARK_OF_CORRUPTION3; break; + case 3: mark_spell = SPELL_MARK_OF_CORRUPTION4; break; + case 4: mark_spell = SPELL_MARK_OF_CORRUPTION5; break; + case 5: mark_spell = SPELL_MARK_OF_CORRUPTION6; break; + } + + DoCast(m_creature->getVictim(), mark_spell); + + if( MarkOfCorruption_Count < 5 ) + MarkOfCorruption_Count++; + } + + MarkOfCorruption_Timer = 15000; + }else MarkOfCorruption_Timer -= diff; + + //VileSludge_Timer + if( VileSludge_Timer < diff ) + { + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if( target ) + DoCast(target, SPELL_VILE_SLUDGE); + + VileSludge_Timer = 15000; + }else VileSludge_Timer -= diff; + + //PosCheck_Timer + if( PosCheck_Timer < diff ) + { + if( m_creature->GetDistance2d(HYDROSS_X, HYDROSS_Y) < SWITCH_RADIUS ) + { + // switch to clean form + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_CLEAN); + CorruptedForm = false; + MarkOfHydross_Count = 0; + + DoYell(SAY_SWITCH_TO_CLEAN, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SWITCH_TO_CLEAN); + DoResetThreat(); + + // spawn 4 adds + DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + + 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); + } + + PosCheck_Timer = 2500; + }else PosCheck_Timer -=diff; + } + // clean form + else + { + //MarkOfHydross_Timer + if( MarkOfHydross_Timer < diff ) + { + if( MarkOfHydross_Count <= 5 ) + { + uint32 mark_spell; + + switch(MarkOfHydross_Count) + { + case 0: mark_spell = SPELL_MARK_OF_HYDROSS1; break; + case 1: mark_spell = SPELL_MARK_OF_HYDROSS2; break; + case 2: mark_spell = SPELL_MARK_OF_HYDROSS3; break; + case 3: mark_spell = SPELL_MARK_OF_HYDROSS4; break; + case 4: mark_spell = SPELL_MARK_OF_HYDROSS5; break; + case 5: mark_spell = SPELL_MARK_OF_HYDROSS6; break; + } + + DoCast(m_creature->getVictim(), mark_spell); + + if( MarkOfHydross_Count < 5 ) + MarkOfHydross_Count++; + } + + MarkOfHydross_Timer = 15000; + }else MarkOfHydross_Timer -= diff; + + //WaterTomb_Timer + if( WaterTomb_Timer < diff ) + { + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if( target ) + DoCast(target, SPELL_WATER_TOMB); + + WaterTomb_Timer = 7000; + }else WaterTomb_Timer -= diff; + + //PosCheck_Timer + if( PosCheck_Timer < diff ) + { + if( m_creature->GetDistance2d(HYDROSS_X, HYDROSS_Y) >= SWITCH_RADIUS ) + { + // switch to corrupted form + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_CORRUPT); + MarkOfCorruption_Count = 0; + CorruptedForm = true; + + DoYell(SAY_SWITCH_TO_CORRUPT, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SWITCH_TO_CORRUPT); + DoResetThreat(); + + // spawn 4 adds + DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + + 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); + } + + PosCheck_Timer = 2500; + }else PosCheck_Timer -=diff; + } + + //EnrageTimer + if( EnrageTimer < diff ) + { + DoCast(m_creature, SPELL_ENRAGE); + EnrageTimer = 60000; + }else EnrageTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_hydross_the_unstable(Creature *_Creature) +{ + return new boss_hydross_the_unstableAI (_Creature); +} + +void AddSC_boss_hydross_the_unstable() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_hydross_the_unstable"; + newscript->GetAI = GetAI_boss_hydross_the_unstable; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp index b078c332251..204c391a266 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp @@ -1,940 +1,922 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA - */ - -/* ScriptData -SDName: Boss_Lady_Vashj -SD%Complete: 99 -SDComment: Missing blizzlike Shield Generators coords -SDCategory: Coilfang Resevoir, Serpent Shrine Cavern -EndScriptData */ - -#include "precompiled.h" -#include "def_serpent_shrine.h" -#include "../../../creature/simple_ai.h" -#include "Item.h" -#include "Spell.h" - -#define SPELL_MULTI_SHOT 38310 -#define SPELL_SHOCK_BLAST 38509 -#define SPELL_ENTANGLE 38316 -#define SPELL_STATIC_CHARGE_TRIGGER 38280 -#define SPELL_FORKED_LIGHTNING 40088 -#define SPELL_SHOOT 40873 -#define SPELL_POISON_BOLT 40095 -#define SPELL_TOXIC_SPORES 38575 -#define SPELL_MAGIC_BARRIER 38112 - -#define SAY_INTRO "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!" -#define SAY_AGGRO1 "I'll split you from stem to stern! " -#define SAY_AGGRO2 "Victory to Lord Illidan!" -#define SAY_AGGRO3 "I spit on you, surface filth!" -#define SAY_AGGRO4 "Death to the outsiders!" -#define SAY_PHASE1 "I did not wish to lower myself by engaging your kind, but you leave me little choice!" -#define SAY_PHASE2 "The time is now! Leave none standing!" -#define SAY_PHASE3 "You may want to take cover." -#define SAY_BOWSHOT1 "Straight to the heart!" -#define SAY_BOWSHOT2 "Seek your mark!" -#define SAY_SLAY1 "Your time ends now!" -#define SAY_SLAY2 "You have failed!" -#define SAY_DEATH "Lord Illidan, I... I am... sorry." - -#define SOUND_INTRO 11531 -#define SOUND_AGGRO1 11532 -#define SOUND_AGGRO2 11533 -#define SOUND_AGGRO3 11534 -#define SOUND_AGGRO4 11535 -#define SOUND_PHASE1 11538 -#define SOUND_PHASE2 11539 -#define SOUND_PHASE3 11540 -#define SOUND_BOWSHOT1 11536 -#define SOUND_BOWSHOT2 11537 -#define SOUND_SLAY1 11541 -#define SOUND_SLAY2 11542 -#define SOUND_DEATH 11544 - -#define MIDDLE_X 30.134 -#define MIDDLE_Y -923.65 -#define MIDDLE_Z 42.9 - -#define SPOREBAT_X 30.977156 -#define SPOREBAT_Y -925.297761 -#define SPOREBAT_Z 77.176567 -#define SPOREBAT_O 5.223932 - -#define SHIED_GENERATOR_CHANNEL 19870 -#define ENCHANTED_ELEMENTAL 21958 -#define TAINTED_ELEMENTAL 22009 -#define COILFANG_STRIDER 22056 -#define COILFANG_ELITE 22055 -#define FATHOM_SPOREBAT 22140 - -float ElementPos[8][4] = -{ - {8.3, -835.3, 21.9, 5}, - {53.4, -835.3, 21.9, 4.5}, - {96, -861.9, 21.8, 4}, - {96, -986.4, 21.4, 2.5}, - {54.4, -1010.6, 22, 1.8}, - {9.8, -1012, 21.7, 1.4}, - {-35, -987.6, 21.5, 0.8}, - {-58.9, -901.6, 21.5, 6} -}; - -float CoilfangElitePos[3][4] = -{ - {28.84, -923.28, 42.9, 6}, - {31.183281, -953.502625, 41.523602, 1.640957}, - {58.895180, -923.124268, 41.545307, 3.152848} -}; - -float CoilfangStriderPos[3][4] = -{ - {66.427010, -948.778503, 41.262245, 2.584220}, - {7.513962, -959.538208, 41.300422, 1.034629}, - {-12.843201, -907.798401, 41.239620, 6.087094} -}; - -float ShieldGeneratorChannelPos[4][4] = -{ - {49.6262, -902.181, 43.0975, 3.95683}, - {10.988, -901.616, 42.5371, 5.4373}, - {10.3859, -944.036, 42.5446, 0.779888}, - {49.3126, -943.398, 42.5501, 2.40174} -}; - -//Lady Vashj AI -struct MANGOS_DLL_DECL boss_lady_vashjAI : public ScriptedAI -{ - boss_lady_vashjAI (Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint64 ShieldGeneratorChannel[4]; - - uint32 ShockBlast_Timer; - uint32 Entangle_Timer; - uint32 StaticCharge_Timer; - uint32 ForkedLightning_Timer; - uint32 Check_Timer; - uint32 EnchantedElemental_Timer; - uint32 TaintedElemental_Timer; - uint32 CoilfangElite_Timer; - uint32 CoilfangStrider_Timer; - uint32 SummonSporebat_Timer; - uint32 SummonSporebat_StaticTimer; - uint8 EnchantedElemental_Pos; - uint8 Phase; - - bool Entangle; - - void Reset() - { - ShockBlast_Timer = 1+rand()%60000; - Entangle_Timer = 30000; - StaticCharge_Timer = 10000+rand()%15000; - ForkedLightning_Timer = 2000; - Check_Timer = 1000; - EnchantedElemental_Timer = 5000; - TaintedElemental_Timer = 50000; - CoilfangElite_Timer = 45000+rand()%5000; - CoilfangStrider_Timer = 60000+rand()%10000; - SummonSporebat_Timer = 10000; - SummonSporebat_StaticTimer = 30000; - EnchantedElemental_Pos = 0; - Phase = 0; - - Entangle = false; - - if(pInstance) - pInstance->SetData(DATA_LADYVASHJEVENT, 0); - - ShieldGeneratorChannel[0] = 0; - ShieldGeneratorChannel[1] = 0; - ShieldGeneratorChannel[2] = 0; - ShieldGeneratorChannel[3] = 0; - - } - - //Called when a tainted elemental dies - void EventTaintedElementalDeath() - { - //the next will spawn 50 seconds after the previous one's death - if(TaintedElemental_Timer > 50000) - TaintedElemental_Timer = 50000; - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - - case 1: - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); - break; - } - } - - void JustDied(Unit *victim) - { - DoPlaySoundToSet(m_creature, SOUND_DEATH); - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - - if(pInstance) - pInstance->SetData(DATA_LADYVASHJEVENT, 0); - } - - void StartEvent() - { - switch(rand()%4) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - break; - case 2: - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); - break; - case 3: - DoPlaySoundToSet(m_creature, SOUND_AGGRO4); - DoYell(SAY_AGGRO4, LANG_UNIVERSAL, NULL); - break; - } - - Phase = 1; - - if(pInstance) - pInstance->SetData(DATA_LADYVASHJEVENT, 1); - } - - void Aggro(Unit *who) - { - //Begin melee attack if we are within range - if(Phase != 2) - DoStartAttackAndMovement(who); - - StartEvent(); - } - - void CastShootOrMultishot() - { - switch(rand()%2) - { - case 0: - //Shoot - //Used in Phases 1 and 3 after Entangle or while having nobody in melee range. A shot that hits her target for 4097-5543 Physical damage. - DoCast(m_creature->getVictim(), SPELL_SHOOT); - break; - case 1: - //Multishot - //Used in Phases 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. - DoCast(m_creature->getVictim(), SPELL_MULTI_SHOT); - break; - } - - if(rand()%3) - { - switch(rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_BOWSHOT1); - DoYell(SAY_BOWSHOT1, LANG_UNIVERSAL, NULL); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_BOWSHOT2); - DoYell(SAY_BOWSHOT2, LANG_UNIVERSAL, NULL); - break; - } - } - } - - void UpdateAI(const uint32 diff) - { - //to prevent abuses during phase 2 - if(Phase == 2 && !m_creature->getVictim() && InCombat) - EnterEvadeMode(); - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(Phase == 1 || Phase == 3) - { - //ShockBlast_Timer - if (ShockBlast_Timer < diff) - { - //Shock Burst - //Randomly used in Phases 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. - DoCast(m_creature->getVictim(), SPELL_SHOCK_BLAST); - m_creature->TauntApply(m_creature->getVictim()); - - ShockBlast_Timer = 1000+rand()%14000; //random cooldown - }else ShockBlast_Timer -= diff; - - //StaticCharge_Timer - if(StaticCharge_Timer < diff) - { - //Static Charge - //Used on random people (only 1 person at any given time) in Phases 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 *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if(target && !target->HasAura(SPELL_STATIC_CHARGE_TRIGGER, 0)) - //cast Static Charge every 2 seconds for 20 seconds - DoCast(target, SPELL_STATIC_CHARGE_TRIGGER); - - StaticCharge_Timer = 10000+rand()%20000; //blizzlike - }else StaticCharge_Timer -= diff; - - //Entangle_Timer - if (Entangle_Timer < diff) - { - if(!Entangle) - { - //Entangle - //Used in Phases 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. - DoCast(m_creature->getVictim(), SPELL_ENTANGLE); - Entangle = true; - Entangle_Timer = 10000; - } - else - { - CastShootOrMultishot(); - Entangle = false; - Entangle_Timer = 20000+rand()%5000; - } - }else Entangle_Timer -= diff; - - //Phase 1 - if(Phase == 1) - { - //Start phase 2 - if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 70) - { - //Phase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. - Phase = 2; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->GetMotionMaster()->Clear(); - m_creature->Relocate(MIDDLE_X, MIDDLE_Y, MIDDLE_Z); - m_creature->SendMonsterMove(MIDDLE_X, MIDDLE_Y, MIDDLE_Z, 0, 0, 0); - - m_creature->RemoveAllAuras(); - // This needs an entry in spell_script_target - DoCast(m_creature, SPELL_MAGIC_BARRIER, true); - - Creature *pCreature; - for(uint8 i = 0; i < 4; i++) - { - pCreature = m_creature->SummonCreature(SHIED_GENERATOR_CHANNEL, ShieldGeneratorChannelPos[i][0], ShieldGeneratorChannelPos[i][1], ShieldGeneratorChannelPos[i][2], ShieldGeneratorChannelPos[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); - if (pCreature) - ShieldGeneratorChannel[i] = pCreature->GetGUID(); - } - - DoPlaySoundToSet(m_creature, SOUND_PHASE2); - DoYell(SAY_PHASE2, LANG_UNIVERSAL, NULL); - } - } - //Phase 3 - else - { - //SummonSporebat_Timer - if(SummonSporebat_Timer < diff) - { - Creature *Sporebat = NULL; - Sporebat = m_creature->SummonCreature(FATHOM_SPOREBAT, SPOREBAT_X, SPOREBAT_Y, SPOREBAT_Z, SPOREBAT_O, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - - if(Sporebat) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - Sporebat->AI()->AttackStart(target); - } - - //summon sporebats faster and faster - if(SummonSporebat_StaticTimer > 1000) - SummonSporebat_StaticTimer -= 1000; - - SummonSporebat_Timer = SummonSporebat_StaticTimer; - }else SummonSporebat_Timer -= diff; - } - - //Melee attack - DoMeleeAttackIfReady(); - - //Check_Timer - used to check if somebody is in melee range - if(Check_Timer < diff) - { - bool InMeleeRange = false; - Unit *target; - std::list t_list = m_creature->getThreatManager().getThreatList(); - for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - //if in melee range - if(target && target->IsWithinDistInMap(m_creature, 5)) - { - InMeleeRange = true; - break; - } - } - - //if nobody is in melee range - if(!InMeleeRange) - CastShootOrMultishot(); - - Check_Timer = 1000; - }else Check_Timer -= diff; - } - //Phase 2 - else - { - //ForkedLightning_Timer - if(ForkedLightning_Timer < diff) - { - //Forked Lightning - //Used constantly in Phase 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 *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if(!target) - target = m_creature->getVictim(); - - DoCast(target, SPELL_FORKED_LIGHTNING); - - ForkedLightning_Timer = 2000+rand()%6000; //blizzlike - }else ForkedLightning_Timer -= diff; - - //EnchantedElemental_Timer - if(EnchantedElemental_Timer < diff) - { - Creature *Elemental; - Elemental = m_creature->SummonCreature(ENCHANTED_ELEMENTAL, ElementPos[EnchantedElemental_Pos][0], ElementPos[EnchantedElemental_Pos][1], ElementPos[EnchantedElemental_Pos][2], ElementPos[EnchantedElemental_Pos][3], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - if(Elemental) - Elemental->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); - - if(EnchantedElemental_Pos == 7) - EnchantedElemental_Pos = 0; - else - EnchantedElemental_Pos++; - - EnchantedElemental_Timer = 10000+rand()%5000; - }else EnchantedElemental_Timer -= diff; - - //TaintedElemental_Timer - if(TaintedElemental_Timer < diff) - { - Creature *Tain_Elemental; - uint32 pos = rand()%8; - Tain_Elemental = m_creature->SummonCreature(TAINTED_ELEMENTAL, ElementPos[pos][0], ElementPos[pos][1], ElementPos[pos][2], ElementPos[pos][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); - if(Tain_Elemental) - { - Tain_Elemental->GetMotionMaster()->Clear(); - Tain_Elemental->GetMotionMaster()->MoveIdle(); - } - - TaintedElemental_Timer = 120000; - }else TaintedElemental_Timer -= diff; - - //CoilfangElite_Timer - if(CoilfangElite_Timer < diff) - { - Creature *CoilfangElite; - uint32 pos = rand()%3; - CoilfangElite = m_creature->SummonCreature(COILFANG_ELITE, CoilfangElitePos[pos][0], CoilfangElitePos[pos][1], CoilfangElitePos[pos][2], CoilfangElitePos[pos][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); - if(CoilfangElite) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - CoilfangElite->AI()->AttackStart(target); - } - - CoilfangElite_Timer = 45000+rand()%5000; //wowwiki says 50 seconds, bosskillers says 45 - }else CoilfangElite_Timer -= diff; - - //CoilfangStrider_Timer - if(CoilfangStrider_Timer < diff) - { - Creature *CoilfangStrider; - uint32 pos = rand()%3; - CoilfangStrider = m_creature->SummonCreature(COILFANG_STRIDER, CoilfangStriderPos[pos][0], CoilfangStriderPos[pos][1], CoilfangStriderPos[pos][2], CoilfangStriderPos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - if(CoilfangStrider) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - CoilfangStrider->AI()->AttackStart(target); - } - - CoilfangStrider_Timer = 60000+rand()%10000; //wowwiki says 60 seconds, bosskillers says 60-70 - }else CoilfangStrider_Timer -= diff; - - //Check_Timer - if(Check_Timer < diff) - { - //Start Phase 3 - if(pInstance && pInstance->GetData(DATA_CANSTARTPHASE3)) - { - //set life 50% - m_creature->SetHealth(m_creature->GetMaxHealth()/2); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveAurasDueToSpell(SPELL_MAGIC_BARRIER); - - DoPlaySoundToSet(m_creature, SOUND_PHASE3); - DoYell(SAY_PHASE3, LANG_UNIVERSAL, NULL); - - Phase = 3; - - //return to the tank - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - } - Check_Timer = 1000; - }else Check_Timer -= diff; - } - } -}; - -//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 *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Check_Timer; - uint32 Movement_Timer; - - void Reset() - { - Check_Timer = 5000; - Movement_Timer = 500; - } - - void Aggro(Unit *who) { return; } - - void MoveInLineOfSight(Unit *who) { return; } - - void UpdateAI(const uint32 diff) - { - //Check_Timer - if(Check_Timer < diff) - { - if(pInstance) - { - Unit *Vashj = NULL; - Vashj = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LADYVASHJ)); - if(Vashj) - { - if(Vashj->IsWithinDistInMap(m_creature, 5)) - { - //increase lady vashj damage (+5%) - const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); - Vashj->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 5))); - Vashj->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 5))); - m_creature->UpdateDamagePhysical(BASE_ATTACK); - - //call Unsummon() - m_creature->setDeathState(JUST_DIED); - } - else if(((boss_lady_vashjAI*)((Creature*)Vashj)->AI())->InCombat == false) - { - //call Unsummon() - m_creature->setDeathState(JUST_DIED); - } - } - } - else error_log("ERROR: Instance Data for Serpentshrine Caverns not set"); - Check_Timer = 1000; - }else Check_Timer -= diff; - } -}; - -//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 -{ - mob_tainted_elementalAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 PoisonBolt_Timer; - - void Reset() - { - PoisonBolt_Timer = 5000+rand()%5000; - } - - void JustDied(Unit *killer) - { - if(pInstance) - { - Creature *Vashj = NULL; - Vashj = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LADYVASHJ))); - - if(Vashj) - ((boss_lady_vashjAI*)Vashj->AI())->EventTaintedElementalDeath(); - } - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - m_creature->AddThreat(who, 0.1f); - } - } - } - - void UpdateAI(const uint32 diff) - { - //PoisonBolt_Timer - if(PoisonBolt_Timer < diff) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if(target && target->IsWithinDistInMap(m_creature, 30)) - DoCast(target, SPELL_POISON_BOLT); - - PoisonBolt_Timer = 5000+rand()%5000; - }else PoisonBolt_Timer -= diff; - } -}; - -//Fathom Sporebat -//Toxic Spores: Used in Phase 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_fathom_sporebatAI : public ScriptedAI -{ - mob_fathom_sporebatAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 ToxicSpore_Timer; - uint32 Check_Timer; - - void Reset() - { - m_creature->setFaction(14); - ToxicSpore_Timer = 5000; - Check_Timer = 1000; - } - - void Aggro(Unit *who) {} - - void UpdateAI (const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ToxicSpore_Timer - if(ToxicSpore_Timer < diff) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - //The Spores will hit you anywhere in the instance: underwater, at the elevator, at the entrance, wherever. - if(target) - DoCast(target, SPELL_TOXIC_SPORES); - - ToxicSpore_Timer = 20000+rand()%5000; - }else ToxicSpore_Timer -= diff; - - //Check_Timer - if(Check_Timer < diff) - { - if(pInstance) - { - //check if vashj is death - Unit *Vashj = NULL; - Vashj = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LADYVASHJ)); - if(!Vashj || (Vashj && !Vashj->isAlive())) - { - //remove - m_creature->setDeathState(DEAD); - m_creature->RemoveCorpse(); - m_creature->setFaction(35); - } - } - - Check_Timer = 1000; - }else Check_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Coilfang Elite -//It's an elite Naga mob with 170,000 HP. It does about 5000 damage on plate, and has a nasty cleave hitting for about 7500 damage -CreatureAI* GetAI_mob_coilfang_elite(Creature *_Creature) -{ - SimpleAI* ai = new SimpleAI (_Creature); - - ai->Spell[0].Enabled = true; - ai->Spell[0].Spell_Id = 31345; //Cleave - ai->Spell[0].Cooldown = 15000; - ai->Spell[0].CooldownRandomAddition = 5000; - ai->Spell[0].First_Cast = 5000; - ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_RANDOM; - - ai->EnterEvadeMode(); - - return ai; -} - -//Coilfang Strifer -//It hits plate for about 8000 damage, has a Mind Blast spell doing about 3000 shadow damage, and a Psychic Scream Aura, which fears everybody in a 8 yard range of it every 2-3 seconds , for 5 seconds and increasing their movement speed by 150% during the fear. -CreatureAI* GetAI_mob_coilfang_strider(Creature *_Creature) -{ - SimpleAI* ai = new SimpleAI (_Creature); - - ai->Spell[0].Enabled = true; - ai->Spell[0].Spell_Id = 41374; //Mind Blast - ai->Spell[0].Cooldown = 30000; - ai->Spell[0].CooldownRandomAddition = 10000; - ai->Spell[0].First_Cast = 8000; - ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; - - //Scream aura not implemented - - ai->EnterEvadeMode(); - - return ai; -} - -struct MANGOS_DLL_DECL mob_shield_generator_channelAI : public ScriptedAI -{ - mob_shield_generator_channelAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Check_Timer; - bool Channeled; - - void Reset() - { - Check_Timer = 1000; - Channeled = false; - //invisible - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID , 11686); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit *who) { return; } - - void MoveInLineOfSight(Unit *who) { return; } - - void UpdateAI (const uint32 diff) - { - if(!pInstance) - return; - - if(!Channeled) - { - Unit *Vashj = NULL; - Vashj = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LADYVASHJ)); - - if(Vashj && Vashj->isAlive()) - { - //start visual channel - m_creature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, Vashj->GetGUID()); - m_creature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_MAGIC_BARRIER); - Channeled = true; - } - } - } -}; - -bool ItemUse_item_tainted_core(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - ScriptedInstance *pInstance = ((ScriptedInstance*)player->GetInstanceData()); - - if(!pInstance) - { - player->GetSession()->SendNotification("ERROR: Instance script not initialized. Notify your administrator."); - error_log("ERROR: Lady Vashj Tainted Core: Instance Script Not Initialized"); - return true; - } - - Creature *Vashj = NULL; - Vashj = (Creature*)(Unit::GetUnit((*player), pInstance->GetData64(DATA_LADYVASHJ))); - if(Vashj && ((boss_lady_vashjAI*)Vashj->AI())->Phase == 2) - { - if(targets.getGOTarget() && targets.getGOTarget()->GetTypeId()==TYPEID_GAMEOBJECT) - { - uint32 identifier; - uint8 channel_identifier; - switch(targets.getGOTarget()->GetEntry()) - { - case 185052: - identifier = DATA_SHIELDGENERATOR1; - channel_identifier = 0; - break; - case 185053: - identifier = DATA_SHIELDGENERATOR2; - channel_identifier = 1; - break; - case 185051: - identifier = DATA_SHIELDGENERATOR3; - channel_identifier = 2; - break; - case 185054: - identifier = DATA_SHIELDGENERATOR4; - channel_identifier = 3; - break; - default: - return true; - break; - } - - if(pInstance->GetData(identifier)) - { - player->GetSession()->SendNotification("Already deactivated"); - return true; - } - - //get and remove channel - Unit *Channel = NULL; - Channel = Unit::GetUnit((*Vashj), ((boss_lady_vashjAI*)Vashj->AI())->ShieldGeneratorChannel[channel_identifier]); - if(Channel) - { - //call Unsummon() - Channel->setDeathState(JUST_DIED); - } - - pInstance->SetData(identifier, 1); - - //remove this item - player->DestroyItemCount(31088, 1, true); - } - } - return true; -} - -CreatureAI* GetAI_boss_lady_vashj(Creature *_Creature) -{ - return new boss_lady_vashjAI (_Creature); -} - -CreatureAI* GetAI_mob_enchanted_elemental(Creature *_Creature) -{ - return new mob_enchanted_elementalAI (_Creature); -} - -CreatureAI* GetAI_mob_tainted_elemental(Creature *_Creature) -{ - return new mob_tainted_elementalAI (_Creature); -} - -CreatureAI* GetAI_mob_fathom_sporebat(Creature *_Creature) -{ - return new mob_fathom_sporebatAI (_Creature); -} - -CreatureAI* GetAI_mob_shield_generator_channel(Creature *_Creature) -{ - return new mob_shield_generator_channelAI (_Creature); -} - -void AddSC_boss_lady_vashj() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_lady_vashj"; - newscript->GetAI = GetAI_boss_lady_vashj; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_enchanted_elemental"; - newscript->GetAI = GetAI_mob_enchanted_elemental; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_tainted_elemental"; - newscript->GetAI = GetAI_mob_tainted_elemental; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_fathom_sporebat"; - newscript->GetAI = GetAI_mob_fathom_sporebat; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_coilfang_elite"; - newscript->GetAI = GetAI_mob_coilfang_elite; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_coilfang_strider"; - newscript->GetAI = GetAI_mob_coilfang_strider; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_shield_generator_channel"; - newscript->GetAI = GetAI_mob_shield_generator_channel; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="item_tainted_core"; - newscript->pItemUse = ItemUse_item_tainted_core; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA + */ + +/* ScriptData +SDName: Boss_Lady_Vashj +SD%Complete: 99 +SDComment: Missing blizzlike Shield Generators coords +SDCategory: Coilfang Resevoir, Serpent Shrine Cavern +EndScriptData */ + +#include "precompiled.h" +#include "def_serpent_shrine.h" +#include "../../../creature/simple_ai.h" +#include "Item.h" +#include "Spell.h" + +#define SPELL_MULTI_SHOT 38310 +#define SPELL_SHOCK_BLAST 38509 +#define SPELL_ENTANGLE 38316 +#define SPELL_STATIC_CHARGE_TRIGGER 38280 +#define SPELL_FORKED_LIGHTNING 40088 +#define SPELL_SHOOT 40873 +#define SPELL_POISON_BOLT 40095 +#define SPELL_TOXIC_SPORES 38575 +#define SPELL_MAGIC_BARRIER 38112 + +#define SAY_INTRO "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!" +#define SAY_AGGRO1 "I'll split you from stem to stern! " +#define SAY_AGGRO2 "Victory to Lord Illidan!" +#define SAY_AGGRO3 "I spit on you, surface filth!" +#define SAY_AGGRO4 "Death to the outsiders!" +#define SAY_PHASE1 "I did not wish to lower myself by engaging your kind, but you leave me little choice!" +#define SAY_PHASE2 "The time is now! Leave none standing!" +#define SAY_PHASE3 "You may want to take cover." +#define SAY_BOWSHOT1 "Straight to the heart!" +#define SAY_BOWSHOT2 "Seek your mark!" +#define SAY_SLAY1 "Your time ends now!" +#define SAY_SLAY2 "You have failed!" +#define SAY_DEATH "Lord Illidan, I... I am... sorry." + +#define SOUND_INTRO 11531 +#define SOUND_AGGRO1 11532 +#define SOUND_AGGRO2 11533 +#define SOUND_AGGRO3 11534 +#define SOUND_AGGRO4 11535 +#define SOUND_PHASE1 11538 +#define SOUND_PHASE2 11539 +#define SOUND_PHASE3 11540 +#define SOUND_BOWSHOT1 11536 +#define SOUND_BOWSHOT2 11537 +#define SOUND_SLAY1 11541 +#define SOUND_SLAY2 11542 +#define SOUND_DEATH 11544 + +#define MIDDLE_X 30.134 +#define MIDDLE_Y -923.65 +#define MIDDLE_Z 42.9 + +#define SPOREBAT_X 30.977156 +#define SPOREBAT_Y -925.297761 +#define SPOREBAT_Z 77.176567 +#define SPOREBAT_O 5.223932 + +#define SHIED_GENERATOR_CHANNEL 19870 +#define ENCHANTED_ELEMENTAL 21958 +#define TAINTED_ELEMENTAL 22009 +#define COILFANG_STRIDER 22056 +#define COILFANG_ELITE 22055 +#define FATHOM_SPOREBAT 22140 + +float ElementPos[8][4] = +{ + {8.3, -835.3, 21.9, 5}, + {53.4, -835.3, 21.9, 4.5}, + {96, -861.9, 21.8, 4}, + {96, -986.4, 21.4, 2.5}, + {54.4, -1010.6, 22, 1.8}, + {9.8, -1012, 21.7, 1.4}, + {-35, -987.6, 21.5, 0.8}, + {-58.9, -901.6, 21.5, 6} +}; + +float CoilfangElitePos[3][4] = +{ + {28.84, -923.28, 42.9, 6}, + {31.183281, -953.502625, 41.523602, 1.640957}, + {58.895180, -923.124268, 41.545307, 3.152848} +}; + +float CoilfangStriderPos[3][4] = +{ + {66.427010, -948.778503, 41.262245, 2.584220}, + {7.513962, -959.538208, 41.300422, 1.034629}, + {-12.843201, -907.798401, 41.239620, 6.087094} +}; + +float ShieldGeneratorChannelPos[4][4] = +{ + {49.6262, -902.181, 43.0975, 3.95683}, + {10.988, -901.616, 42.5371, 5.4373}, + {10.3859, -944.036, 42.5446, 0.779888}, + {49.3126, -943.398, 42.5501, 2.40174} +}; + +//Lady Vashj AI +struct MANGOS_DLL_DECL boss_lady_vashjAI : public ScriptedAI +{ + boss_lady_vashjAI (Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint64 ShieldGeneratorChannel[4]; + + uint32 ShockBlast_Timer; + uint32 Entangle_Timer; + uint32 StaticCharge_Timer; + uint32 ForkedLightning_Timer; + uint32 Check_Timer; + uint32 EnchantedElemental_Timer; + uint32 TaintedElemental_Timer; + uint32 CoilfangElite_Timer; + uint32 CoilfangStrider_Timer; + uint32 SummonSporebat_Timer; + uint32 SummonSporebat_StaticTimer; + uint8 EnchantedElemental_Pos; + uint8 Phase; + + bool Entangle; + + void Reset() + { + ShockBlast_Timer = 1+rand()%60000; + Entangle_Timer = 30000; + StaticCharge_Timer = 10000+rand()%15000; + ForkedLightning_Timer = 2000; + Check_Timer = 1000; + EnchantedElemental_Timer = 5000; + TaintedElemental_Timer = 50000; + CoilfangElite_Timer = 45000+rand()%5000; + CoilfangStrider_Timer = 60000+rand()%10000; + SummonSporebat_Timer = 10000; + SummonSporebat_StaticTimer = 30000; + EnchantedElemental_Pos = 0; + Phase = 0; + + Entangle = false; + + if(pInstance) + pInstance->SetData(DATA_LADYVASHJEVENT, 0); + + ShieldGeneratorChannel[0] = 0; + ShieldGeneratorChannel[1] = 0; + ShieldGeneratorChannel[2] = 0; + ShieldGeneratorChannel[3] = 0; + + } + + //Called when a tainted elemental dies + void EventTaintedElementalDeath() + { + //the next will spawn 50 seconds after the previous one's death + if(TaintedElemental_Timer > 50000) + TaintedElemental_Timer = 50000; + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + + case 1: + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); + break; + } + } + + void JustDied(Unit *victim) + { + DoPlaySoundToSet(m_creature, SOUND_DEATH); + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + + if(pInstance) + pInstance->SetData(DATA_LADYVASHJEVENT, 0); + } + + void StartEvent() + { + switch(rand()%4) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + break; + case 1: + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + break; + case 2: + DoPlaySoundToSet(m_creature, SOUND_AGGRO3); + DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); + break; + case 3: + DoPlaySoundToSet(m_creature, SOUND_AGGRO4); + DoYell(SAY_AGGRO4, LANG_UNIVERSAL, NULL); + break; + } + + Phase = 1; + + if(pInstance) + pInstance->SetData(DATA_LADYVASHJEVENT, 1); + } + + void Aggro(Unit *who) + { + //Begin melee attack if we are within range + if(Phase != 2) + DoStartAttackAndMovement(who); + + StartEvent(); + } + + void CastShootOrMultishot() + { + switch(rand()%2) + { + case 0: + //Shoot + //Used in Phases 1 and 3 after Entangle or while having nobody in melee range. A shot that hits her target for 4097-5543 Physical damage. + DoCast(m_creature->getVictim(), SPELL_SHOOT); + break; + case 1: + //Multishot + //Used in Phases 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. + DoCast(m_creature->getVictim(), SPELL_MULTI_SHOT); + break; + } + + if(rand()%3) + { + switch(rand()%2) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_BOWSHOT1); + DoYell(SAY_BOWSHOT1, LANG_UNIVERSAL, NULL); + break; + case 1: + DoPlaySoundToSet(m_creature, SOUND_BOWSHOT2); + DoYell(SAY_BOWSHOT2, LANG_UNIVERSAL, NULL); + break; + } + } + } + + void UpdateAI(const uint32 diff) + { + //to prevent abuses during phase 2 + if(Phase == 2 && !m_creature->getVictim() && InCombat) + EnterEvadeMode(); + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(Phase == 1 || Phase == 3) + { + //ShockBlast_Timer + if (ShockBlast_Timer < diff) + { + //Shock Burst + //Randomly used in Phases 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. + DoCast(m_creature->getVictim(), SPELL_SHOCK_BLAST); + m_creature->TauntApply(m_creature->getVictim()); + + ShockBlast_Timer = 1000+rand()%14000; //random cooldown + }else ShockBlast_Timer -= diff; + + //StaticCharge_Timer + if(StaticCharge_Timer < diff) + { + //Static Charge + //Used on random people (only 1 person at any given time) in Phases 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 *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if(target && !target->HasAura(SPELL_STATIC_CHARGE_TRIGGER, 0)) + //cast Static Charge every 2 seconds for 20 seconds + DoCast(target, SPELL_STATIC_CHARGE_TRIGGER); + + StaticCharge_Timer = 10000+rand()%20000; //blizzlike + }else StaticCharge_Timer -= diff; + + //Entangle_Timer + if (Entangle_Timer < diff) + { + if(!Entangle) + { + //Entangle + //Used in Phases 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. + DoCast(m_creature->getVictim(), SPELL_ENTANGLE); + Entangle = true; + Entangle_Timer = 10000; + } + else + { + CastShootOrMultishot(); + Entangle = false; + Entangle_Timer = 20000+rand()%5000; + } + }else Entangle_Timer -= diff; + + //Phase 1 + if(Phase == 1) + { + //Start phase 2 + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 70) + { + //Phase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. + Phase = 2; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->GetMotionMaster()->Clear(); + m_creature->Relocate(MIDDLE_X, MIDDLE_Y, MIDDLE_Z); + m_creature->SendMonsterMove(MIDDLE_X, MIDDLE_Y, MIDDLE_Z, 0, 0, 0); + + m_creature->RemoveAllAuras(); + // This needs an entry in spell_script_target + DoCast(m_creature, SPELL_MAGIC_BARRIER, true); + + Creature *pCreature; + for(uint8 i = 0; i < 4; i++) + { + pCreature = m_creature->SummonCreature(SHIED_GENERATOR_CHANNEL, ShieldGeneratorChannelPos[i][0], ShieldGeneratorChannelPos[i][1], ShieldGeneratorChannelPos[i][2], ShieldGeneratorChannelPos[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); + if (pCreature) + ShieldGeneratorChannel[i] = pCreature->GetGUID(); + } + + DoPlaySoundToSet(m_creature, SOUND_PHASE2); + DoYell(SAY_PHASE2, LANG_UNIVERSAL, NULL); + } + } + //Phase 3 + else + { + //SummonSporebat_Timer + if(SummonSporebat_Timer < diff) + { + Creature *Sporebat = NULL; + Sporebat = m_creature->SummonCreature(FATHOM_SPOREBAT, SPOREBAT_X, SPOREBAT_Y, SPOREBAT_Z, SPOREBAT_O, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + + if(Sporebat) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + Sporebat->AI()->AttackStart(target); + } + + //summon sporebats faster and faster + if(SummonSporebat_StaticTimer > 1000) + SummonSporebat_StaticTimer -= 1000; + + SummonSporebat_Timer = SummonSporebat_StaticTimer; + }else SummonSporebat_Timer -= diff; + } + + //Melee attack + DoMeleeAttackIfReady(); + + //Check_Timer - used to check if somebody is in melee range + if(Check_Timer < diff) + { + bool InMeleeRange = false; + Unit *target; + std::list t_list = m_creature->getThreatManager().getThreatList(); + for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + //if in melee range + if(target && target->IsWithinDistInMap(m_creature, 5)) + { + InMeleeRange = true; + break; + } + } + + //if nobody is in melee range + if(!InMeleeRange) + CastShootOrMultishot(); + + Check_Timer = 1000; + }else Check_Timer -= diff; + } + //Phase 2 + else + { + //ForkedLightning_Timer + if(ForkedLightning_Timer < diff) + { + //Forked Lightning + //Used constantly in Phase 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 *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if(!target) + target = m_creature->getVictim(); + + DoCast(target, SPELL_FORKED_LIGHTNING); + + ForkedLightning_Timer = 2000+rand()%6000; //blizzlike + }else ForkedLightning_Timer -= diff; + + //EnchantedElemental_Timer + if(EnchantedElemental_Timer < diff) + { + Creature *Elemental; + Elemental = m_creature->SummonCreature(ENCHANTED_ELEMENTAL, ElementPos[EnchantedElemental_Pos][0], ElementPos[EnchantedElemental_Pos][1], ElementPos[EnchantedElemental_Pos][2], ElementPos[EnchantedElemental_Pos][3], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); + if(Elemental) + Elemental->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + + if(EnchantedElemental_Pos == 7) + EnchantedElemental_Pos = 0; + else + EnchantedElemental_Pos++; + + EnchantedElemental_Timer = 10000+rand()%5000; + }else EnchantedElemental_Timer -= diff; + + //TaintedElemental_Timer + if(TaintedElemental_Timer < diff) + { + Creature *Tain_Elemental; + uint32 pos = rand()%8; + Tain_Elemental = m_creature->SummonCreature(TAINTED_ELEMENTAL, ElementPos[pos][0], ElementPos[pos][1], ElementPos[pos][2], ElementPos[pos][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + if(Tain_Elemental) + { + Tain_Elemental->GetMotionMaster()->Clear(); + Tain_Elemental->GetMotionMaster()->MoveIdle(); + } + + TaintedElemental_Timer = 120000; + }else TaintedElemental_Timer -= diff; + + //CoilfangElite_Timer + if(CoilfangElite_Timer < diff) + { + Creature *CoilfangElite; + uint32 pos = rand()%3; + CoilfangElite = m_creature->SummonCreature(COILFANG_ELITE, CoilfangElitePos[pos][0], CoilfangElitePos[pos][1], CoilfangElitePos[pos][2], CoilfangElitePos[pos][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); + if(CoilfangElite) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + CoilfangElite->AI()->AttackStart(target); + } + + CoilfangElite_Timer = 45000+rand()%5000; //wowwiki says 50 seconds, bosskillers says 45 + }else CoilfangElite_Timer -= diff; + + //CoilfangStrider_Timer + if(CoilfangStrider_Timer < diff) + { + Creature *CoilfangStrider; + uint32 pos = rand()%3; + CoilfangStrider = m_creature->SummonCreature(COILFANG_STRIDER, CoilfangStriderPos[pos][0], CoilfangStriderPos[pos][1], CoilfangStriderPos[pos][2], CoilfangStriderPos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + if(CoilfangStrider) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + CoilfangStrider->AI()->AttackStart(target); + } + + CoilfangStrider_Timer = 60000+rand()%10000; //wowwiki says 60 seconds, bosskillers says 60-70 + }else CoilfangStrider_Timer -= diff; + + //Check_Timer + if(Check_Timer < diff) + { + //Start Phase 3 + if(pInstance && pInstance->GetData(DATA_CANSTARTPHASE3)) + { + //set life 50% + m_creature->SetHealth(m_creature->GetMaxHealth()/2); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveAurasDueToSpell(SPELL_MAGIC_BARRIER); + + DoPlaySoundToSet(m_creature, SOUND_PHASE3); + DoYell(SAY_PHASE3, LANG_UNIVERSAL, NULL); + + Phase = 3; + + //return to the tank + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + Check_Timer = 1000; + }else Check_Timer -= diff; + } + } +}; + +//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 *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Check_Timer; + uint32 Movement_Timer; + + void Reset() + { + Check_Timer = 5000; + Movement_Timer = 500; + } + + void Aggro(Unit *who) { return; } + + void MoveInLineOfSight(Unit *who) { return; } + + void UpdateAI(const uint32 diff) + { + //Check_Timer + if(Check_Timer < diff) + { + if(pInstance) + { + Unit *Vashj = NULL; + Vashj = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LADYVASHJ)); + if(Vashj) + { + if(Vashj->IsWithinDistInMap(m_creature, 5)) + { + //increase lady vashj damage (+5%) + const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); + Vashj->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 5))); + Vashj->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 5))); + m_creature->UpdateDamagePhysical(BASE_ATTACK); + + //call Unsummon() + m_creature->setDeathState(JUST_DIED); + } + else if(((boss_lady_vashjAI*)((Creature*)Vashj)->AI())->InCombat == false) + { + //call Unsummon() + m_creature->setDeathState(JUST_DIED); + } + } + } + else error_log("ERROR: Instance Data for Serpentshrine Caverns not set"); + Check_Timer = 1000; + }else Check_Timer -= diff; + } +}; + +//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 +{ + mob_tainted_elementalAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 PoisonBolt_Timer; + + void Reset() + { + PoisonBolt_Timer = 5000+rand()%5000; + } + + void JustDied(Unit *killer) + { + if(pInstance) + { + Creature *Vashj = NULL; + Vashj = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LADYVASHJ))); + + if(Vashj) + ((boss_lady_vashjAI*)Vashj->AI())->EventTaintedElementalDeath(); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //PoisonBolt_Timer + if(PoisonBolt_Timer < diff) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if(target && target->IsWithinDistInMap(m_creature, 30)) + DoCast(target, SPELL_POISON_BOLT); + + PoisonBolt_Timer = 5000+rand()%5000; + }else PoisonBolt_Timer -= diff; + } +}; + +//Fathom Sporebat +//Toxic Spores: Used in Phase 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_fathom_sporebatAI : public ScriptedAI +{ + mob_fathom_sporebatAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 ToxicSpore_Timer; + uint32 Check_Timer; + + void Reset() + { + m_creature->setFaction(14); + ToxicSpore_Timer = 5000; + Check_Timer = 1000; + } + + void Aggro(Unit *who) {} + + void UpdateAI (const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ToxicSpore_Timer + if(ToxicSpore_Timer < diff) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + //The Spores will hit you anywhere in the instance: underwater, at the elevator, at the entrance, wherever. + if(target) + DoCast(target, SPELL_TOXIC_SPORES); + + ToxicSpore_Timer = 20000+rand()%5000; + }else ToxicSpore_Timer -= diff; + + //Check_Timer + if(Check_Timer < diff) + { + if(pInstance) + { + //check if vashj is death + Unit *Vashj = NULL; + Vashj = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LADYVASHJ)); + if(!Vashj || (Vashj && !Vashj->isAlive())) + { + //remove + m_creature->setDeathState(DEAD); + m_creature->RemoveCorpse(); + m_creature->setFaction(35); + } + } + + Check_Timer = 1000; + }else Check_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Coilfang Elite +//It's an elite Naga mob with 170,000 HP. It does about 5000 damage on plate, and has a nasty cleave hitting for about 7500 damage +CreatureAI* GetAI_mob_coilfang_elite(Creature *_Creature) +{ + SimpleAI* ai = new SimpleAI (_Creature); + + ai->Spell[0].Enabled = true; + ai->Spell[0].Spell_Id = 31345; //Cleave + ai->Spell[0].Cooldown = 15000; + ai->Spell[0].CooldownRandomAddition = 5000; + ai->Spell[0].First_Cast = 5000; + ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_RANDOM; + + ai->EnterEvadeMode(); + + return ai; +} + +//Coilfang Strifer +//It hits plate for about 8000 damage, has a Mind Blast spell doing about 3000 shadow damage, and a Psychic Scream Aura, which fears everybody in a 8 yard range of it every 2-3 seconds , for 5 seconds and increasing their movement speed by 150% during the fear. +CreatureAI* GetAI_mob_coilfang_strider(Creature *_Creature) +{ + SimpleAI* ai = new SimpleAI (_Creature); + + ai->Spell[0].Enabled = true; + ai->Spell[0].Spell_Id = 41374; //Mind Blast + ai->Spell[0].Cooldown = 30000; + ai->Spell[0].CooldownRandomAddition = 10000; + ai->Spell[0].First_Cast = 8000; + ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; + + //Scream aura not implemented + + ai->EnterEvadeMode(); + + return ai; +} + +struct MANGOS_DLL_DECL mob_shield_generator_channelAI : public ScriptedAI +{ + mob_shield_generator_channelAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Check_Timer; + bool Channeled; + + void Reset() + { + Check_Timer = 1000; + Channeled = false; + //invisible + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID , 11686); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit *who) { return; } + + void MoveInLineOfSight(Unit *who) { return; } + + void UpdateAI (const uint32 diff) + { + if(!pInstance) + return; + + if(!Channeled) + { + Unit *Vashj = NULL; + Vashj = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LADYVASHJ)); + + if(Vashj && Vashj->isAlive()) + { + //start visual channel + m_creature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, Vashj->GetGUID()); + m_creature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_MAGIC_BARRIER); + Channeled = true; + } + } + } +}; + +bool ItemUse_item_tainted_core(Player *player, Item* _Item, SpellCastTargets const& targets) +{ + ScriptedInstance *pInstance = ((ScriptedInstance*)player->GetInstanceData()); + + if(!pInstance) + { + player->GetSession()->SendNotification("ERROR: Instance script not initialized. Notify your administrator."); + error_log("ERROR: Lady Vashj Tainted Core: Instance Script Not Initialized"); + return true; + } + + Creature *Vashj = NULL; + Vashj = (Creature*)(Unit::GetUnit((*player), pInstance->GetData64(DATA_LADYVASHJ))); + if(Vashj && ((boss_lady_vashjAI*)Vashj->AI())->Phase == 2) + { + if(targets.getGOTarget() && targets.getGOTarget()->GetTypeId()==TYPEID_GAMEOBJECT) + { + uint32 identifier; + uint8 channel_identifier; + switch(targets.getGOTarget()->GetEntry()) + { + case 185052: + identifier = DATA_SHIELDGENERATOR1; + channel_identifier = 0; + break; + case 185053: + identifier = DATA_SHIELDGENERATOR2; + channel_identifier = 1; + break; + case 185051: + identifier = DATA_SHIELDGENERATOR3; + channel_identifier = 2; + break; + case 185054: + identifier = DATA_SHIELDGENERATOR4; + channel_identifier = 3; + break; + default: + return true; + break; + } + + if(pInstance->GetData(identifier)) + { + player->GetSession()->SendNotification("Already deactivated"); + return true; + } + + //get and remove channel + Unit *Channel = NULL; + Channel = Unit::GetUnit((*Vashj), ((boss_lady_vashjAI*)Vashj->AI())->ShieldGeneratorChannel[channel_identifier]); + if(Channel) + { + //call Unsummon() + Channel->setDeathState(JUST_DIED); + } + + pInstance->SetData(identifier, 1); + + //remove this item + player->DestroyItemCount(31088, 1, true); + } + } + return true; +} + +CreatureAI* GetAI_boss_lady_vashj(Creature *_Creature) +{ + return new boss_lady_vashjAI (_Creature); +} + +CreatureAI* GetAI_mob_enchanted_elemental(Creature *_Creature) +{ + return new mob_enchanted_elementalAI (_Creature); +} + +CreatureAI* GetAI_mob_tainted_elemental(Creature *_Creature) +{ + return new mob_tainted_elementalAI (_Creature); +} + +CreatureAI* GetAI_mob_fathom_sporebat(Creature *_Creature) +{ + return new mob_fathom_sporebatAI (_Creature); +} + +CreatureAI* GetAI_mob_shield_generator_channel(Creature *_Creature) +{ + return new mob_shield_generator_channelAI (_Creature); +} + +void AddSC_boss_lady_vashj() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_lady_vashj"; + newscript->GetAI = GetAI_boss_lady_vashj; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_enchanted_elemental"; + newscript->GetAI = GetAI_mob_enchanted_elemental; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_tainted_elemental"; + newscript->GetAI = GetAI_mob_tainted_elemental; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_fathom_sporebat"; + newscript->GetAI = GetAI_mob_fathom_sporebat; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_coilfang_elite"; + newscript->GetAI = GetAI_mob_coilfang_elite; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_coilfang_strider"; + newscript->GetAI = GetAI_mob_coilfang_strider; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_shield_generator_channel"; + newscript->GetAI = GetAI_mob_shield_generator_channel; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="item_tainted_core"; + newscript->pItemUse = ItemUse_item_tainted_core; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp index ea54e5ffcab..e689da4c585 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp @@ -1,359 +1,338 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Leotheras_The_Blind -SD%Complete: 50 -SDComment: Missing Inner Demons -SDCategory: Coilfang Resevoir, Serpent Shrine Cavern -EndScriptData */ - -#include "precompiled.h" -#include "def_serpent_shrine.h" - -#define SPELL_WHIRLWIND 40653 -#define SPELL_CHAOS_BLAST 37675 -//#define SPELL_INSIDIOUS_WHISPER 37676 // useless - dummy effect that can't be implemented - -#define SAY_AGGRO "Finally my banishment ends!" -#define SAY_SWITCH_TO_DEMON "Be gone trifling elf. I'm in control now." -#define SAY_INNER_DEMONS "We all have our demons..." -#define SAY_DEMON_SLAY1 "I have no equal." -#define SAY_DEMON_SLAY2 "Perish, mortal." -#define SAY_DEMON_SLAY3 "Yes, YES! Ahahah!" -#define SAY_NIGHTELF_SLAY1 "Kill! KILL!" -#define SAY_NIGHTELF_SLAY2 "That's right! Yes!" -#define SAY_NIGHTELF_SLAY3 "Who's the master now?" -#define SAY_FINAL_FORM "No! NO! What have you done?! I am the master, do you hear me? I... aaghh... Can't... contain him..." -#define SAY_FREE "At last I am liberated. It has been too long since I have tasted true freedom!" -#define SAY_DEATH "You cannot kill me! Fools, I'll be back! I'll... aarghh..." - -#define SOUND_AGGRO 11312 -#define SOUND_SWITCH_TO_DEMON 11304 -#define SOUND_INNER_DEMONS 11305 -#define SOUND_DEMON_SLAY1 11306 -#define SOUND_DEMON_SLAY2 11307 -#define SOUND_DEMON_SLAY3 11308 -#define SOUND_NIGHTELF_SLAY1 11314 -#define SOUND_NIGHTELF_SLAY2 11315 -#define SOUND_NIGHTELF_SLAY3 11316 -#define SOUND_FINAL_FORM 11313 -#define SOUND_FREE 11309 -#define SOUND_DEATH 11317 - -#define MODEL_DEMON 14555 -#define MODEL_NIGHTELF 20514 - -#define DEMON_FORM 21845 - -//Original Leotheras the Blind AI -struct MANGOS_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI -{ - boss_leotheras_the_blindAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Demon = 0; - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Whirlwind_Timer; - uint32 ChaosBlast_Timer; - uint32 Switch_Timer; - - bool DemonForm; - bool IsFinalForm; - - uint64 Demon; - - void Reset() - { - Whirlwind_Timer = 20000; - ChaosBlast_Timer = 1000; - Switch_Timer = 45000; - - DemonForm = false; - IsFinalForm = false; - - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_NIGHTELF); - - if(pInstance) - pInstance->SetData(DATA_LEOTHERASTHEBLINDEVENT, 0); - } - - void StartEvent() - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - - if(pInstance) - pInstance->SetData(DATA_LEOTHERASTHEBLINDEVENT, 1); - } - - void KilledUnit(Unit *victim) - { - if(victim->GetTypeId() != TYPEID_PLAYER) - return; - - if(DemonForm) - switch(rand()%3) - { - case 0: - DoYell(SAY_DEMON_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY1); - break; - case 1: - DoYell(SAY_DEMON_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY2); - break; - case 2: - DoYell(SAY_DEMON_SLAY3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY3); - break; - } - else - switch(rand()%3) - { - case 0: - DoYell(SAY_NIGHTELF_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_NIGHTELF_SLAY1); - break; - case 1: - DoYell(SAY_NIGHTELF_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_NIGHTELF_SLAY2); - break; - case 2: - DoYell(SAY_NIGHTELF_SLAY3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_NIGHTELF_SLAY3); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - //despawn copy - if(Demon) - { - Unit *pUnit = NULL; - pUnit = Unit::GetUnit((*m_creature), Demon); - - if(pUnit) - pUnit->DealDamage(pUnit, pUnit->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - - if(pInstance) - pInstance->SetData(DATA_LEOTHERASTHEBLINDEVENT, 0); - } - - void Aggro(Unit *who) - { - StartEvent(); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(!DemonForm) - { - //Whirlwind_Timer - if(Whirlwind_Timer < diff) - { - DoCast(m_creature, SPELL_WHIRLWIND); - Whirlwind_Timer = 25000; - }else Whirlwind_Timer -= diff; - - //Switch_Timer - if(!IsFinalForm) - if(Switch_Timer < diff) - { - //switch to demon form - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_DEMON); - DoYell(SAY_SWITCH_TO_DEMON, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SWITCH_TO_DEMON); - DemonForm = true; - - Switch_Timer = 60000; - }else Switch_Timer -= diff; - - DoMeleeAttackIfReady(); - } - else - { - //ChaosBlast_Timer - if(ChaosBlast_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CHAOS_BLAST); - ChaosBlast_Timer = 1500; - }else ChaosBlast_Timer -= diff; - - //Switch_Timer - if(Switch_Timer < diff) - { - //switch to nightelf form - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_NIGHTELF); - DemonForm = false; - - Switch_Timer = 45000; - }else Switch_Timer -= diff; - } - - if(!IsFinalForm && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 15) - { - //at this point he divides himself in two parts - Creature *Copy = NULL; - Copy = DoSpawnCreature(DEMON_FORM, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - - if(Copy) - { - Demon = Copy->GetGUID(); - Copy->AI()->AttackStart(m_creature->getVictim()); - } - - //set nightelf final form - IsFinalForm = true; - DemonForm = false; - - DoYell(SAY_FINAL_FORM, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_FINAL_FORM); - - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_NIGHTELF); - } - } -}; - -//Leotheras the Blind Demon Form AI -struct MANGOS_DLL_DECL boss_leotheras_the_blind_demonformAI : public ScriptedAI -{ - boss_leotheras_the_blind_demonformAI(Creature *c) : ScriptedAI(c) - { - Reset(); - } - - uint32 ChaosBlast_Timer; - - void Reset() - { - ChaosBlast_Timer = 1000; - } - - void StartEvent() - { - DoYell(SAY_FREE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_FREE); - } - - void KilledUnit(Unit *victim) - { - if(victim->GetTypeId() != TYPEID_PLAYER) - return; - - switch(rand()%3) - { - case 0: - DoYell(SAY_DEMON_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY1); - break; - case 1: - DoYell(SAY_DEMON_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY2); - break; - case 2: - DoYell(SAY_DEMON_SLAY3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY3); - break; - } - } - - void JustDied(Unit *victim) - { - //invisibility (blizzlike, at the end of the fight he doesn't die, he disappears) - m_creature->CastSpell(m_creature, 8149, true); - } - - void Aggro(Unit *who) - { - StartEvent(); - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - - if(!InCombat) - StartEvent(); - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ChaosBlast_Timer - if(ChaosBlast_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CHAOS_BLAST); - ChaosBlast_Timer = 1500; - }else ChaosBlast_Timer -= diff; - - //Do NOT deal any melee damage to the target. - } -}; - -CreatureAI* GetAI_boss_leotheras_the_blind(Creature *_Creature) -{ - return new boss_leotheras_the_blindAI (_Creature); -} - -CreatureAI* GetAI_boss_leotheras_the_blind_demonform(Creature *_Creature) -{ - return new boss_leotheras_the_blind_demonformAI (_Creature); -} - -void AddSC_boss_leotheras_the_blind() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_leotheras_the_blind"; - newscript->GetAI = GetAI_boss_leotheras_the_blind; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_leotheras_the_blind_demonform"; - newscript->GetAI = GetAI_boss_leotheras_the_blind_demonform; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Leotheras_The_Blind +SD%Complete: 50 +SDComment: Missing Inner Demons +SDCategory: Coilfang Resevoir, Serpent Shrine Cavern +EndScriptData */ + +#include "precompiled.h" +#include "def_serpent_shrine.h" + +#define SPELL_WHIRLWIND 40653 +#define SPELL_CHAOS_BLAST 37675 +//#define SPELL_INSIDIOUS_WHISPER 37676 // useless - dummy effect that can't be implemented + +#define SAY_AGGRO "Finally my banishment ends!" +#define SAY_SWITCH_TO_DEMON "Be gone trifling elf. I'm in control now." +#define SAY_INNER_DEMONS "We all have our demons..." +#define SAY_DEMON_SLAY1 "I have no equal." +#define SAY_DEMON_SLAY2 "Perish, mortal." +#define SAY_DEMON_SLAY3 "Yes, YES! Ahahah!" +#define SAY_NIGHTELF_SLAY1 "Kill! KILL!" +#define SAY_NIGHTELF_SLAY2 "That's right! Yes!" +#define SAY_NIGHTELF_SLAY3 "Who's the master now?" +#define SAY_FINAL_FORM "No! NO! What have you done?! I am the master, do you hear me? I... aaghh... Can't... contain him..." +#define SAY_FREE "At last I am liberated. It has been too long since I have tasted true freedom!" +#define SAY_DEATH "You cannot kill me! Fools, I'll be back! I'll... aarghh..." + +#define SOUND_AGGRO 11312 +#define SOUND_SWITCH_TO_DEMON 11304 +#define SOUND_INNER_DEMONS 11305 +#define SOUND_DEMON_SLAY1 11306 +#define SOUND_DEMON_SLAY2 11307 +#define SOUND_DEMON_SLAY3 11308 +#define SOUND_NIGHTELF_SLAY1 11314 +#define SOUND_NIGHTELF_SLAY2 11315 +#define SOUND_NIGHTELF_SLAY3 11316 +#define SOUND_FINAL_FORM 11313 +#define SOUND_FREE 11309 +#define SOUND_DEATH 11317 + +#define MODEL_DEMON 14555 +#define MODEL_NIGHTELF 20514 + +#define DEMON_FORM 21845 + +//Original Leotheras the Blind AI +struct MANGOS_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI +{ + boss_leotheras_the_blindAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Demon = 0; + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Whirlwind_Timer; + uint32 ChaosBlast_Timer; + uint32 Switch_Timer; + + bool DemonForm; + bool IsFinalForm; + + uint64 Demon; + + void Reset() + { + Whirlwind_Timer = 20000; + ChaosBlast_Timer = 1000; + Switch_Timer = 45000; + + DemonForm = false; + IsFinalForm = false; + + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_NIGHTELF); + + if(pInstance) + pInstance->SetData(DATA_LEOTHERASTHEBLINDEVENT, 0); + } + + void StartEvent() + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + + if(pInstance) + pInstance->SetData(DATA_LEOTHERASTHEBLINDEVENT, 1); + } + + void KilledUnit(Unit *victim) + { + if(victim->GetTypeId() != TYPEID_PLAYER) + return; + + if(DemonForm) + switch(rand()%3) + { + case 0: + DoYell(SAY_DEMON_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY1); + break; + case 1: + DoYell(SAY_DEMON_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY2); + break; + case 2: + DoYell(SAY_DEMON_SLAY3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY3); + break; + } + else + switch(rand()%3) + { + case 0: + DoYell(SAY_NIGHTELF_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_NIGHTELF_SLAY1); + break; + case 1: + DoYell(SAY_NIGHTELF_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_NIGHTELF_SLAY2); + break; + case 2: + DoYell(SAY_NIGHTELF_SLAY3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_NIGHTELF_SLAY3); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + //despawn copy + if(Demon) + { + Unit *pUnit = NULL; + pUnit = Unit::GetUnit((*m_creature), Demon); + + if(pUnit) + pUnit->DealDamage(pUnit, pUnit->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + if(pInstance) + pInstance->SetData(DATA_LEOTHERASTHEBLINDEVENT, 0); + } + + void Aggro(Unit *who) + { + StartEvent(); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(!DemonForm) + { + //Whirlwind_Timer + if(Whirlwind_Timer < diff) + { + DoCast(m_creature, SPELL_WHIRLWIND); + Whirlwind_Timer = 25000; + }else Whirlwind_Timer -= diff; + + //Switch_Timer + if(!IsFinalForm) + if(Switch_Timer < diff) + { + //switch to demon form + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_DEMON); + DoYell(SAY_SWITCH_TO_DEMON, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SWITCH_TO_DEMON); + DemonForm = true; + + Switch_Timer = 60000; + }else Switch_Timer -= diff; + + DoMeleeAttackIfReady(); + } + else + { + //ChaosBlast_Timer + if(ChaosBlast_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CHAOS_BLAST); + ChaosBlast_Timer = 1500; + }else ChaosBlast_Timer -= diff; + + //Switch_Timer + if(Switch_Timer < diff) + { + //switch to nightelf form + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_NIGHTELF); + DemonForm = false; + + Switch_Timer = 45000; + }else Switch_Timer -= diff; + } + + if(!IsFinalForm && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 15) + { + //at this point he divides himself in two parts + Creature *Copy = NULL; + Copy = DoSpawnCreature(DEMON_FORM, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + + if(Copy) + { + Demon = Copy->GetGUID(); + Copy->AI()->AttackStart(m_creature->getVictim()); + } + + //set nightelf final form + IsFinalForm = true; + DemonForm = false; + + DoYell(SAY_FINAL_FORM, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_FINAL_FORM); + + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_NIGHTELF); + } + } +}; + +//Leotheras the Blind Demon Form AI +struct MANGOS_DLL_DECL boss_leotheras_the_blind_demonformAI : public ScriptedAI +{ + boss_leotheras_the_blind_demonformAI(Creature *c) : ScriptedAI(c) + { + Reset(); + } + + uint32 ChaosBlast_Timer; + + void Reset() + { + ChaosBlast_Timer = 1000; + } + + void StartEvent() + { + DoYell(SAY_FREE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_FREE); + } + + void KilledUnit(Unit *victim) + { + if(victim->GetTypeId() != TYPEID_PLAYER) + return; + + switch(rand()%3) + { + case 0: + DoYell(SAY_DEMON_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY1); + break; + case 1: + DoYell(SAY_DEMON_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY2); + break; + case 2: + DoYell(SAY_DEMON_SLAY3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEMON_SLAY3); + break; + } + } + + void JustDied(Unit *victim) + { + //invisibility (blizzlike, at the end of the fight he doesn't die, he disappears) + m_creature->CastSpell(m_creature, 8149, true); + } + + void Aggro(Unit *who) + { + StartEvent(); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ChaosBlast_Timer + if(ChaosBlast_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CHAOS_BLAST); + ChaosBlast_Timer = 1500; + }else ChaosBlast_Timer -= diff; + + //Do NOT deal any melee damage to the target. + } +}; + +CreatureAI* GetAI_boss_leotheras_the_blind(Creature *_Creature) +{ + return new boss_leotheras_the_blindAI (_Creature); +} + +CreatureAI* GetAI_boss_leotheras_the_blind_demonform(Creature *_Creature) +{ + return new boss_leotheras_the_blind_demonformAI (_Creature); +} + +void AddSC_boss_leotheras_the_blind() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_leotheras_the_blind"; + newscript->GetAI = GetAI_boss_leotheras_the_blind; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_leotheras_the_blind_demonform"; + newscript->GetAI = GetAI_boss_leotheras_the_blind_demonform; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp index 27ebaf4bd7e..9283c30fe72 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp @@ -1,406 +1,406 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* ScriptData -SDName: Boss_Morogrim_Tidewalker -SD%Complete: 90 -SDComment: Water globules don't explode properly -SDCategory: Coilfang Resevoir, Serpent Shrine Cavern -EndScriptData */ - -#include "precompiled.h" -#include "def_serpent_shrine.h" - -#define SPELL_TIDAL_WAVE 37730 -#define SPELL_WATERY_GRAVE 38049 -#define SPELL_EARTHQUAKE 37764 -#define SPELL_WATERY_GRAVE_EXPLOSION 37852 - -#define SAY_AGGRO "Flood of the deep, take you!" -#define SAY_SUMMON1 "By the Tides, kill them at once!" -#define SAY_SUMMON2 "Destroy them my subjects!" -#define SAY_SLAY1 "It is done!" -#define SAY_SLAY2 "Strugging only makes it worse." -#define SAY_SLAY3 "Only the strong survive." -#define SAY_SUMMON_BUBL1 "There is nowhere to hide!" -#define SAY_SUMMON_BUBL2 "Soon it will be finished!" -#define SAY_DEATH "Great... currents of... Ageon." - -#define SOUND_AGGRO 11321 -#define SOUND_SUMMON1 11322 -#define SOUND_SUMMON2 11323 -#define SOUND_SLAY1 11326 -#define SOUND_SLAY2 11327 -#define SOUND_SLAY3 11328 -#define SOUND_SUMMON_BUBL1 11324 -#define SOUND_SUMMON_BUBL2 11325 -#define SOUND_DEATH 11329 - -#define WATERY_GRAVE_X1 334.64 -#define WATERY_GRAVE_Y1 -728.89 -#define WATERY_GRAVE_Z1 -14.42 -#define WATERY_GRAVE_X2 365.51 -#define WATERY_GRAVE_Y2 -737.14 -#define WATERY_GRAVE_Z2 -14.44 -#define WATERY_GRAVE_X3 366.19 -#define WATERY_GRAVE_Y3 -709.59 -#define WATERY_GRAVE_Z3 -14.36 -#define WATERY_GRAVE_X4 372.93 -#define WATERY_GRAVE_Y4 -690.96 -#define WATERY_GRAVE_Z4 -14.44 - -#define EMOTE_WATERY_GRAVE "sends his enemies to their watery graves!" -#define EMOTE_EARTHQUAKE "The violent earthquake has alerted nearby murlocs!" -#define EMOTE_WATERY_GLOBULES "summons Watery Globules!" - -#define WATER_GLOBULE 21913 -#define TIDEWALKER_LURKER 21920 - -//Morogrim Tidewalker AI -struct MANGOS_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI -{ - boss_morogrim_tidewalkerAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 TidalWave_Timer; - uint32 WateryGrave_Timer; - uint32 Earthquake_Timer; - uint32 WateryGlobules_Timer; - - bool Earthquake; - bool Phase2; - - void Reset() - { - TidalWave_Timer = 10000; - WateryGrave_Timer = 30000; - Earthquake_Timer = 40000; - WateryGlobules_Timer = 0; - - Earthquake = false; - Phase2 = false; - - if(pInstance) - pInstance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, NOT_STARTED); - } - - void StartEvent() - { - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - - if(pInstance) - pInstance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, IN_PROGRESS); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - break; - - case 1: - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); - break; - - case 2: - DoPlaySoundToSet(m_creature, SOUND_SLAY3); - DoYell(SAY_SLAY3, LANG_UNIVERSAL, NULL); - break; - } - } - - void JustDied(Unit *victim) - { - DoPlaySoundToSet(m_creature, SOUND_DEATH); - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - - if(pInstance) - pInstance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, NOT_STARTED); - } - - void Aggro(Unit *who) { StartEvent(); } - - void ApplyWateryGrave(Unit *player, uint8 pos) - { - float x, y, z; - - switch(pos) - { - case 0: - x = WATERY_GRAVE_X1; - y = WATERY_GRAVE_Y1; - z = WATERY_GRAVE_Z1; - break; - - case 1: - x = WATERY_GRAVE_X2; - y = WATERY_GRAVE_Y2; - z = WATERY_GRAVE_Z2; - break; - - case 2: - x = WATERY_GRAVE_X3; - y = WATERY_GRAVE_Y3; - z = WATERY_GRAVE_Z3; - break; - - case 3: - x = WATERY_GRAVE_X4; - y = WATERY_GRAVE_Y4; - z = WATERY_GRAVE_Z4; - break; - } - - DoTeleportPlayer(player, x, y, z+1, player->GetOrientation()); - DoCast(player, SPELL_WATERY_GRAVE); - } - - void SummonMurloc(float x, float y, float z) - { - Creature *Summoned; - - Summoned = m_creature->SummonCreature(TIDEWALKER_LURKER, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - if(Summoned) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - Summoned->AI()->AttackStart(target); - } - } - - void SummonWaterGlobule(float x, float y, float z) - { - Creature *Globule; - - Globule = m_creature->SummonCreature(WATER_GLOBULE, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); //they despawn after 30 seconds - if(Globule) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - Globule->AI()->AttackStart(target); - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Earthquake_Timer - if(Earthquake_Timer < diff) - { - if(!Earthquake) - { - DoCast(m_creature->getVictim(), SPELL_EARTHQUAKE); - Earthquake = true; - Earthquake_Timer = 10000; - } - else - { - switch(rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_SUMMON1); - DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); - break; - - case 1: - DoPlaySoundToSet(m_creature, SOUND_SUMMON2); - DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); - break; - } - - //north - SummonMurloc(486.10, -723.64, -7.14); - SummonMurloc(482.58, -723.78, -7.14); - SummonMurloc(479.38, -723.91, -7.14); - SummonMurloc(476.03, -723.86, -7.14); - SummonMurloc(472.69, -723.69, -7.14); - SummonMurloc(469.04, -723.63, -7.14); - - //south - SummonMurloc(311.63, -725.04, -13.15); - SummonMurloc(307.81, -725.34, -13.15); - SummonMurloc(303.91, -725.64, -13.06); - SummonMurloc(300.23, -726, -11.89); - SummonMurloc(296.82, -726.33, -10.82); - SummonMurloc(293.64, -726.64, -9.81); - - DoTextEmote(EMOTE_EARTHQUAKE, NULL); - - Earthquake = false; - Earthquake_Timer = 40000+rand()%5000; - } - }else Earthquake_Timer -= diff; - - //TidalWave_Timer - if(TidalWave_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_TIDAL_WAVE); - TidalWave_Timer = 20000; - }else TidalWave_Timer -= diff; - - if(!Phase2) - { - //WateryGrave_Timer - if(WateryGrave_Timer < diff) - { - //Teleport 4 players under the waterfalls - Unit *target; - for(uint8 i = 0; i < 4; i++) - { - target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(target && (target->GetTypeId() == TYPEID_PLAYER) && !target->HasAura(SPELL_WATERY_GRAVE, 0) && target->IsWithinDistInMap(m_creature, 50)) - ApplyWateryGrave(target, i); - } - - switch(rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_SUMMON_BUBL1); - DoYell(SAY_SUMMON_BUBL1, LANG_UNIVERSAL, NULL); - break; - - case 1: - DoPlaySoundToSet(m_creature, SOUND_SUMMON_BUBL2); - DoYell(SAY_SUMMON_BUBL2, LANG_UNIVERSAL, NULL); - break; - - case 2: - break; - } - - DoTextEmote(EMOTE_WATERY_GRAVE, NULL); - - WateryGrave_Timer = 30000; - }else WateryGrave_Timer -= diff; - - //Start Phase2 - if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) - Phase2 = true; - } - else - { - //WateryGlobules_Timer - if(WateryGlobules_Timer < diff) - { - SummonWaterGlobule(WATERY_GRAVE_X1, WATERY_GRAVE_Y1, WATERY_GRAVE_Z1); - SummonWaterGlobule(WATERY_GRAVE_X2, WATERY_GRAVE_Y2, WATERY_GRAVE_Z2); - SummonWaterGlobule(WATERY_GRAVE_X3, WATERY_GRAVE_Y3, WATERY_GRAVE_Z3); - SummonWaterGlobule(WATERY_GRAVE_X4, WATERY_GRAVE_Y4, WATERY_GRAVE_Z4); - - DoTextEmote(EMOTE_WATERY_GLOBULES, NULL); - - WateryGlobules_Timer = 25000; - }else WateryGlobules_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; - -//Water Globule AI -struct MANGOS_DLL_DECL mob_water_globuleAI : public ScriptedAI -{ - mob_water_globuleAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Check_Timer; - - void Reset() - { - Check_Timer = 1000; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(14); - } - - void Aggro(Unit *who) {} - - void MoveInLineOfSight(Unit *who) - { - if (!who || m_creature->getVictim()) - return; - - if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) - { - //no attack radius check - it attacks the first target that moves in his los - if(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(Check_Timer < diff) - { - if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 5)) - { - uint32 damage = 4000+rand()%2000; - m_creature->DealDamage(m_creature->getVictim(), damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_FROST, NULL, false); - - //despawn - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - Check_Timer = 500; - }else Check_Timer -= diff; - - //do NOT deal any melee damage to the target. - } -}; - -CreatureAI* GetAI_boss_morogrim_tidewalker(Creature *_Creature) -{ - return new boss_morogrim_tidewalkerAI (_Creature); -} -CreatureAI* GetAI_mob_water_globule(Creature *_Creature) -{ - return new mob_water_globuleAI (_Creature); -} - -void AddSC_boss_morogrim_tidewalker() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_morogrim_tidewalker"; - newscript->GetAI = GetAI_boss_morogrim_tidewalker; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_water_globule"; - newscript->GetAI = GetAI_mob_water_globule; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: Boss_Morogrim_Tidewalker +SD%Complete: 90 +SDComment: Water globules don't explode properly +SDCategory: Coilfang Resevoir, Serpent Shrine Cavern +EndScriptData */ + +#include "precompiled.h" +#include "def_serpent_shrine.h" + +#define SPELL_TIDAL_WAVE 37730 +#define SPELL_WATERY_GRAVE 38049 +#define SPELL_EARTHQUAKE 37764 +#define SPELL_WATERY_GRAVE_EXPLOSION 37852 + +#define SAY_AGGRO "Flood of the deep, take you!" +#define SAY_SUMMON1 "By the Tides, kill them at once!" +#define SAY_SUMMON2 "Destroy them my subjects!" +#define SAY_SLAY1 "It is done!" +#define SAY_SLAY2 "Strugging only makes it worse." +#define SAY_SLAY3 "Only the strong survive." +#define SAY_SUMMON_BUBL1 "There is nowhere to hide!" +#define SAY_SUMMON_BUBL2 "Soon it will be finished!" +#define SAY_DEATH "Great... currents of... Ageon." + +#define SOUND_AGGRO 11321 +#define SOUND_SUMMON1 11322 +#define SOUND_SUMMON2 11323 +#define SOUND_SLAY1 11326 +#define SOUND_SLAY2 11327 +#define SOUND_SLAY3 11328 +#define SOUND_SUMMON_BUBL1 11324 +#define SOUND_SUMMON_BUBL2 11325 +#define SOUND_DEATH 11329 + +#define WATERY_GRAVE_X1 334.64 +#define WATERY_GRAVE_Y1 -728.89 +#define WATERY_GRAVE_Z1 -14.42 +#define WATERY_GRAVE_X2 365.51 +#define WATERY_GRAVE_Y2 -737.14 +#define WATERY_GRAVE_Z2 -14.44 +#define WATERY_GRAVE_X3 366.19 +#define WATERY_GRAVE_Y3 -709.59 +#define WATERY_GRAVE_Z3 -14.36 +#define WATERY_GRAVE_X4 372.93 +#define WATERY_GRAVE_Y4 -690.96 +#define WATERY_GRAVE_Z4 -14.44 + +#define EMOTE_WATERY_GRAVE "sends his enemies to their watery graves!" +#define EMOTE_EARTHQUAKE "The violent earthquake has alerted nearby murlocs!" +#define EMOTE_WATERY_GLOBULES "summons Watery Globules!" + +#define WATER_GLOBULE 21913 +#define TIDEWALKER_LURKER 21920 + +//Morogrim Tidewalker AI +struct MANGOS_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI +{ + boss_morogrim_tidewalkerAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 TidalWave_Timer; + uint32 WateryGrave_Timer; + uint32 Earthquake_Timer; + uint32 WateryGlobules_Timer; + + bool Earthquake; + bool Phase2; + + void Reset() + { + TidalWave_Timer = 10000; + WateryGrave_Timer = 30000; + Earthquake_Timer = 40000; + WateryGlobules_Timer = 0; + + Earthquake = false; + Phase2 = false; + + if(pInstance) + pInstance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, NOT_STARTED); + } + + void StartEvent() + { + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + + if(pInstance) + pInstance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + break; + + case 1: + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); + break; + + case 2: + DoPlaySoundToSet(m_creature, SOUND_SLAY3); + DoYell(SAY_SLAY3, LANG_UNIVERSAL, NULL); + break; + } + } + + void JustDied(Unit *victim) + { + DoPlaySoundToSet(m_creature, SOUND_DEATH); + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + + if(pInstance) + pInstance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, NOT_STARTED); + } + + void Aggro(Unit *who) { StartEvent(); } + + void ApplyWateryGrave(Unit *player, uint8 pos) + { + float x, y, z; + + switch(pos) + { + case 0: + x = WATERY_GRAVE_X1; + y = WATERY_GRAVE_Y1; + z = WATERY_GRAVE_Z1; + break; + + case 1: + x = WATERY_GRAVE_X2; + y = WATERY_GRAVE_Y2; + z = WATERY_GRAVE_Z2; + break; + + case 2: + x = WATERY_GRAVE_X3; + y = WATERY_GRAVE_Y3; + z = WATERY_GRAVE_Z3; + break; + + case 3: + x = WATERY_GRAVE_X4; + y = WATERY_GRAVE_Y4; + z = WATERY_GRAVE_Z4; + break; + } + + DoTeleportPlayer(player, x, y, z+1, player->GetOrientation()); + DoCast(player, SPELL_WATERY_GRAVE); + } + + void SummonMurloc(float x, float y, float z) + { + Creature *Summoned; + + Summoned = m_creature->SummonCreature(TIDEWALKER_LURKER, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + if(Summoned) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + Summoned->AI()->AttackStart(target); + } + } + + void SummonWaterGlobule(float x, float y, float z) + { + Creature *Globule; + + Globule = m_creature->SummonCreature(WATER_GLOBULE, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); //they despawn after 30 seconds + if(Globule) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + Globule->AI()->AttackStart(target); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Earthquake_Timer + if(Earthquake_Timer < diff) + { + if(!Earthquake) + { + DoCast(m_creature->getVictim(), SPELL_EARTHQUAKE); + Earthquake = true; + Earthquake_Timer = 10000; + } + else + { + switch(rand()%2) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_SUMMON1); + DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); + break; + + case 1: + DoPlaySoundToSet(m_creature, SOUND_SUMMON2); + DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); + break; + } + + //north + SummonMurloc(486.10, -723.64, -7.14); + SummonMurloc(482.58, -723.78, -7.14); + SummonMurloc(479.38, -723.91, -7.14); + SummonMurloc(476.03, -723.86, -7.14); + SummonMurloc(472.69, -723.69, -7.14); + SummonMurloc(469.04, -723.63, -7.14); + + //south + SummonMurloc(311.63, -725.04, -13.15); + SummonMurloc(307.81, -725.34, -13.15); + SummonMurloc(303.91, -725.64, -13.06); + SummonMurloc(300.23, -726, -11.89); + SummonMurloc(296.82, -726.33, -10.82); + SummonMurloc(293.64, -726.64, -9.81); + + DoTextEmote(EMOTE_EARTHQUAKE, NULL); + + Earthquake = false; + Earthquake_Timer = 40000+rand()%5000; + } + }else Earthquake_Timer -= diff; + + //TidalWave_Timer + if(TidalWave_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_TIDAL_WAVE); + TidalWave_Timer = 20000; + }else TidalWave_Timer -= diff; + + if(!Phase2) + { + //WateryGrave_Timer + if(WateryGrave_Timer < diff) + { + //Teleport 4 players under the waterfalls + Unit *target; + for(uint8 i = 0; i < 4; i++) + { + target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(target && (target->GetTypeId() == TYPEID_PLAYER) && !target->HasAura(SPELL_WATERY_GRAVE, 0) && target->IsWithinDistInMap(m_creature, 50)) + ApplyWateryGrave(target, i); + } + + switch(rand()%2) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_SUMMON_BUBL1); + DoYell(SAY_SUMMON_BUBL1, LANG_UNIVERSAL, NULL); + break; + + case 1: + DoPlaySoundToSet(m_creature, SOUND_SUMMON_BUBL2); + DoYell(SAY_SUMMON_BUBL2, LANG_UNIVERSAL, NULL); + break; + + case 2: + break; + } + + DoTextEmote(EMOTE_WATERY_GRAVE, NULL); + + WateryGrave_Timer = 30000; + }else WateryGrave_Timer -= diff; + + //Start Phase2 + if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) + Phase2 = true; + } + else + { + //WateryGlobules_Timer + if(WateryGlobules_Timer < diff) + { + SummonWaterGlobule(WATERY_GRAVE_X1, WATERY_GRAVE_Y1, WATERY_GRAVE_Z1); + SummonWaterGlobule(WATERY_GRAVE_X2, WATERY_GRAVE_Y2, WATERY_GRAVE_Z2); + SummonWaterGlobule(WATERY_GRAVE_X3, WATERY_GRAVE_Y3, WATERY_GRAVE_Z3); + SummonWaterGlobule(WATERY_GRAVE_X4, WATERY_GRAVE_Y4, WATERY_GRAVE_Z4); + + DoTextEmote(EMOTE_WATERY_GLOBULES, NULL); + + WateryGlobules_Timer = 25000; + }else WateryGlobules_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +//Water Globule AI +struct MANGOS_DLL_DECL mob_water_globuleAI : public ScriptedAI +{ + mob_water_globuleAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Check_Timer; + + void Reset() + { + Check_Timer = 1000; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->setFaction(14); + } + + void Aggro(Unit *who) {} + + void MoveInLineOfSight(Unit *who) + { + if (!who || m_creature->getVictim()) + return; + + if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) + { + //no attack radius check - it attacks the first target that moves in his los + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + DoStartAttackAndMovement(who); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(Check_Timer < diff) + { + if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 5)) + { + uint32 damage = 4000+rand()%2000; + m_creature->DealDamage(m_creature->getVictim(), damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_FROST, NULL, false); + + //despawn + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + Check_Timer = 500; + }else Check_Timer -= diff; + + //do NOT deal any melee damage to the target. + } +}; + +CreatureAI* GetAI_boss_morogrim_tidewalker(Creature *_Creature) +{ + return new boss_morogrim_tidewalkerAI (_Creature); +} +CreatureAI* GetAI_mob_water_globule(Creature *_Creature) +{ + return new mob_water_globuleAI (_Creature); +} + +void AddSC_boss_morogrim_tidewalker() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_morogrim_tidewalker"; + newscript->GetAI = GetAI_boss_morogrim_tidewalker; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_water_globule"; + newscript->GetAI = GetAI_mob_water_globule; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/def_serpent_shrine.h b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/def_serpent_shrine.h index 21d76d6854a..52b8a88ebc3 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/def_serpent_shrine.h +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/def_serpent_shrine.h @@ -1,26 +1,26 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_SERPENT_SHRINE_H -#define DEF_SERPENT_SHRINE_H - -#define DATA_CANSTARTPHASE3 1 -#define DATA_CARIBDIS 2 -#define DATA_HYDROSSTHEUNSTABLEEVENT 3 -#define DATA_KARATHRESS 4 -#define DATA_KARATHRESSEVENT 5 -#define DATA_KARATHRESSEVENT_STARTER 6 -#define DATA_LADYVASHJ 7 -#define DATA_LADYVASHJEVENT 8 -#define DATA_LEOTHERASTHEBLINDEVENT 9 -#define DATA_MOROGRIMTIDEWALKEREVENT 10 -#define DATA_SHARKKIS 11 -#define DATA_SHIELDGENERATOR1 12 -#define DATA_SHIELDGENERATOR2 13 -#define DATA_SHIELDGENERATOR3 14 -#define DATA_SHIELDGENERATOR4 15 -#define DATA_THELURKERBELOWEVENT 16 -#define DATA_TIDALVESS 17 -#define DATA_FATHOMLORDKARATHRESSEVENT 18 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_SERPENT_SHRINE_H +#define DEF_SERPENT_SHRINE_H + +#define DATA_CANSTARTPHASE3 1 +#define DATA_CARIBDIS 2 +#define DATA_HYDROSSTHEUNSTABLEEVENT 3 +#define DATA_KARATHRESS 4 +#define DATA_KARATHRESSEVENT 5 +#define DATA_KARATHRESSEVENT_STARTER 6 +#define DATA_LADYVASHJ 7 +#define DATA_LADYVASHJEVENT 8 +#define DATA_LEOTHERASTHEBLINDEVENT 9 +#define DATA_MOROGRIMTIDEWALKEREVENT 10 +#define DATA_SHARKKIS 11 +#define DATA_SHIELDGENERATOR1 12 +#define DATA_SHIELDGENERATOR2 13 +#define DATA_SHIELDGENERATOR3 14 +#define DATA_SHIELDGENERATOR4 15 +#define DATA_THELURKERBELOWEVENT 16 +#define DATA_TIDALVESS 17 +#define DATA_FATHOMLORDKARATHRESSEVENT 18 +#endif diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp index d1a90449abf..4dcfbc9189d 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp @@ -1,227 +1,227 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Serpent_Shrine -SD%Complete: 0 -SDComment: VERIFY SCRIPT -SDCategory: Coilfang Resevoir, Serpent Shrine Cavern -EndScriptData */ - -#include "precompiled.h" -#include "def_serpent_shrine.h" - -#define ENCOUNTERS 6 - -/* Serpentshrine cavern encounters: -0 - Hydross The Unstable event -1 - Leotheras The Blind Event -2 - The Lurker Below Event -3 - Fathom-Lord Karathress Event -4 - Morogrim Tidewalker Event -5 - Lady Vashj Event -*/ - -struct MANGOS_DLL_DECL instance_serpentshrine_cavern : public ScriptedInstance -{ - instance_serpentshrine_cavern(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint64 Sharkkis; - uint64 Tidalvess; - uint64 Caribdis; - uint64 LadyVashj; - uint64 Karathress; - uint64 KarathressEvent_Starter; - - bool ShieldGeneratorDeactivated[4]; - - bool Encounters[ENCOUNTERS]; - - void Initialize() - { - Sharkkis = 0; - Tidalvess = 0; - Caribdis = 0; - LadyVashj = 0; - Karathress = 0; - KarathressEvent_Starter = 0; - - ShieldGeneratorDeactivated[0] = false; - ShieldGeneratorDeactivated[1] = false; - ShieldGeneratorDeactivated[2] = false; - ShieldGeneratorDeactivated[3] = false; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounters[i] = false; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; i++) - if(Encounters[i]) return true; - - return false; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case 21212: LadyVashj = creature->GetGUID(); break; - case 21214: Karathress = creature->GetGUID(); break; - case 21966: Sharkkis = creature->GetGUID(); break; - case 21965: Tidalvess = creature->GetGUID(); break; - case 21964: Caribdis = creature->GetGUID(); break; - } - } - - void SetData64(uint32 type, uint64 data) - { - if(type == DATA_KARATHRESSEVENT_STARTER) - KarathressEvent_Starter = data; - } - - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_SHARKKIS: - return Sharkkis; - case DATA_TIDALVESS: - return Tidalvess; - case DATA_CARIBDIS: - return Caribdis; - case DATA_LADYVASHJ: - return LadyVashj; - case DATA_KARATHRESS: - return Karathress; - case DATA_KARATHRESSEVENT_STARTER: - return KarathressEvent_Starter; - } - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_HYDROSSTHEUNSTABLEEVENT: - Encounters[0] = (data) ? true : false; - break; - - case DATA_LEOTHERASTHEBLINDEVENT: - Encounters[1] = (data) ? true : false; - break; - - case DATA_THELURKERBELOWEVENT: - Encounters[2] = (data) ? true : false; - break; - - case DATA_KARATHRESSEVENT: - Encounters[3] = (data) ? true : false; - break; - - case DATA_MOROGRIMTIDEWALKEREVENT: - Encounters[4] = (data) ? true : false; - break; - //Lady Vashj - case DATA_LADYVASHJEVENT: - if(data == 0) - { - ShieldGeneratorDeactivated[0] = false; - ShieldGeneratorDeactivated[1] = false; - ShieldGeneratorDeactivated[2] = false; - ShieldGeneratorDeactivated[3] = false; - } - Encounters[5] = (data) ? true : false; - break; - - case DATA_SHIELDGENERATOR1: - ShieldGeneratorDeactivated[0] = (data) ? true : false; - break; - - case DATA_SHIELDGENERATOR2: - ShieldGeneratorDeactivated[1] = (data) ? true : false; - break; - - case DATA_SHIELDGENERATOR3: - ShieldGeneratorDeactivated[2] = (data) ? true : false; - break; - - case DATA_SHIELDGENERATOR4: - ShieldGeneratorDeactivated[3] = (data) ? true : false; - break; - } - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_HYDROSSTHEUNSTABLEEVENT: - return Encounters[0]; - - case DATA_LEOTHERASTHEBLINDEVENT: - return Encounters[1]; - - case DATA_THELURKERBELOWEVENT: - return Encounters[2]; - - case DATA_KARATHRESSEVENT: - return Encounters[3]; - - case DATA_MOROGRIMTIDEWALKEREVENT: - return Encounters[4]; - - //Lady Vashj - case DATA_LADYVASHJEVENT: - return Encounters[5]; - - case DATA_SHIELDGENERATOR1: - return ShieldGeneratorDeactivated[0]; - - case DATA_SHIELDGENERATOR2: - return ShieldGeneratorDeactivated[1]; - - case DATA_SHIELDGENERATOR3: - return ShieldGeneratorDeactivated[2]; - - case DATA_SHIELDGENERATOR4: - return ShieldGeneratorDeactivated[3]; - - case DATA_CANSTARTPHASE3: - if(ShieldGeneratorDeactivated[0] && ShieldGeneratorDeactivated[1] && ShieldGeneratorDeactivated[2] && ShieldGeneratorDeactivated[3]) - return 1; - break; - } - - return 0; - } -}; - -InstanceData* GetInstanceData_instance_serpentshrine_cavern(Map* map) -{ - return new instance_serpentshrine_cavern(map); -} - -void AddSC_instance_serpentshrine_cavern() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_serpent_shrine"; - newscript->GetInstanceData = GetInstanceData_instance_serpentshrine_cavern; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Serpent_Shrine +SD%Complete: 0 +SDComment: VERIFY SCRIPT +SDCategory: Coilfang Resevoir, Serpent Shrine Cavern +EndScriptData */ + +#include "precompiled.h" +#include "def_serpent_shrine.h" + +#define ENCOUNTERS 6 + +/* Serpentshrine cavern encounters: +0 - Hydross The Unstable event +1 - Leotheras The Blind Event +2 - The Lurker Below Event +3 - Fathom-Lord Karathress Event +4 - Morogrim Tidewalker Event +5 - Lady Vashj Event +*/ + +struct MANGOS_DLL_DECL instance_serpentshrine_cavern : public ScriptedInstance +{ + instance_serpentshrine_cavern(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint64 Sharkkis; + uint64 Tidalvess; + uint64 Caribdis; + uint64 LadyVashj; + uint64 Karathress; + uint64 KarathressEvent_Starter; + + bool ShieldGeneratorDeactivated[4]; + + bool Encounters[ENCOUNTERS]; + + void Initialize() + { + Sharkkis = 0; + Tidalvess = 0; + Caribdis = 0; + LadyVashj = 0; + Karathress = 0; + KarathressEvent_Starter = 0; + + ShieldGeneratorDeactivated[0] = false; + ShieldGeneratorDeactivated[1] = false; + ShieldGeneratorDeactivated[2] = false; + ShieldGeneratorDeactivated[3] = false; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounters[i] = false; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounters[i]) return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case 21212: LadyVashj = creature->GetGUID(); break; + case 21214: Karathress = creature->GetGUID(); break; + case 21966: Sharkkis = creature->GetGUID(); break; + case 21965: Tidalvess = creature->GetGUID(); break; + case 21964: Caribdis = creature->GetGUID(); break; + } + } + + void SetData64(uint32 type, uint64 data) + { + if(type == DATA_KARATHRESSEVENT_STARTER) + KarathressEvent_Starter = data; + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_SHARKKIS: + return Sharkkis; + case DATA_TIDALVESS: + return Tidalvess; + case DATA_CARIBDIS: + return Caribdis; + case DATA_LADYVASHJ: + return LadyVashj; + case DATA_KARATHRESS: + return Karathress; + case DATA_KARATHRESSEVENT_STARTER: + return KarathressEvent_Starter; + } + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_HYDROSSTHEUNSTABLEEVENT: + Encounters[0] = (data) ? true : false; + break; + + case DATA_LEOTHERASTHEBLINDEVENT: + Encounters[1] = (data) ? true : false; + break; + + case DATA_THELURKERBELOWEVENT: + Encounters[2] = (data) ? true : false; + break; + + case DATA_KARATHRESSEVENT: + Encounters[3] = (data) ? true : false; + break; + + case DATA_MOROGRIMTIDEWALKEREVENT: + Encounters[4] = (data) ? true : false; + break; + //Lady Vashj + case DATA_LADYVASHJEVENT: + if(data == 0) + { + ShieldGeneratorDeactivated[0] = false; + ShieldGeneratorDeactivated[1] = false; + ShieldGeneratorDeactivated[2] = false; + ShieldGeneratorDeactivated[3] = false; + } + Encounters[5] = (data) ? true : false; + break; + + case DATA_SHIELDGENERATOR1: + ShieldGeneratorDeactivated[0] = (data) ? true : false; + break; + + case DATA_SHIELDGENERATOR2: + ShieldGeneratorDeactivated[1] = (data) ? true : false; + break; + + case DATA_SHIELDGENERATOR3: + ShieldGeneratorDeactivated[2] = (data) ? true : false; + break; + + case DATA_SHIELDGENERATOR4: + ShieldGeneratorDeactivated[3] = (data) ? true : false; + break; + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_HYDROSSTHEUNSTABLEEVENT: + return Encounters[0]; + + case DATA_LEOTHERASTHEBLINDEVENT: + return Encounters[1]; + + case DATA_THELURKERBELOWEVENT: + return Encounters[2]; + + case DATA_KARATHRESSEVENT: + return Encounters[3]; + + case DATA_MOROGRIMTIDEWALKEREVENT: + return Encounters[4]; + + //Lady Vashj + case DATA_LADYVASHJEVENT: + return Encounters[5]; + + case DATA_SHIELDGENERATOR1: + return ShieldGeneratorDeactivated[0]; + + case DATA_SHIELDGENERATOR2: + return ShieldGeneratorDeactivated[1]; + + case DATA_SHIELDGENERATOR3: + return ShieldGeneratorDeactivated[2]; + + case DATA_SHIELDGENERATOR4: + return ShieldGeneratorDeactivated[3]; + + case DATA_CANSTARTPHASE3: + if(ShieldGeneratorDeactivated[0] && ShieldGeneratorDeactivated[1] && ShieldGeneratorDeactivated[2] && ShieldGeneratorDeactivated[3]) + return 1; + break; + } + + return 0; + } +}; + +InstanceData* GetInstanceData_instance_serpentshrine_cavern(Map* map) +{ + return new instance_serpentshrine_cavern(map); +} + +void AddSC_instance_serpentshrine_cavern() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_serpent_shrine"; + newscript->GetInstanceData = GetInstanceData_instance_serpentshrine_cavern; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/slave_pens/boss_rokmar.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/slave_pens/boss_rokmar.cpp index 7d0e9d72822..97a18c1e245 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/slave_pens/boss_rokmar.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/slave_pens/boss_rokmar.cpp @@ -1,65 +1,65 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Rokmar -SD%Complete: 100 -SDComment: -SDCategory: Coilfang Resevoir, Slave Pens -EndScriptData */ - -#include "../../../creature/simple_ai.h" - -#define SPELL_WATTER_SPIT 40086 -#define SPELL_GRIEVOUS_WOUND 31956 -#define SPELL_ENSARING_MOSS 31948 - -CreatureAI* GetAI_boss_rokmar_the_crackler(Creature *_Creature) -{ - SimpleAI* ai = new SimpleAI (_Creature); - - //Watter Spit - ai->Spell[0].Enabled = true; - ai->Spell[0].Spell_Id = SPELL_WATTER_SPIT; - ai->Spell[0].Cooldown = 15000; - ai->Spell[0].First_Cast = 15000; - ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; - - //Grievous Wound - ai->Spell[1].Enabled = true; - ai->Spell[1].Spell_Id = SPELL_GRIEVOUS_WOUND; - ai->Spell[1].Cooldown = 25000; - ai->Spell[1].First_Cast = 15000; - ai->Spell[1].Cast_Target_Type = CAST_HOSTILE_TARGET; - - //Ensaring Moss - ai->Spell[2].Enabled = true; - ai->Spell[2].Spell_Id = SPELL_ENSARING_MOSS; - ai->Spell[2].Cooldown = 15000 + (rand()%10000); - ai->Spell[2].First_Cast = 25000; - ai->Spell[2].Cast_Target_Type = CAST_HOSTILE_TARGET; - - return ai; -} - -void AddSC_boss_rokmar_the_crackler() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_rokmar_the_crackler"; - newscript->GetAI = GetAI_boss_rokmar_the_crackler; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Rokmar +SD%Complete: 100 +SDComment: +SDCategory: Coilfang Resevoir, Slave Pens +EndScriptData */ + +#include "../../../creature/simple_ai.h" + +#define SPELL_WATTER_SPIT 40086 +#define SPELL_GRIEVOUS_WOUND 31956 +#define SPELL_ENSARING_MOSS 31948 + +CreatureAI* GetAI_boss_rokmar_the_crackler(Creature *_Creature) +{ + SimpleAI* ai = new SimpleAI (_Creature); + + //Watter Spit + ai->Spell[0].Enabled = true; + ai->Spell[0].Spell_Id = SPELL_WATTER_SPIT; + ai->Spell[0].Cooldown = 15000; + ai->Spell[0].First_Cast = 15000; + ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; + + //Grievous Wound + ai->Spell[1].Enabled = true; + ai->Spell[1].Spell_Id = SPELL_GRIEVOUS_WOUND; + ai->Spell[1].Cooldown = 25000; + ai->Spell[1].First_Cast = 15000; + ai->Spell[1].Cast_Target_Type = CAST_HOSTILE_TARGET; + + //Ensaring Moss + ai->Spell[2].Enabled = true; + ai->Spell[2].Spell_Id = SPELL_ENSARING_MOSS; + ai->Spell[2].Cooldown = 15000 + (rand()%10000); + ai->Spell[2].First_Cast = 25000; + ai->Spell[2].Cast_Target_Type = CAST_HOSTILE_TARGET; + + return ai; +} + +void AddSC_boss_rokmar_the_crackler() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_rokmar_the_crackler"; + newscript->GetAI = GetAI_boss_rokmar_the_crackler; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_hydromancer_thespia.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_hydromancer_thespia.cpp index 74fb09726c7..d1c02f0140a 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_hydromancer_thespia.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_hydromancer_thespia.cpp @@ -1,223 +1,223 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Hydromancer_Thespia -SD%Complete: 80 -SDComment: Normal/heroic mode: to be tested. Needs additional adjustments (when instance script is adjusted) -SDCategory: Coilfang Resevoir, The Steamvault -EndScriptData */ - -/* ContentData -boss_hydromancer_thespia -mob_coilfang_waterelemental -EndContentData */ - -#include "precompiled.h" -#include "def_steam_vault.h" - -#define SAY_SUMMON "Surge forth my pets!" -#define SOUND_SUMMON 10360 - -#define SAY_AGGRO_1 "The depths will consume you!" -#define SOUND_AGGRO_1 10361 -#define SAY_AGGRO_2 "Meet your doom, surface dwellers!" -#define SOUND_AGGRO_2 10362 -#define SAY_AGGRO_3 "You will drown in blood!" -#define SOUND_AGGRO_3 10363 - -#define SAY_SLAY_1 "To the depths of oblivion with you!" -#define SOUND_SLAY_1 10364 -#define SAY_SLAY_2 "For my lady and master!" -#define SOUND_SLAY_2 10365 - -#define SAY_DEAD "Our matron will be.. the end of.. you.." -#define SOUND_DEAD 10366 - -#define SPELL_LIGHTNING_CLOUD 25033 -#define SPELL_LUNG_BURST 31481 -#define SPELL_ENVELOPING_WINDS 31718 - -struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI -{ - boss_thespiaAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - bool HeroicMode; - - uint32 LightningCloud_Timer; - uint32 LungBurst_Timer; - uint32 EnvelopingWinds_Timer; - - void Reset() - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - - LightningCloud_Timer = 28000; - LungBurst_Timer = 7000; - EnvelopingWinds_Timer = 9000; - - if( pInstance ) pInstance->SetData(TYPE_HYDROMANCER_THESPIA, NOT_STARTED); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEAD, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEAD); - - if( pInstance ) pInstance->SetData(TYPE_HYDROMANCER_THESPIA, DONE); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_2); - break; - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - - if( pInstance ) pInstance->SetData(TYPE_HYDROMANCER_THESPIA, IN_PROGRESS); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //LightningCloud_Timer - if( LightningCloud_Timer < diff ) - { - //cast twice in Heroic mode - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target, SPELL_LIGHTNING_CLOUD); - if( HeroicMode ) - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target, SPELL_LIGHTNING_CLOUD); - LightningCloud_Timer = 28000; - }else LightningCloud_Timer -=diff; - - //LungBurst_Timer - if( LungBurst_Timer < diff ) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target, SPELL_LUNG_BURST); - LungBurst_Timer = 10000+rand()%5000; - }else LungBurst_Timer -=diff; - - //EnvelopingWinds_Timer - if( EnvelopingWinds_Timer < diff ) - { - //cast twice in Heroic mode - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target, SPELL_ENVELOPING_WINDS); - if( HeroicMode ) - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target, SPELL_ENVELOPING_WINDS); - EnvelopingWinds_Timer = 10000+rand()%5000; - }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 *c) : ScriptedAI(c) {Reset();} - - bool HeroicMode; - uint32 WaterBoltVolley_Timer; - - void Reset() - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - WaterBoltVolley_Timer = 3000+rand()%3000; - } - - void Aggro(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( WaterBoltVolley_Timer < diff ) - { - if( HeroicMode ) DoCast(m_creature,H_SPELL_WATER_BOLT_VOLLEY); - else DoCast(m_creature,SPELL_WATER_BOLT_VOLLEY); - - WaterBoltVolley_Timer = 10000+rand()%5000; - }else WaterBoltVolley_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_thespiaAI(Creature *_Creature) -{ - return new boss_thespiaAI (_Creature); -} - -CreatureAI* GetAI_mob_coilfang_waterelementalAI(Creature *_Creature) -{ - return new mob_coilfang_waterelementalAI (_Creature); -} - -void AddSC_boss_hydromancer_thespia() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_hydromancer_thespia"; - newscript->GetAI = GetAI_boss_thespiaAI; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_coilfang_waterelemental"; - newscript->GetAI = GetAI_mob_coilfang_waterelementalAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Hydromancer_Thespia +SD%Complete: 80 +SDComment: Normal/heroic mode: to be tested. Needs additional adjustments (when instance script is adjusted) +SDCategory: Coilfang Resevoir, The Steamvault +EndScriptData */ + +/* ContentData +boss_hydromancer_thespia +mob_coilfang_waterelemental +EndContentData */ + +#include "precompiled.h" +#include "def_steam_vault.h" + +#define SAY_SUMMON "Surge forth my pets!" +#define SOUND_SUMMON 10360 + +#define SAY_AGGRO_1 "The depths will consume you!" +#define SOUND_AGGRO_1 10361 +#define SAY_AGGRO_2 "Meet your doom, surface dwellers!" +#define SOUND_AGGRO_2 10362 +#define SAY_AGGRO_3 "You will drown in blood!" +#define SOUND_AGGRO_3 10363 + +#define SAY_SLAY_1 "To the depths of oblivion with you!" +#define SOUND_SLAY_1 10364 +#define SAY_SLAY_2 "For my lady and master!" +#define SOUND_SLAY_2 10365 + +#define SAY_DEAD "Our matron will be.. the end of.. you.." +#define SOUND_DEAD 10366 + +#define SPELL_LIGHTNING_CLOUD 25033 +#define SPELL_LUNG_BURST 31481 +#define SPELL_ENVELOPING_WINDS 31718 + +struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI +{ + boss_thespiaAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + bool HeroicMode; + + uint32 LightningCloud_Timer; + uint32 LungBurst_Timer; + uint32 EnvelopingWinds_Timer; + + void Reset() + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + + LightningCloud_Timer = 28000; + LungBurst_Timer = 7000; + EnvelopingWinds_Timer = 9000; + + if( pInstance ) pInstance->SetData(TYPE_HYDROMANCER_THESPIA, NOT_STARTED); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEAD, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEAD); + + if( pInstance ) pInstance->SetData(TYPE_HYDROMANCER_THESPIA, DONE); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_2); + break; + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + + if( pInstance ) pInstance->SetData(TYPE_HYDROMANCER_THESPIA, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //LightningCloud_Timer + if( LightningCloud_Timer < diff ) + { + //cast twice in Heroic mode + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target, SPELL_LIGHTNING_CLOUD); + if( HeroicMode ) + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target, SPELL_LIGHTNING_CLOUD); + LightningCloud_Timer = 28000; + }else LightningCloud_Timer -=diff; + + //LungBurst_Timer + if( LungBurst_Timer < diff ) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target, SPELL_LUNG_BURST); + LungBurst_Timer = 10000+rand()%5000; + }else LungBurst_Timer -=diff; + + //EnvelopingWinds_Timer + if( EnvelopingWinds_Timer < diff ) + { + //cast twice in Heroic mode + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target, SPELL_ENVELOPING_WINDS); + if( HeroicMode ) + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target, SPELL_ENVELOPING_WINDS); + EnvelopingWinds_Timer = 10000+rand()%5000; + }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 *c) : ScriptedAI(c) {Reset();} + + bool HeroicMode; + uint32 WaterBoltVolley_Timer; + + void Reset() + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + WaterBoltVolley_Timer = 3000+rand()%3000; + } + + void Aggro(Unit *who) { } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( WaterBoltVolley_Timer < diff ) + { + if( HeroicMode ) DoCast(m_creature,H_SPELL_WATER_BOLT_VOLLEY); + else DoCast(m_creature,SPELL_WATER_BOLT_VOLLEY); + + WaterBoltVolley_Timer = 10000+rand()%5000; + }else WaterBoltVolley_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_thespiaAI(Creature *_Creature) +{ + return new boss_thespiaAI (_Creature); +} + +CreatureAI* GetAI_mob_coilfang_waterelementalAI(Creature *_Creature) +{ + return new mob_coilfang_waterelementalAI (_Creature); +} + +void AddSC_boss_hydromancer_thespia() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_hydromancer_thespia"; + newscript->GetAI = GetAI_boss_thespiaAI; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_coilfang_waterelemental"; + newscript->GetAI = GetAI_mob_coilfang_waterelementalAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_mekgineer_steamrigger.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_mekgineer_steamrigger.cpp index 83177d88fa2..c88da0f7e65 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_mekgineer_steamrigger.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_mekgineer_steamrigger.cpp @@ -1,297 +1,297 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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. -SDCategory: Coilfang Resevoir, The Steamvault -EndScriptData */ - -/* ContentData -boss_mekgineer_steamrigger -mob_steamrigger_mechanic -EndContentData */ - -#include "precompiled.h" -#include "def_steam_vault.h" - -#define SAY_MECHANICS "I'm bringin' the pain!" -#define SOUND_MECHANICS 10367 - -#define SAY_AGGRO_1 "You're in for a world of hurt!" -#define SOUND_AGGRO_1 10368 -#define SAY_AGGRO_2 "Eat hot metal, scumbag!" -#define SOUND_AGGRO_2 10369 -#define SAY_AGGRO_3 "I'll come over there!" -#define SOUND_AGGRO_3 10370 -#define SAY_AGGRO_4 "I'm bringin' the pain!" -#define SOUND_AGGRO_4 10371 - -#define SAY_SLAY_1 "You just got served, punk!" -#define SOUND_SLAY_1 10372 -#define SAY_SLAY_2 "I own you!" -#define SOUND_SLAY_2 10373 -#define SAY_SLAY_3 "Have fun dyin', cupcake!" -#define SOUND_SLAY_3 10374 - -#define SAY_DEATH "Mommy!" -#define SOUND_DEATH 10375 - -#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 - -#define ENTRY_STREAMRIGGER_MECHANIC 17951 - -struct MANGOS_DLL_DECL boss_mekgineer_steamriggerAI : public ScriptedAI -{ - boss_mekgineer_steamriggerAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Shrink_Timer; - uint32 Saw_Blade_Timer; - uint32 Electrified_Net_Timer; - bool Summon75; - bool Summon50; - bool Summon25; - - void Reset() - { - Shrink_Timer = 20000; - Saw_Blade_Timer = 15000; - Electrified_Net_Timer = 10000; - - Summon75 = false; - Summon50 = false; - Summon25 = false; - - if( pInstance ) pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, NOT_STARTED); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - - if( pInstance ) pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, DONE); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_2); - break; - case 2: - DoYell(SAY_SLAY_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_3); - break; - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - - if( pInstance ) pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, IN_PROGRESS); - } - - //no known summon spells exist - void SummonMechanichs() - { - DoYell(SAY_MECHANICS, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_MECHANICS); - - 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( rand()%2 ) - DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,5,-7,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); - if( rand()%2 ) - DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,7,-5,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( Shrink_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_SUPER_SHRINK_RAY); - Shrink_Timer = 20000; - }else Shrink_Timer -= diff; - - if( Saw_Blade_Timer < diff ) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) DoCast(target,SPELL_SAW_BLADE); - else DoCast(m_creature->getVictim(),SPELL_SAW_BLADE); - Saw_Blade_Timer = 15000; - } else Saw_Blade_Timer -= diff; - - if( Electrified_Net_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_ELECTRIFIED_NET); - Electrified_Net_Timer = 10000; - } - else Electrified_Net_Timer -= diff; - - if( !Summon75 ) - if( (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75 ) - { - SummonMechanichs(); - Summon75 = true; - } - if( !Summon50 ) - if( (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50 ) - { - SummonMechanichs(); - Summon50 = true; - } - if( !Summon25 ) - if( (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25 ) - { - SummonMechanichs(); - Summon25 = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_mekgineer_steamrigger(Creature *_Creature) -{ - return new boss_mekgineer_steamriggerAI (_Creature); -} - -#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 *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 Repair_Timer; - bool HeroicMode; - - void Reset() - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - Repair_Timer = 2000; - } - - void MoveInLineOfSight(Unit* who) - { - //react only if attacked - return; - } - - void Aggro(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if( Repair_Timer < diff ) - { - if( pInstance && pInstance->GetData64(DATA_MEKGINEERSTEAMRIGGER) && pInstance->GetData(TYPE_MEKGINEER_STEAMRIGGER) == IN_PROGRESS) - { - if( Unit* pMekgineer = Unit::GetUnit((*m_creature), 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(); - - if( HeroicMode ) DoCast(m_creature,H_SPELL_REPAIR,true); - else DoCast(m_creature,SPELL_REPAIR,true); - } - Repair_Timer = 5000; - } - else - { - //m_creature->GetMotionMaster()->MovementExpired(); - //m_creature->GetMotionMaster()->MoveFollow(pMekgineer,0,0); - } - } - }else Repair_Timer = 5000; - }else Repair_Timer -= diff; - - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_steamrigger_mechanic(Creature *_Creature) -{ - return new mob_steamrigger_mechanicAI (_Creature); -} - -void AddSC_boss_mekgineer_steamrigger() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_mekgineer_steamrigger"; - newscript->GetAI = GetAI_boss_mekgineer_steamrigger; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_steamrigger_mechanic"; - newscript->GetAI = GetAI_mob_steamrigger_mechanic; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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. +SDCategory: Coilfang Resevoir, The Steamvault +EndScriptData */ + +/* ContentData +boss_mekgineer_steamrigger +mob_steamrigger_mechanic +EndContentData */ + +#include "precompiled.h" +#include "def_steam_vault.h" + +#define SAY_MECHANICS "I'm bringin' the pain!" +#define SOUND_MECHANICS 10367 + +#define SAY_AGGRO_1 "You're in for a world of hurt!" +#define SOUND_AGGRO_1 10368 +#define SAY_AGGRO_2 "Eat hot metal, scumbag!" +#define SOUND_AGGRO_2 10369 +#define SAY_AGGRO_3 "I'll come over there!" +#define SOUND_AGGRO_3 10370 +#define SAY_AGGRO_4 "I'm bringin' the pain!" +#define SOUND_AGGRO_4 10371 + +#define SAY_SLAY_1 "You just got served, punk!" +#define SOUND_SLAY_1 10372 +#define SAY_SLAY_2 "I own you!" +#define SOUND_SLAY_2 10373 +#define SAY_SLAY_3 "Have fun dyin', cupcake!" +#define SOUND_SLAY_3 10374 + +#define SAY_DEATH "Mommy!" +#define SOUND_DEATH 10375 + +#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 + +#define ENTRY_STREAMRIGGER_MECHANIC 17951 + +struct MANGOS_DLL_DECL boss_mekgineer_steamriggerAI : public ScriptedAI +{ + boss_mekgineer_steamriggerAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Shrink_Timer; + uint32 Saw_Blade_Timer; + uint32 Electrified_Net_Timer; + bool Summon75; + bool Summon50; + bool Summon25; + + void Reset() + { + Shrink_Timer = 20000; + Saw_Blade_Timer = 15000; + Electrified_Net_Timer = 10000; + + Summon75 = false; + Summon50 = false; + Summon25 = false; + + if( pInstance ) pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, NOT_STARTED); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + + if( pInstance ) pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, DONE); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_2); + break; + case 2: + DoYell(SAY_SLAY_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_3); + break; + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + + if( pInstance ) pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, IN_PROGRESS); + } + + //no known summon spells exist + void SummonMechanichs() + { + DoYell(SAY_MECHANICS, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_MECHANICS); + + 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( rand()%2 ) + DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,5,-7,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); + if( rand()%2 ) + DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,7,-5,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( Shrink_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_SUPER_SHRINK_RAY); + Shrink_Timer = 20000; + }else Shrink_Timer -= diff; + + if( Saw_Blade_Timer < diff ) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) DoCast(target,SPELL_SAW_BLADE); + else DoCast(m_creature->getVictim(),SPELL_SAW_BLADE); + Saw_Blade_Timer = 15000; + } else Saw_Blade_Timer -= diff; + + if( Electrified_Net_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_ELECTRIFIED_NET); + Electrified_Net_Timer = 10000; + } + else Electrified_Net_Timer -= diff; + + if( !Summon75 ) + if( (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75 ) + { + SummonMechanichs(); + Summon75 = true; + } + if( !Summon50 ) + if( (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50 ) + { + SummonMechanichs(); + Summon50 = true; + } + if( !Summon25 ) + if( (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25 ) + { + SummonMechanichs(); + Summon25 = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_mekgineer_steamrigger(Creature *_Creature) +{ + return new boss_mekgineer_steamriggerAI (_Creature); +} + +#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 *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 Repair_Timer; + bool HeroicMode; + + void Reset() + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + Repair_Timer = 2000; + } + + void MoveInLineOfSight(Unit* who) + { + //react only if attacked + return; + } + + void Aggro(Unit *who) { } + + void UpdateAI(const uint32 diff) + { + if( Repair_Timer < diff ) + { + if( pInstance && pInstance->GetData64(DATA_MEKGINEERSTEAMRIGGER) && pInstance->GetData(TYPE_MEKGINEER_STEAMRIGGER) == IN_PROGRESS) + { + if( Unit* pMekgineer = Unit::GetUnit((*m_creature), 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(); + + if( HeroicMode ) DoCast(m_creature,H_SPELL_REPAIR,true); + else DoCast(m_creature,SPELL_REPAIR,true); + } + Repair_Timer = 5000; + } + else + { + //m_creature->GetMotionMaster()->MovementExpired(); + //m_creature->GetMotionMaster()->MoveFollow(pMekgineer,0,0); + } + } + }else Repair_Timer = 5000; + }else Repair_Timer -= diff; + + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_steamrigger_mechanic(Creature *_Creature) +{ + return new mob_steamrigger_mechanicAI (_Creature); +} + +void AddSC_boss_mekgineer_steamrigger() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_mekgineer_steamrigger"; + newscript->GetAI = GetAI_boss_mekgineer_steamrigger; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_steamrigger_mechanic"; + newscript->GetAI = GetAI_mob_steamrigger_mechanic; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp index 49172341514..c5987d6d11c 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp @@ -1,255 +1,255 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Kalithres -SD%Complete: 65 -SDComment: Contains workarounds regarding warlord's rage spells not acting as expected. Both scripts here require review and fine tuning. -SDCategory: Coilfang Resevoir, The Steamvault -EndScriptData */ - -#include "precompiled.h" -#include "def_steam_vault.h" - -#define SAY_INTRO "You deem yourselves worthy simply because you bested my guards? Our work here will not be compromised!" -#define SOUND_INTRO 10390 - -#define SAY_REGEN "This is not nearly over..." -#define SOUND_REGEN 10391 - -#define SAY_AGGRO1 "Your head will roll!" -#define SOUND_AGGRO1 10392 -#define SAY_AGGRO2 "I despise all of your kind!" -#define SOUND_AGGRO2 10393 -#define SAY_AGGRO3 "Ba'ahntha sol'dorei!" -#define SOUND_AGGRO3 10394 - -#define SAY_SLAY1 "Scram, surface filth!" -#define SOUND_SLAY1 10395 -#define SAY_SLAY2 "Ah ha ha ha ha ha ha!" -#define SOUND_SLAY2 10396 - -#define SAY_DEATH "For her Excellency... for... Vashj!" -#define SOUND_DEATH 10397 - -#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 -{ - mob_naga_distillerAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *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( pInstance ) - if( 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 Aggro(Unit *who) { } - - void StartRageGen(Unit *caster) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoCast(m_creature,SPELL_WARLORDS_RAGE_NAGA,true); - if( pInstance ) pInstance->SetData(TYPE_DISTILLER,IN_PROGRESS); - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if( m_creature->GetHealth() <= damage ) - if( pInstance ) pInstance->SetData(TYPE_DISTILLER,DONE); - } -}; - -struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI -{ - boss_warlord_kalithreshAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Reflection_Timer; - uint32 Impale_Timer; - uint32 Rage_Timer; - bool CanRage; - - void Reset() - { - Reflection_Timer = 10000; - Impale_Timer = 30000; - Rage_Timer = 45000; - CanRage = false; - - if( pInstance ) pInstance->SetData(TYPE_WARLORD_KALITHRESH, NOT_STARTED); - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO3); - break; - } - - if( pInstance ) pInstance->SetData(TYPE_WARLORD_KALITHRESH, IN_PROGRESS); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_SLAY2); - break; - } - } - - Creature* SelectCreatureInGrid(uint32 entry, float range) - { - Creature* pCreature = NULL; - - CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*m_creature, entry, true, range); - MaNGOS::CreatureLastSearcher searcher(pCreature, creature_check); - - TypeContainerVisitor, GridTypeMapContainer> creature_searcher(searcher); - - CellLock cell_lock(cell, pair); - cell_lock->Visit(cell_lock, creature_searcher,*(m_creature->GetMap())); - - return pCreature; - } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - //hack :( - if( spell->Id == SPELL_WARLORDS_RAGE_PROC ) - if( pInstance ) - if( pInstance->GetData(TYPE_DISTILLER) == DONE ) - m_creature->RemoveAurasDueToSpell(SPELL_WARLORDS_RAGE_PROC); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if( pInstance ) pInstance->SetData(TYPE_WARLORD_KALITHRESH, DONE); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( Rage_Timer < diff ) - { - Creature* distiller = SelectCreatureInGrid(17954, 100); - if( distiller ) - { - DoYell(SAY_REGEN, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_REGEN); - DoCast(m_creature,SPELL_WARLORDS_RAGE); - ((mob_naga_distillerAI*)distiller->AI())->StartRageGen(m_creature); - } - Rage_Timer = 45000; - }else Rage_Timer -= diff; - - //Reflection_Timer - if( Reflection_Timer < diff ) - { - DoCast(m_creature, SPELL_SPELL_REFLECTION); - Reflection_Timer = 20000+rand()%5000; - }else Reflection_Timer -= diff; - - //Impale_Timer - if( Impale_Timer < diff ) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_IMPALE); - - Impale_Timer = 7500+rand()%5000; - }else Impale_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_naga_distiller(Creature *_Creature) -{ - return new mob_naga_distillerAI (_Creature); -} - -CreatureAI* GetAI_boss_warlord_kalithresh(Creature *_Creature) -{ - return new boss_warlord_kalithreshAI (_Creature); -} - -void AddSC_boss_warlord_kalithresh() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_naga_distiller"; - newscript->GetAI = GetAI_mob_naga_distiller; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_warlord_kalithresh"; - newscript->GetAI = GetAI_boss_warlord_kalithresh; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Kalithres +SD%Complete: 65 +SDComment: Contains workarounds regarding warlord's rage spells not acting as expected. Both scripts here require review and fine tuning. +SDCategory: Coilfang Resevoir, The Steamvault +EndScriptData */ + +#include "precompiled.h" +#include "def_steam_vault.h" + +#define SAY_INTRO "You deem yourselves worthy simply because you bested my guards? Our work here will not be compromised!" +#define SOUND_INTRO 10390 + +#define SAY_REGEN "This is not nearly over..." +#define SOUND_REGEN 10391 + +#define SAY_AGGRO1 "Your head will roll!" +#define SOUND_AGGRO1 10392 +#define SAY_AGGRO2 "I despise all of your kind!" +#define SOUND_AGGRO2 10393 +#define SAY_AGGRO3 "Ba'ahntha sol'dorei!" +#define SOUND_AGGRO3 10394 + +#define SAY_SLAY1 "Scram, surface filth!" +#define SOUND_SLAY1 10395 +#define SAY_SLAY2 "Ah ha ha ha ha ha ha!" +#define SOUND_SLAY2 10396 + +#define SAY_DEATH "For her Excellency... for... Vashj!" +#define SOUND_DEATH 10397 + +#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 +{ + mob_naga_distillerAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *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( pInstance ) + if( 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 Aggro(Unit *who) { } + + void StartRageGen(Unit *caster) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoCast(m_creature,SPELL_WARLORDS_RAGE_NAGA,true); + if( pInstance ) pInstance->SetData(TYPE_DISTILLER,IN_PROGRESS); + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if( m_creature->GetHealth() <= damage ) + if( pInstance ) pInstance->SetData(TYPE_DISTILLER,DONE); + } +}; + +struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI +{ + boss_warlord_kalithreshAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Reflection_Timer; + uint32 Impale_Timer; + uint32 Rage_Timer; + bool CanRage; + + void Reset() + { + Reflection_Timer = 10000; + Impale_Timer = 30000; + Rage_Timer = 45000; + CanRage = false; + + if( pInstance ) pInstance->SetData(TYPE_WARLORD_KALITHRESH, NOT_STARTED); + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO3); + break; + } + + if( pInstance ) pInstance->SetData(TYPE_WARLORD_KALITHRESH, IN_PROGRESS); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_SLAY2); + break; + } + } + + Creature* SelectCreatureInGrid(uint32 entry, float range) + { + Creature* pCreature = NULL; + + CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*m_creature, entry, true, range); + MaNGOS::CreatureLastSearcher searcher(pCreature, creature_check); + + TypeContainerVisitor, GridTypeMapContainer> creature_searcher(searcher); + + CellLock cell_lock(cell, pair); + cell_lock->Visit(cell_lock, creature_searcher,*(m_creature->GetMap())); + + return pCreature; + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + //hack :( + if( spell->Id == SPELL_WARLORDS_RAGE_PROC ) + if( pInstance ) + if( pInstance->GetData(TYPE_DISTILLER) == DONE ) + m_creature->RemoveAurasDueToSpell(SPELL_WARLORDS_RAGE_PROC); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if( pInstance ) pInstance->SetData(TYPE_WARLORD_KALITHRESH, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( Rage_Timer < diff ) + { + Creature* distiller = SelectCreatureInGrid(17954, 100); + if( distiller ) + { + DoYell(SAY_REGEN, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_REGEN); + DoCast(m_creature,SPELL_WARLORDS_RAGE); + ((mob_naga_distillerAI*)distiller->AI())->StartRageGen(m_creature); + } + Rage_Timer = 45000; + }else Rage_Timer -= diff; + + //Reflection_Timer + if( Reflection_Timer < diff ) + { + DoCast(m_creature, SPELL_SPELL_REFLECTION); + Reflection_Timer = 20000+rand()%5000; + }else Reflection_Timer -= diff; + + //Impale_Timer + if( Impale_Timer < diff ) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_IMPALE); + + Impale_Timer = 7500+rand()%5000; + }else Impale_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_naga_distiller(Creature *_Creature) +{ + return new mob_naga_distillerAI (_Creature); +} + +CreatureAI* GetAI_boss_warlord_kalithresh(Creature *_Creature) +{ + return new boss_warlord_kalithreshAI (_Creature); +} + +void AddSC_boss_warlord_kalithresh() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_naga_distiller"; + newscript->GetAI = GetAI_mob_naga_distiller; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_warlord_kalithresh"; + newscript->GetAI = GetAI_boss_warlord_kalithresh; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/def_steam_vault.h b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/def_steam_vault.h index 0f8ae80fe2c..2841ed84fa5 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/def_steam_vault.h +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/def_steam_vault.h @@ -1,16 +1,16 @@ -/* Copyright (C) 2006 - 2008 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 - -#define DATA_MEKGINEERSTEAMRIGGER 5 -#define DATA_KALITRESH 6 -#define DATA_THESPIA 7 -#endif +/* Copyright (C) 2006 - 2008 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 + +#define DATA_MEKGINEERSTEAMRIGGER 5 +#define DATA_KALITRESH 6 +#define DATA_THESPIA 7 +#endif diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp index 0e524f3d4b8..cdb28a910ed 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp @@ -1,170 +1,170 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Steam_Vault -SD%Complete: 60 -SDComment: Workaround for opening of Main Chamber door. Mangos does not support scripting of Gameobject as this instance require. -SDCategory: Coilfang Resevoir, The Steamvault -EndScriptData */ - -#include "precompiled.h" -#include "def_steam_vault.h" - -#define ENCOUNTERS 4 - -#define MAIN_CHAMBERS_DOOR 183049 //door opened when hydromancer and mekgineer are died -#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 -*/ - -struct MANGOS_DLL_DECL instance_steam_vault : public ScriptedInstance -{ - instance_steam_vault(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint64 ThespiaGUID; - uint64 MekgineerGUID; - uint64 KalithreshGUID; - uint32 Encounter[ENCOUNTERS]; - - bool IsHydromancerDead, IsMekgineerDead; - GameObject *MainChambersDoor; - GameObject *AccessPanelHydro; - GameObject *AccessPanelMek; - - void Initialize() - { - ThespiaGUID = 0; - MekgineerGUID = 0; - KalithreshGUID = 0; - IsHydromancerDead = false; - IsMekgineerDead = false; - MainChambersDoor = NULL; - AccessPanelHydro = NULL; - AccessPanelMek = NULL; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounter[i] = false; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; i++) - if( Encounter[i] ) return true; - - return false; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case 17797: ThespiaGUID = creature->GetGUID(); break; - case 17796: MekgineerGUID = creature->GetGUID(); break; - case 17798: KalithreshGUID = creature->GetGUID(); break; - } - } - - void OnObjectCreate(GameObject *go) - { - switch(go->GetEntry()) - { - case MAIN_CHAMBERS_DOOR: MainChambersDoor = go; break; - case ACCESS_PANEL_HYDRO: AccessPanelHydro = go; break; - case ACCESS_PANEL_MEK: AccessPanelMek = go; break; - } - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case TYPE_HYDROMANCER_THESPIA: - if(data == DONE) - { - IsHydromancerDead = true; - if( IsMekgineerDead && MainChambersDoor ) - MainChambersDoor->SetGoState(0); - } - Encounter[0] = data; - break; - case TYPE_MEKGINEER_STEAMRIGGER: - if(data == DONE) - { - IsMekgineerDead = true; - if( IsHydromancerDead && MainChambersDoor ) - MainChambersDoor->SetGoState(0); - } - Encounter[1] = data; - break; - case TYPE_WARLORD_KALITHRESH: - Encounter[2] = data; - break; - case TYPE_DISTILLER: - Encounter[3] = data; - break; - } - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case TYPE_HYDROMANCER_THESPIA: - return Encounter[0]; - case TYPE_MEKGINEER_STEAMRIGGER: - return Encounter[1]; - case TYPE_WARLORD_KALITHRESH: - return Encounter[2]; - case TYPE_DISTILLER: - return Encounter[3]; - } - return 0; - } - - uint64 GetData64(uint32 data) - { - switch(data) - { - case DATA_THESPIA: - return ThespiaGUID; - case DATA_MEKGINEERSTEAMRIGGER: - return MekgineerGUID; - case DATA_KALITRESH: - return KalithreshGUID; - } - return 0; - } -}; - -InstanceData* GetInstanceData_instance_steam_vault(Map* map) -{ - return new instance_steam_vault(map); -} - -void AddSC_instance_steam_vault() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_steam_vault"; - newscript->GetInstanceData = GetInstanceData_instance_steam_vault; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Steam_Vault +SD%Complete: 60 +SDComment: Workaround for opening of Main Chamber door. Mangos does not support scripting of Gameobject as this instance require. +SDCategory: Coilfang Resevoir, The Steamvault +EndScriptData */ + +#include "precompiled.h" +#include "def_steam_vault.h" + +#define ENCOUNTERS 4 + +#define MAIN_CHAMBERS_DOOR 183049 //door opened when hydromancer and mekgineer are died +#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 +*/ + +struct MANGOS_DLL_DECL instance_steam_vault : public ScriptedInstance +{ + instance_steam_vault(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint64 ThespiaGUID; + uint64 MekgineerGUID; + uint64 KalithreshGUID; + uint32 Encounter[ENCOUNTERS]; + + bool IsHydromancerDead, IsMekgineerDead; + GameObject *MainChambersDoor; + GameObject *AccessPanelHydro; + GameObject *AccessPanelMek; + + void Initialize() + { + ThespiaGUID = 0; + MekgineerGUID = 0; + KalithreshGUID = 0; + IsHydromancerDead = false; + IsMekgineerDead = false; + MainChambersDoor = NULL; + AccessPanelHydro = NULL; + AccessPanelMek = NULL; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounter[i] = false; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; i++) + if( Encounter[i] ) return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case 17797: ThespiaGUID = creature->GetGUID(); break; + case 17796: MekgineerGUID = creature->GetGUID(); break; + case 17798: KalithreshGUID = creature->GetGUID(); break; + } + } + + void OnObjectCreate(GameObject *go) + { + switch(go->GetEntry()) + { + case MAIN_CHAMBERS_DOOR: MainChambersDoor = go; break; + case ACCESS_PANEL_HYDRO: AccessPanelHydro = go; break; + case ACCESS_PANEL_MEK: AccessPanelMek = go; break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case TYPE_HYDROMANCER_THESPIA: + if(data == DONE) + { + IsHydromancerDead = true; + if( IsMekgineerDead && MainChambersDoor ) + MainChambersDoor->SetGoState(0); + } + Encounter[0] = data; + break; + case TYPE_MEKGINEER_STEAMRIGGER: + if(data == DONE) + { + IsMekgineerDead = true; + if( IsHydromancerDead && MainChambersDoor ) + MainChambersDoor->SetGoState(0); + } + Encounter[1] = data; + break; + case TYPE_WARLORD_KALITHRESH: + Encounter[2] = data; + break; + case TYPE_DISTILLER: + Encounter[3] = data; + break; + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case TYPE_HYDROMANCER_THESPIA: + return Encounter[0]; + case TYPE_MEKGINEER_STEAMRIGGER: + return Encounter[1]; + case TYPE_WARLORD_KALITHRESH: + return Encounter[2]; + case TYPE_DISTILLER: + return Encounter[3]; + } + return 0; + } + + uint64 GetData64(uint32 data) + { + switch(data) + { + case DATA_THESPIA: + return ThespiaGUID; + case DATA_MEKGINEERSTEAMRIGGER: + return MekgineerGUID; + case DATA_KALITRESH: + return KalithreshGUID; + } + return 0; + } +}; + +InstanceData* GetInstanceData_instance_steam_vault(Map* map) +{ + return new instance_steam_vault(map); +} + +void AddSC_instance_steam_vault() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_steam_vault"; + newscript->GetInstanceData = GetInstanceData_instance_steam_vault; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_ghazan.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_ghazan.cpp index 6bb2635fa7b..81ca43b26f3 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_ghazan.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_ghazan.cpp @@ -1,78 +1,78 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Ghazan -SD%Complete: 100 -SDComment: -SDCategory: Coilfang Resevoir, Underbog -EndScriptData */ - -#include "../../../creature/simple_ai.h" - -/* ---== Ghaz'an ==-- -*Acid Spit - 34290; timer: 8sec -*Enrage - 20% hp; 40683 -*Tail Sweep - 34267; timer: ~10sec -*Acid Breath - 34268; timer: 5sec -*/ - -CreatureAI* GetAI_boss_ghazan(Creature *_Creature) -{ - SimpleAI* ai = new SimpleAI (_Creature); - - // Acid Spit - 34290; timer: 8sec - ai->Spell[0].Enabled = true; - ai->Spell[0].Spell_Id = 34290; - ai->Spell[0].Cooldown = 8000; - ai->Spell[0].First_Cast = 8000; - ai->Spell[0].Cast_Target_Type = CAST_SELF; - - // Acid Breath - 34268; timer: 5sec - ai->Spell[1].Enabled = true; - ai->Spell[1].Spell_Id = 34268; - ai->Spell[1].Cooldown = 5000; - ai->Spell[1].First_Cast = 5000; - ai->Spell[1].Cast_Target_Type = CAST_SELF; - - // Tail Sweep - 34267 - ai->Spell[2].Enabled = true; - ai->Spell[2].Spell_Id = 34267; - ai->Spell[2].Cooldown = 10000; - ai->Spell[2].First_Cast = 10000; - ai->Spell[2].Cast_Target_Type = CAST_SELF; - - // Enrage - 20% hp; 40683 - ai->Spell[3].Enabled = true; - ai->Spell[3].Spell_Id = 40683; - ai->Spell[3].Cooldown = -1; - ai->Spell[3].First_Cast = -80; - ai->Spell[3].Cast_Target_Type = CAST_SELF; - - ai->EnterEvadeMode(); - - return ai; -} - -void AddSC_boss_ghazan() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ghazan"; - newscript->GetAI = GetAI_boss_ghazan; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Ghazan +SD%Complete: 100 +SDComment: +SDCategory: Coilfang Resevoir, Underbog +EndScriptData */ + +#include "../../../creature/simple_ai.h" + +/* +--== Ghaz'an ==-- +*Acid Spit - 34290; timer: 8sec +*Enrage - 20% hp; 40683 +*Tail Sweep - 34267; timer: ~10sec +*Acid Breath - 34268; timer: 5sec +*/ + +CreatureAI* GetAI_boss_ghazan(Creature *_Creature) +{ + SimpleAI* ai = new SimpleAI (_Creature); + + // Acid Spit - 34290; timer: 8sec + ai->Spell[0].Enabled = true; + ai->Spell[0].Spell_Id = 34290; + ai->Spell[0].Cooldown = 8000; + ai->Spell[0].First_Cast = 8000; + ai->Spell[0].Cast_Target_Type = CAST_SELF; + + // Acid Breath - 34268; timer: 5sec + ai->Spell[1].Enabled = true; + ai->Spell[1].Spell_Id = 34268; + ai->Spell[1].Cooldown = 5000; + ai->Spell[1].First_Cast = 5000; + ai->Spell[1].Cast_Target_Type = CAST_SELF; + + // Tail Sweep - 34267 + ai->Spell[2].Enabled = true; + ai->Spell[2].Spell_Id = 34267; + ai->Spell[2].Cooldown = 10000; + ai->Spell[2].First_Cast = 10000; + ai->Spell[2].Cast_Target_Type = CAST_SELF; + + // Enrage - 20% hp; 40683 + ai->Spell[3].Enabled = true; + ai->Spell[3].Spell_Id = 40683; + ai->Spell[3].Cooldown = -1; + ai->Spell[3].First_Cast = -80; + ai->Spell[3].Cast_Target_Type = CAST_SELF; + + ai->EnterEvadeMode(); + + return ai; +} + +void AddSC_boss_ghazan() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ghazan"; + newscript->GetAI = GetAI_boss_ghazan; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_hungarfen.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_hungarfen.cpp index 663db35a946..d55fbcd2652 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_hungarfen.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_hungarfen.cpp @@ -1,156 +1,156 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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 -SDCategory: Coilfang Resevoir, Underbog -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FOUL_SPORES 31673 -#define SPELL_ACID_GEYSER 38739 - -struct MANGOS_DLL_DECL boss_hungarfenAI : public ScriptedAI -{ - boss_hungarfenAI(Creature *c) : ScriptedAI(c) - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - Reset(); - } - - bool HeroicMode; - bool Root; - uint32 Mushroom_Timer; - uint32 AcidGeyser_Timer; - - void Reset() - { - Root = false; - Mushroom_Timer = 5000; // 1 mushroom after 5s, then one per 10s. This should be different in heroic mode - AcidGeyser_Timer = 10000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 20 ) - { - if( !Root ) - { - DoCast(m_creature,SPELL_FOUL_SPORES); - Root = true; - } - } - - if( Mushroom_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_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); - - Mushroom_Timer = 10000; - }else Mushroom_Timer -= diff; - - if( AcidGeyser_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_ACID_GEYSER); - AcidGeyser_Timer = 10000+rand()%7500; - }else AcidGeyser_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_hungarfen(Creature *_Creature) -{ - return new boss_hungarfenAI (_Creature); -} - -#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 *c) : ScriptedAI(c) { Reset(); } - - bool Stop; - uint32 Grow_Timer; - uint32 Shrink_Timer; - - void Reset() - { - Stop = false; - Grow_Timer = 0; - Shrink_Timer = 20000; - - DoCast(m_creature,SPELL_PUTRID_MUSHROOM,true); - DoCast(m_creature,SPELL_SPORE_CLOUD,true); - } - - void MoveInLineOfSight(Unit *who) { return; } - - void AttackStart(Unit* who) { return; } - - void Aggro(Unit* who) { } - - void UpdateAI(const uint32 diff) - { - if( Stop ) - return; - - if( Grow_Timer <= diff ) - { - DoCast(m_creature,SPELL_GROW); - Grow_Timer = 3000; - }else Grow_Timer -= diff; - - if( Shrink_Timer <= diff ) - { - m_creature->RemoveAurasDueToSpell(SPELL_GROW); - Stop = true; - }else Shrink_Timer -= diff; - } -}; -CreatureAI* GetAI_mob_underbog_mushroom(Creature *_Creature) -{ - return new mob_underbog_mushroomAI (_Creature); -} - -void AddSC_boss_hungarfen() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_hungarfen"; - newscript->GetAI = GetAI_boss_hungarfen; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_underbog_mushroom"; - newscript->GetAI = GetAI_mob_underbog_mushroom; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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 +SDCategory: Coilfang Resevoir, Underbog +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_FOUL_SPORES 31673 +#define SPELL_ACID_GEYSER 38739 + +struct MANGOS_DLL_DECL boss_hungarfenAI : public ScriptedAI +{ + boss_hungarfenAI(Creature *c) : ScriptedAI(c) + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + Reset(); + } + + bool HeroicMode; + bool Root; + uint32 Mushroom_Timer; + uint32 AcidGeyser_Timer; + + void Reset() + { + Root = false; + Mushroom_Timer = 5000; // 1 mushroom after 5s, then one per 10s. This should be different in heroic mode + AcidGeyser_Timer = 10000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 20 ) + { + if( !Root ) + { + DoCast(m_creature,SPELL_FOUL_SPORES); + Root = true; + } + } + + if( Mushroom_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_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); + + Mushroom_Timer = 10000; + }else Mushroom_Timer -= diff; + + if( AcidGeyser_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_ACID_GEYSER); + AcidGeyser_Timer = 10000+rand()%7500; + }else AcidGeyser_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_hungarfen(Creature *_Creature) +{ + return new boss_hungarfenAI (_Creature); +} + +#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 *c) : ScriptedAI(c) { Reset(); } + + bool Stop; + uint32 Grow_Timer; + uint32 Shrink_Timer; + + void Reset() + { + Stop = false; + Grow_Timer = 0; + Shrink_Timer = 20000; + + DoCast(m_creature,SPELL_PUTRID_MUSHROOM,true); + DoCast(m_creature,SPELL_SPORE_CLOUD,true); + } + + void MoveInLineOfSight(Unit *who) { return; } + + void AttackStart(Unit* who) { return; } + + void Aggro(Unit* who) { } + + void UpdateAI(const uint32 diff) + { + if( Stop ) + return; + + if( Grow_Timer <= diff ) + { + DoCast(m_creature,SPELL_GROW); + Grow_Timer = 3000; + }else Grow_Timer -= diff; + + if( Shrink_Timer <= diff ) + { + m_creature->RemoveAurasDueToSpell(SPELL_GROW); + Stop = true; + }else Shrink_Timer -= diff; + } +}; +CreatureAI* GetAI_mob_underbog_mushroom(Creature *_Creature) +{ + return new mob_underbog_mushroomAI (_Creature); +} + +void AddSC_boss_hungarfen() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_hungarfen"; + newscript->GetAI = GetAI_boss_hungarfen; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_underbog_mushroom"; + newscript->GetAI = GetAI_mob_underbog_mushroom; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp b/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp index 02acd88a491..2a0ed0187f7 100644 --- a/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp +++ b/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp @@ -1,24 +1,24 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Darkshore -SD%Complete: 0 -SDComment: Placeholder -SDCategory: Darkshore -EndScriptData */ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Darkshore +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Darkshore +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp b/src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp index 535d8c86410..0b3325d6e84 100644 --- a/src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp +++ b/src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp @@ -1,24 +1,24 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Deadmines -SD%Complete: 0 -SDComment: Placeholder -SDCategory: Deadmines -EndScriptData */ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Deadmines +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Deadmines +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/deadmines/instance_deadmines.cpp b/src/bindings/scripts/scripts/zone/deadmines/instance_deadmines.cpp index d97db663273..e2d386beda0 100644 --- a/src/bindings/scripts/scripts/zone/deadmines/instance_deadmines.cpp +++ b/src/bindings/scripts/scripts/zone/deadmines/instance_deadmines.cpp @@ -1,22 +1,22 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Deadmines -SD%Complete: 0 -SDComment: Placeholder -SDCategory: Deadmines -EndScriptData */ +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Deadmines +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Deadmines +EndScriptData */ diff --git a/src/bindings/scripts/scripts/zone/dun_morogh/dun_morogh.cpp b/src/bindings/scripts/scripts/zone/dun_morogh/dun_morogh.cpp index d584dc0690e..58136ceae9f 100644 --- a/src/bindings/scripts/scripts/zone/dun_morogh/dun_morogh.cpp +++ b/src/bindings/scripts/scripts/zone/dun_morogh/dun_morogh.cpp @@ -1,98 +1,98 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Dun_Morogh -SD%Complete: 50 -SDComment: Quest support: 1783 -SDCategory: Dun Morogh -EndScriptData */ - -/* ContentData -npc_narm_faulk -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_narm_faulk -######*/ - -#define SAY_HEAL "Thank you, dear Paladin, you just saved my life." - -struct MANGOS_DLL_DECL npc_narm_faulkAI : public ScriptedAI -{ - uint32 lifeTimer; - bool spellHit; - - npc_narm_faulkAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - lifeTimer = 120000; - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 32); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,7); // lay down - spellHit = false; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - return; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->GetUInt32Value(UNIT_FIELD_BYTES_1)) - { - if(lifeTimer < diff) - m_creature->AI()->EnterEvadeMode(); - else - lifeTimer -= diff; - } - } - - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) - { - if(Spellkind->Id == 8593 && !spellHit) - { - DoCast(m_creature,32343); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - //m_creature->RemoveAllAuras(); - DoSay(SAY_HEAL,LANG_COMMON,NULL); - spellHit = true; - } - } - -}; -CreatureAI* GetAI_npc_narm_faulk(Creature *_Creature) -{ - return new npc_narm_faulkAI (_Creature); -} - -void AddSC_dun_morogh() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_narm_faulk"; - newscript->GetAI = GetAI_npc_narm_faulk; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Dun_Morogh +SD%Complete: 50 +SDComment: Quest support: 1783 +SDCategory: Dun Morogh +EndScriptData */ + +/* ContentData +npc_narm_faulk +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_narm_faulk +######*/ + +#define SAY_HEAL "Thank you, dear Paladin, you just saved my life." + +struct MANGOS_DLL_DECL npc_narm_faulkAI : public ScriptedAI +{ + uint32 lifeTimer; + bool spellHit; + + npc_narm_faulkAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + lifeTimer = 120000; + m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 32); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,7); // lay down + spellHit = false; + } + + void Aggro(Unit *who) + { + } + + void MoveInLineOfSight(Unit *who) + { + return; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->GetUInt32Value(UNIT_FIELD_BYTES_1)) + { + if(lifeTimer < diff) + m_creature->AI()->EnterEvadeMode(); + else + lifeTimer -= diff; + } + } + + void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) + { + if(Spellkind->Id == 8593 && !spellHit) + { + DoCast(m_creature,32343); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); + m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); + //m_creature->RemoveAllAuras(); + DoSay(SAY_HEAL,LANG_COMMON,NULL); + spellHit = true; + } + } + +}; +CreatureAI* GetAI_npc_narm_faulk(Creature *_Creature) +{ + return new npc_narm_faulkAI (_Creature); +} + +void AddSC_dun_morogh() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_narm_faulk"; + newscript->GetAI = GetAI_npc_narm_faulk; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/dustwallow_marsh/dustwallow_marsh.cpp b/src/bindings/scripts/scripts/zone/dustwallow_marsh/dustwallow_marsh.cpp index a29dda1c811..d63a8a8c948 100644 --- a/src/bindings/scripts/scripts/zone/dustwallow_marsh/dustwallow_marsh.cpp +++ b/src/bindings/scripts/scripts/zone/dustwallow_marsh/dustwallow_marsh.cpp @@ -1,231 +1,231 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Dustwallow_Marsh -SD%Complete: 95 -SDComment: Quest support: 11180, 558, 11126. Vendor Nat Pagle -SDCategory: Dustwallow Marsh -EndScriptData */ - -/* ContentData -mobs_risen_husk_spirit -npc_restless_apparition -npc_deserter_agitator -npc_lady_jaina_proudmoore -npc_nat_pagle -EndContentData */ - -#include "precompiled.h" - -/*###### -## mobs_risen_husk_spirit -######*/ - -#define SPELL_SUMMON_RESTLESS_APPARITION 42511 -#define SPELL_CONSUME_FLESH 37933 //Risen Husk -#define SPELL_INTANGIBLE_PRESENCE 43127 //Risen Spirit - -struct MANGOS_DLL_DECL mobs_risen_husk_spiritAI : public ScriptedAI -{ - mobs_risen_husk_spiritAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ConsumeFlesh_Timer; - uint32 IntangiblePresence_Timer; - - void Reset() - { - ConsumeFlesh_Timer = 10000; - IntangiblePresence_Timer = 5000; - } - - void Aggro(Unit* who) { } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if( done_by->GetTypeId() == TYPEID_PLAYER ) - if( damage >= m_creature->GetHealth() && ((Player*)done_by)->GetQuestStatus(11180) == QUEST_STATUS_INCOMPLETE ) - m_creature->CastSpell(done_by,SPELL_SUMMON_RESTLESS_APPARITION,false); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( ConsumeFlesh_Timer < diff ) - { - if( m_creature->GetEntry() == 23555 ) - DoCast(m_creature->getVictim(),SPELL_CONSUME_FLESH); - ConsumeFlesh_Timer = 15000; - } else ConsumeFlesh_Timer -= diff; - - if( IntangiblePresence_Timer < diff ) - { - if( m_creature->GetEntry() == 23554 ) - DoCast(m_creature->getVictim(),SPELL_INTANGIBLE_PRESENCE); - IntangiblePresence_Timer = 20000; - } else IntangiblePresence_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_mobs_risen_husk_spirit(Creature *_Creature) -{ - return new mobs_risen_husk_spiritAI (_Creature); -} - -/*###### -## npc_restless_apparition -######*/ - -bool GossipHello_npc_restless_apparition(Player *player, Creature *_Creature) -{ - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); - _Creature->SetInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - return true; -} - -/*###### -## npc_deserter_agitator -######*/ - -struct MANGOS_DLL_DECL npc_deserter_agitatorAI : public ScriptedAI -{ - npc_deserter_agitatorAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - m_creature->setFaction(894); - } - - void Aggro(Unit* who) {} -}; - -CreatureAI* GetAI_npc_deserter_agitator(Creature *_Creature) -{ - return new npc_deserter_agitatorAI (_Creature); -} - -bool GossipHello_npc_deserter_agitator(Player *player, Creature *_Creature) -{ - if (player->GetQuestStatus(11126) == QUEST_STATUS_INCOMPLETE) - { - _Creature->setFaction(1883); - player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -/*###### -## npc_lady_jaina_proudmoore -######*/ - -#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 *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->GetQuestStatus(558) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_JAINA, GOSSIP_SENDER_MAIN, GOSSIP_SENDER_INFO ); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lady_jaina_proudmoore(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_SENDER_INFO ) - { - player->SEND_GOSSIP_MENU( 7012, _Creature->GetGUID() ); - player->CastSpell( player, 23122, false); - } - return true; -} - -/*###### -## npc_nat_pagle -######*/ - -bool GossipHello_npc_nat_pagle(Player *player, Creature *_Creature) -{ - if(_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if(_Creature->isVendor() && player->GetQuestRewardStatus(8227)) - { - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU( 7640, _Creature->GetGUID() ); - } - else - player->SEND_GOSSIP_MENU( 7638, _Creature->GetGUID() ); - - return true; -} - -bool GossipSelect_npc_nat_pagle(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if(action == GOSSIP_ACTION_TRADE) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - - return true; -} - -/*###### -## -######*/ - -void AddSC_dustwallow_marsh() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mobs_risen_husk_spirit"; - newscript->GetAI = GetAI_mobs_risen_husk_spirit; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_restless_apparition"; - newscript->pGossipHello = &GossipHello_npc_restless_apparition; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_deserter_agitator"; - newscript->GetAI = GetAI_npc_deserter_agitator; - newscript->pGossipHello = &GossipHello_npc_deserter_agitator; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_lady_jaina_proudmoore"; - newscript->pGossipHello = &GossipHello_npc_lady_jaina_proudmoore; - newscript->pGossipSelect = &GossipSelect_npc_lady_jaina_proudmoore; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_nat_pagle"; - newscript->pGossipHello = &GossipHello_npc_nat_pagle; - newscript->pGossipSelect = &GossipSelect_npc_nat_pagle; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Dustwallow_Marsh +SD%Complete: 95 +SDComment: Quest support: 11180, 558, 11126. Vendor Nat Pagle +SDCategory: Dustwallow Marsh +EndScriptData */ + +/* ContentData +mobs_risen_husk_spirit +npc_restless_apparition +npc_deserter_agitator +npc_lady_jaina_proudmoore +npc_nat_pagle +EndContentData */ + +#include "precompiled.h" + +/*###### +## mobs_risen_husk_spirit +######*/ + +#define SPELL_SUMMON_RESTLESS_APPARITION 42511 +#define SPELL_CONSUME_FLESH 37933 //Risen Husk +#define SPELL_INTANGIBLE_PRESENCE 43127 //Risen Spirit + +struct MANGOS_DLL_DECL mobs_risen_husk_spiritAI : public ScriptedAI +{ + mobs_risen_husk_spiritAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ConsumeFlesh_Timer; + uint32 IntangiblePresence_Timer; + + void Reset() + { + ConsumeFlesh_Timer = 10000; + IntangiblePresence_Timer = 5000; + } + + void Aggro(Unit* who) { } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if( done_by->GetTypeId() == TYPEID_PLAYER ) + if( damage >= m_creature->GetHealth() && ((Player*)done_by)->GetQuestStatus(11180) == QUEST_STATUS_INCOMPLETE ) + m_creature->CastSpell(done_by,SPELL_SUMMON_RESTLESS_APPARITION,false); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( ConsumeFlesh_Timer < diff ) + { + if( m_creature->GetEntry() == 23555 ) + DoCast(m_creature->getVictim(),SPELL_CONSUME_FLESH); + ConsumeFlesh_Timer = 15000; + } else ConsumeFlesh_Timer -= diff; + + if( IntangiblePresence_Timer < diff ) + { + if( m_creature->GetEntry() == 23554 ) + DoCast(m_creature->getVictim(),SPELL_INTANGIBLE_PRESENCE); + IntangiblePresence_Timer = 20000; + } else IntangiblePresence_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_mobs_risen_husk_spirit(Creature *_Creature) +{ + return new mobs_risen_husk_spiritAI (_Creature); +} + +/*###### +## npc_restless_apparition +######*/ + +bool GossipHello_npc_restless_apparition(Player *player, Creature *_Creature) +{ + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); + _Creature->SetInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + return true; +} + +/*###### +## npc_deserter_agitator +######*/ + +struct MANGOS_DLL_DECL npc_deserter_agitatorAI : public ScriptedAI +{ + npc_deserter_agitatorAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + m_creature->setFaction(894); + } + + void Aggro(Unit* who) {} +}; + +CreatureAI* GetAI_npc_deserter_agitator(Creature *_Creature) +{ + return new npc_deserter_agitatorAI (_Creature); +} + +bool GossipHello_npc_deserter_agitator(Player *player, Creature *_Creature) +{ + if (player->GetQuestStatus(11126) == QUEST_STATUS_INCOMPLETE) + { + _Creature->setFaction(1883); + player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +/*###### +## npc_lady_jaina_proudmoore +######*/ + +#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 *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->GetQuestStatus(558) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_JAINA, GOSSIP_SENDER_MAIN, GOSSIP_SENDER_INFO ); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_lady_jaina_proudmoore(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_SENDER_INFO ) + { + player->SEND_GOSSIP_MENU( 7012, _Creature->GetGUID() ); + player->CastSpell( player, 23122, false); + } + return true; +} + +/*###### +## npc_nat_pagle +######*/ + +bool GossipHello_npc_nat_pagle(Player *player, Creature *_Creature) +{ + if(_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if(_Creature->isVendor() && player->GetQuestRewardStatus(8227)) + { + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + player->SEND_GOSSIP_MENU( 7640, _Creature->GetGUID() ); + } + else + player->SEND_GOSSIP_MENU( 7638, _Creature->GetGUID() ); + + return true; +} + +bool GossipSelect_npc_nat_pagle(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if(action == GOSSIP_ACTION_TRADE) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + + return true; +} + +/*###### +## +######*/ + +void AddSC_dustwallow_marsh() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mobs_risen_husk_spirit"; + newscript->GetAI = GetAI_mobs_risen_husk_spirit; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_restless_apparition"; + newscript->pGossipHello = &GossipHello_npc_restless_apparition; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_deserter_agitator"; + newscript->GetAI = GetAI_npc_deserter_agitator; + newscript->pGossipHello = &GossipHello_npc_deserter_agitator; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_lady_jaina_proudmoore"; + newscript->pGossipHello = &GossipHello_npc_lady_jaina_proudmoore; + newscript->pGossipSelect = &GossipSelect_npc_lady_jaina_proudmoore; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_nat_pagle"; + newscript->pGossipHello = &GossipHello_npc_nat_pagle; + newscript->pGossipSelect = &GossipSelect_npc_nat_pagle; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp b/src/bindings/scripts/scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp index aa7ae7b2879..e0b2067b145 100644 --- a/src/bindings/scripts/scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp +++ b/src/bindings/scripts/scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp @@ -1,180 +1,180 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Eastern_Plaguelands -SD%Complete: 100 -SDComment: Quest support: 5211, 5742. Special vendor Augustus the Touched -SDCategory: Eastern Plaguelands -EndScriptData */ - -/* ContentData -mobs_ghoul_flayer -npc_augustus_the_touched -npc_darrowshire_spirit -npc_tirion_fordring -EndContentData */ - -#include "precompiled.h" - -//id8530 - cannibal ghoul -//id8531 - gibbering ghoul -//id8532 - diseased flayer - -struct MANGOS_DLL_DECL mobs_ghoul_flayerAI : public ScriptedAI -{ - mobs_ghoul_flayerAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() { } - - void Aggro(Unit* who) { } - - void JustDied(Unit* Killer) - { - if( Killer->GetTypeId() == TYPEID_PLAYER ) - DoSpawnCreature(11064,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN,60000); - } - -}; - -CreatureAI* GetAI_mobs_ghoul_flayer(Creature *_Creature) -{ - return new mobs_ghoul_flayerAI (_Creature); -} - -/*###### -## npc_augustus_the_touched -######*/ - -bool GossipHello_npc_augustus_the_touched(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( _Creature->isVendor() && player->GetQuestRewardStatus(6164) ) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_augustus_the_touched(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_TRADE ) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - return true; -} - -/*###### -## npc_darrowshire_spirit -######*/ - -#define SPELL_SPIRIT_SPAWNIN 17321 - -struct MANGOS_DLL_DECL npc_darrowshire_spiritAI : public ScriptedAI -{ - npc_darrowshire_spiritAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - DoCast(m_creature,SPELL_SPIRIT_SPAWNIN); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit *who) { } - -}; -CreatureAI* GetAI_npc_darrowshire_spirit(Creature *_Creature) -{ - return new npc_darrowshire_spiritAI (_Creature); -} - -bool GossipHello_npc_darrowshire_spirit(Player *player, Creature *_Creature) -{ - player->SEND_GOSSIP_MENU(3873,_Creature->GetGUID()); - player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); - _Creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - return true; -} - -/*###### -## npc_tirion_fordring -######*/ - -bool GossipHello_npc_tirion_fordring(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && player->getStandState() == PLAYER_STATE_SIT ) - player->ADD_GOSSIP_ITEM( 0, "I am ready to hear your tale, Tirion.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_tirion_fordring(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "Thank you, Tirion. What of your identity?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(4493, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "That is terrible.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(4494, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "I will, Tirion.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(4495, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(5742); - break; - } - return true; -} - -void AddSC_eastern_plaguelands() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mobs_ghoul_flayer"; - newscript->GetAI = GetAI_mobs_ghoul_flayer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_augustus_the_touched"; - newscript->pGossipHello = &GossipHello_npc_augustus_the_touched; - newscript->pGossipSelect = &GossipSelect_npc_augustus_the_touched; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_darrowshire_spirit"; - newscript->GetAI = GetAI_npc_darrowshire_spirit; - newscript->pGossipHello = &GossipHello_npc_darrowshire_spirit; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_tirion_fordring"; - newscript->pGossipHello = &GossipHello_npc_tirion_fordring; - newscript->pGossipSelect = &GossipSelect_npc_tirion_fordring; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Eastern_Plaguelands +SD%Complete: 100 +SDComment: Quest support: 5211, 5742. Special vendor Augustus the Touched +SDCategory: Eastern Plaguelands +EndScriptData */ + +/* ContentData +mobs_ghoul_flayer +npc_augustus_the_touched +npc_darrowshire_spirit +npc_tirion_fordring +EndContentData */ + +#include "precompiled.h" + +//id8530 - cannibal ghoul +//id8531 - gibbering ghoul +//id8532 - diseased flayer + +struct MANGOS_DLL_DECL mobs_ghoul_flayerAI : public ScriptedAI +{ + mobs_ghoul_flayerAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() { } + + void Aggro(Unit* who) { } + + void JustDied(Unit* Killer) + { + if( Killer->GetTypeId() == TYPEID_PLAYER ) + DoSpawnCreature(11064,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN,60000); + } + +}; + +CreatureAI* GetAI_mobs_ghoul_flayer(Creature *_Creature) +{ + return new mobs_ghoul_flayerAI (_Creature); +} + +/*###### +## npc_augustus_the_touched +######*/ + +bool GossipHello_npc_augustus_the_touched(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( _Creature->isVendor() && player->GetQuestRewardStatus(6164) ) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_augustus_the_touched(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_TRADE ) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + return true; +} + +/*###### +## npc_darrowshire_spirit +######*/ + +#define SPELL_SPIRIT_SPAWNIN 17321 + +struct MANGOS_DLL_DECL npc_darrowshire_spiritAI : public ScriptedAI +{ + npc_darrowshire_spiritAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + DoCast(m_creature,SPELL_SPIRIT_SPAWNIN); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit *who) { } + +}; +CreatureAI* GetAI_npc_darrowshire_spirit(Creature *_Creature) +{ + return new npc_darrowshire_spiritAI (_Creature); +} + +bool GossipHello_npc_darrowshire_spirit(Player *player, Creature *_Creature) +{ + player->SEND_GOSSIP_MENU(3873,_Creature->GetGUID()); + player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); + _Creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + return true; +} + +/*###### +## npc_tirion_fordring +######*/ + +bool GossipHello_npc_tirion_fordring(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && player->getStandState() == PLAYER_STATE_SIT ) + player->ADD_GOSSIP_ITEM( 0, "I am ready to hear your tale, Tirion.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_tirion_fordring(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "Thank you, Tirion. What of your identity?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(4493, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "That is terrible.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(4494, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "I will, Tirion.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(4495, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(5742); + break; + } + return true; +} + +void AddSC_eastern_plaguelands() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mobs_ghoul_flayer"; + newscript->GetAI = GetAI_mobs_ghoul_flayer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_augustus_the_touched"; + newscript->pGossipHello = &GossipHello_npc_augustus_the_touched; + newscript->pGossipSelect = &GossipSelect_npc_augustus_the_touched; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_darrowshire_spirit"; + newscript->GetAI = GetAI_npc_darrowshire_spirit; + newscript->pGossipHello = &GossipHello_npc_darrowshire_spirit; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_tirion_fordring"; + newscript->pGossipHello = &GossipHello_npc_tirion_fordring; + newscript->pGossipSelect = &GossipSelect_npc_tirion_fordring; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/elwynn_forest/elwynn_forest.cpp b/src/bindings/scripts/scripts/zone/elwynn_forest/elwynn_forest.cpp index 0fc754f91c6..7d2c22e6381 100644 --- a/src/bindings/scripts/scripts/zone/elwynn_forest/elwynn_forest.cpp +++ b/src/bindings/scripts/scripts/zone/elwynn_forest/elwynn_forest.cpp @@ -1,98 +1,98 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Elwynn_Forest -SD%Complete: 50 -SDComment: Quest support: 1786 -SDCategory: Elwynn Forest -EndScriptData */ - -/* ContentData -npc_henze_faulk -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_henze_faulk -######*/ - -#define SAY_HEAL "Thank you, dear Paladin, you just saved my life." - -struct MANGOS_DLL_DECL npc_henze_faulkAI : public ScriptedAI -{ - uint32 lifeTimer; - bool spellHit; - - npc_henze_faulkAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - lifeTimer = 120000; - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 32); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,7); // lay down - spellHit = false; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - return; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->GetUInt32Value(UNIT_FIELD_BYTES_1)) - { - if(lifeTimer < diff) - m_creature->AI()->EnterEvadeMode(); - else - lifeTimer -= diff; - } - } - - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) - { - if(Spellkind->Id == 8593 && !spellHit) - { - DoCast(m_creature,32343); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - //m_creature->RemoveAllAuras(); - DoSay(SAY_HEAL,LANG_COMMON,NULL); - spellHit = true; - } - } - -}; -CreatureAI* GetAI_npc_henze_faulk(Creature *_Creature) -{ - return new npc_henze_faulkAI (_Creature); -} - -void AddSC_elwynn_forest() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_henze_faulk"; - newscript->GetAI = GetAI_npc_henze_faulk; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Elwynn_Forest +SD%Complete: 50 +SDComment: Quest support: 1786 +SDCategory: Elwynn Forest +EndScriptData */ + +/* ContentData +npc_henze_faulk +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_henze_faulk +######*/ + +#define SAY_HEAL "Thank you, dear Paladin, you just saved my life." + +struct MANGOS_DLL_DECL npc_henze_faulkAI : public ScriptedAI +{ + uint32 lifeTimer; + bool spellHit; + + npc_henze_faulkAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + lifeTimer = 120000; + m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 32); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,7); // lay down + spellHit = false; + } + + void Aggro(Unit *who) + { + } + + void MoveInLineOfSight(Unit *who) + { + return; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->GetUInt32Value(UNIT_FIELD_BYTES_1)) + { + if(lifeTimer < diff) + m_creature->AI()->EnterEvadeMode(); + else + lifeTimer -= diff; + } + } + + void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) + { + if(Spellkind->Id == 8593 && !spellHit) + { + DoCast(m_creature,32343); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); + m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); + //m_creature->RemoveAllAuras(); + DoSay(SAY_HEAL,LANG_COMMON,NULL); + spellHit = true; + } + } + +}; +CreatureAI* GetAI_npc_henze_faulk(Creature *_Creature) +{ + return new npc_henze_faulkAI (_Creature); +} + +void AddSC_elwynn_forest() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_henze_faulk"; + newscript->GetAI = GetAI_npc_henze_faulk; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp b/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp index aab21ed5cb3..12931cb52e7 100644 --- a/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp +++ b/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp @@ -1,163 +1,163 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Eversong_Woods -SD%Complete: 100 -SDComment: Quest support: 8346, 8483 -SDCategory: Eversong Woods -EndScriptData */ - -/* ContentData -mobs_mana_tapped -npc_prospector_anvilward -EndContentData */ - -#include "precompiled.h" -#include "../../npc/npc_escortAI.h" - -/*###### -## mobs_mana_tapped -######*/ - -struct MANGOS_DLL_DECL mobs_mana_tappedAI : public ScriptedAI -{ - mobs_mana_tappedAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() { } - - void Aggro(Unit *who) { } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if( caster->GetTypeId() == TYPEID_PLAYER) - if( ((Player*)caster)->GetQuestStatus(8346) == QUEST_STATUS_INCOMPLETE && !((Player*)caster)->GetReqKillOrCastCurrentCount(8346, m_creature->GetEntry()) && spell->Id == 28734) - ((Player*)caster)->CastedCreatureOrGO(15468, m_creature->GetGUID(), spell->Id); - return; - } -}; -CreatureAI* GetAI_mobs_mana_tapped(Creature *_Creature) -{ - return new mobs_mana_tappedAI (_Creature); -} - -/*###### -## npc_prospector_anvilward -######*/ - -#define QUEST_THE_DWARVEN_SPY 8483 - -struct MANGOS_DLL_DECL npc_prospector_anvilwardAI : public npc_escortAI -{ - // CreatureAI functions - npc_prospector_anvilwardAI(Creature *c) : npc_escortAI(c) {Reset();} - - // Pure Virtual Functions - void WaypointReached(uint32 i) - { - switch (i) - { - case 0: - m_creature->Say("Very well. Let's see what you have to show me, $N.", LANG_UNIVERSAL, PlayerGUID); - break; - case 5: - m_creature->Say("What manner of trick is this, $R? If you seek to ambush me, I warn you I will not go down quietly!", LANG_UNIVERSAL, PlayerGUID); - break; - case 6: - m_creature->setFaction(24); - break; - } - } - - void Aggro(Unit* who) { } - - void Reset() - { - //Default npc faction - m_creature->setFaction(35); - } - - void JustDied(Unit* killer) - { - //Default npc faction - m_creature->setFaction(35); - } - - void UpdateAI(const uint32 diff) - { - npc_escortAI::UpdateAI(diff); //Must update npc_escortAI - - } -}; - -CreatureAI* GetAI_npc_prospector_anvilward(Creature *_Creature) -{ - npc_prospector_anvilwardAI* thisAI = new npc_prospector_anvilwardAI(_Creature); - - thisAI->AddWaypoint(0, 9294.78, -6682.51, 22.42); - thisAI->AddWaypoint(1, 9298.27, -6667.99, 22.42); - thisAI->AddWaypoint(2, 9309.63, -6658.84, 22.43); - thisAI->AddWaypoint(3, 9304.43, -6649.31, 26.46); - thisAI->AddWaypoint(4, 9298.83, -6648.00, 28.61); - thisAI->AddWaypoint(5, 9291.06, -6653.46, 31.83,2500); - thisAI->AddWaypoint(6, 9289.08, -6660.17, 31.85,5000); - thisAI->AddWaypoint(7, 9291.06, -6653.46, 31.83); - - return (CreatureAI*)thisAI; -} - -bool GossipHello_npc_prospector_anvilward(Player *player, Creature *_Creature) -{ - if( player->GetQuestStatus(QUEST_THE_DWARVEN_SPY) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM(0, "I need a moment of your time, sir.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(8239, _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_prospector_anvilward(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "Why... yes, of course. I've something to show you right inside this building, Mr. Anvilward.",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(8240, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->CLOSE_GOSSIP_MENU(); - //attack,defend,walk - ((npc_escortAI*)(_Creature->AI()))->Start(true, true, false, player->GetGUID()); - break; - } - return true; -} - -void AddSC_eversong_woods() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mobs_mana_tapped"; - newscript->GetAI = GetAI_mobs_mana_tapped; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name= "npc_prospector_anvilward"; - newscript->GetAI = GetAI_npc_prospector_anvilward; - newscript->pGossipHello = &GossipHello_npc_prospector_anvilward; - newscript->pGossipSelect = &GossipSelect_npc_prospector_anvilward; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Eversong_Woods +SD%Complete: 100 +SDComment: Quest support: 8346, 8483 +SDCategory: Eversong Woods +EndScriptData */ + +/* ContentData +mobs_mana_tapped +npc_prospector_anvilward +EndContentData */ + +#include "precompiled.h" +#include "../../npc/npc_escortAI.h" + +/*###### +## mobs_mana_tapped +######*/ + +struct MANGOS_DLL_DECL mobs_mana_tappedAI : public ScriptedAI +{ + mobs_mana_tappedAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() { } + + void Aggro(Unit *who) { } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if( caster->GetTypeId() == TYPEID_PLAYER) + if( ((Player*)caster)->GetQuestStatus(8346) == QUEST_STATUS_INCOMPLETE && !((Player*)caster)->GetReqKillOrCastCurrentCount(8346, m_creature->GetEntry()) && spell->Id == 28734) + ((Player*)caster)->CastedCreatureOrGO(15468, m_creature->GetGUID(), spell->Id); + return; + } +}; +CreatureAI* GetAI_mobs_mana_tapped(Creature *_Creature) +{ + return new mobs_mana_tappedAI (_Creature); +} + +/*###### +## npc_prospector_anvilward +######*/ + +#define QUEST_THE_DWARVEN_SPY 8483 + +struct MANGOS_DLL_DECL npc_prospector_anvilwardAI : public npc_escortAI +{ + // CreatureAI functions + npc_prospector_anvilwardAI(Creature *c) : npc_escortAI(c) {Reset();} + + // Pure Virtual Functions + void WaypointReached(uint32 i) + { + switch (i) + { + case 0: + m_creature->Say("Very well. Let's see what you have to show me, $N.", LANG_UNIVERSAL, PlayerGUID); + break; + case 5: + m_creature->Say("What manner of trick is this, $R? If you seek to ambush me, I warn you I will not go down quietly!", LANG_UNIVERSAL, PlayerGUID); + break; + case 6: + m_creature->setFaction(24); + break; + } + } + + void Aggro(Unit* who) { } + + void Reset() + { + //Default npc faction + m_creature->setFaction(35); + } + + void JustDied(Unit* killer) + { + //Default npc faction + m_creature->setFaction(35); + } + + void UpdateAI(const uint32 diff) + { + npc_escortAI::UpdateAI(diff); //Must update npc_escortAI + + } +}; + +CreatureAI* GetAI_npc_prospector_anvilward(Creature *_Creature) +{ + npc_prospector_anvilwardAI* thisAI = new npc_prospector_anvilwardAI(_Creature); + + thisAI->AddWaypoint(0, 9294.78, -6682.51, 22.42); + thisAI->AddWaypoint(1, 9298.27, -6667.99, 22.42); + thisAI->AddWaypoint(2, 9309.63, -6658.84, 22.43); + thisAI->AddWaypoint(3, 9304.43, -6649.31, 26.46); + thisAI->AddWaypoint(4, 9298.83, -6648.00, 28.61); + thisAI->AddWaypoint(5, 9291.06, -6653.46, 31.83,2500); + thisAI->AddWaypoint(6, 9289.08, -6660.17, 31.85,5000); + thisAI->AddWaypoint(7, 9291.06, -6653.46, 31.83); + + return (CreatureAI*)thisAI; +} + +bool GossipHello_npc_prospector_anvilward(Player *player, Creature *_Creature) +{ + if( player->GetQuestStatus(QUEST_THE_DWARVEN_SPY) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM(0, "I need a moment of your time, sir.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(8239, _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_prospector_anvilward(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "Why... yes, of course. I've something to show you right inside this building, Mr. Anvilward.",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(8240, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->CLOSE_GOSSIP_MENU(); + //attack,defend,walk + ((npc_escortAI*)(_Creature->AI()))->Start(true, true, false, player->GetGUID()); + break; + } + return true; +} + +void AddSC_eversong_woods() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mobs_mana_tapped"; + newscript->GetAI = GetAI_mobs_mana_tapped; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name= "npc_prospector_anvilward"; + newscript->GetAI = GetAI_npc_prospector_anvilward; + newscript->pGossipHello = &GossipHello_npc_prospector_anvilward; + newscript->pGossipSelect = &GossipSelect_npc_prospector_anvilward; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/felwood/felwood.cpp b/src/bindings/scripts/scripts/zone/felwood/felwood.cpp index 4e8b6e3cdc3..f0f0a081859 100644 --- a/src/bindings/scripts/scripts/zone/felwood/felwood.cpp +++ b/src/bindings/scripts/scripts/zone/felwood/felwood.cpp @@ -1,89 +1,89 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Felwood -SD%Complete: 95 -SDComment: Quest support: related to 4101&4102 (To obtain Cenarion Beacon) -SDCategory: Felwood -EndScriptData */ - -/* ContentData -npcs_riverbreeze_and_silversky -EndContentData */ - -#include "precompiled.h" - -/*###### -## npcs_riverbreeze_and_silversky -######*/ - -#define GOSSIP_ITEM_BEACON "Please make me a Cenarion Beacon" - -bool GossipHello_npcs_riverbreeze_and_silversky(Player *player, Creature *_Creature) -{ - uint32 eCreature = _Creature->GetEntry(); - - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( eCreature==9528 ) - { - if( player->GetQuestRewardStatus(4101) ) - { - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_BEACON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(2848, _Creature->GetGUID()); - }else if( player->GetTeam()==HORDE ) - player->SEND_GOSSIP_MENU(2845, _Creature->GetGUID()); - else - player->SEND_GOSSIP_MENU(2844, _Creature->GetGUID()); - } - - if( eCreature==9529 ) - { - if( player->GetQuestRewardStatus(4102) ) - { - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_BEACON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(2849, _Creature->GetGUID()); - }else if( player->GetTeam()==ALLIANCE ) - player->SEND_GOSSIP_MENU(2843, _Creature->GetGUID()); - else - player->SEND_GOSSIP_MENU(2842, _Creature->GetGUID()); - } - - return true; -} - -bool GossipSelect_npcs_riverbreeze_and_silversky(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if( action==GOSSIP_ACTION_INFO_DEF+1 ) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player, 15120, false); - } - return true; -} - -void AddSC_felwood() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npcs_riverbreeze_and_silversky"; - newscript->pGossipHello = &GossipHello_npcs_riverbreeze_and_silversky; - newscript->pGossipSelect = &GossipSelect_npcs_riverbreeze_and_silversky; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Felwood +SD%Complete: 95 +SDComment: Quest support: related to 4101&4102 (To obtain Cenarion Beacon) +SDCategory: Felwood +EndScriptData */ + +/* ContentData +npcs_riverbreeze_and_silversky +EndContentData */ + +#include "precompiled.h" + +/*###### +## npcs_riverbreeze_and_silversky +######*/ + +#define GOSSIP_ITEM_BEACON "Please make me a Cenarion Beacon" + +bool GossipHello_npcs_riverbreeze_and_silversky(Player *player, Creature *_Creature) +{ + uint32 eCreature = _Creature->GetEntry(); + + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( eCreature==9528 ) + { + if( player->GetQuestRewardStatus(4101) ) + { + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_BEACON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(2848, _Creature->GetGUID()); + }else if( player->GetTeam()==HORDE ) + player->SEND_GOSSIP_MENU(2845, _Creature->GetGUID()); + else + player->SEND_GOSSIP_MENU(2844, _Creature->GetGUID()); + } + + if( eCreature==9529 ) + { + if( player->GetQuestRewardStatus(4102) ) + { + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_BEACON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(2849, _Creature->GetGUID()); + }else if( player->GetTeam()==ALLIANCE ) + player->SEND_GOSSIP_MENU(2843, _Creature->GetGUID()); + else + player->SEND_GOSSIP_MENU(2842, _Creature->GetGUID()); + } + + return true; +} + +bool GossipSelect_npcs_riverbreeze_and_silversky(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if( action==GOSSIP_ACTION_INFO_DEF+1 ) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player, 15120, false); + } + return true; +} + +void AddSC_felwood() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npcs_riverbreeze_and_silversky"; + newscript->pGossipHello = &GossipHello_npcs_riverbreeze_and_silversky; + newscript->pGossipSelect = &GossipSelect_npcs_riverbreeze_and_silversky; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/feralas/feralas.cpp b/src/bindings/scripts/scripts/zone/feralas/feralas.cpp index ef886eadc65..a5062ebc21f 100644 --- a/src/bindings/scripts/scripts/zone/feralas/feralas.cpp +++ b/src/bindings/scripts/scripts/zone/feralas/feralas.cpp @@ -1,85 +1,85 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Feralas -SD%Complete: 100 -SDComment: Quest support: 3520. Special vendor Gregan Brewspewer -SDCategory: Feralas -EndScriptData */ - -#include "precompiled.h" - -/*###### -## npc_gregan_brewspewer -######*/ - -bool GossipHello_npc_gregan_brewspewer(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( _Creature->isVendor() && player->GetQuestStatus(3909) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM(0, "Buy somethin', will ya?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(2433,_Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_gregan_brewspewer(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_INFO_DEF+1 ) - { - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU(2434,_Creature->GetGUID()); - } - if( action == GOSSIP_ACTION_TRADE ) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - return true; -} - -/*###### -## npc_screecher_spirit -######*/ - -bool GossipHello_npc_screecher_spirit(Player *player, Creature *_Creature) -{ - player->SEND_GOSSIP_MENU(2039,_Creature->GetGUID() ); - player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); - _Creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - return true; -} - -/*###### -## AddSC -######*/ - -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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_screecher_spirit"; - newscript->pGossipHello = &GossipHello_npc_screecher_spirit; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Feralas +SD%Complete: 100 +SDComment: Quest support: 3520. Special vendor Gregan Brewspewer +SDCategory: Feralas +EndScriptData */ + +#include "precompiled.h" + +/*###### +## npc_gregan_brewspewer +######*/ + +bool GossipHello_npc_gregan_brewspewer(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( _Creature->isVendor() && player->GetQuestStatus(3909) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM(0, "Buy somethin', will ya?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(2433,_Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_gregan_brewspewer(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + { + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + player->SEND_GOSSIP_MENU(2434,_Creature->GetGUID()); + } + if( action == GOSSIP_ACTION_TRADE ) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + return true; +} + +/*###### +## npc_screecher_spirit +######*/ + +bool GossipHello_npc_screecher_spirit(Player *player, Creature *_Creature) +{ + player->SEND_GOSSIP_MENU(2039,_Creature->GetGUID() ); + player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); + _Creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + return true; +} + +/*###### +## AddSC +######*/ + +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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_screecher_spirit"; + newscript->pGossipHello = &GossipHello_npc_screecher_spirit; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/ghostlands/ghostlands.cpp b/src/bindings/scripts/scripts/zone/ghostlands/ghostlands.cpp index 759da44db12..bceb03da348 100644 --- a/src/bindings/scripts/scripts/zone/ghostlands/ghostlands.cpp +++ b/src/bindings/scripts/scripts/zone/ghostlands/ghostlands.cpp @@ -1,134 +1,134 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Ghostlands -SD%Complete: 100 -SDComment: Quest support: 9692. Obtain Budd's Guise of Zul'aman. Vendor Rathis Tomber -SDCategory: Ghostlands -EndScriptData */ - -/* ContentData -npc_blood_knight_dawnstar -npc_budd_nedreck -npc_rathis_tomber -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_blood_knight_dawnstar -######*/ - -bool GossipHello_npc_blood_knight_dawnstar(Player *player, Creature *_Creature) -{ - if (player->GetQuestStatus(9692) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(24226,1,true)) - player->ADD_GOSSIP_ITEM( 0, "Take Blood Knight Insignia", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_blood_knight_dawnstar(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 24226, 1, false); - if( msg == EQUIP_ERR_OK ) - { - player->StoreNewItem( dest, 24226, 1, true); - player->PlayerTalkClass->ClearMenus(); - } - } - return true; -} - -/*###### -## npc_budd_nedreck -######*/ - -bool GossipHello_npc_budd_nedreck(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->GetQuestStatus(11166) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(0,"You gave the crew disguises?",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_budd_nedreck(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action==GOSSIP_ACTION_INFO_DEF ) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player, 42540, false); - } - return true; -} - -/*###### -## npc_rathis_tomber -######*/ - -bool GossipHello_npc_rathis_tomber(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( _Creature->isVendor() && player->GetQuestRewardStatus(9152) ) - { - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU(8432,_Creature->GetGUID()); - }else - player->SEND_GOSSIP_MENU(8431,_Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_rathis_tomber(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_TRADE ) - player->SEND_VENDORLIST( _Creature->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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_budd_nedreck"; - newscript->pGossipHello = &GossipHello_npc_budd_nedreck; - newscript->pGossipSelect = &GossipSelect_npc_budd_nedreck; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_rathis_tomber"; - newscript->pGossipHello = &GossipHello_npc_rathis_tomber; - newscript->pGossipSelect = &GossipSelect_npc_rathis_tomber; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Ghostlands +SD%Complete: 100 +SDComment: Quest support: 9692. Obtain Budd's Guise of Zul'aman. Vendor Rathis Tomber +SDCategory: Ghostlands +EndScriptData */ + +/* ContentData +npc_blood_knight_dawnstar +npc_budd_nedreck +npc_rathis_tomber +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_blood_knight_dawnstar +######*/ + +bool GossipHello_npc_blood_knight_dawnstar(Player *player, Creature *_Creature) +{ + if (player->GetQuestStatus(9692) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(24226,1,true)) + player->ADD_GOSSIP_ITEM( 0, "Take Blood Knight Insignia", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_blood_knight_dawnstar(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 24226, 1, false); + if( msg == EQUIP_ERR_OK ) + { + player->StoreNewItem( dest, 24226, 1, true); + player->PlayerTalkClass->ClearMenus(); + } + } + return true; +} + +/*###### +## npc_budd_nedreck +######*/ + +bool GossipHello_npc_budd_nedreck(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->GetQuestStatus(11166) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(0,"You gave the crew disguises?",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_budd_nedreck(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action==GOSSIP_ACTION_INFO_DEF ) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player, 42540, false); + } + return true; +} + +/*###### +## npc_rathis_tomber +######*/ + +bool GossipHello_npc_rathis_tomber(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( _Creature->isVendor() && player->GetQuestRewardStatus(9152) ) + { + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + player->SEND_GOSSIP_MENU(8432,_Creature->GetGUID()); + }else + player->SEND_GOSSIP_MENU(8431,_Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_rathis_tomber(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_TRADE ) + player->SEND_VENDORLIST( _Creature->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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_budd_nedreck"; + newscript->pGossipHello = &GossipHello_npc_budd_nedreck; + newscript->pGossipSelect = &GossipSelect_npc_budd_nedreck; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_rathis_tomber"; + newscript->pGossipHello = &GossipHello_npc_rathis_tomber; + newscript->pGossipSelect = &GossipSelect_npc_rathis_tomber; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_gruul.cpp b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_gruul.cpp index d43ac25f08c..90974ccc360 100644 --- a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_gruul.cpp +++ b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_gruul.cpp @@ -1,281 +1,281 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Gruul -SD%Complete: 25 -SDComment: Ground Slam seriously messed up due to core problem -SDCategory: Gruul's Lair -EndScriptData */ - -#include "precompiled.h" -#include "def_gruuls_lair.h" - -#define SPELL_GROWTH 36300 -#define SPELL_CAVE_IN 36240 -#define 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) -#define SPELL_SHATTER_EFFECT 33671 -#define SPELL_HURTFUL_STRIKE 33813 -#define SPELL_REVERBERATION 36297 //AoE Silence -#define SPELL_GRONN_LORDS_GRASP 33572 //Already handled in GroundSlam -#define SPELL_STONED 33652 //-- Spell is self cast -#define SPELL_SHATTER 33654 -#define SPELL_MAGNETIC_PULL 28337 -#define SPELL_KNOCK_BACK 24199 //Knockback spell until correct implementation is made - -#define EMOTE_GROW "grows in size!" -#define SAY_AGGRO "Come.... and die." - -struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI -{ - boss_gruulAI(Creature *c) : ScriptedAI(c) { Reset(); } - - ScriptedInstance *pInstance; - - uint32 Growth_Timer; - uint32 CaveIn_Timer; - uint32 GroundSlamTimer; - uint32 GroundSlamStage; - uint32 PerformingGroundSlam; - uint32 HurtfulStrike_Timer; - uint32 Reverberation_Timer; - - void Reset() - { - pInstance = (ScriptedInstance*)m_creature->GetInstanceData(); - - Growth_Timer= 30000; - CaveIn_Timer= 40000; - GroundSlamTimer= 35000; - GroundSlamStage= 0; - PerformingGroundSlam= false; - HurtfulStrike_Timer= 8000; - Reverberation_Timer= 60000+45000; - - if(pInstance) - pInstance->SetData(DATA_GRUULEVENT, 0); - } - - void JustDied(Unit* Killer) - { - if(pInstance) - pInstance->SetData(DATA_GRUULEVENT, 1); - } - - void Aggro(Unit *who) - { - - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - - if(pInstance) - pInstance->SetData(DATA_GRUULEVENT, 1); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - // Growth - // Gruul can cast this spell up to 30 times - if (Growth_Timer < diff) - { - DoCast(m_creature,SPELL_GROWTH); - DoTextEmote(EMOTE_GROW,NULL); - Growth_Timer = 30000; - }else Growth_Timer -= diff; - - if(PerformingGroundSlam) - { - if(GroundSlamTimer < diff) - { - switch(GroundSlamStage) - { - case 0: - { - //Begin the whole ordeal - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - - std::vector knockback_targets; - - //First limit the list to only players - for(std::list::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) - { - Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - - if(target && target->GetTypeId() == TYPEID_PLAYER) - knockback_targets.push_back(target); - } - - //Now to totally disoriend those players - for(std::vector::iterator itr = knockback_targets.begin(); itr!= knockback_targets.end(); ++itr) - { - Unit *target = *itr; - Unit *target2 = *(knockback_targets.begin() + rand()%knockback_targets.size()); - - if(target && target2) - { - switch(rand()%2) - { - case 0: target2->CastSpell(target, SPELL_MAGNETIC_PULL, true, NULL, NULL, m_creature->GetGUID()); break; - case 1: target2->CastSpell(target, SPELL_KNOCK_BACK, true, NULL, NULL, m_creature->GetGUID()); break; - } - } - } - - GroundSlamTimer = 7000; - } break; - - case 1: - { - //Players are going to get stoned - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - - for(std::list::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) - { - Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - - if(target) - { - target->RemoveAurasDueToSpell(SPELL_GRONN_LORDS_GRASP); - target->CastSpell(target, SPELL_STONED, true, NULL, NULL, m_creature->GetGUID()); - } - } - - GroundSlamTimer = 5000; - - } break; - - case 2: - { - //The dummy shatter spell is cast - DoCast(m_creature, SPELL_SHATTER); - - GroundSlamTimer = 1000; - - } break; - - case 3: - { - //Shatter takes effect - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - - for(std::list::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) - { - Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - - if(target) - { - target->RemoveAurasDueToSpell(SPELL_STONED); - - if(target->GetTypeId() == TYPEID_PLAYER) - target->CastSpell(target, SPELL_SHATTER_EFFECT, false, NULL, NULL, m_creature->GetGUID()); - } - - } - - m_creature->GetMotionMaster()->Clear(); - - Unit *victim = m_creature->getVictim(); - if(victim) - { - m_creature->GetMotionMaster()->MoveChase(victim); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); - } - - PerformingGroundSlam = false; - - GroundSlamTimer =120000; - HurtfulStrike_Timer= 8000; - if(Reverberation_Timer < 10000) //Give a little time to the players to undo the damage from shatter - Reverberation_Timer += 10000; - - } break; - } - - GroundSlamStage++; - } - else - GroundSlamTimer-=diff; - } - else - { - // Hurtful Strike - if (HurtfulStrike_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_TOPAGGRO,1); - - if (target && m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - DoCast(target,SPELL_HURTFUL_STRIKE); - else - DoCast(m_creature->getVictim(),SPELL_HURTFUL_STRIKE); - - HurtfulStrike_Timer= 8000; - }else HurtfulStrike_Timer -= diff; - - // Reverberation - if (Reverberation_Timer < diff) - { - m_creature->CastSpell(m_creature->getVictim(), SPELL_REVERBERATION, true); - - Reverberation_Timer = 30000; - }else Reverberation_Timer -= diff; - - // Cave In - if (CaveIn_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - if(target) - DoCast(target,SPELL_CAVE_IN); - - CaveIn_Timer = 20000; - }else CaveIn_Timer -= diff; - - // Ground Slam, Gronn Lord's Grasp, Stoned, Shatter - if (GroundSlamTimer < diff) - { - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); - - PerformingGroundSlam= true; - GroundSlamTimer = 0; - GroundSlamStage = 0; - DoCast(m_creature->getVictim(), SPELL_GROUND_SLAM); - } else GroundSlamTimer -=diff; - - DoMeleeAttackIfReady(); - } - } -}; - -CreatureAI* GetAI_boss_gruul(Creature *_Creature) -{ - return new boss_gruulAI (_Creature); -} - -void AddSC_boss_gruul() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gruul"; - newscript->GetAI = GetAI_boss_gruul; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Gruul +SD%Complete: 25 +SDComment: Ground Slam seriously messed up due to core problem +SDCategory: Gruul's Lair +EndScriptData */ + +#include "precompiled.h" +#include "def_gruuls_lair.h" + +#define SPELL_GROWTH 36300 +#define SPELL_CAVE_IN 36240 +#define 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) +#define SPELL_SHATTER_EFFECT 33671 +#define SPELL_HURTFUL_STRIKE 33813 +#define SPELL_REVERBERATION 36297 //AoE Silence +#define SPELL_GRONN_LORDS_GRASP 33572 //Already handled in GroundSlam +#define SPELL_STONED 33652 //-- Spell is self cast +#define SPELL_SHATTER 33654 +#define SPELL_MAGNETIC_PULL 28337 +#define SPELL_KNOCK_BACK 24199 //Knockback spell until correct implementation is made + +#define EMOTE_GROW "grows in size!" +#define SAY_AGGRO "Come.... and die." + +struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI +{ + boss_gruulAI(Creature *c) : ScriptedAI(c) { Reset(); } + + ScriptedInstance *pInstance; + + uint32 Growth_Timer; + uint32 CaveIn_Timer; + uint32 GroundSlamTimer; + uint32 GroundSlamStage; + uint32 PerformingGroundSlam; + uint32 HurtfulStrike_Timer; + uint32 Reverberation_Timer; + + void Reset() + { + pInstance = (ScriptedInstance*)m_creature->GetInstanceData(); + + Growth_Timer= 30000; + CaveIn_Timer= 40000; + GroundSlamTimer= 35000; + GroundSlamStage= 0; + PerformingGroundSlam= false; + HurtfulStrike_Timer= 8000; + Reverberation_Timer= 60000+45000; + + if(pInstance) + pInstance->SetData(DATA_GRUULEVENT, 0); + } + + void JustDied(Unit* Killer) + { + if(pInstance) + pInstance->SetData(DATA_GRUULEVENT, 1); + } + + void Aggro(Unit *who) + { + + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + + if(pInstance) + pInstance->SetData(DATA_GRUULEVENT, 1); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + // Growth + // Gruul can cast this spell up to 30 times + if (Growth_Timer < diff) + { + DoCast(m_creature,SPELL_GROWTH); + DoTextEmote(EMOTE_GROW,NULL); + Growth_Timer = 30000; + }else Growth_Timer -= diff; + + if(PerformingGroundSlam) + { + if(GroundSlamTimer < diff) + { + switch(GroundSlamStage) + { + case 0: + { + //Begin the whole ordeal + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + + std::vector knockback_targets; + + //First limit the list to only players + for(std::list::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + { + Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + + if(target && target->GetTypeId() == TYPEID_PLAYER) + knockback_targets.push_back(target); + } + + //Now to totally disoriend those players + for(std::vector::iterator itr = knockback_targets.begin(); itr!= knockback_targets.end(); ++itr) + { + Unit *target = *itr; + Unit *target2 = *(knockback_targets.begin() + rand()%knockback_targets.size()); + + if(target && target2) + { + switch(rand()%2) + { + case 0: target2->CastSpell(target, SPELL_MAGNETIC_PULL, true, NULL, NULL, m_creature->GetGUID()); break; + case 1: target2->CastSpell(target, SPELL_KNOCK_BACK, true, NULL, NULL, m_creature->GetGUID()); break; + } + } + } + + GroundSlamTimer = 7000; + } break; + + case 1: + { + //Players are going to get stoned + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + + for(std::list::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + { + Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + + if(target) + { + target->RemoveAurasDueToSpell(SPELL_GRONN_LORDS_GRASP); + target->CastSpell(target, SPELL_STONED, true, NULL, NULL, m_creature->GetGUID()); + } + } + + GroundSlamTimer = 5000; + + } break; + + case 2: + { + //The dummy shatter spell is cast + DoCast(m_creature, SPELL_SHATTER); + + GroundSlamTimer = 1000; + + } break; + + case 3: + { + //Shatter takes effect + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + + for(std::list::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + { + Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + + if(target) + { + target->RemoveAurasDueToSpell(SPELL_STONED); + + if(target->GetTypeId() == TYPEID_PLAYER) + target->CastSpell(target, SPELL_SHATTER_EFFECT, false, NULL, NULL, m_creature->GetGUID()); + } + + } + + m_creature->GetMotionMaster()->Clear(); + + Unit *victim = m_creature->getVictim(); + if(victim) + { + m_creature->GetMotionMaster()->MoveChase(victim); + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); + } + + PerformingGroundSlam = false; + + GroundSlamTimer =120000; + HurtfulStrike_Timer= 8000; + if(Reverberation_Timer < 10000) //Give a little time to the players to undo the damage from shatter + Reverberation_Timer += 10000; + + } break; + } + + GroundSlamStage++; + } + else + GroundSlamTimer-=diff; + } + else + { + // Hurtful Strike + if (HurtfulStrike_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_TOPAGGRO,1); + + if (target && m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + DoCast(target,SPELL_HURTFUL_STRIKE); + else + DoCast(m_creature->getVictim(),SPELL_HURTFUL_STRIKE); + + HurtfulStrike_Timer= 8000; + }else HurtfulStrike_Timer -= diff; + + // Reverberation + if (Reverberation_Timer < diff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_REVERBERATION, true); + + Reverberation_Timer = 30000; + }else Reverberation_Timer -= diff; + + // Cave In + if (CaveIn_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + if(target) + DoCast(target,SPELL_CAVE_IN); + + CaveIn_Timer = 20000; + }else CaveIn_Timer -= diff; + + // Ground Slam, Gronn Lord's Grasp, Stoned, Shatter + if (GroundSlamTimer < diff) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); + + PerformingGroundSlam= true; + GroundSlamTimer = 0; + GroundSlamStage = 0; + DoCast(m_creature->getVictim(), SPELL_GROUND_SLAM); + } else GroundSlamTimer -=diff; + + DoMeleeAttackIfReady(); + } + } +}; + +CreatureAI* GetAI_boss_gruul(Creature *_Creature) +{ + return new boss_gruulAI (_Creature); +} + +void AddSC_boss_gruul() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gruul"; + newscript->GetAI = GetAI_boss_gruul; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp index e69a46104d3..59edbd5a05b 100644 --- a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp +++ b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp @@ -1,687 +1,687 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_King_Maulgar -SD%Complete: 80 -SDComment: Verify that the script is working properly -SDCategory: Gruul's Lair -EndScriptData */ - -#include "precompiled.h" -#include "def_gruuls_lair.h" - -#define SOUND_AGGRO 11367 //"Gronn are the real power in outland." - -#define SOUND_ENRAGE 11368 //"You will not defeat the hand of Gruul!" - -#define SOUND_OGRE_DEATH1 11369 //"You won't kill next one so easy!" -#define SOUND_OGRE_DEATH2 11370 //"Pah! Does not prove anything!" -#define SOUND_OGRE_DEATH3 11371 //"I'm not afraid of you." -#define SOUND_OGRE_DEATH4 11372 //"Good, now you fight me!" - -#define SOUND_SLAY1 11373 //"You not so tough afterall!" -#define SOUND_SLAY2 11374 //"Aha ha ha ha!" -#define SOUND_SLAY3 11375 //"Mulgar is king!" - -#define SOUND_DEATH 11376 //"Gruul ...will crush you..." - -// High King Maulgar -#define SPELL_ARCING_SMASH 39144 -#define SPELL_MIGHTY_BLOW 33230 -#define SPELL_WHIRLWIND 33238 -#define SPELL_ENRAGE 34970 - -// Council spells -#define SPELL_DARK_DECAY 33129 -#define SPELL_GREATER_POLYMORPH 33173 -#define SPELL_LIGHTNING_BOLT 36152 -#define SPELL_ARCANE_SHOCK 33175 -#define SPELL_ARCANE_EXPLOSION 33237 -#define SPELL_GREATER_PW_SHIELD 33147 -#define SPELL_HEAL 33144 -#define SPELL_GREATER_FIREBALL 33051 -#define SPELL_SPELLSHIELD 33054 -#define SPELL_BLAST_WAVE 33061 - -//High King Maulgar AI -struct MANGOS_DLL_DECL boss_high_king_maulgarAI : public ScriptedAI -{ - boss_high_king_maulgarAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - for(uint8 i = 0; i < 4; ++i) - Council[i] = 0; - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 ArcingSmash_Timer; - uint32 MightyBlow_Timer; - uint32 Whirlwind_Timer; - uint32 Charging_Timer; - - bool Phase2; - - uint64 Council[4]; - - void Reset() - { - ArcingSmash_Timer = 10000; - MightyBlow_Timer = 40000; - Whirlwind_Timer = 30000; - Charging_Timer = 0; - Phase2 = false; - - Creature *pCreature = NULL; - for(uint8 i = 0; i < 4; i++) - { - if(Council[i]) - { - pCreature = (Creature*)(Unit::GetUnit((*m_creature), Council[i])); - if(pCreature && !pCreature->isAlive()) - { - pCreature->Respawn(); - pCreature->AI()->EnterEvadeMode(); - } - } - } - - //reset encounter - if (pInstance) - pInstance->SetData(DATA_MAULGAREVENT, 0); - } - - void KilledUnit() - { - switch(rand()%2) - { - case 0: DoPlaySoundToSet(m_creature, SOUND_SLAY1); break; - case 1: DoPlaySoundToSet(m_creature, SOUND_SLAY2); break; - case 2: DoPlaySoundToSet(m_creature, SOUND_SLAY3); break; - } - } - - void JustDied(Unit* Killer) - { - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if (pInstance) - pInstance->SetData(DATA_MAULGAREVENT, 0); - } - - void Aggro(Unit *who) { StartEvent(who); } - - void GetCouncil() - { - //get council member's guid to respawn them if needed - Council[0] = pInstance->GetData64(DATA_KIGGLERTHECRAZED); - Council[1] = pInstance->GetData64(DATA_BLINDEYETHESEER); - Council[2] = pInstance->GetData64(DATA_OLMTHESUMMONER); - Council[3] = pInstance->GetData64(DATA_KROSHFIREHAND); - } - - void StartEvent(Unit *who) - { - if(!pInstance) - return; - - GetCouncil(); - - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - - pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); - pInstance->SetData(DATA_MAULGAREVENT, 1); - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); - - if(target) - { - DoStartAttackAndMovement(target); - - GetCouncil(); - - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) - EnterEvadeMode(); - - //ArcingSmash_Timer - if (ArcingSmash_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ARCING_SMASH); - ArcingSmash_Timer = 10000; - }else ArcingSmash_Timer -= diff; - - //Whirlwind_Timer - if (Whirlwind_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_WHIRLWIND); - Whirlwind_Timer = 55000; - }else Whirlwind_Timer -= diff; - - //MightyBlow_Timer - if (MightyBlow_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_MIGHTY_BLOW); - MightyBlow_Timer = 30000+rand()%10000; - }else MightyBlow_Timer -= diff; - - //Entering Phase 2 - if(!Phase2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) - { - Phase2 = true; - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - } - - if(Phase2) - { - //Charging_Timer - if(Charging_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - DoStartAttackAndMovement(target); - - Charging_Timer = 20000; - }else Charging_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; - -//Olm The Summoner AI -struct MANGOS_DLL_DECL boss_olm_the_summonerAI : public ScriptedAI -{ - boss_olm_the_summonerAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - uint32 DarkDecay_Timer; - uint32 Summon_Timer; - - ScriptedInstance* pInstance; - - void Reset() - { - DarkDecay_Timer = 10000; - Summon_Timer = 15000; - - //reset encounter - if (pInstance) - pInstance->SetData(DATA_MAULGAREVENT, 0); - } - - void Aggro(Unit *who) - { - if(pInstance) - { - pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); - pInstance->SetData(DATA_MAULGAREVENT, 1); - } - } - - float DoCalculateRandomLocation() - { - float Loc; - float Rand = rand()%8; - - switch(rand()%2) - { - case 0: Loc = 0 + Rand; break; - case 1: Loc = 0 - Rand; break; - } - return Loc; - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); - - if(target) - { - DoStartAttackAndMovement(target); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) - EnterEvadeMode(); - - //DarkDecay_Timer - if(DarkDecay_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_DARK_DECAY); - DarkDecay_Timer = 20000; - }else DarkDecay_Timer -= diff; - - //Summon_Timer - if(Summon_Timer < diff) - { - Creature *Add = NULL; - Add = DoSpawnCreature(18847, DoCalculateRandomLocation(), DoCalculateRandomLocation(), 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - Summon_Timer = 30000; - }else Summon_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Kiggler The Crazed AI -struct MANGOS_DLL_DECL boss_kiggler_the_crazedAI : public ScriptedAI -{ - boss_kiggler_the_crazedAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - uint32 GreatherPolymorph_Timer; - uint32 LightningBolt_Timer; - uint32 ArcaneShock_Timer; - uint32 ArcaneExplosion_Timer; - - ScriptedInstance* pInstance; - - void Reset() - { - GreatherPolymorph_Timer = 5000; - LightningBolt_Timer = 10000; - ArcaneShock_Timer = 20000; - ArcaneExplosion_Timer = 30000; - - //reset encounter - if (pInstance) - pInstance->SetData(DATA_MAULGAREVENT, 0); - } - - void Aggro(Unit *who) - { - if(pInstance) - { - pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); - pInstance->SetData(DATA_MAULGAREVENT, 1); - } - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if(!InCombat) - { - DoStartAttackAndMovement(who); - if(pInstance) - { - pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); - pInstance->SetData(DATA_MAULGAREVENT, 1); - } - } - } - } - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); - - if(target) - { - DoStartAttackAndMovement(target); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) - EnterEvadeMode(); - - //GreaterPolymorph_Timer / disabled: it makes you fall under the texture / if you've got vmaps feel free to uncomment this - /*if(GreaterPolymorph_Timer < diff) - { - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - DoCast(target, SPELL_GREATER_POLYMORPH); - - GreaterPolymorph_Timer = 20000; - }else GreaterPolymorph_Timer -= diff;*/ - - //LightningBolt_Timer - if(LightningBolt_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_LIGHTNING_BOLT); - LightningBolt_Timer = 15000; - }else LightningBolt_Timer -= diff; - - //ArcaneShock_Timer - if(ArcaneShock_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ARCANE_SHOCK); - ArcaneShock_Timer = 20000; - }else ArcaneShock_Timer -= diff; - - //ArcaneExplosion_Timer - if(ArcaneExplosion_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); - ArcaneExplosion_Timer = 30000; - }else ArcaneExplosion_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Blindeye The Seer AI -struct MANGOS_DLL_DECL boss_blindeye_the_seerAI : public ScriptedAI -{ - boss_blindeye_the_seerAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - uint32 GreaterPowerWordShield_Timer; - uint32 Heal_Timer; - - ScriptedInstance* pInstance; - - void Reset() - { - GreaterPowerWordShield_Timer = 5000; - Heal_Timer = 30000; - - //reset encounter - if (pInstance) - pInstance->SetData(DATA_MAULGAREVENT, 0); - } - - void Aggro(Unit *who) - { - if(pInstance) - { - pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); - pInstance->SetData(DATA_MAULGAREVENT, 1); - } - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if(!InCombat) - { - DoStartAttackAndMovement(who); - if(pInstance) - { - pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); - pInstance->SetData(DATA_MAULGAREVENT, 1); - } - } - } - } - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); - - if(target) - { - DoStartAttackAndMovement(target); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) - EnterEvadeMode(); - - //GreaterPowerWordShield_Timer - if(GreaterPowerWordShield_Timer < diff) - { - DoCast(m_creature, SPELL_GREATER_PW_SHIELD); - GreaterPowerWordShield_Timer = 40000; - }else GreaterPowerWordShield_Timer -= diff; - - //Heal_Timer - if(Heal_Timer < diff) - { - DoCast(m_creature, SPELL_HEAL); - Heal_Timer = 60000; - }else Heal_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Krosh Firehand AI -struct MANGOS_DLL_DECL boss_krosh_firehandAI : public ScriptedAI -{ - boss_krosh_firehandAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - uint32 GreaterFireball_Timer; - uint32 SpellShield_Timer; - uint32 BlastWave_Timer; - - ScriptedInstance* pInstance; - - void Reset() - { - GreaterFireball_Timer = 1000; - SpellShield_Timer = 5000; - BlastWave_Timer = 20000; - - //reset encounter - if (pInstance) - pInstance->SetData(DATA_MAULGAREVENT, 0); - } - - void Aggro(Unit *who) - { - if(pInstance) - { - pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); - pInstance->SetData(DATA_MAULGAREVENT, 1); - } - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if(!InCombat) - { - DoStartAttackAndMovement(who); - if(pInstance) - { - pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); - pInstance->SetData(DATA_MAULGAREVENT, 1); - } - } - } - } - } - - void UpdateAI(const uint32 diff) - { - //Only if not incombat check if the event is started - if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) - { - Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); - - if(target) - { - DoStartAttackAndMovement(target); - } - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //someone evaded! - if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) - EnterEvadeMode(); - - //GreaterFireball_Timer - if(GreaterFireball_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_GREATER_FIREBALL); - GreaterFireball_Timer = 2000; - }else GreaterFireball_Timer -= diff; - - //SpellShield_Timer - if(SpellShield_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature->getVictim(), SPELL_SPELLSHIELD); - SpellShield_Timer = 30000; - }else SpellShield_Timer -= diff; - - //BlastWave_Timer - if(BlastWave_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature->getVictim(), SPELL_BLAST_WAVE); - BlastWave_Timer = 60000; - }else BlastWave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_high_king_maulgar(Creature *_Creature) -{ - return new boss_high_king_maulgarAI (_Creature); -} - -CreatureAI* GetAI_boss_olm_the_summoner(Creature *_Creature) -{ - return new boss_olm_the_summonerAI (_Creature); -} - -CreatureAI *GetAI_boss_kiggler_the_crazed(Creature *_Creature) -{ - return new boss_kiggler_the_crazedAI (_Creature); -} - -CreatureAI *GetAI_boss_blindeye_the_seer(Creature *_Creature) -{ - return new boss_blindeye_the_seerAI (_Creature); -} - -CreatureAI *GetAI_boss_krosh_firehand(Creature *_Creature) -{ - return new boss_krosh_firehandAI (_Creature); -} - -void AddSC_boss_high_king_maulgar() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_high_king_maulgar"; - newscript->GetAI = GetAI_boss_high_king_maulgar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_kiggler_the_crazed"; - newscript->GetAI = GetAI_boss_kiggler_the_crazed; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_blindeye_the_seer"; - newscript->GetAI = GetAI_boss_blindeye_the_seer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_olm_the_summoner"; - newscript->GetAI = GetAI_boss_olm_the_summoner; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_krosh_firehand"; - newscript->GetAI = GetAI_boss_krosh_firehand; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_King_Maulgar +SD%Complete: 80 +SDComment: Verify that the script is working properly +SDCategory: Gruul's Lair +EndScriptData */ + +#include "precompiled.h" +#include "def_gruuls_lair.h" + +#define SOUND_AGGRO 11367 //"Gronn are the real power in outland." + +#define SOUND_ENRAGE 11368 //"You will not defeat the hand of Gruul!" + +#define SOUND_OGRE_DEATH1 11369 //"You won't kill next one so easy!" +#define SOUND_OGRE_DEATH2 11370 //"Pah! Does not prove anything!" +#define SOUND_OGRE_DEATH3 11371 //"I'm not afraid of you." +#define SOUND_OGRE_DEATH4 11372 //"Good, now you fight me!" + +#define SOUND_SLAY1 11373 //"You not so tough afterall!" +#define SOUND_SLAY2 11374 //"Aha ha ha ha!" +#define SOUND_SLAY3 11375 //"Mulgar is king!" + +#define SOUND_DEATH 11376 //"Gruul ...will crush you..." + +// High King Maulgar +#define SPELL_ARCING_SMASH 39144 +#define SPELL_MIGHTY_BLOW 33230 +#define SPELL_WHIRLWIND 33238 +#define SPELL_ENRAGE 34970 + +// Council spells +#define SPELL_DARK_DECAY 33129 +#define SPELL_GREATER_POLYMORPH 33173 +#define SPELL_LIGHTNING_BOLT 36152 +#define SPELL_ARCANE_SHOCK 33175 +#define SPELL_ARCANE_EXPLOSION 33237 +#define SPELL_GREATER_PW_SHIELD 33147 +#define SPELL_HEAL 33144 +#define SPELL_GREATER_FIREBALL 33051 +#define SPELL_SPELLSHIELD 33054 +#define SPELL_BLAST_WAVE 33061 + +//High King Maulgar AI +struct MANGOS_DLL_DECL boss_high_king_maulgarAI : public ScriptedAI +{ + boss_high_king_maulgarAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + for(uint8 i = 0; i < 4; ++i) + Council[i] = 0; + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 ArcingSmash_Timer; + uint32 MightyBlow_Timer; + uint32 Whirlwind_Timer; + uint32 Charging_Timer; + + bool Phase2; + + uint64 Council[4]; + + void Reset() + { + ArcingSmash_Timer = 10000; + MightyBlow_Timer = 40000; + Whirlwind_Timer = 30000; + Charging_Timer = 0; + Phase2 = false; + + Creature *pCreature = NULL; + for(uint8 i = 0; i < 4; i++) + { + if(Council[i]) + { + pCreature = (Creature*)(Unit::GetUnit((*m_creature), Council[i])); + if(pCreature && !pCreature->isAlive()) + { + pCreature->Respawn(); + pCreature->AI()->EnterEvadeMode(); + } + } + } + + //reset encounter + if (pInstance) + pInstance->SetData(DATA_MAULGAREVENT, 0); + } + + void KilledUnit() + { + switch(rand()%2) + { + case 0: DoPlaySoundToSet(m_creature, SOUND_SLAY1); break; + case 1: DoPlaySoundToSet(m_creature, SOUND_SLAY2); break; + case 2: DoPlaySoundToSet(m_creature, SOUND_SLAY3); break; + } + } + + void JustDied(Unit* Killer) + { + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if (pInstance) + pInstance->SetData(DATA_MAULGAREVENT, 0); + } + + void Aggro(Unit *who) { StartEvent(who); } + + void GetCouncil() + { + //get council member's guid to respawn them if needed + Council[0] = pInstance->GetData64(DATA_KIGGLERTHECRAZED); + Council[1] = pInstance->GetData64(DATA_BLINDEYETHESEER); + Council[2] = pInstance->GetData64(DATA_OLMTHESUMMONER); + Council[3] = pInstance->GetData64(DATA_KROSHFIREHAND); + } + + void StartEvent(Unit *who) + { + if(!pInstance) + return; + + GetCouncil(); + + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + + pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); + pInstance->SetData(DATA_MAULGAREVENT, 1); + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); + + if(target) + { + DoStartAttackAndMovement(target); + + GetCouncil(); + + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) + EnterEvadeMode(); + + //ArcingSmash_Timer + if (ArcingSmash_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ARCING_SMASH); + ArcingSmash_Timer = 10000; + }else ArcingSmash_Timer -= diff; + + //Whirlwind_Timer + if (Whirlwind_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_WHIRLWIND); + Whirlwind_Timer = 55000; + }else Whirlwind_Timer -= diff; + + //MightyBlow_Timer + if (MightyBlow_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_MIGHTY_BLOW); + MightyBlow_Timer = 30000+rand()%10000; + }else MightyBlow_Timer -= diff; + + //Entering Phase 2 + if(!Phase2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) + { + Phase2 = true; + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + } + + if(Phase2) + { + //Charging_Timer + if(Charging_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + DoStartAttackAndMovement(target); + + Charging_Timer = 20000; + }else Charging_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +//Olm The Summoner AI +struct MANGOS_DLL_DECL boss_olm_the_summonerAI : public ScriptedAI +{ + boss_olm_the_summonerAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + uint32 DarkDecay_Timer; + uint32 Summon_Timer; + + ScriptedInstance* pInstance; + + void Reset() + { + DarkDecay_Timer = 10000; + Summon_Timer = 15000; + + //reset encounter + if (pInstance) + pInstance->SetData(DATA_MAULGAREVENT, 0); + } + + void Aggro(Unit *who) + { + if(pInstance) + { + pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); + pInstance->SetData(DATA_MAULGAREVENT, 1); + } + } + + float DoCalculateRandomLocation() + { + float Loc; + float Rand = rand()%8; + + switch(rand()%2) + { + case 0: Loc = 0 + Rand; break; + case 1: Loc = 0 - Rand; break; + } + return Loc; + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); + + if(target) + { + DoStartAttackAndMovement(target); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) + EnterEvadeMode(); + + //DarkDecay_Timer + if(DarkDecay_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_DARK_DECAY); + DarkDecay_Timer = 20000; + }else DarkDecay_Timer -= diff; + + //Summon_Timer + if(Summon_Timer < diff) + { + Creature *Add = NULL; + Add = DoSpawnCreature(18847, DoCalculateRandomLocation(), DoCalculateRandomLocation(), 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + Summon_Timer = 30000; + }else Summon_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Kiggler The Crazed AI +struct MANGOS_DLL_DECL boss_kiggler_the_crazedAI : public ScriptedAI +{ + boss_kiggler_the_crazedAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + uint32 GreatherPolymorph_Timer; + uint32 LightningBolt_Timer; + uint32 ArcaneShock_Timer; + uint32 ArcaneExplosion_Timer; + + ScriptedInstance* pInstance; + + void Reset() + { + GreatherPolymorph_Timer = 5000; + LightningBolt_Timer = 10000; + ArcaneShock_Timer = 20000; + ArcaneExplosion_Timer = 30000; + + //reset encounter + if (pInstance) + pInstance->SetData(DATA_MAULGAREVENT, 0); + } + + void Aggro(Unit *who) + { + if(pInstance) + { + pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); + pInstance->SetData(DATA_MAULGAREVENT, 1); + } + } + + void MoveInLineOfSight(Unit *who) + { + if (!m_creature->getVictim() && 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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if(!InCombat) + { + DoStartAttackAndMovement(who); + if(pInstance) + { + pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); + pInstance->SetData(DATA_MAULGAREVENT, 1); + } + } + } + } + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); + + if(target) + { + DoStartAttackAndMovement(target); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) + EnterEvadeMode(); + + //GreaterPolymorph_Timer / disabled: it makes you fall under the texture / if you've got vmaps feel free to uncomment this + /*if(GreaterPolymorph_Timer < diff) + { + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + DoCast(target, SPELL_GREATER_POLYMORPH); + + GreaterPolymorph_Timer = 20000; + }else GreaterPolymorph_Timer -= diff;*/ + + //LightningBolt_Timer + if(LightningBolt_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_LIGHTNING_BOLT); + LightningBolt_Timer = 15000; + }else LightningBolt_Timer -= diff; + + //ArcaneShock_Timer + if(ArcaneShock_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ARCANE_SHOCK); + ArcaneShock_Timer = 20000; + }else ArcaneShock_Timer -= diff; + + //ArcaneExplosion_Timer + if(ArcaneExplosion_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); + ArcaneExplosion_Timer = 30000; + }else ArcaneExplosion_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Blindeye The Seer AI +struct MANGOS_DLL_DECL boss_blindeye_the_seerAI : public ScriptedAI +{ + boss_blindeye_the_seerAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + uint32 GreaterPowerWordShield_Timer; + uint32 Heal_Timer; + + ScriptedInstance* pInstance; + + void Reset() + { + GreaterPowerWordShield_Timer = 5000; + Heal_Timer = 30000; + + //reset encounter + if (pInstance) + pInstance->SetData(DATA_MAULGAREVENT, 0); + } + + void Aggro(Unit *who) + { + if(pInstance) + { + pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); + pInstance->SetData(DATA_MAULGAREVENT, 1); + } + } + + void MoveInLineOfSight(Unit *who) + { + if (!m_creature->getVictim() && 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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if(!InCombat) + { + DoStartAttackAndMovement(who); + if(pInstance) + { + pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); + pInstance->SetData(DATA_MAULGAREVENT, 1); + } + } + } + } + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); + + if(target) + { + DoStartAttackAndMovement(target); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) + EnterEvadeMode(); + + //GreaterPowerWordShield_Timer + if(GreaterPowerWordShield_Timer < diff) + { + DoCast(m_creature, SPELL_GREATER_PW_SHIELD); + GreaterPowerWordShield_Timer = 40000; + }else GreaterPowerWordShield_Timer -= diff; + + //Heal_Timer + if(Heal_Timer < diff) + { + DoCast(m_creature, SPELL_HEAL); + Heal_Timer = 60000; + }else Heal_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Krosh Firehand AI +struct MANGOS_DLL_DECL boss_krosh_firehandAI : public ScriptedAI +{ + boss_krosh_firehandAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + uint32 GreaterFireball_Timer; + uint32 SpellShield_Timer; + uint32 BlastWave_Timer; + + ScriptedInstance* pInstance; + + void Reset() + { + GreaterFireball_Timer = 1000; + SpellShield_Timer = 5000; + BlastWave_Timer = 20000; + + //reset encounter + if (pInstance) + pInstance->SetData(DATA_MAULGAREVENT, 0); + } + + void Aggro(Unit *who) + { + if(pInstance) + { + pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); + pInstance->SetData(DATA_MAULGAREVENT, 1); + } + } + + void MoveInLineOfSight(Unit *who) + { + if (!m_creature->getVictim() && 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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if(!InCombat) + { + DoStartAttackAndMovement(who); + if(pInstance) + { + pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID()); + pInstance->SetData(DATA_MAULGAREVENT, 1); + } + } + } + } + } + + void UpdateAI(const uint32 diff) + { + //Only if not incombat check if the event is started + if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT)) + { + Unit* target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_MAULGAREVENT_TANK)); + + if(target) + { + DoStartAttackAndMovement(target); + } + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //someone evaded! + if(pInstance && !pInstance->GetData(DATA_MAULGAREVENT)) + EnterEvadeMode(); + + //GreaterFireball_Timer + if(GreaterFireball_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_GREATER_FIREBALL); + GreaterFireball_Timer = 2000; + }else GreaterFireball_Timer -= diff; + + //SpellShield_Timer + if(SpellShield_Timer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature->getVictim(), SPELL_SPELLSHIELD); + SpellShield_Timer = 30000; + }else SpellShield_Timer -= diff; + + //BlastWave_Timer + if(BlastWave_Timer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature->getVictim(), SPELL_BLAST_WAVE); + BlastWave_Timer = 60000; + }else BlastWave_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_high_king_maulgar(Creature *_Creature) +{ + return new boss_high_king_maulgarAI (_Creature); +} + +CreatureAI* GetAI_boss_olm_the_summoner(Creature *_Creature) +{ + return new boss_olm_the_summonerAI (_Creature); +} + +CreatureAI *GetAI_boss_kiggler_the_crazed(Creature *_Creature) +{ + return new boss_kiggler_the_crazedAI (_Creature); +} + +CreatureAI *GetAI_boss_blindeye_the_seer(Creature *_Creature) +{ + return new boss_blindeye_the_seerAI (_Creature); +} + +CreatureAI *GetAI_boss_krosh_firehand(Creature *_Creature) +{ + return new boss_krosh_firehandAI (_Creature); +} + +void AddSC_boss_high_king_maulgar() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_high_king_maulgar"; + newscript->GetAI = GetAI_boss_high_king_maulgar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_kiggler_the_crazed"; + newscript->GetAI = GetAI_boss_kiggler_the_crazed; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_blindeye_the_seer"; + newscript->GetAI = GetAI_boss_blindeye_the_seer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_olm_the_summoner"; + newscript->GetAI = GetAI_boss_olm_the_summoner; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_krosh_firehand"; + newscript->GetAI = GetAI_boss_krosh_firehand; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/gruuls_lair/def_gruuls_lair.h b/src/bindings/scripts/scripts/zone/gruuls_lair/def_gruuls_lair.h index e2d780dabda..4c432a8f5d5 100644 --- a/src/bindings/scripts/scripts/zone/gruuls_lair/def_gruuls_lair.h +++ b/src/bindings/scripts/scripts/zone/gruuls_lair/def_gruuls_lair.h @@ -1,15 +1,15 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_GRUULS_LAIR_H -#define DEF_GRUULS_LAIR_H - -#define DATA_BLINDEYETHESEER 1 -#define DATA_GRUULEVENT 2 -#define DATA_KIGGLERTHECRAZED 3 -#define DATA_KROSHFIREHAND 4 -#define DATA_MAULGAREVENT 5 -#define DATA_MAULGAREVENT_TANK 6 -#define DATA_OLMTHESUMMONER 7 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_GRUULS_LAIR_H +#define DEF_GRUULS_LAIR_H + +#define DATA_BLINDEYETHESEER 1 +#define DATA_GRUULEVENT 2 +#define DATA_KIGGLERTHECRAZED 3 +#define DATA_KROSHFIREHAND 4 +#define DATA_MAULGAREVENT 5 +#define DATA_MAULGAREVENT_TANK 6 +#define DATA_OLMTHESUMMONER 7 +#endif diff --git a/src/bindings/scripts/scripts/zone/gruuls_lair/instance_gruuls_lair.cpp b/src/bindings/scripts/scripts/zone/gruuls_lair/instance_gruuls_lair.cpp index 158af022905..055bf9c7e16 100644 --- a/src/bindings/scripts/scripts/zone/gruuls_lair/instance_gruuls_lair.cpp +++ b/src/bindings/scripts/scripts/zone/gruuls_lair/instance_gruuls_lair.cpp @@ -1,139 +1,139 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Gruuls_Lair -SD%Complete: 100 -SDComment: -SDCategory: Gruul's Lair -EndScriptData */ - -#include "precompiled.h" -#include "def_gruuls_lair.h" - -#define ENCOUNTERS 2 - -/* Gruuls Lair encounters: -1 - High King Maulgar event -2 - Gruul event -*/ - -struct MANGOS_DLL_DECL instance_gruuls_lair : public ScriptedInstance -{ - instance_gruuls_lair(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - bool Encounters[ENCOUNTERS]; - - uint64 MaulgarEvent_Tank; - uint64 KigglerTheCrazed; - uint64 BlindeyeTheSeer; - uint64 OlmTheSummoner; - uint64 KroshFirehand; - - void Initialize() - { - MaulgarEvent_Tank = 0; - KigglerTheCrazed = 0; - BlindeyeTheSeer = 0; - OlmTheSummoner = 0; - KroshFirehand = 0; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounters[i] = false; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; i++) - if(Encounters[i]) return true; - - return false; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case 18835: KigglerTheCrazed = creature->GetGUID(); break; - case 18836: BlindeyeTheSeer = creature->GetGUID(); break; - case 18834: OlmTheSummoner = creature->GetGUID(); break; - case 18832: KroshFirehand = creature->GetGUID(); break; - } - } - - void SetData64(uint32 type, uint64 data) - { - if(type == DATA_MAULGAREVENT_TANK) - MaulgarEvent_Tank = data; - } - - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_MAULGAREVENT_TANK: - return MaulgarEvent_Tank; - case DATA_KIGGLERTHECRAZED: - return KigglerTheCrazed; - case DATA_BLINDEYETHESEER: - return BlindeyeTheSeer; - case DATA_OLMTHESUMMONER: - return OlmTheSummoner; - case DATA_KROSHFIREHAND: - return KroshFirehand; - } - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_MAULGAREVENT: - Encounters[0] = (data) ? true : false; - break; - case DATA_GRUULEVENT: - Encounters[1] = (data) ? true : false; - break; - } - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_MAULGAREVENT: - return Encounters[0]; - case DATA_GRUULEVENT: - return Encounters[1]; - } - return 0; - } -}; - -InstanceData* GetInstanceData_instance_gruuls_lair(Map* map) -{ - return new instance_gruuls_lair(map); -} - -void AddSC_instance_gruuls_lair() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_gruuls_lair"; - newscript->GetInstanceData = GetInstanceData_instance_gruuls_lair; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Gruuls_Lair +SD%Complete: 100 +SDComment: +SDCategory: Gruul's Lair +EndScriptData */ + +#include "precompiled.h" +#include "def_gruuls_lair.h" + +#define ENCOUNTERS 2 + +/* Gruuls Lair encounters: +1 - High King Maulgar event +2 - Gruul event +*/ + +struct MANGOS_DLL_DECL instance_gruuls_lair : public ScriptedInstance +{ + instance_gruuls_lair(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + bool Encounters[ENCOUNTERS]; + + uint64 MaulgarEvent_Tank; + uint64 KigglerTheCrazed; + uint64 BlindeyeTheSeer; + uint64 OlmTheSummoner; + uint64 KroshFirehand; + + void Initialize() + { + MaulgarEvent_Tank = 0; + KigglerTheCrazed = 0; + BlindeyeTheSeer = 0; + OlmTheSummoner = 0; + KroshFirehand = 0; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounters[i] = false; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounters[i]) return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case 18835: KigglerTheCrazed = creature->GetGUID(); break; + case 18836: BlindeyeTheSeer = creature->GetGUID(); break; + case 18834: OlmTheSummoner = creature->GetGUID(); break; + case 18832: KroshFirehand = creature->GetGUID(); break; + } + } + + void SetData64(uint32 type, uint64 data) + { + if(type == DATA_MAULGAREVENT_TANK) + MaulgarEvent_Tank = data; + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_MAULGAREVENT_TANK: + return MaulgarEvent_Tank; + case DATA_KIGGLERTHECRAZED: + return KigglerTheCrazed; + case DATA_BLINDEYETHESEER: + return BlindeyeTheSeer; + case DATA_OLMTHESUMMONER: + return OlmTheSummoner; + case DATA_KROSHFIREHAND: + return KroshFirehand; + } + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_MAULGAREVENT: + Encounters[0] = (data) ? true : false; + break; + case DATA_GRUULEVENT: + Encounters[1] = (data) ? true : false; + break; + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_MAULGAREVENT: + return Encounters[0]; + case DATA_GRUULEVENT: + return Encounters[1]; + } + return 0; + } +}; + +InstanceData* GetInstanceData_instance_gruuls_lair(Map* map) +{ + return new instance_gruuls_lair(map); +} + +void AddSC_instance_gruuls_lair() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_gruuls_lair"; + newscript->GetInstanceData = GetInstanceData_instance_gruuls_lair; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_broggok.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_broggok.cpp index 86c300ff57a..2d0e6d1706c 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_broggok.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_broggok.cpp @@ -1,132 +1,132 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Broggok -SD%Complete: 100 -SDComment: -SDCategory: Hellfire Citadel, Blood Furnace -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SLIME_SPRAY 30913 -#define SPELL_POISON_CLOUD 30916 -#define SPELL_POISON_BOLT 30917 - -#define SPELL_POISON 30914 - -#define SAY_AGGRO "Come intruders...." - -struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI -{ - boss_broggokAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 AcidSpray_Timer; - uint32 PoisonSpawn_Timer; - uint32 PoisonBolt_Timer; - - void Reset() - { - AcidSpray_Timer = 10000; - PoisonSpawn_Timer = 5000; - PoisonBolt_Timer = 7000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - } - - void UpdateAI(const uint32 diff) - { - - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(AcidSpray_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SLIME_SPRAY); - AcidSpray_Timer = 4000+rand()%8000; - }else AcidSpray_Timer -=diff; - - if(PoisonBolt_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POISON_BOLT); - PoisonBolt_Timer = 4000+rand()%8000; - }else PoisonBolt_Timer -=diff; - - if(PoisonSpawn_Timer < diff) - { - DoCast(m_creature,SPELL_POISON_CLOUD); - PoisonSpawn_Timer = 20000; - }else PoisonSpawn_Timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_broggok_poisoncloudAI : public ScriptedAI -{ - mob_broggok_poisoncloudAI(Creature *c) : ScriptedAI(c) {Reset();} - - bool Start; - - void Reset() - { - Start = false; - } - - void Aggro(Unit* who) - { - } - - void UpdateAI(const uint32 diff) - { - if(!Start) - { - m_creature->SetUInt32Value(UNIT_NPC_FLAGS,0); - m_creature->setFaction(45); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Start = true; - DoCast(m_creature,SPELL_POISON); - } - } -}; - -CreatureAI* GetAI_boss_broggokAI(Creature *_Creature) -{ - return new boss_broggokAI (_Creature); -} - -CreatureAI* GetAI_mob_broggok_poisoncloudAI(Creature *_Creature) -{ - return new mob_broggok_poisoncloudAI (_Creature); -} - -void AddSC_boss_broggok() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_broggok"; - newscript->GetAI = GetAI_boss_broggokAI; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_broggok_poisoncloud"; - newscript->GetAI = GetAI_mob_broggok_poisoncloudAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Broggok +SD%Complete: 100 +SDComment: +SDCategory: Hellfire Citadel, Blood Furnace +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SLIME_SPRAY 30913 +#define SPELL_POISON_CLOUD 30916 +#define SPELL_POISON_BOLT 30917 + +#define SPELL_POISON 30914 + +#define SAY_AGGRO "Come intruders...." + +struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI +{ + boss_broggokAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 AcidSpray_Timer; + uint32 PoisonSpawn_Timer; + uint32 PoisonBolt_Timer; + + void Reset() + { + AcidSpray_Timer = 10000; + PoisonSpawn_Timer = 5000; + PoisonBolt_Timer = 7000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + } + + void UpdateAI(const uint32 diff) + { + + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(AcidSpray_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SLIME_SPRAY); + AcidSpray_Timer = 4000+rand()%8000; + }else AcidSpray_Timer -=diff; + + if(PoisonBolt_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POISON_BOLT); + PoisonBolt_Timer = 4000+rand()%8000; + }else PoisonBolt_Timer -=diff; + + if(PoisonSpawn_Timer < diff) + { + DoCast(m_creature,SPELL_POISON_CLOUD); + PoisonSpawn_Timer = 20000; + }else PoisonSpawn_Timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_broggok_poisoncloudAI : public ScriptedAI +{ + mob_broggok_poisoncloudAI(Creature *c) : ScriptedAI(c) {Reset();} + + bool Start; + + void Reset() + { + Start = false; + } + + void Aggro(Unit* who) + { + } + + void UpdateAI(const uint32 diff) + { + if(!Start) + { + m_creature->SetUInt32Value(UNIT_NPC_FLAGS,0); + m_creature->setFaction(45); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Start = true; + DoCast(m_creature,SPELL_POISON); + } + } +}; + +CreatureAI* GetAI_boss_broggokAI(Creature *_Creature) +{ + return new boss_broggokAI (_Creature); +} + +CreatureAI* GetAI_mob_broggok_poisoncloudAI(Creature *_Creature) +{ + return new mob_broggok_poisoncloudAI (_Creature); +} + +void AddSC_boss_broggok() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_broggok"; + newscript->GetAI = GetAI_boss_broggokAI; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_broggok_poisoncloud"; + newscript->GetAI = GetAI_mob_broggok_poisoncloudAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp index bf77b23d0b3..17980f595f6 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp @@ -1,253 +1,253 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Kelidan_The_Breaker -SD%Complete: 60 -SDComment: Event with channeleres vs. boss not implemented yet -SDCategory: Hellfire Citadel, Blood Furnace -EndScriptData */ - -/* ContentData -boss_kelidan_the_breaker -mob_shadowmoon_channeler -EndContentData */ - -#include "precompiled.h" - -#define SAY_WAKE "Who dares interrupt... What is this? What have you done? You ruin everything!" -#define SOUND_WAKE 10164 - -#define SAY_ADD_AGGRO_1 "You mustn't let him loose!" -#define SOUND_ADD_AGGRO_1 10166 -#define SAY_ADD_AGGRO_2 "Ignorant whelps!" -#define SOUND_ADD_AGGRO_2 10167 -#define SAY_ADD_AGGRO_3 "You fools! He'll kill us all!" -#define SOUND_ADD_AGGRO_3 10168 - -#define SAY_KILL_1 "Just as you deserve!" -#define SOUND_KILL_1 10169 -#define SAY_KILL_2 "Your friends will soon be joining you." -#define SOUND_KILL_2 10170 - -#define SAY_NOVA "Closer... Come closer.. and burn!" -#define SOUND_NOVA 10165 - -#define SAY_DIE "Good luck... you'll need it.." -#define SOUND_DIE 10171 - -#define SPELL_CORRUPTION 30938 - -#define SPELL_FIRE_NOVA 33775 -#define H_SPELL_FIRE_NOVA 37371 - -#define SPELL_SHADOW_BOLT_VOLLEY 17228 -#define H_SPELL_SHADOW_BOLT_VOLLEY 40070 - -#define SPELL_BURNING_NOVA 30940 -#define SPELL_VORTEX 37370 - -struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI -{ - boss_kelidan_the_breakerAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - HeroicMode = m_creature->GetMap()->IsHeroic(); - Reset(); - } - - ScriptedInstance* pInstance; - bool HeroicMode; - - uint32 ShadowVolley_Timer; - uint32 BurningNova_Timer; - uint32 Firenova_Timer; - uint32 Corruption_Timer; - bool Firenova; - - void Reset() - { - ShadowVolley_Timer = 1000; - BurningNova_Timer = 15000; - Corruption_Timer = 5000; - Firenova = false; - } - - void Aggro(Unit *who) - { - DoYell(SAY_WAKE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_WAKE); - } - - void KilledUnit(Unit* victim) - { - if (rand()%2) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DIE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DIE); - } - - void UpdateAI(const uint32 diff) - { - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( Firenova ) - { - if( Firenova_Timer < diff ) - { - DoCast(m_creature,HeroicMode ? H_SPELL_FIRE_NOVA : SPELL_FIRE_NOVA); - Firenova = false; - ShadowVolley_Timer = 2000; - }else Firenova_Timer -=diff; - - return; - } - - if( ShadowVolley_Timer < diff ) - { - DoCast(m_creature,HeroicMode ? H_SPELL_SHADOW_BOLT_VOLLEY : SPELL_SHADOW_BOLT_VOLLEY); - ShadowVolley_Timer = 5000+rand()%8000; - }else ShadowVolley_Timer -=diff; - - if( Corruption_Timer < diff ) - { - DoCast(m_creature,SPELL_CORRUPTION); - Corruption_Timer = 30000+rand()%20000; - }else Corruption_Timer -=diff; - - if( BurningNova_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - DoYell(SAY_NOVA, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_NOVA); - - if( HeroicMode ) - DoCast(m_creature,SPELL_VORTEX); - - DoCast(m_creature,SPELL_BURNING_NOVA); - - BurningNova_Timer = 20000+rand()%8000; - Firenova_Timer= 5000; - Firenova = true; - }else BurningNova_Timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_kelidan_the_breaker(Creature *_Creature) -{ - return new boss_kelidan_the_breakerAI (_Creature); -} - -/*###### -## mob_shadowmoon_channeler -######*/ - -#define SPELL_SHADOW_BOLT 12739 -#define H_SPELL_SHADOW_BOLT 15472 - -#define SPELL_MARK_OF_SHADOW 30937 - -#define 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 -{ - mob_shadowmoon_channelerAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - HeroicMode = m_creature->GetMap()->IsHeroic(); - Reset(); - } - - ScriptedInstance* pInstance; - bool HeroicMode; - - uint32 ShadowBolt_Timer; - uint32 MarkOfShadow_Timer; - - void Reset() - { - ShadowBolt_Timer = 1000+rand()%1000; - MarkOfShadow_Timer = 5000+rand()%2000; - } - - void Aggro(Unit* who) - { - //trigger boss to yell - } - - void UpdateAI(const uint32 diff) - { - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( MarkOfShadow_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0) ) - DoCast(target,SPELL_MARK_OF_SHADOW); - MarkOfShadow_Timer = 15000+rand()%5000; - }else MarkOfShadow_Timer -=diff; - - if( ShadowBolt_Timer < diff ) - { - DoCast(m_creature->getVictim(),HeroicMode ? H_SPELL_SHADOW_BOLT : SPELL_SHADOW_BOLT); - ShadowBolt_Timer = 5000+rand()%1000; - }else ShadowBolt_Timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_shadowmoon_channeler(Creature *_Creature) -{ - return new mob_shadowmoon_channelerAI (_Creature); -} - -void AddSC_boss_kelidan_the_breaker() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_kelidan_the_breaker"; - newscript->GetAI = GetAI_boss_kelidan_the_breaker; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_shadowmoon_channeler"; - newscript->GetAI = GetAI_mob_shadowmoon_channeler; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Kelidan_The_Breaker +SD%Complete: 60 +SDComment: Event with channeleres vs. boss not implemented yet +SDCategory: Hellfire Citadel, Blood Furnace +EndScriptData */ + +/* ContentData +boss_kelidan_the_breaker +mob_shadowmoon_channeler +EndContentData */ + +#include "precompiled.h" + +#define SAY_WAKE "Who dares interrupt... What is this? What have you done? You ruin everything!" +#define SOUND_WAKE 10164 + +#define SAY_ADD_AGGRO_1 "You mustn't let him loose!" +#define SOUND_ADD_AGGRO_1 10166 +#define SAY_ADD_AGGRO_2 "Ignorant whelps!" +#define SOUND_ADD_AGGRO_2 10167 +#define SAY_ADD_AGGRO_3 "You fools! He'll kill us all!" +#define SOUND_ADD_AGGRO_3 10168 + +#define SAY_KILL_1 "Just as you deserve!" +#define SOUND_KILL_1 10169 +#define SAY_KILL_2 "Your friends will soon be joining you." +#define SOUND_KILL_2 10170 + +#define SAY_NOVA "Closer... Come closer.. and burn!" +#define SOUND_NOVA 10165 + +#define SAY_DIE "Good luck... you'll need it.." +#define SOUND_DIE 10171 + +#define SPELL_CORRUPTION 30938 + +#define SPELL_FIRE_NOVA 33775 +#define H_SPELL_FIRE_NOVA 37371 + +#define SPELL_SHADOW_BOLT_VOLLEY 17228 +#define H_SPELL_SHADOW_BOLT_VOLLEY 40070 + +#define SPELL_BURNING_NOVA 30940 +#define SPELL_VORTEX 37370 + +struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI +{ + boss_kelidan_the_breakerAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + HeroicMode = m_creature->GetMap()->IsHeroic(); + Reset(); + } + + ScriptedInstance* pInstance; + bool HeroicMode; + + uint32 ShadowVolley_Timer; + uint32 BurningNova_Timer; + uint32 Firenova_Timer; + uint32 Corruption_Timer; + bool Firenova; + + void Reset() + { + ShadowVolley_Timer = 1000; + BurningNova_Timer = 15000; + Corruption_Timer = 5000; + Firenova = false; + } + + void Aggro(Unit *who) + { + DoYell(SAY_WAKE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_WAKE); + } + + void KilledUnit(Unit* victim) + { + if (rand()%2) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DIE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DIE); + } + + void UpdateAI(const uint32 diff) + { + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( Firenova ) + { + if( Firenova_Timer < diff ) + { + DoCast(m_creature,HeroicMode ? H_SPELL_FIRE_NOVA : SPELL_FIRE_NOVA); + Firenova = false; + ShadowVolley_Timer = 2000; + }else Firenova_Timer -=diff; + + return; + } + + if( ShadowVolley_Timer < diff ) + { + DoCast(m_creature,HeroicMode ? H_SPELL_SHADOW_BOLT_VOLLEY : SPELL_SHADOW_BOLT_VOLLEY); + ShadowVolley_Timer = 5000+rand()%8000; + }else ShadowVolley_Timer -=diff; + + if( Corruption_Timer < diff ) + { + DoCast(m_creature,SPELL_CORRUPTION); + Corruption_Timer = 30000+rand()%20000; + }else Corruption_Timer -=diff; + + if( BurningNova_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + DoYell(SAY_NOVA, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_NOVA); + + if( HeroicMode ) + DoCast(m_creature,SPELL_VORTEX); + + DoCast(m_creature,SPELL_BURNING_NOVA); + + BurningNova_Timer = 20000+rand()%8000; + Firenova_Timer= 5000; + Firenova = true; + }else BurningNova_Timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_kelidan_the_breaker(Creature *_Creature) +{ + return new boss_kelidan_the_breakerAI (_Creature); +} + +/*###### +## mob_shadowmoon_channeler +######*/ + +#define SPELL_SHADOW_BOLT 12739 +#define H_SPELL_SHADOW_BOLT 15472 + +#define SPELL_MARK_OF_SHADOW 30937 + +#define 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 +{ + mob_shadowmoon_channelerAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + HeroicMode = m_creature->GetMap()->IsHeroic(); + Reset(); + } + + ScriptedInstance* pInstance; + bool HeroicMode; + + uint32 ShadowBolt_Timer; + uint32 MarkOfShadow_Timer; + + void Reset() + { + ShadowBolt_Timer = 1000+rand()%1000; + MarkOfShadow_Timer = 5000+rand()%2000; + } + + void Aggro(Unit* who) + { + //trigger boss to yell + } + + void UpdateAI(const uint32 diff) + { + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( MarkOfShadow_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0) ) + DoCast(target,SPELL_MARK_OF_SHADOW); + MarkOfShadow_Timer = 15000+rand()%5000; + }else MarkOfShadow_Timer -=diff; + + if( ShadowBolt_Timer < diff ) + { + DoCast(m_creature->getVictim(),HeroicMode ? H_SPELL_SHADOW_BOLT : SPELL_SHADOW_BOLT); + ShadowBolt_Timer = 5000+rand()%1000; + }else ShadowBolt_Timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_shadowmoon_channeler(Creature *_Creature) +{ + return new mob_shadowmoon_channelerAI (_Creature); +} + +void AddSC_boss_kelidan_the_breaker() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_kelidan_the_breaker"; + newscript->GetAI = GetAI_boss_kelidan_the_breaker; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_shadowmoon_channeler"; + newscript->GetAI = GetAI_mob_shadowmoon_channeler; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_the_maker.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_the_maker.cpp index fa5d22e33d1..29e11e7ba91 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_the_maker.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/blood_furnace/boss_the_maker.cpp @@ -1,160 +1,160 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Maker -SD%Complete: 80 -SDComment: Mind control no support -SDCategory: Hellfire Citadel, Blood Furnace -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_ACID_SPRAY 38153 // heroic 38973 ??? 38153 -#define SPELL_EXPLODING_BREAKER 30925 -#define SPELL_KNOCKDOWN 20276 -#define SPELL_DOMINATION 25772 // ??? - -#define SAY_KILL_1 "Let's see what I can make of you." -#define SOUND_KILL_1 10289 -#define SAY_KILL_2 "It is pointless to resist." -#define SOUND_KILL_2 10290 - -#define SAY_AGGRO_1 "My work must not be interrupted." -#define SOUND_AGGRO_1 10286 -#define SAY_AGGRO_2 "Perhaps I can find a use for you." -#define SOUND_AGGRO_2 10287 -#define SAY_AGGRO_3 "Anger... Hate... These are tools I can use." -#define SOUND_AGGRO_3 10288 - -#define SAY_DIE "Stay away from... me." -#define SOUND_DIE 10291 - -struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI -{ - boss_the_makerAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 AcidSpray_Timer; - uint32 ExplodingBreaker_Timer; - uint32 Domination_Timer; - uint32 Knockdown_Timer; - - void Reset() - { - AcidSpray_Timer = 10000; - ExplodingBreaker_Timer = 4000; - Domination_Timer = 120000; - Knockdown_Timer = 6000; - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - } - - void KilledUnit(Unit* victim) - { - if (rand()%5) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DIE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DIE); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(AcidSpray_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ACID_SPRAY); - AcidSpray_Timer = 16000+rand()%8000; - }else AcidSpray_Timer -=diff; - - if(ExplodingBreaker_Timer < diff) - { - Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(target,SPELL_EXPLODING_BREAKER); - ExplodingBreaker_Timer = 4000+rand()%8000; - }else ExplodingBreaker_Timer -=diff; - - /* // Disabled until Core Support for mind control - if(domination_timer_timer < diff) - { - Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(target,SPELL_DOMINATION); - - domination_timer = 120000; - }else domination_timer -=diff; - */ - - if(Knockdown_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKDOWN); - Knockdown_Timer = 4000+rand()%8000; - }else Knockdown_Timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_the_makerAI(Creature *_Creature) -{ - return new boss_the_makerAI (_Creature); -} - -void AddSC_boss_the_maker() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_the_maker"; - newscript->GetAI = GetAI_boss_the_makerAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Maker +SD%Complete: 80 +SDComment: Mind control no support +SDCategory: Hellfire Citadel, Blood Furnace +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_ACID_SPRAY 38153 // heroic 38973 ??? 38153 +#define SPELL_EXPLODING_BREAKER 30925 +#define SPELL_KNOCKDOWN 20276 +#define SPELL_DOMINATION 25772 // ??? + +#define SAY_KILL_1 "Let's see what I can make of you." +#define SOUND_KILL_1 10289 +#define SAY_KILL_2 "It is pointless to resist." +#define SOUND_KILL_2 10290 + +#define SAY_AGGRO_1 "My work must not be interrupted." +#define SOUND_AGGRO_1 10286 +#define SAY_AGGRO_2 "Perhaps I can find a use for you." +#define SOUND_AGGRO_2 10287 +#define SAY_AGGRO_3 "Anger... Hate... These are tools I can use." +#define SOUND_AGGRO_3 10288 + +#define SAY_DIE "Stay away from... me." +#define SOUND_DIE 10291 + +struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI +{ + boss_the_makerAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 AcidSpray_Timer; + uint32 ExplodingBreaker_Timer; + uint32 Domination_Timer; + uint32 Knockdown_Timer; + + void Reset() + { + AcidSpray_Timer = 10000; + ExplodingBreaker_Timer = 4000; + Domination_Timer = 120000; + Knockdown_Timer = 6000; + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + } + + void KilledUnit(Unit* victim) + { + if (rand()%5) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DIE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DIE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(AcidSpray_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ACID_SPRAY); + AcidSpray_Timer = 16000+rand()%8000; + }else AcidSpray_Timer -=diff; + + if(ExplodingBreaker_Timer < diff) + { + Unit* target; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(target,SPELL_EXPLODING_BREAKER); + ExplodingBreaker_Timer = 4000+rand()%8000; + }else ExplodingBreaker_Timer -=diff; + + /* // Disabled until Core Support for mind control + if(domination_timer_timer < diff) + { + Unit* target; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(target,SPELL_DOMINATION); + + domination_timer = 120000; + }else domination_timer -=diff; + */ + + if(Knockdown_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKDOWN); + Knockdown_Timer = 4000+rand()%8000; + }else Knockdown_Timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_the_makerAI(Creature *_Creature) +{ + return new boss_the_makerAI (_Creature); +} + +void AddSC_boss_the_maker() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_the_maker"; + newscript->GetAI = GetAI_boss_the_makerAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp index 970a1774683..37eb692fa84 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp @@ -1,277 +1,279 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Omar_The_Unscarred -SD%Complete: 90 -SDComment: Normal/Heroic support: both, to be tested. Temporary solution for orbital/shadow whip-ability. Needs more core support before making it more proper. -SDCategory: Hellfire Citadel, Hellfire Ramparts -EndScriptData */ - -#include "precompiled.h" - -#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 - -#define SAY_AGGRO_1 "You dare stand against me?!" -#define SOUND_AGGRO_1 10280 -#define SAY_AGGRO_2 "I will not be defeated!" -#define SOUND_AGGRO_2 10279 -#define SAY_AGGRO_3 "Your insolence will be your death." -#define SOUND_AGGRO_3 10281 - -#define SAY_SUMMON "Achor-she-ki! Feast my pet! Eat your fill!" -#define SOUND_SUMMON 10277 - -#define SAY_CURSE "A-Kreesh!" -#define SOUND_CURSE 10278 - -#define SAY_KILL_1 "Die, weakling!" -#define SOUND_KILL_1 10282 - -#define SAY_DIE "It is... not over." -#define SOUND_DIE 10284 - -#define SAY_WIPE "I am victorious!" -#define SOUND_WIPE 10283 - -struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI -{ - boss_omor_the_unscarredAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 OrbitalStrike_Timer; - uint32 ShadowWhip_Timer; - uint32 Aura_Timer; - uint32 DemonicShield_Timer; - uint32 Shadowbolt_Timer; - uint32 Summon_Timer; - uint32 SummonedCount; - uint64 playerGUID; - bool CanPullBack; - bool HeroicMode; - - void Reset() - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - - DoYell(SAY_WIPE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_WIPE); - - OrbitalStrike_Timer = 25000; - ShadowWhip_Timer = 2000; - Aura_Timer = 10000; - DemonicShield_Timer = 1000; - Shadowbolt_Timer = 2000; - Summon_Timer = 10000; - SummonedCount = 0; - playerGUID = 0; - CanPullBack = false; - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - } - - void AttackStart(Unit* who) - { - if (!who) - return; - - if (who->isTargetableForAttack()) - { - DoStartAttackNoMovement(who); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - - void MoveInLineOfSight(Unit* who) - { - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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)) - { - DoStartAttackNoMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void KilledUnit(Unit* victim) - { - if (rand()%2) - return; - - DoYell(SAY_KILL_1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_1); - } - - void JustSummoned(Creature* summoned) - { - DoYell(SAY_SUMMON,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SUMMON); - - if( Unit* random = SelectUnit(SELECT_TARGET_RANDOM,0) ) - summoned->AI()->AttackStart(random); - - ++SummonedCount; - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DIE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DIE); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //only two may be wrong, perhaps increase timer and spawn periodically instead. - if( SummonedCount < 2 ) - { - if( Summon_Timer < diff ) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature,SPELL_SUMMON_FIENDISH_HOUND); - Summon_Timer = 15000+rand()%15000; - }else Summon_Timer -= diff; - } - - if( CanPullBack ) - { - if( ShadowWhip_Timer < diff ) - { - if( Unit* temp = Unit::GetUnit(*m_creature,playerGUID) ) - { - //if unit dosen't have this flag, then no pulling back (script will attempt cast, even if orbital strike was resisted) - if( temp->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) ) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(temp,SPELL_SHADOW_WHIP); - } - } - playerGUID = 0; - ShadowWhip_Timer = 2000; - CanPullBack = false; - }else ShadowWhip_Timer -= diff; - } - else if( OrbitalStrike_Timer < diff ) - { - Unit* temp = NULL; - if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE) ) - temp = m_creature->getVictim(); - else temp = SelectUnit(SELECT_TARGET_RANDOM,0); - - if( temp && temp->GetTypeId() == TYPEID_PLAYER ) - { - DoCast(temp,SPELL_ORBITAL_STRIKE); - OrbitalStrike_Timer = 14000+rand()%2000; - playerGUID = temp->GetGUID(); - if( playerGUID ) - CanPullBack = true; - } - }else OrbitalStrike_Timer -= diff; - - if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 20 ) - { - if( DemonicShield_Timer < diff ) - { - DoCast(m_creature,SPELL_DEMONIC_SHIELD); - DemonicShield_Timer = 15000; - }else DemonicShield_Timer -= diff; - } - - if( Aura_Timer < diff ) - { - DoYell(SAY_CURSE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_CURSE); - - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - { - if( HeroicMode ) DoCast(target,H_SPELL_BANE_OF_TREACHERY); - else DoCast(target,SPELL_TREACHEROUS_AURA); - - Aura_Timer = 8000+rand()%8000; - } - }else Aura_Timer -= diff; - - if( Shadowbolt_Timer < diff ) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - { - if( target ) - target = m_creature->getVictim(); - - if( HeroicMode ) DoCast(target,H_SPELL_SHADOW_BOLT); - else DoCast(target,SPELL_SHADOW_BOLT); - - Shadowbolt_Timer = 4000+rand()%2500; - } - }else Shadowbolt_Timer -= diff; - } -}; - -CreatureAI* GetAI_boss_omor_the_unscarredAI(Creature *_Creature) -{ - return new boss_omor_the_unscarredAI (_Creature); -} - -void AddSC_boss_omor_the_unscarred() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_omor_the_unscarred"; - newscript->GetAI = GetAI_boss_omor_the_unscarredAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Omar_The_Unscarred +SD%Complete: 90 +SDComment: Normal/Heroic support: both, to be tested. Temporary solution for orbital/shadow whip-ability. Needs more core support before making it more proper. +SDCategory: Hellfire Citadel, Hellfire Ramparts +EndScriptData */ + +#include "precompiled.h" + +#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 + +#define SAY_AGGRO_1 "You dare stand against me?!" +#define SOUND_AGGRO_1 10280 +#define SAY_AGGRO_2 "I will not be defeated!" +#define SOUND_AGGRO_2 10279 +#define SAY_AGGRO_3 "Your insolence will be your death." +#define SOUND_AGGRO_3 10281 + +#define SAY_SUMMON "Achor-she-ki! Feast my pet! Eat your fill!" +#define SOUND_SUMMON 10277 + +#define SAY_CURSE "A-Kreesh!" +#define SOUND_CURSE 10278 + +#define SAY_KILL_1 "Die, weakling!" +#define SOUND_KILL_1 10282 + +#define SAY_DIE "It is... not over." +#define SOUND_DIE 10284 + +#define SAY_WIPE "I am victorious!" +#define SOUND_WIPE 10283 + +struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI +{ + boss_omor_the_unscarredAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 OrbitalStrike_Timer; + uint32 ShadowWhip_Timer; + uint32 Aura_Timer; + uint32 DemonicShield_Timer; + uint32 Shadowbolt_Timer; + uint32 Summon_Timer; + uint32 SummonedCount; + uint64 playerGUID; + bool CanPullBack; + bool HeroicMode; + + void Reset() + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + + DoYell(SAY_WIPE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_WIPE); + + OrbitalStrike_Timer = 25000; + ShadowWhip_Timer = 2000; + Aura_Timer = 10000; + DemonicShield_Timer = 1000; + Shadowbolt_Timer = 2000; + Summon_Timer = 10000; + SummonedCount = 0; + playerGUID = 0; + CanPullBack = false; + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (who->isTargetableForAttack()) + { + DoStartAttackNoMovement(who); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + + void MoveInLineOfSight(Unit* who) + { + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if(m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) + { + DoStartAttackNoMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void KilledUnit(Unit* victim) + { + if (rand()%2) + return; + + DoYell(SAY_KILL_1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_1); + } + + void JustSummoned(Creature* summoned) + { + DoYell(SAY_SUMMON,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SUMMON); + + if( Unit* random = SelectUnit(SELECT_TARGET_RANDOM,0) ) + summoned->AI()->AttackStart(random); + + ++SummonedCount; + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DIE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DIE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //only two may be wrong, perhaps increase timer and spawn periodically instead. + if( SummonedCount < 2 ) + { + if( Summon_Timer < diff ) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature,SPELL_SUMMON_FIENDISH_HOUND); + Summon_Timer = 15000+rand()%15000; + }else Summon_Timer -= diff; + } + + if( CanPullBack ) + { + if( ShadowWhip_Timer < diff ) + { + if( Unit* temp = Unit::GetUnit(*m_creature,playerGUID) ) + { + //if unit dosen't have this flag, then no pulling back (script will attempt cast, even if orbital strike was resisted) + if( temp->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) ) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(temp,SPELL_SHADOW_WHIP); + } + } + playerGUID = 0; + ShadowWhip_Timer = 2000; + CanPullBack = false; + }else ShadowWhip_Timer -= diff; + } + else if( OrbitalStrike_Timer < diff ) + { + Unit* temp = NULL; + if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE) ) + temp = m_creature->getVictim(); + else temp = SelectUnit(SELECT_TARGET_RANDOM,0); + + if( temp && temp->GetTypeId() == TYPEID_PLAYER ) + { + DoCast(temp,SPELL_ORBITAL_STRIKE); + OrbitalStrike_Timer = 14000+rand()%2000; + playerGUID = temp->GetGUID(); + if( playerGUID ) + CanPullBack = true; + } + }else OrbitalStrike_Timer -= diff; + + if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 20 ) + { + if( DemonicShield_Timer < diff ) + { + DoCast(m_creature,SPELL_DEMONIC_SHIELD); + DemonicShield_Timer = 15000; + }else DemonicShield_Timer -= diff; + } + + if( Aura_Timer < diff ) + { + DoYell(SAY_CURSE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_CURSE); + + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + { + if( HeroicMode ) DoCast(target,H_SPELL_BANE_OF_TREACHERY); + else DoCast(target,SPELL_TREACHEROUS_AURA); + + Aura_Timer = 8000+rand()%8000; + } + }else Aura_Timer -= diff; + + if( Shadowbolt_Timer < diff ) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + { + if( target ) + target = m_creature->getVictim(); + + if( HeroicMode ) DoCast(target,H_SPELL_SHADOW_BOLT); + else DoCast(target,SPELL_SHADOW_BOLT); + + Shadowbolt_Timer = 4000+rand()%2500; + } + }else Shadowbolt_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_omor_the_unscarredAI(Creature *_Creature) +{ + return new boss_omor_the_unscarredAI (_Creature); +} + +void AddSC_boss_omor_the_unscarred() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_omor_the_unscarred"; + newscript->GetAI = GetAI_boss_omor_the_unscarredAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp index 247af6545fd..f44c384911a 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp @@ -1,200 +1,200 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Watchkeeper_Gargolmar -SD%Complete: 80 -SDComment: Normal/Heroic support: both, to be tested. Missing adds to heal him. Surge should be used on target furthest away, not random. -SDCategory: Hellfire Citadel, Hellfire Ramparts -EndScriptData */ - -#include "precompiled.h" - -#define SAY_HEAL "Heal me! QUICKLY!" -#define SOUND_HEAL 10329 - -#define SAY_SURGE "Back off, pup!" -#define SOUND_SURGE 10330 - -#define SAY_TAUNT "Do you smell that? Fresh meat has somehow breached our citadel. Be wary of any intruders." - -#define SAY_AGGRO_1 "What have we here...?" -#define SOUND_AGGRO_1 10331 -#define SAY_AGGRO_2 "Heh... this may hurt a little." -#define SOUND_AGGRO_2 10332 -#define SAY_AGGRO_3 "I'm gonna enjoy this." -#define SOUND_AGGRO_3 10333 - -#define SAY_KILL_1 "Say farewell!" -#define SOUND_KILL_1 10334 -#define SAY_KILL_2 "Much too easy..." -#define SOUND_KILL_2 10335 - -#define SOUND_DIE 10336 - -#define SPELL_MORTAL_WOUND 30641 -#define H_SPELL_MORTAL_WOUND 36814 -#define SPELL_SURGE 34645 -#define SPELL_RETALIATION 22857 - -struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI -{ - boss_watchkeeper_gargolmarAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Surge_Timer; - uint32 MortalWound_Timer; - uint32 Retaliation_Timer; - - bool HasTaunted; - bool YelledForHeal; - bool HeroicMode; - - void Reset() - { - HeroicMode = m_creature->GetMap()->IsHeroic(); - - Surge_Timer = 5000; - MortalWound_Timer = 4000; - Retaliation_Timer = 0; - - HasTaunted = false; - YelledForHeal = false; - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - break; - case 1: - DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - break; - case 2: - DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - break; - } - } - - void MoveInLineOfSight(Unit* who) - { - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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)) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f)) - { - DoYell(SAY_TAUNT, LANG_UNIVERSAL, NULL); - HasTaunted = true; - } - } - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoPlaySoundToSet(m_creature,SOUND_DIE); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( MortalWound_Timer < diff ) - { - if( HeroicMode ) DoCast(m_creature->getVictim(),H_SPELL_MORTAL_WOUND); - else DoCast(m_creature->getVictim(),SPELL_MORTAL_WOUND); - - MortalWound_Timer = 5000+rand()%8000; - }else MortalWound_Timer -= diff; - - if( Surge_Timer < diff ) - { - DoYell(SAY_SURGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SURGE); - - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_SURGE); - - Surge_Timer = 5000+rand()%8000; - }else Surge_Timer -= diff; - - if((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 20) - { - if( Retaliation_Timer < diff ) - { - DoCast(m_creature,SPELL_RETALIATION); - Retaliation_Timer = 30000; - }else Retaliation_Timer -= diff; - } - - if( !YelledForHeal ) - if((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 40) - { - DoYell(SAY_HEAL, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_HEAL); - YelledForHeal = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_watchkeeper_gargolmarAI(Creature *_Creature) -{ - return new boss_watchkeeper_gargolmarAI (_Creature); -} - -void AddSC_boss_watchkeeper_gargolmar() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_watchkeeper_gargolmar"; - newscript->GetAI = GetAI_boss_watchkeeper_gargolmarAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Watchkeeper_Gargolmar +SD%Complete: 80 +SDComment: Normal/Heroic support: both, to be tested. Missing adds to heal him. Surge should be used on target furthest away, not random. +SDCategory: Hellfire Citadel, Hellfire Ramparts +EndScriptData */ + +#include "precompiled.h" + +#define SAY_HEAL "Heal me! QUICKLY!" +#define SOUND_HEAL 10329 + +#define SAY_SURGE "Back off, pup!" +#define SOUND_SURGE 10330 + +#define SAY_TAUNT "Do you smell that? Fresh meat has somehow breached our citadel. Be wary of any intruders." + +#define SAY_AGGRO_1 "What have we here...?" +#define SOUND_AGGRO_1 10331 +#define SAY_AGGRO_2 "Heh... this may hurt a little." +#define SOUND_AGGRO_2 10332 +#define SAY_AGGRO_3 "I'm gonna enjoy this." +#define SOUND_AGGRO_3 10333 + +#define SAY_KILL_1 "Say farewell!" +#define SOUND_KILL_1 10334 +#define SAY_KILL_2 "Much too easy..." +#define SOUND_KILL_2 10335 + +#define SOUND_DIE 10336 + +#define SPELL_MORTAL_WOUND 30641 +#define H_SPELL_MORTAL_WOUND 36814 +#define SPELL_SURGE 34645 +#define SPELL_RETALIATION 22857 + +struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI +{ + boss_watchkeeper_gargolmarAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Surge_Timer; + uint32 MortalWound_Timer; + uint32 Retaliation_Timer; + + bool HasTaunted; + bool YelledForHeal; + bool HeroicMode; + + void Reset() + { + HeroicMode = m_creature->GetMap()->IsHeroic(); + + Surge_Timer = 5000; + MortalWound_Timer = 4000; + Retaliation_Timer = 0; + + HasTaunted = false; + YelledForHeal = false; + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + break; + case 1: + DoYell(SAY_AGGRO_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + break; + case 2: + DoYell(SAY_AGGRO_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + break; + } + } + + void MoveInLineOfSight(Unit* who) + { + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if(m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f)) + { + DoYell(SAY_TAUNT, LANG_UNIVERSAL, NULL); + HasTaunted = true; + } + } + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoPlaySoundToSet(m_creature,SOUND_DIE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( MortalWound_Timer < diff ) + { + if( HeroicMode ) DoCast(m_creature->getVictim(),H_SPELL_MORTAL_WOUND); + else DoCast(m_creature->getVictim(),SPELL_MORTAL_WOUND); + + MortalWound_Timer = 5000+rand()%8000; + }else MortalWound_Timer -= diff; + + if( Surge_Timer < diff ) + { + DoYell(SAY_SURGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SURGE); + + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_SURGE); + + Surge_Timer = 5000+rand()%8000; + }else Surge_Timer -= diff; + + if((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 20) + { + if( Retaliation_Timer < diff ) + { + DoCast(m_creature,SPELL_RETALIATION); + Retaliation_Timer = 30000; + }else Retaliation_Timer -= diff; + } + + if( !YelledForHeal ) + if((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 40) + { + DoYell(SAY_HEAL, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_HEAL); + YelledForHeal = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_watchkeeper_gargolmarAI(Creature *_Creature) +{ + return new boss_watchkeeper_gargolmarAI (_Creature); +} + +void AddSC_boss_watchkeeper_gargolmar() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_watchkeeper_gargolmar"; + newscript->GetAI = GetAI_boss_watchkeeper_gargolmarAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp index 32da6416b79..69a7b86c078 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp @@ -1,437 +1,437 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Magtheridon -SD%Complete: 60 -SDComment: In Development -SDCategory: Hellfire Citadel, Magtheridon's lair -EndScriptData */ - -#include "precompiled.h" -#include "def_magtheridons_lair.h" -#include "WorldPacket.h" - -//Phase 2 Spells -#define SPELL_QUAKE_PROC 30571 -#define SPELL_QUAKE 30576 //must be cast with 30561 as the proc spell -#define SPELL_BLASTNOVA 30616 -#define SPELL_CLEAVE 30619 -#define SPELL_BERSERK 27680 -#define SPELL_DEBRIS 30631 -#define SPELL_CAMERA_SHAKE 36455 - -//Banish -#define SPELL_SHADOW_CAGE 30205 - -//Player version of the banish -#define SPELL_SHADOW_CAGE_2 30168 - -//Spell that is cast on players from the cube -#define SPELL_SHADOW_GRASP 30410 -#define SPELL_SHADOW_GRASP_UKN 30166 -#define SPELL_SHADOW_GRASP_VIS 30207 - -//Dialog -#define SAY_AGGRO "Thank you for releasing me. Now...die!" -#define SOUND_AGGRO 10254 - -#define SAY_BANISH "Not again...NOT AGAIN!" -#define SOUND_BANISH 10256 - -#define SAY_FREED "I...am...UNLEASHED!!!" -#define SOUND_FREED 10253 - -#define SAY_CHAMBER_DESTROY "I will not be taken so easily. Let the walls of this prison tremble...and FALL!!!" -#define SOUND_CHAMBER_DESTROY 10257 - -#define SAY_PLAYER_KILLED "Did you think me weak? Soft? Who is the weak one now?!" -#define SOUND_PLAYER_KILLED 10255 - -#define SAY_DEATH "The Legion...will consume you...all...." -#define SOUND_DEATH 10258 - -#define EMOTE_BERSERK "becomes enraged!" -#define EMOTE_BLASTNOVA "begins to cast Blast Nova!" -#define EMOTE_BEGIN "%s's bonds begin to weaken!" - -//Spawned objects -#define SPELL_COLLAPSE 34233 //This spell casted by the "cave in" type object - -#define SPELL_CONFLAGERATION 35840 //Actually casted by a creature or object spawned on the ground - -//Cubes -#define SPELL_MIND_EXHAUSTIOIN 30509 //Casted by the cubes when channeling ends - -//Channeler spells -//#define MOB_HELLFIRE_CHANNELLER 17256 - -#define SPELL_SOUL_TRANSFER 30531 -#define SPELL_SHADOW_BOLT_VOLLEY 30510 -#define SPELL_DARK_MENDING 30528 -#define SPELL_HELLFIRE_CHANNELING 31059 -#define SPELL_HELLFIRE_CAST_VISUAL 24207 -#define SPELL_FEAR 39176 - -#define SPELL_BURNING_ABYSSAL 30511 - -// Unkown sounds -uint32 RandomSound[] = {10247, 10248, 10249, 10250, 10251, 10252}; - -struct MANGOS_DLL_DECL boss_magtheridonAI : public ScriptedAI -{ - boss_magtheridonAI(Creature *c) : ScriptedAI(c) - { - pInst = (ScriptedInstance*)m_creature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* pInst; - - uint32 Phase1_Timer; - uint32 Cleave_Timer; - uint32 BlastNova_Timer; - uint32 Quake_Timer; - uint32 QuakePhase; - uint32 Collapse_Timer; - uint32 Berserk_Timer; - bool Banished; - bool Phase3; - - uint32 RandChat_Timer; - - void Reset() - { - RandChat_Timer = 90000; - - Phase1_Timer = 0; - Cleave_Timer = 15000; - Berserk_Timer = 1200000; //20 minutes - BlastNova_Timer = 60000; - Quake_Timer = 40000; - QuakePhase = 0; - Collapse_Timer = 0; - Banished = false; - - m_creature->setFaction(35); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->CastSpell(m_creature, SPELL_SHADOW_CAGE, false); - - if(pInst) - pInst->SetData(DATA_MAGTHERIDON_EVENT_ENDED, false); - } - - void KilledUnit(Unit* victim) - { - DoYell(SAY_PLAYER_KILLED, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PLAYER_KILLED); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) {} - - void MoveInLineOfSight(Unit* who) {} - - void UpdateAI(const uint32 diff) - { - if (!InCombat && !Phase1_Timer) - if (RandChat_Timer < diff) - { - DoPlaySoundToSet(m_creature, RandomSound[rand()%5]); - - RandChat_Timer = 90000; - }else RandChat_Timer -= diff; - - if (!InCombat && !Phase1_Timer && pInst && pInst->GetData64(DATA_EVENT_STARTER)) - { - //Unbanish self after 2 minutes - Phase1_Timer = 120000; - DoTextEmote(EMOTE_BEGIN, NULL); - return; - } - - //Phase timer - if (Phase1_Timer) - if (Phase1_Timer <= diff) - { - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - DoYell(SAY_FREED, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_FREED); - m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE); - AttackStart(Unit::GetUnit(*m_creature, pInst->GetData64(DATA_EVENT_STARTER))); - - Phase1_Timer = 0; - }else - { - if (!Unit::GetUnit(*m_creature, pInst->GetData64(DATA_EVENT_STARTER))) - { - Phase1_Timer = 0; - return; - } - - Phase1_Timer -= diff; - return; - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Interrupt Blast Nova - if (m_creature->HasAura(SPELL_SHADOW_GRASP_VIS, 0) && m_creature->HasAura(SPELL_BLASTNOVA, 0) && !Banished) - { - DoYell(SAY_BANISH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_BANISH); - m_creature->RemoveAurasDueToSpell(SPELL_BLASTNOVA); - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature, SPELL_SHADOW_CAGE_2); - Banished = true; - } - - if (Banished && !m_creature->HasAura(SPELL_SHADOW_GRASP_VIS, 0)) - { - Banished = false; - m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE_2); - } - - //Berserk_Timer - if (Berserk_Timer < diff) - { - DoCast(m_creature, SPELL_BERSERK); - DoTextEmote(EMOTE_BERSERK, NULL); - - Berserk_Timer = 300000; - }else Berserk_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 10000; - }else Cleave_Timer -= diff; - - //Quake_Timer - if (Quake_Timer < diff) - { - int32 i = SPELL_QUAKE_PROC; - m_creature->CastCustomSpell(m_creature, SPELL_QUAKE, &i, 0, 0, false); - - Quake_Timer = 40000; - }else Quake_Timer -= diff; - - //BlastNova_Timer - if (BlastNova_Timer < diff) - { - //Inturrupt Quake if it is casting - m_creature->InterruptNonMeleeSpells(false); - - DoTextEmote(EMOTE_BLASTNOVA, NULL); - DoCast(m_creature, SPELL_BLASTNOVA); - - BlastNova_Timer = 40000; - }else BlastNova_Timer -= diff; - - //Phase3 if not already enraged and below 30% - if (!Phase3 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) - { - Phase3 = true; - - DoYell(SAY_CHAMBER_DESTROY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CHAMBER_DESTROY); - } - - //Melee - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_hellfire_channelerAI : public ScriptedAI -{ - mob_hellfire_channelerAI(Creature *c) : ScriptedAI(c) - { - pInst = (ScriptedInstance*)m_creature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* pInst; - - uint32 ShadowBoltVolley_Timer; - uint32 DarkMending_Timer; - uint32 Fear_Timer; - uint32 Infernal_Timer; - - bool InfernalSpawned; - - void Reset() - { - ShadowBoltVolley_Timer = 8000 + rand()%2000; - DarkMending_Timer = 30000; - Fear_Timer = 15000 + rand()%5000; - Infernal_Timer = 20000 + rand()%5000; - - InfernalSpawned = false; - - //Suprisingly this works very well, but only if the channelers are spawned after magtheridon - DoCast(m_creature, SPELL_SHADOW_GRASP_VIS); - if(pInst) - pInst->SetData(DATA_MAGTHERIDON_EVENT_ENDED, false); - } - - void Aggro(Unit *who) - { - m_creature->InterruptNonMeleeSpells(false); - - if(!pInst || pInst->GetData64(DATA_EVENT_STARTER)) - return; - - pInst->SetData64(DATA_EVENT_STARTER, who->GetGUID()); - pInst->SetData(DATA_MAGTHERIDON_EVENT_STARTED, true); - } - - void MoveInLineOfSight(Unit*) - { - } - - void UpdateAI(const uint32 diff) - { - if (!InCombat && pInst && pInst->GetData64(DATA_EVENT_STARTER)) - { - m_creature->InterruptNonMeleeSpells(false); - AttackStart(Unit::GetUnit(*m_creature, pInst->GetData64(DATA_EVENT_STARTER))); - return; - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Shadow bolt volley - if (ShadowBoltVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOW_BOLT_VOLLEY); - - ShadowBoltVolley_Timer = 10000 + (rand()%10000); - }else ShadowBoltVolley_Timer -= diff; - - //Dark Mending - if (DarkMending_Timer < diff) - { - if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) - { - //Cast on ourselves if we are lower then lowest hp friendly unit - /*if (pLowestHPTarget && LowestHP < m_creature->GetHealth()) - DoCast(pLowestHPTarget, SPELL_DARK_MENDING); - else*/ - DoCast(m_creature, SPELL_DARK_MENDING); - } - - DarkMending_Timer = 10000 + (rand() % 10000); - }else DarkMending_Timer -= diff; - - //Fear - if (Fear_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 1); - - if (target) - DoCast(target,SPELL_FEAR); - - Fear_Timer = 25000 + (rand()%15000); - }else Fear_Timer -= diff; - - //Infernal spawning - if (!InfernalSpawned && Infernal_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if (target) - DoCast(target, SPELL_BURNING_ABYSSAL); - - InfernalSpawned = true; - }else Infernal_Timer -= diff; - - DoMeleeAttackIfReady(); - } - -}; - -//Manticron Cube -bool GOHello_go_Manticron_Cube(Player *player, GameObject* _GO) -{ - ScriptedInstance* pInst = (ScriptedInstance*)_GO->GetInstanceData(); - - Unit* pUnit = NULL; - if(pInst) - pUnit = Unit::GetUnit(*_GO, pInst->GetData64(DATA_MAGTHERIDON)); - else - { - _GO->TextEmote("Manticron Cube: NO INSTANCE", 0); - return true; - } - - if (!pUnit || !pUnit->isAlive() || !player) - { - _GO->TextEmote("Mantricon Cube: NO TARGET", 0); - return true; - } - - player->InterruptNonMeleeSpells(false); - player->CastSpell(pUnit, SPELL_SHADOW_GRASP, true); - player->CastSpell(pUnit, SPELL_SHADOW_GRASP_VIS, false); - - _GO->Say("Mantricon Cube Clicked", LANG_UNIVERSAL, 0); - return true; -} - -CreatureAI* GetAI_boss_magtheridon(Creature *_Creature) -{ - return new boss_magtheridonAI (_Creature); -} - -CreatureAI* GetAI_mob_hellfire_channeler(Creature *_Creature) -{ - return new mob_hellfire_channelerAI (_Creature); -} - -void AddSC_boss_magtheridon() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_magtheridon"; - newscript->GetAI = GetAI_boss_magtheridon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_hellfire_channeler"; - newscript->GetAI = GetAI_mob_hellfire_channeler; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="go_manticron_cube"; - newscript->pGOHello = &GOHello_go_Manticron_Cube; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Magtheridon +SD%Complete: 60 +SDComment: In Development +SDCategory: Hellfire Citadel, Magtheridon's lair +EndScriptData */ + +#include "precompiled.h" +#include "def_magtheridons_lair.h" +#include "WorldPacket.h" + +//Phase 2 Spells +#define SPELL_QUAKE_PROC 30571 +#define SPELL_QUAKE 30576 //must be cast with 30561 as the proc spell +#define SPELL_BLASTNOVA 30616 +#define SPELL_CLEAVE 30619 +#define SPELL_BERSERK 27680 +#define SPELL_DEBRIS 30631 +#define SPELL_CAMERA_SHAKE 36455 + +//Banish +#define SPELL_SHADOW_CAGE 30205 + +//Player version of the banish +#define SPELL_SHADOW_CAGE_2 30168 + +//Spell that is cast on players from the cube +#define SPELL_SHADOW_GRASP 30410 +#define SPELL_SHADOW_GRASP_UKN 30166 +#define SPELL_SHADOW_GRASP_VIS 30207 + +//Dialog +#define SAY_AGGRO "Thank you for releasing me. Now...die!" +#define SOUND_AGGRO 10254 + +#define SAY_BANISH "Not again...NOT AGAIN!" +#define SOUND_BANISH 10256 + +#define SAY_FREED "I...am...UNLEASHED!!!" +#define SOUND_FREED 10253 + +#define SAY_CHAMBER_DESTROY "I will not be taken so easily. Let the walls of this prison tremble...and FALL!!!" +#define SOUND_CHAMBER_DESTROY 10257 + +#define SAY_PLAYER_KILLED "Did you think me weak? Soft? Who is the weak one now?!" +#define SOUND_PLAYER_KILLED 10255 + +#define SAY_DEATH "The Legion...will consume you...all...." +#define SOUND_DEATH 10258 + +#define EMOTE_BERSERK "becomes enraged!" +#define EMOTE_BLASTNOVA "begins to cast Blast Nova!" +#define EMOTE_BEGIN "%s's bonds begin to weaken!" + +//Spawned objects +#define SPELL_COLLAPSE 34233 //This spell casted by the "cave in" type object + +#define SPELL_CONFLAGERATION 35840 //Actually casted by a creature or object spawned on the ground + +//Cubes +#define SPELL_MIND_EXHAUSTIOIN 30509 //Casted by the cubes when channeling ends + +//Channeler spells +//#define MOB_HELLFIRE_CHANNELLER 17256 + +#define SPELL_SOUL_TRANSFER 30531 +#define SPELL_SHADOW_BOLT_VOLLEY 30510 +#define SPELL_DARK_MENDING 30528 +#define SPELL_HELLFIRE_CHANNELING 31059 +#define SPELL_HELLFIRE_CAST_VISUAL 24207 +#define SPELL_FEAR 39176 + +#define SPELL_BURNING_ABYSSAL 30511 + +// Unkown sounds +uint32 RandomSound[] = {10247, 10248, 10249, 10250, 10251, 10252}; + +struct MANGOS_DLL_DECL boss_magtheridonAI : public ScriptedAI +{ + boss_magtheridonAI(Creature *c) : ScriptedAI(c) + { + pInst = (ScriptedInstance*)m_creature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* pInst; + + uint32 Phase1_Timer; + uint32 Cleave_Timer; + uint32 BlastNova_Timer; + uint32 Quake_Timer; + uint32 QuakePhase; + uint32 Collapse_Timer; + uint32 Berserk_Timer; + bool Banished; + bool Phase3; + + uint32 RandChat_Timer; + + void Reset() + { + RandChat_Timer = 90000; + + Phase1_Timer = 0; + Cleave_Timer = 15000; + Berserk_Timer = 1200000; //20 minutes + BlastNova_Timer = 60000; + Quake_Timer = 40000; + QuakePhase = 0; + Collapse_Timer = 0; + Banished = false; + + m_creature->setFaction(35); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->CastSpell(m_creature, SPELL_SHADOW_CAGE, false); + + if(pInst) + pInst->SetData(DATA_MAGTHERIDON_EVENT_ENDED, false); + } + + void KilledUnit(Unit* victim) + { + DoYell(SAY_PLAYER_KILLED, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PLAYER_KILLED); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) {} + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (!InCombat && !Phase1_Timer) + if (RandChat_Timer < diff) + { + DoPlaySoundToSet(m_creature, RandomSound[rand()%5]); + + RandChat_Timer = 90000; + }else RandChat_Timer -= diff; + + if (!InCombat && !Phase1_Timer && pInst && pInst->GetData64(DATA_EVENT_STARTER)) + { + //Unbanish self after 2 minutes + Phase1_Timer = 120000; + DoTextEmote(EMOTE_BEGIN, NULL); + return; + } + + //Phase timer + if (Phase1_Timer) + if (Phase1_Timer <= diff) + { + m_creature->setFaction(14); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + DoYell(SAY_FREED, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_FREED); + m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE); + AttackStart(Unit::GetUnit(*m_creature, pInst->GetData64(DATA_EVENT_STARTER))); + + Phase1_Timer = 0; + }else + { + if (!Unit::GetUnit(*m_creature, pInst->GetData64(DATA_EVENT_STARTER))) + { + Phase1_Timer = 0; + return; + } + + Phase1_Timer -= diff; + return; + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Interrupt Blast Nova + if (m_creature->HasAura(SPELL_SHADOW_GRASP_VIS, 0) && m_creature->HasAura(SPELL_BLASTNOVA, 0) && !Banished) + { + DoYell(SAY_BANISH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_BANISH); + m_creature->RemoveAurasDueToSpell(SPELL_BLASTNOVA); + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_SHADOW_CAGE_2); + Banished = true; + } + + if (Banished && !m_creature->HasAura(SPELL_SHADOW_GRASP_VIS, 0)) + { + Banished = false; + m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE_2); + } + + //Berserk_Timer + if (Berserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + DoTextEmote(EMOTE_BERSERK, NULL); + + Berserk_Timer = 300000; + }else Berserk_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 10000; + }else Cleave_Timer -= diff; + + //Quake_Timer + if (Quake_Timer < diff) + { + int32 i = SPELL_QUAKE_PROC; + m_creature->CastCustomSpell(m_creature, SPELL_QUAKE, &i, 0, 0, false); + + Quake_Timer = 40000; + }else Quake_Timer -= diff; + + //BlastNova_Timer + if (BlastNova_Timer < diff) + { + //Inturrupt Quake if it is casting + m_creature->InterruptNonMeleeSpells(false); + + DoTextEmote(EMOTE_BLASTNOVA, NULL); + DoCast(m_creature, SPELL_BLASTNOVA); + + BlastNova_Timer = 40000; + }else BlastNova_Timer -= diff; + + //Phase3 if not already enraged and below 30% + if (!Phase3 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) + { + Phase3 = true; + + DoYell(SAY_CHAMBER_DESTROY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CHAMBER_DESTROY); + } + + //Melee + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_hellfire_channelerAI : public ScriptedAI +{ + mob_hellfire_channelerAI(Creature *c) : ScriptedAI(c) + { + pInst = (ScriptedInstance*)m_creature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* pInst; + + uint32 ShadowBoltVolley_Timer; + uint32 DarkMending_Timer; + uint32 Fear_Timer; + uint32 Infernal_Timer; + + bool InfernalSpawned; + + void Reset() + { + ShadowBoltVolley_Timer = 8000 + rand()%2000; + DarkMending_Timer = 30000; + Fear_Timer = 15000 + rand()%5000; + Infernal_Timer = 20000 + rand()%5000; + + InfernalSpawned = false; + + //Suprisingly this works very well, but only if the channelers are spawned after magtheridon + DoCast(m_creature, SPELL_SHADOW_GRASP_VIS); + if(pInst) + pInst->SetData(DATA_MAGTHERIDON_EVENT_ENDED, false); + } + + void Aggro(Unit *who) + { + m_creature->InterruptNonMeleeSpells(false); + + if(!pInst || pInst->GetData64(DATA_EVENT_STARTER)) + return; + + pInst->SetData64(DATA_EVENT_STARTER, who->GetGUID()); + pInst->SetData(DATA_MAGTHERIDON_EVENT_STARTED, true); + } + + void MoveInLineOfSight(Unit*) + { + } + + void UpdateAI(const uint32 diff) + { + if (!InCombat && pInst && pInst->GetData64(DATA_EVENT_STARTER)) + { + m_creature->InterruptNonMeleeSpells(false); + AttackStart(Unit::GetUnit(*m_creature, pInst->GetData64(DATA_EVENT_STARTER))); + return; + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Shadow bolt volley + if (ShadowBoltVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOW_BOLT_VOLLEY); + + ShadowBoltVolley_Timer = 10000 + (rand()%10000); + }else ShadowBoltVolley_Timer -= diff; + + //Dark Mending + if (DarkMending_Timer < diff) + { + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) + { + //Cast on ourselves if we are lower then lowest hp friendly unit + /*if (pLowestHPTarget && LowestHP < m_creature->GetHealth()) + DoCast(pLowestHPTarget, SPELL_DARK_MENDING); + else*/ + DoCast(m_creature, SPELL_DARK_MENDING); + } + + DarkMending_Timer = 10000 + (rand() % 10000); + }else DarkMending_Timer -= diff; + + //Fear + if (Fear_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 1); + + if (target) + DoCast(target,SPELL_FEAR); + + Fear_Timer = 25000 + (rand()%15000); + }else Fear_Timer -= diff; + + //Infernal spawning + if (!InfernalSpawned && Infernal_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if (target) + DoCast(target, SPELL_BURNING_ABYSSAL); + + InfernalSpawned = true; + }else Infernal_Timer -= diff; + + DoMeleeAttackIfReady(); + } + +}; + +//Manticron Cube +bool GOHello_go_Manticron_Cube(Player *player, GameObject* _GO) +{ + ScriptedInstance* pInst = (ScriptedInstance*)_GO->GetInstanceData(); + + Unit* pUnit = NULL; + if(pInst) + pUnit = Unit::GetUnit(*_GO, pInst->GetData64(DATA_MAGTHERIDON)); + else + { + _GO->TextEmote("Manticron Cube: NO INSTANCE", 0); + return true; + } + + if (!pUnit || !pUnit->isAlive() || !player) + { + _GO->TextEmote("Mantricon Cube: NO TARGET", 0); + return true; + } + + player->InterruptNonMeleeSpells(false); + player->CastSpell(pUnit, SPELL_SHADOW_GRASP, true); + player->CastSpell(pUnit, SPELL_SHADOW_GRASP_VIS, false); + + _GO->Say("Mantricon Cube Clicked", LANG_UNIVERSAL, 0); + return true; +} + +CreatureAI* GetAI_boss_magtheridon(Creature *_Creature) +{ + return new boss_magtheridonAI (_Creature); +} + +CreatureAI* GetAI_mob_hellfire_channeler(Creature *_Creature) +{ + return new mob_hellfire_channelerAI (_Creature); +} + +void AddSC_boss_magtheridon() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_magtheridon"; + newscript->GetAI = GetAI_boss_magtheridon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_hellfire_channeler"; + newscript->GetAI = GetAI_mob_hellfire_channeler; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="go_manticron_cube"; + newscript->pGOHello = &GOHello_go_Manticron_Cube; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/def_magtheridons_lair.h b/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/def_magtheridons_lair.h index dab98703c15..3001a964c34 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/def_magtheridons_lair.h +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/def_magtheridons_lair.h @@ -1,13 +1,13 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_MAGTHERIDONS_LAIR_H -#define DEF_MAGTHERIDONS_LAIR_H - -#define DATA_EVENT_STARTER 1 -#define DATA_MAGTHERIDON 2 -#define DATA_MAGTHERIDON_EVENT_ENDED 3 -#define DATA_MAGTHERIDON_EVENT_STARTED 4 -#define DATA_MAGTHERIDON_EVENT_STATUS 5 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_MAGTHERIDONS_LAIR_H +#define DEF_MAGTHERIDONS_LAIR_H + +#define DATA_EVENT_STARTER 1 +#define DATA_MAGTHERIDON 2 +#define DATA_MAGTHERIDON_EVENT_ENDED 3 +#define DATA_MAGTHERIDON_EVENT_STARTED 4 +#define DATA_MAGTHERIDON_EVENT_STATUS 5 +#endif diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp index 91ce5ce453c..63a6f02f9a1 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp @@ -1,116 +1,116 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Magtheridons_Lair -SD%Complete: 100 -SDComment: -SDCategory: Hellfire Citadel, Magtheridon's lair -EndScriptData */ - -#include "precompiled.h" -#include "def_magtheridons_lair.h" - -struct MANGOS_DLL_DECL instance_magtheridons_lair : public ScriptedInstance -{ - instance_magtheridons_lair(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - bool EncounterInProgress; - uint64 Magtheridon; - uint64 EventStarter; - - void Initialize() - { - Magtheridon = 0; - EventStarter = 0; - EncounterInProgress = false; - } - - bool IsEncounterInProgress() const - { - return EncounterInProgress; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - if (creature_entry == 17257) - Magtheridon = creature->GetGUID(); - } - - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_MAGTHERIDON: - return Magtheridon; - - case DATA_EVENT_STARTER: - return EventStarter; - } - return 0; - } - - void SetData64(uint32 identifier, uint64 guid) - { - switch(identifier) - { - case DATA_MAGTHERIDON: - Magtheridon = guid; - break; - - case DATA_EVENT_STARTER: - EventStarter = guid; - break; - } - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_MAGTHERIDON_EVENT_STARTED: - EncounterInProgress = true; - break; - - case DATA_MAGTHERIDON_EVENT_ENDED: - EncounterInProgress = false; - EventStarter = 0; - break; - } - } - - uint32 GetData(uint32 type) - { - if(type == DATA_MAGTHERIDON_EVENT_STATUS) - return EncounterInProgress; - - return 0; - } -}; - -InstanceData* GetInstanceData_instance_magtheridons_lair(Map* map) -{ - return new instance_magtheridons_lair(map); -} - -void AddSC_instance_magtheridons_lair() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_magtheridons_lair"; - newscript->GetInstanceData = GetInstanceData_instance_magtheridons_lair; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Magtheridons_Lair +SD%Complete: 100 +SDComment: +SDCategory: Hellfire Citadel, Magtheridon's lair +EndScriptData */ + +#include "precompiled.h" +#include "def_magtheridons_lair.h" + +struct MANGOS_DLL_DECL instance_magtheridons_lair : public ScriptedInstance +{ + instance_magtheridons_lair(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + bool EncounterInProgress; + uint64 Magtheridon; + uint64 EventStarter; + + void Initialize() + { + Magtheridon = 0; + EventStarter = 0; + EncounterInProgress = false; + } + + bool IsEncounterInProgress() const + { + return EncounterInProgress; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + if (creature_entry == 17257) + Magtheridon = creature->GetGUID(); + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_MAGTHERIDON: + return Magtheridon; + + case DATA_EVENT_STARTER: + return EventStarter; + } + return 0; + } + + void SetData64(uint32 identifier, uint64 guid) + { + switch(identifier) + { + case DATA_MAGTHERIDON: + Magtheridon = guid; + break; + + case DATA_EVENT_STARTER: + EventStarter = guid; + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_MAGTHERIDON_EVENT_STARTED: + EncounterInProgress = true; + break; + + case DATA_MAGTHERIDON_EVENT_ENDED: + EncounterInProgress = false; + EventStarter = 0; + break; + } + } + + uint32 GetData(uint32 type) + { + if(type == DATA_MAGTHERIDON_EVENT_STATUS) + return EncounterInProgress; + + return 0; + } +}; + +InstanceData* GetInstanceData_instance_magtheridons_lair(Map* map) +{ + return new instance_magtheridons_lair(map); +} + +void AddSC_instance_magtheridons_lair() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_magtheridons_lair"; + newscript->GetInstanceData = GetInstanceData_instance_magtheridons_lair; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp index fa2619cc8fc..286913c8881 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp @@ -1,505 +1,505 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Warlock_Nethekurse -SD%Complete: 75 -SDComment: encounter not fully complete. missing part where boss kill minions. -SDCategory: Hellfire Citadel, Shattered Halls -EndScriptData */ - -/* ContentData -boss_grand_warlock_nethekurse -mob_fel_orc_convert -mob_lesser_shadow_fissure -EndContentData */ - -#include "precompiled.h" -#include "def_shattered_halls.h" - -struct Say -{ - const char* text; - uint32 sound; -}; - -#define SAY_INTRO "You wish to fight us all at once? This should be amusing!" -#define SOUND_INTRO 10262 - -static Say PeonAttacked[]= -{ - {"You can have that one. I no longer need him.", 10263}, - {"Yes, beat him mercilessly. His skull is a thick as an ogres.", 10264}, - {"Don't waste your time on that one. He's weak!", 10265}, - {"You want him? Very well, take him!", 10266}, -}; -static Say PeonDies[]= -{ - {"One pitiful wretch down. Go on, take another one.", 10267}, - {"Ahh, what a waste... Next!", 10268}, - {"I was going to kill him anyway!", 10269}, - {"Thank you for saving me the trouble! Now it's my turn to have some fun...", 10270}, -}; - -#define SAY_TAUNT_1 "Beg for your pittyfull life!" -#define SOUND_TAUNT_1 10259 -#define SAY_TAUNT_2 "Run covad, ruun!" -#define SOUND_TAUNT_2 10260 -#define SAY_TAUNT_3 "Your pain amuses me." -#define SOUND_TAUNT_3 10261 - -#define SAY_AGGRO_1 "I'm already bored." -#define SOUND_AGGRO_1 10271 -#define SAY_AGGRO_2 "Come on! ... Show me a real fight." -#define SOUND_AGGRO_2 10272 -#define SAY_AGGRO_3 "I had more fun torturing the peons." -#define SOUND_AGGRO_3 10273 - -#define SAY_SLAY_1 "You Loose." -#define SOUND_SLAY_1 10274 -#define SAY_SLAY_2 "Ohh! Just die." -#define SOUND_SLAY_2 10275 - -#define SAY_DIE "What a ... a shame." -#define SOUND_DIE 10276 - -#define SPELL_DEATH_COIL 30500 -#define SPELL_DARK_SPIN 30502 // core bug spell attack caster :D -#define SPELL_SHADOW_FISSURE 30496 // Summon the ShadowFissure NPC - -#define SPELL_SHADOW_CLEAVE 30495 -#define H_SPELL_SHADOW_SLAM 35953 - -#define SPELL_HEMORRHAGE 30478 - -#define SPELL_CONSUMPTION 30497 -#define SPELL_TEMPORARY_VISUAL 39312 // this is wrong, a temporary solution. spell consumption already has the purple visual, but doesn't display as it should - -struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI -{ - boss_grand_warlock_nethekurseAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - bool HeroicMode; - bool IntroOnce; - bool IsIntroEvent; - bool IsMainEvent; - bool SpinOnce; - //bool HasTaunted; - bool Phase; - - uint32 PeonEngagedCount; - uint32 PeonKilledCount; - - uint32 IntroEvent_Timer; - uint32 DeathCoil_Timer; - uint32 ShadowFissure_Timer; - uint32 Cleave_Timer; - - void Reset() - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - HeroicMode = m_creature->GetMap()->IsHeroic(); - IsIntroEvent = false; - IntroOnce = false; - IsMainEvent = false; - //HasTaunted = false; - SpinOnce = false; - Phase = false; - - PeonEngagedCount = 0; - PeonKilledCount = 0; - - IntroEvent_Timer = 90000; //how long before getting bored and kills his minions? - DeathCoil_Timer = 20000; - ShadowFissure_Timer = 8000; - Cleave_Timer = 5000; - } - - void DoYellForPeonAggro() - { - if( PeonEngagedCount >= 4 ) - return; - - DoYell(PeonAttacked[PeonEngagedCount].text, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, PeonAttacked[PeonEngagedCount].sound); - ++PeonEngagedCount; - } - - void DoYellForPeonDeath() - { - if( PeonKilledCount >= 4 ) - return; - - DoYell(PeonDies[PeonKilledCount].text, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, PeonDies[PeonKilledCount].sound); - ++PeonKilledCount; - - if( PeonKilledCount == 4 ) - { - IsIntroEvent = false; - IsMainEvent = true; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - } - - void DoTauntPeons() - { - switch(rand()%3) - { - case 0: - DoPlaySoundToSet(m_creature,SOUND_TAUNT_1); - DoYell(SAY_TAUNT_1,LANG_UNIVERSAL,NULL); - break; - case 1: - DoPlaySoundToSet(m_creature,SOUND_TAUNT_2); - DoYell(SAY_TAUNT_2,LANG_UNIVERSAL,NULL); - break; - case 2: - DoPlaySoundToSet(m_creature,SOUND_TAUNT_3); - DoYell(SAY_TAUNT_3,LANG_UNIVERSAL,NULL); - break; - } - - //TODO: kill the peons first - IsIntroEvent = false; - PeonEngagedCount = 4; - PeonKilledCount = 4; - IsMainEvent = true; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - void AttackStart(Unit* who) - { - if ( IsIntroEvent || !IsMainEvent ) - return; - - if( who->isTargetableForAttack() ) - { - if( Phase ) DoStartAttackNoMovement(who); - else DoStartAttackAndMovement(who); - - if( !InCombat ) - { - Aggro(who); - InCombat = true; - } - } - } - - void MoveInLineOfSight(Unit *who) - { - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if( !IntroOnce && m_creature->IsWithinDistInMap(who, 75) ) - { - DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_INTRO); - IntroOnce = true; - IsIntroEvent = true; - - if( pInstance ) - pInstance->SetData(TYPE_NETHEKURSE,IN_PROGRESS); - } - - if( m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE ) - return; - - if( IsIntroEvent || !IsMainEvent ) - return; - - float attackRadius = m_creature->GetAttackDistance(who); - if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) - { - if( Phase ) DoStartAttackNoMovement(who); - else DoStartAttackAndMovement(who); - - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if( !InCombat ) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); - DoYell(SAY_AGGRO_1,LANG_UNIVERSAL,NULL); - break; - case 1: - DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); - DoYell(SAY_AGGRO_2,LANG_UNIVERSAL,NULL); - break; - case 2: - DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); - DoYell(SAY_AGGRO_3,LANG_UNIVERSAL,NULL); - break; - } - } - - void JustSummoned(Creature *summoned) - { - summoned->setFaction(14); - summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - DoYell(SAY_SLAY_1,LANG_UNIVERSAL,NULL); - break; - case 1: - DoPlaySoundToSet(m_creature,SOUND_SLAY_2); - DoYell(SAY_SLAY_2,LANG_UNIVERSAL,NULL); - break; - } - } - - void JustDied(Unit* Killer) - { - DoPlaySoundToSet(m_creature,SOUND_DIE); - DoYell(SAY_DIE,LANG_UNIVERSAL,NULL); - - if( !pInstance ) - return; - - pInstance->SetData(TYPE_NETHEKURSE,DONE); - - if( pInstance->GetData64(DATA_NETHEKURSE_DOOR) ) - { - if( GameObject *Door = GameObject::GetGameObject(*m_creature,pInstance->GetData64(DATA_NETHEKURSE_DOOR)) ) - Door->SetGoState(0); - } - } - - void UpdateAI(const uint32 diff) - { - if( IsIntroEvent ) - { - if( !pInstance ) - return; - - if( pInstance->GetData(TYPE_NETHEKURSE) == IN_PROGRESS ) - { - if( IntroEvent_Timer < diff ) - { - DoTauntPeons(); - }else IntroEvent_Timer -= diff; - } - } - - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( !IsMainEvent ) - return; - - if( Phase ) - { - if( !SpinOnce ) - { - DoCast(m_creature->getVictim(),SPELL_DARK_SPIN); - SpinOnce = true; - } - - if( Cleave_Timer < diff ) - { - DoCast(m_creature->getVictim(),(HeroicMode ? H_SPELL_SHADOW_SLAM : SPELL_SHADOW_CLEAVE)); - Cleave_Timer = 6000+rand()%2500; - }else Cleave_Timer -= diff; - } - else - { - if( ShadowFissure_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_SHADOW_FISSURE); - ShadowFissure_Timer = 7500+rand()%7500; - }else ShadowFissure_Timer -= diff; - - if( DeathCoil_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_DEATH_COIL); - DeathCoil_Timer = 15000+rand()%5000; - }else DeathCoil_Timer -= diff; - - if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 20 ) - Phase = true; - - DoMeleeAttackIfReady(); - } - } -}; - -struct MANGOS_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI -{ - mob_fel_orc_convertAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - uint32 Hemorrhage_Timer; - - void Reset() - { - m_creature->SetNoCallAssistence(true); //we don't want any assistance (WE R HEROZ!) - Hemorrhage_Timer = 3000; - } - - void MoveInLineOfSight(Unit *who) - { - return; - } - - void Aggro(Unit* who) - { - if( pInstance ) - { - if( pInstance->GetData64(DATA_NETHEKURSE) ) - { - Creature *pKurse = (Creature*)Unit::GetUnit(*m_creature,pInstance->GetData64(DATA_NETHEKURSE)); - if( pKurse ) - ((boss_grand_warlock_nethekurseAI*)pKurse->AI())->DoYellForPeonAggro(); - } - - if( pInstance->GetData(TYPE_NETHEKURSE) == IN_PROGRESS ) - return; - else pInstance->SetData(TYPE_NETHEKURSE,IN_PROGRESS); - } - } - - void JustDied(Unit* Killer) - { - if( pInstance ) - { - if( pInstance->GetData64(DATA_NETHEKURSE) ) - { - Creature *pKurse = (Creature*)Unit::GetUnit(*m_creature,pInstance->GetData64(DATA_NETHEKURSE)); - if( pKurse ) - ((boss_grand_warlock_nethekurseAI*)pKurse->AI())->DoYellForPeonDeath(); - } - } - } - - void UpdateAI(const uint32 diff) - { - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( Hemorrhage_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_HEMORRHAGE); - Hemorrhage_Timer = 15000; - }else Hemorrhage_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//NOTE: this creature are also summoned by other spells, for different creatures -struct MANGOS_DLL_DECL mob_lesser_shadow_fissureAI : public ScriptedAI -{ - mob_lesser_shadow_fissureAI(Creature *c) : ScriptedAI(c) {Reset();} - - bool Start; - uint32 Stop_Timer; - - void Reset() - { - Start = false; - Stop_Timer = 30000; - } - - void Aggro(Unit* who) { } - - void MoveInLineOfSight(Unit *who) { return; } - - void AttackStart(Unit* who) { return; } - - void UpdateAI(const uint32 diff) - { - if( !Start ) - { - //triggered spell of consumption does not properly show it's SpellVisual, hack it a bit - m_creature->CastSpell(m_creature,SPELL_TEMPORARY_VISUAL,true); - m_creature->CastSpell(m_creature,SPELL_CONSUMPTION,false); - Start = true; - } - - if( Stop_Timer < diff) - { - m_creature->setDeathState(JUST_DIED); - m_creature->SetHealth(0); - m_creature->CombatStop(); - m_creature->DeleteThreatList(); - }else Stop_Timer -= diff; - } -}; - -CreatureAI* GetAI_boss_grand_warlock_nethekurse(Creature *_Creature) -{ - return new boss_grand_warlock_nethekurseAI (_Creature); -} - -CreatureAI* GetAI_mob_fel_orc_convert(Creature *_Creature) -{ - return new mob_fel_orc_convertAI (_Creature); -} - -CreatureAI* GetAI_mob_lesser_shadow_fissure(Creature *_Creature) -{ - return new mob_lesser_shadow_fissureAI (_Creature); -} - -void AddSC_boss_grand_warlock_nethekurse() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_grand_warlock_nethekurse"; - newscript->GetAI = GetAI_boss_grand_warlock_nethekurse; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_fel_orc_convert"; - newscript->GetAI = GetAI_mob_fel_orc_convert; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_lesser_shadow_fissure"; - newscript->GetAI = GetAI_mob_lesser_shadow_fissure; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Warlock_Nethekurse +SD%Complete: 75 +SDComment: encounter not fully complete. missing part where boss kill minions. +SDCategory: Hellfire Citadel, Shattered Halls +EndScriptData */ + +/* ContentData +boss_grand_warlock_nethekurse +mob_fel_orc_convert +mob_lesser_shadow_fissure +EndContentData */ + +#include "precompiled.h" +#include "def_shattered_halls.h" + +struct Say +{ + const char* text; + uint32 sound; +}; + +#define SAY_INTRO "You wish to fight us all at once? This should be amusing!" +#define SOUND_INTRO 10262 + +static Say PeonAttacked[]= +{ + {"You can have that one. I no longer need him.", 10263}, + {"Yes, beat him mercilessly. His skull is a thick as an ogres.", 10264}, + {"Don't waste your time on that one. He's weak!", 10265}, + {"You want him? Very well, take him!", 10266}, +}; +static Say PeonDies[]= +{ + {"One pitiful wretch down. Go on, take another one.", 10267}, + {"Ahh, what a waste... Next!", 10268}, + {"I was going to kill him anyway!", 10269}, + {"Thank you for saving me the trouble! Now it's my turn to have some fun...", 10270}, +}; + +#define SAY_TAUNT_1 "Beg for your pittyfull life!" +#define SOUND_TAUNT_1 10259 +#define SAY_TAUNT_2 "Run covad, ruun!" +#define SOUND_TAUNT_2 10260 +#define SAY_TAUNT_3 "Your pain amuses me." +#define SOUND_TAUNT_3 10261 + +#define SAY_AGGRO_1 "I'm already bored." +#define SOUND_AGGRO_1 10271 +#define SAY_AGGRO_2 "Come on! ... Show me a real fight." +#define SOUND_AGGRO_2 10272 +#define SAY_AGGRO_3 "I had more fun torturing the peons." +#define SOUND_AGGRO_3 10273 + +#define SAY_SLAY_1 "You Loose." +#define SOUND_SLAY_1 10274 +#define SAY_SLAY_2 "Ohh! Just die." +#define SOUND_SLAY_2 10275 + +#define SAY_DIE "What a ... a shame." +#define SOUND_DIE 10276 + +#define SPELL_DEATH_COIL 30500 +#define SPELL_DARK_SPIN 30502 // core bug spell attack caster :D +#define SPELL_SHADOW_FISSURE 30496 // Summon the ShadowFissure NPC + +#define SPELL_SHADOW_CLEAVE 30495 +#define H_SPELL_SHADOW_SLAM 35953 + +#define SPELL_HEMORRHAGE 30478 + +#define SPELL_CONSUMPTION 30497 +#define SPELL_TEMPORARY_VISUAL 39312 // this is wrong, a temporary solution. spell consumption already has the purple visual, but doesn't display as it should + +struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI +{ + boss_grand_warlock_nethekurseAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + bool HeroicMode; + bool IntroOnce; + bool IsIntroEvent; + bool IsMainEvent; + bool SpinOnce; + //bool HasTaunted; + bool Phase; + + uint32 PeonEngagedCount; + uint32 PeonKilledCount; + + uint32 IntroEvent_Timer; + uint32 DeathCoil_Timer; + uint32 ShadowFissure_Timer; + uint32 Cleave_Timer; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + HeroicMode = m_creature->GetMap()->IsHeroic(); + IsIntroEvent = false; + IntroOnce = false; + IsMainEvent = false; + //HasTaunted = false; + SpinOnce = false; + Phase = false; + + PeonEngagedCount = 0; + PeonKilledCount = 0; + + IntroEvent_Timer = 90000; //how long before getting bored and kills his minions? + DeathCoil_Timer = 20000; + ShadowFissure_Timer = 8000; + Cleave_Timer = 5000; + } + + void DoYellForPeonAggro() + { + if( PeonEngagedCount >= 4 ) + return; + + DoYell(PeonAttacked[PeonEngagedCount].text, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, PeonAttacked[PeonEngagedCount].sound); + ++PeonEngagedCount; + } + + void DoYellForPeonDeath() + { + if( PeonKilledCount >= 4 ) + return; + + DoYell(PeonDies[PeonKilledCount].text, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, PeonDies[PeonKilledCount].sound); + ++PeonKilledCount; + + if( PeonKilledCount == 4 ) + { + IsIntroEvent = false; + IsMainEvent = true; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + + void DoTauntPeons() + { + switch(rand()%3) + { + case 0: + DoPlaySoundToSet(m_creature,SOUND_TAUNT_1); + DoYell(SAY_TAUNT_1,LANG_UNIVERSAL,NULL); + break; + case 1: + DoPlaySoundToSet(m_creature,SOUND_TAUNT_2); + DoYell(SAY_TAUNT_2,LANG_UNIVERSAL,NULL); + break; + case 2: + DoPlaySoundToSet(m_creature,SOUND_TAUNT_3); + DoYell(SAY_TAUNT_3,LANG_UNIVERSAL,NULL); + break; + } + + //TODO: kill the peons first + IsIntroEvent = false; + PeonEngagedCount = 4; + PeonKilledCount = 4; + IsMainEvent = true; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void AttackStart(Unit* who) + { + if ( IsIntroEvent || !IsMainEvent ) + return; + + if( who->isTargetableForAttack() ) + { + if( Phase ) DoStartAttackNoMovement(who); + else DoStartAttackAndMovement(who); + + if( !InCombat ) + { + Aggro(who); + InCombat = true; + } + } + } + + void MoveInLineOfSight(Unit *who) + { + if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) + { + if( !IntroOnce && m_creature->IsWithinDistInMap(who, 75) ) + { + DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_INTRO); + IntroOnce = true; + IsIntroEvent = true; + + if( pInstance ) + pInstance->SetData(TYPE_NETHEKURSE,IN_PROGRESS); + } + + if(!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE ) + return; + + if( IsIntroEvent || !IsMainEvent ) + return; + + float attackRadius = m_creature->GetAttackDistance(who); + if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + { + if( Phase ) DoStartAttackNoMovement(who); + else DoStartAttackAndMovement(who); + + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if( !InCombat ) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoPlaySoundToSet(m_creature,SOUND_AGGRO_1); + DoYell(SAY_AGGRO_1,LANG_UNIVERSAL,NULL); + break; + case 1: + DoPlaySoundToSet(m_creature,SOUND_AGGRO_2); + DoYell(SAY_AGGRO_2,LANG_UNIVERSAL,NULL); + break; + case 2: + DoPlaySoundToSet(m_creature,SOUND_AGGRO_3); + DoYell(SAY_AGGRO_3,LANG_UNIVERSAL,NULL); + break; + } + } + + void JustSummoned(Creature *summoned) + { + summoned->setFaction(14); + summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + DoYell(SAY_SLAY_1,LANG_UNIVERSAL,NULL); + break; + case 1: + DoPlaySoundToSet(m_creature,SOUND_SLAY_2); + DoYell(SAY_SLAY_2,LANG_UNIVERSAL,NULL); + break; + } + } + + void JustDied(Unit* Killer) + { + DoPlaySoundToSet(m_creature,SOUND_DIE); + DoYell(SAY_DIE,LANG_UNIVERSAL,NULL); + + if( !pInstance ) + return; + + pInstance->SetData(TYPE_NETHEKURSE,DONE); + + if( pInstance->GetData64(DATA_NETHEKURSE_DOOR) ) + { + if( GameObject *Door = GameObject::GetGameObject(*m_creature,pInstance->GetData64(DATA_NETHEKURSE_DOOR)) ) + Door->SetGoState(0); + } + } + + void UpdateAI(const uint32 diff) + { + if( IsIntroEvent ) + { + if( !pInstance ) + return; + + if( pInstance->GetData(TYPE_NETHEKURSE) == IN_PROGRESS ) + { + if( IntroEvent_Timer < diff ) + { + DoTauntPeons(); + }else IntroEvent_Timer -= diff; + } + } + + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( !IsMainEvent ) + return; + + if( Phase ) + { + if( !SpinOnce ) + { + DoCast(m_creature->getVictim(),SPELL_DARK_SPIN); + SpinOnce = true; + } + + if( Cleave_Timer < diff ) + { + DoCast(m_creature->getVictim(),(HeroicMode ? H_SPELL_SHADOW_SLAM : SPELL_SHADOW_CLEAVE)); + Cleave_Timer = 6000+rand()%2500; + }else Cleave_Timer -= diff; + } + else + { + if( ShadowFissure_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_SHADOW_FISSURE); + ShadowFissure_Timer = 7500+rand()%7500; + }else ShadowFissure_Timer -= diff; + + if( DeathCoil_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_DEATH_COIL); + DeathCoil_Timer = 15000+rand()%5000; + }else DeathCoil_Timer -= diff; + + if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 20 ) + Phase = true; + + DoMeleeAttackIfReady(); + } + } +}; + +struct MANGOS_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI +{ + mob_fel_orc_convertAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + uint32 Hemorrhage_Timer; + + void Reset() + { + m_creature->SetNoCallAssistence(true); //we don't want any assistance (WE R HEROZ!) + Hemorrhage_Timer = 3000; + } + + void MoveInLineOfSight(Unit *who) + { + return; + } + + void Aggro(Unit* who) + { + if( pInstance ) + { + if( pInstance->GetData64(DATA_NETHEKURSE) ) + { + Creature *pKurse = (Creature*)Unit::GetUnit(*m_creature,pInstance->GetData64(DATA_NETHEKURSE)); + if( pKurse ) + ((boss_grand_warlock_nethekurseAI*)pKurse->AI())->DoYellForPeonAggro(); + } + + if( pInstance->GetData(TYPE_NETHEKURSE) == IN_PROGRESS ) + return; + else pInstance->SetData(TYPE_NETHEKURSE,IN_PROGRESS); + } + } + + void JustDied(Unit* Killer) + { + if( pInstance ) + { + if( pInstance->GetData64(DATA_NETHEKURSE) ) + { + Creature *pKurse = (Creature*)Unit::GetUnit(*m_creature,pInstance->GetData64(DATA_NETHEKURSE)); + if( pKurse ) + ((boss_grand_warlock_nethekurseAI*)pKurse->AI())->DoYellForPeonDeath(); + } + } + } + + void UpdateAI(const uint32 diff) + { + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( Hemorrhage_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_HEMORRHAGE); + Hemorrhage_Timer = 15000; + }else Hemorrhage_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//NOTE: this creature are also summoned by other spells, for different creatures +struct MANGOS_DLL_DECL mob_lesser_shadow_fissureAI : public ScriptedAI +{ + mob_lesser_shadow_fissureAI(Creature *c) : ScriptedAI(c) {Reset();} + + bool Start; + uint32 Stop_Timer; + + void Reset() + { + Start = false; + Stop_Timer = 30000; + } + + void Aggro(Unit* who) { } + + void MoveInLineOfSight(Unit *who) { return; } + + void AttackStart(Unit* who) { return; } + + void UpdateAI(const uint32 diff) + { + if( !Start ) + { + //triggered spell of consumption does not properly show it's SpellVisual, hack it a bit + m_creature->CastSpell(m_creature,SPELL_TEMPORARY_VISUAL,true); + m_creature->CastSpell(m_creature,SPELL_CONSUMPTION,false); + Start = true; + } + + if( Stop_Timer < diff) + { + m_creature->setDeathState(JUST_DIED); + m_creature->SetHealth(0); + m_creature->CombatStop(); + m_creature->DeleteThreatList(); + }else Stop_Timer -= diff; + } +}; + +CreatureAI* GetAI_boss_grand_warlock_nethekurse(Creature *_Creature) +{ + return new boss_grand_warlock_nethekurseAI (_Creature); +} + +CreatureAI* GetAI_mob_fel_orc_convert(Creature *_Creature) +{ + return new mob_fel_orc_convertAI (_Creature); +} + +CreatureAI* GetAI_mob_lesser_shadow_fissure(Creature *_Creature) +{ + return new mob_lesser_shadow_fissureAI (_Creature); +} + +void AddSC_boss_grand_warlock_nethekurse() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_grand_warlock_nethekurse"; + newscript->GetAI = GetAI_boss_grand_warlock_nethekurse; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_fel_orc_convert"; + newscript->GetAI = GetAI_mob_fel_orc_convert; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_lesser_shadow_fissure"; + newscript->GetAI = GetAI_mob_lesser_shadow_fissure; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp index 96b4e6f29a0..81d9f6c5348 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp @@ -1,414 +1,414 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Warbringer_Omrogg -SD%Complete: 85 -SDComment: Heroic enabled. Spell timing may need additional tweaks -SDCategory: Hellfire Citadel, Shattered Halls -EndScriptData */ - -/* ContentData -mob_omrogg_heads -boss_warbringer_omrogg -EndContentData */ - -#include "precompiled.h" -#include "def_shattered_halls.h" - -#define ENTRY_LEFT_HEAD 19523 -#define ENTRY_RIGHT_HEAD 19524 - -struct Yell -{ - const char* text; - uint32 sound; - uint32 creature; -}; - -static Yell GoCombat[]= -{ - {"Smash!", 10306, ENTRY_LEFT_HEAD}, - {"If you nice me let you live.", 10308, ENTRY_LEFT_HEAD}, - {"Me hungry!", 10309, ENTRY_LEFT_HEAD}, -}; -static Yell GoCombatDelay[]= -{ - {"Why don't you let me do the talking?", 10317, ENTRY_RIGHT_HEAD}, - {"No, we will NOT let you live!", 10318, ENTRY_RIGHT_HEAD}, - {"You always hungry. That why we so fat!", 10319, ENTRY_RIGHT_HEAD}, -}; - -static Yell Threat[]= -{ - {"You stay here. Me go kill someone else!", 10303, ENTRY_LEFT_HEAD}, - {"What are you doing!", 10315, ENTRY_RIGHT_HEAD}, - {"Me kill someone else...", 10302, ENTRY_LEFT_HEAD}, - {"Me not like this one...",10300, ENTRY_LEFT_HEAD}, -}; -static Yell ThreatDelay1[]= -{ - {"That's not funny!", 10314, ENTRY_RIGHT_HEAD}, - {"Me get bored...", 10305, ENTRY_LEFT_HEAD}, - {"I'm not done yet, idiot!", 10313, ENTRY_RIGHT_HEAD}, - {"Hey you numbskull!", 10312, ENTRY_RIGHT_HEAD}, -}; -static Yell ThreatDelay2[]= -{ - {"Ha ha ha.", 10304, ENTRY_LEFT_HEAD}, - {"Whhy! He almost dead!", 10316, ENTRY_RIGHT_HEAD}, - {"H'ey...", 10307, ENTRY_LEFT_HEAD}, - {"We kill his friend!", 10301, ENTRY_LEFT_HEAD}, -}; - -static Yell Killing[]= -{ - {"This one die easy!", 10310, ENTRY_LEFT_HEAD}, - {"I'm tired. You kill next one!", 10320, ENTRY_RIGHT_HEAD}, -}; -static Yell KillingDelay[]= -{ - {"That's because I do all the hard work!", 10321, ENTRY_RIGHT_HEAD}, - {"SD2 script error, should not see this.", 0, ENTRY_LEFT_HEAD}, -}; - -#define EMOTE_ENRAGE "enrages" - -#define YELL_DIE_L "This all...your fault!" -#define SOUND_DIE_L 10311 -#define YELL_DIE_R "I...hate...you..." -#define SOUND_DIE_R 10322 - -#define SPELL_BLAST_WAVE 30600 -#define SPELL_FEAR 30584 -#define SPELL_THUNDERCLAP 30633 - -#define SPELL_BURNING_MAUL 30598 -#define H_SPELL_BURNING_MAUL 36056 - -struct MANGOS_DLL_DECL mob_omrogg_headsAI : public ScriptedAI -{ - mob_omrogg_headsAI(Creature *c) : ScriptedAI(c) { Reset(); } - - bool DeathYell; - uint32 Death_Timer; - - void Reset() {} - void Aggro(Unit* who) { } - - void DoDeathYell() - { - Death_Timer = 4000; - DeathYell = true; - } - - void UpdateAI(const uint32 diff) - { - if( !DeathYell ) - return; - - if( Death_Timer < diff ) - { - DoYell(YELL_DIE_R,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DIE_R); - DeathYell = false; - }else Death_Timer -= diff; - } -}; - -struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI -{ - boss_warbringer_omroggAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - HeroicMode = m_creature->GetMap()->IsHeroic(); - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 LeftHead; - uint64 RightHead; - int iaggro; - int ithreat; - int ikilling; - - bool HeroicMode; - bool AggroYell; - bool ThreatYell; - bool ThreatYell2; - bool KillingYell; - - uint32 Delay_Timer; - uint32 BlastWave_Timer; - uint32 BlastCount; - uint32 Fear_Timer; - uint32 BurningMaul_Timer; - uint32 ThunderClap_Timer; - uint32 ResetThreat_Timer; - - void Reset() - { - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - - LeftHead = 0; - RightHead = 0; - - AggroYell = false; - ThreatYell = false; - ThreatYell2 = false; - KillingYell = false; - - Delay_Timer = 4000; - BlastWave_Timer = 0; - BlastCount = 0; - Fear_Timer = 8000; - BurningMaul_Timer = 25000; - ThunderClap_Timer = 15000; - ResetThreat_Timer = 30000; - - if( pInstance ) - pInstance->SetData(TYPE_OMROGG, NOT_STARTED); //End boss can use this later. O'mrogg must be defeated(DONE) or he will come to aid. - } - - void DoYellForThreat() - { - if( LeftHead && RightHead ) - { - Unit *Left = Unit::GetUnit(*m_creature,LeftHead); - Unit *Right = Unit::GetUnit(*m_creature,RightHead); - - if( !Left && !Right ) - return; - - ithreat = rand()%4; - - Unit *source = (Left->GetEntry() == Threat[ithreat].creature ? Left : Right); - - source->MonsterYell(Threat[ithreat].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(source, Threat[ithreat].sound); - - Delay_Timer = 3500; - ThreatYell = true; - } - } - - void Aggro(Unit *who) - { - DoSpawnCreature(ENTRY_LEFT_HEAD,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN,1800000); - DoSpawnCreature(ENTRY_RIGHT_HEAD,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN,1800000); - - if( Unit *Left = Unit::GetUnit(*m_creature,LeftHead) ) - { - iaggro = rand()%3; - - Left->MonsterYell(GoCombat[iaggro].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(Left, GoCombat[iaggro].sound); - - Delay_Timer = 3500; - AggroYell = true; - } - if( pInstance ) - pInstance->SetData(TYPE_OMROGG, IN_PROGRESS); - } - - void JustSummoned(Creature *summoned) - { - if( summoned->GetEntry() == ENTRY_LEFT_HEAD ) - LeftHead = summoned->GetGUID(); - - if( summoned->GetEntry() == ENTRY_RIGHT_HEAD ) - RightHead = summoned->GetGUID(); - - //summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - //summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - summoned->SetVisibility(VISIBILITY_OFF); - } - - void KilledUnit(Unit* victim) - { - if( LeftHead && RightHead ) - { - Unit *Left = Unit::GetUnit(*m_creature,LeftHead); - Unit *Right = Unit::GetUnit(*m_creature,RightHead); - - if( !Left && !Right ) - return; - - ikilling = rand()%2; - - Unit *source = (Left->GetEntry() == Killing[ikilling].creature ? Left : Right); - - switch(ikilling) - { - case 0: - source->MonsterYell(Killing[ikilling].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(source, Killing[ikilling].sound); - Delay_Timer = 3500; - KillingYell = true; - break; - case 1: - source->MonsterYell(Killing[ikilling].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(source, Killing[ikilling].sound); - KillingYell = false; - break; - } - } - } - - void JustDied(Unit* Killer) - { - if( LeftHead && RightHead ) - { - Unit *Left = Unit::GetUnit(*m_creature,LeftHead); - Unit *Right = Unit::GetUnit(*m_creature,RightHead); - - if( !Left && !Right ) - return; - - Left->MonsterYell(YELL_DIE_L, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(Left,SOUND_DIE_L); - - ((mob_omrogg_headsAI*)((Creature*)Right)->AI())->DoDeathYell(); - } - if( pInstance ) - pInstance->SetData(TYPE_OMROGG, DONE); - } - - void UpdateAI(const uint32 diff) - { - if( Delay_Timer < diff ) - { - Delay_Timer = 3500; - - if( !LeftHead && !RightHead ) - return; - - Unit *Left = Unit::GetUnit(*m_creature,LeftHead); - Unit *Right = Unit::GetUnit(*m_creature,RightHead); - - if( !Left && !Right ) - return; - - if( AggroYell ) - { - Right->MonsterYell(GoCombatDelay[iaggro].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(Right, GoCombatDelay[iaggro].sound); - AggroYell = false; - } - - if( ThreatYell2 ) - { - Unit *source = (Left->GetEntry() == ThreatDelay2[ithreat].creature ? Left : Right); - - source->MonsterYell(ThreatDelay2[ithreat].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(source, ThreatDelay2[ithreat].sound); - ThreatYell2 = false; - } - - if( ThreatYell ) - { - Unit *source = (Left->GetEntry() == ThreatDelay1[ithreat].creature ? Left : Right); - - source->MonsterYell(ThreatDelay1[ithreat].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(source, ThreatDelay1[ithreat].sound); - ThreatYell = false; - ThreatYell2 = true; - } - - if( KillingYell ) - { - Unit *source = (Left->GetEntry() == KillingDelay[ikilling].creature ? Left : Right); - - source->MonsterYell(KillingDelay[ikilling].text, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(source, KillingDelay[ikilling].sound); - KillingYell = false; - } - }else Delay_Timer -= diff; - - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( BlastCount && BlastWave_Timer <= diff ) - { - DoCast(m_creature,SPELL_BLAST_WAVE); - BlastWave_Timer = 5000; - ++BlastCount; - if( BlastCount == 3 ) - BlastCount = 0; - }else BlastWave_Timer -= diff; - - if( BurningMaul_Timer < diff ) - { - DoTextEmote(EMOTE_ENRAGE,NULL); - DoCast(m_creature,HeroicMode ? H_SPELL_BURNING_MAUL : SPELL_BURNING_MAUL); - BurningMaul_Timer = 40000; - BlastWave_Timer = 16000; - BlastCount = 1; - }else BurningMaul_Timer -= diff; - - if( ResetThreat_Timer < diff ) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - { - DoYellForThreat(); - DoResetThreat(); - m_creature->AddThreat(target, 0.0f); - } - ResetThreat_Timer = 35000+rand()%10000; - }else ResetThreat_Timer -= diff; - - if( Fear_Timer < diff ) - { - DoCast(m_creature,SPELL_FEAR); - Fear_Timer = 15000+rand()%25000; - }else Fear_Timer -= diff; - - if( ThunderClap_Timer < diff ) - { - DoCast(m_creature,SPELL_THUNDERCLAP); - ThunderClap_Timer = 25000+rand()%15000; - }else ThunderClap_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_warbringer_omrogg(Creature *_Creature) -{ - return new boss_warbringer_omroggAI (_Creature); -} - -CreatureAI* GetAI_mob_omrogg_heads(Creature *_Creature) -{ - return new mob_omrogg_headsAI (_Creature); -} - -void AddSC_boss_warbringer_omrogg() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_warbringer_omrogg"; - newscript->GetAI = GetAI_boss_warbringer_omrogg; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_omrogg_heads"; - newscript->GetAI = GetAI_mob_omrogg_heads; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Warbringer_Omrogg +SD%Complete: 85 +SDComment: Heroic enabled. Spell timing may need additional tweaks +SDCategory: Hellfire Citadel, Shattered Halls +EndScriptData */ + +/* ContentData +mob_omrogg_heads +boss_warbringer_omrogg +EndContentData */ + +#include "precompiled.h" +#include "def_shattered_halls.h" + +#define ENTRY_LEFT_HEAD 19523 +#define ENTRY_RIGHT_HEAD 19524 + +struct Yell +{ + const char* text; + uint32 sound; + uint32 creature; +}; + +static Yell GoCombat[]= +{ + {"Smash!", 10306, ENTRY_LEFT_HEAD}, + {"If you nice me let you live.", 10308, ENTRY_LEFT_HEAD}, + {"Me hungry!", 10309, ENTRY_LEFT_HEAD}, +}; +static Yell GoCombatDelay[]= +{ + {"Why don't you let me do the talking?", 10317, ENTRY_RIGHT_HEAD}, + {"No, we will NOT let you live!", 10318, ENTRY_RIGHT_HEAD}, + {"You always hungry. That why we so fat!", 10319, ENTRY_RIGHT_HEAD}, +}; + +static Yell Threat[]= +{ + {"You stay here. Me go kill someone else!", 10303, ENTRY_LEFT_HEAD}, + {"What are you doing!", 10315, ENTRY_RIGHT_HEAD}, + {"Me kill someone else...", 10302, ENTRY_LEFT_HEAD}, + {"Me not like this one...",10300, ENTRY_LEFT_HEAD}, +}; +static Yell ThreatDelay1[]= +{ + {"That's not funny!", 10314, ENTRY_RIGHT_HEAD}, + {"Me get bored...", 10305, ENTRY_LEFT_HEAD}, + {"I'm not done yet, idiot!", 10313, ENTRY_RIGHT_HEAD}, + {"Hey you numbskull!", 10312, ENTRY_RIGHT_HEAD}, +}; +static Yell ThreatDelay2[]= +{ + {"Ha ha ha.", 10304, ENTRY_LEFT_HEAD}, + {"Whhy! He almost dead!", 10316, ENTRY_RIGHT_HEAD}, + {"H'ey...", 10307, ENTRY_LEFT_HEAD}, + {"We kill his friend!", 10301, ENTRY_LEFT_HEAD}, +}; + +static Yell Killing[]= +{ + {"This one die easy!", 10310, ENTRY_LEFT_HEAD}, + {"I'm tired. You kill next one!", 10320, ENTRY_RIGHT_HEAD}, +}; +static Yell KillingDelay[]= +{ + {"That's because I do all the hard work!", 10321, ENTRY_RIGHT_HEAD}, + {"SD2 script error, should not see this.", 0, ENTRY_LEFT_HEAD}, +}; + +#define EMOTE_ENRAGE "enrages" + +#define YELL_DIE_L "This all...your fault!" +#define SOUND_DIE_L 10311 +#define YELL_DIE_R "I...hate...you..." +#define SOUND_DIE_R 10322 + +#define SPELL_BLAST_WAVE 30600 +#define SPELL_FEAR 30584 +#define SPELL_THUNDERCLAP 30633 + +#define SPELL_BURNING_MAUL 30598 +#define H_SPELL_BURNING_MAUL 36056 + +struct MANGOS_DLL_DECL mob_omrogg_headsAI : public ScriptedAI +{ + mob_omrogg_headsAI(Creature *c) : ScriptedAI(c) { Reset(); } + + bool DeathYell; + uint32 Death_Timer; + + void Reset() {} + void Aggro(Unit* who) { } + + void DoDeathYell() + { + Death_Timer = 4000; + DeathYell = true; + } + + void UpdateAI(const uint32 diff) + { + if( !DeathYell ) + return; + + if( Death_Timer < diff ) + { + DoYell(YELL_DIE_R,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DIE_R); + DeathYell = false; + }else Death_Timer -= diff; + } +}; + +struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI +{ + boss_warbringer_omroggAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + HeroicMode = m_creature->GetMap()->IsHeroic(); + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 LeftHead; + uint64 RightHead; + int iaggro; + int ithreat; + int ikilling; + + bool HeroicMode; + bool AggroYell; + bool ThreatYell; + bool ThreatYell2; + bool KillingYell; + + uint32 Delay_Timer; + uint32 BlastWave_Timer; + uint32 BlastCount; + uint32 Fear_Timer; + uint32 BurningMaul_Timer; + uint32 ThunderClap_Timer; + uint32 ResetThreat_Timer; + + void Reset() + { + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + + LeftHead = 0; + RightHead = 0; + + AggroYell = false; + ThreatYell = false; + ThreatYell2 = false; + KillingYell = false; + + Delay_Timer = 4000; + BlastWave_Timer = 0; + BlastCount = 0; + Fear_Timer = 8000; + BurningMaul_Timer = 25000; + ThunderClap_Timer = 15000; + ResetThreat_Timer = 30000; + + if( pInstance ) + pInstance->SetData(TYPE_OMROGG, NOT_STARTED); //End boss can use this later. O'mrogg must be defeated(DONE) or he will come to aid. + } + + void DoYellForThreat() + { + if( LeftHead && RightHead ) + { + Unit *Left = Unit::GetUnit(*m_creature,LeftHead); + Unit *Right = Unit::GetUnit(*m_creature,RightHead); + + if( !Left && !Right ) + return; + + ithreat = rand()%4; + + Unit *source = (Left->GetEntry() == Threat[ithreat].creature ? Left : Right); + + source->MonsterYell(Threat[ithreat].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(source, Threat[ithreat].sound); + + Delay_Timer = 3500; + ThreatYell = true; + } + } + + void Aggro(Unit *who) + { + DoSpawnCreature(ENTRY_LEFT_HEAD,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN,1800000); + DoSpawnCreature(ENTRY_RIGHT_HEAD,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN,1800000); + + if( Unit *Left = Unit::GetUnit(*m_creature,LeftHead) ) + { + iaggro = rand()%3; + + Left->MonsterYell(GoCombat[iaggro].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(Left, GoCombat[iaggro].sound); + + Delay_Timer = 3500; + AggroYell = true; + } + if( pInstance ) + pInstance->SetData(TYPE_OMROGG, IN_PROGRESS); + } + + void JustSummoned(Creature *summoned) + { + if( summoned->GetEntry() == ENTRY_LEFT_HEAD ) + LeftHead = summoned->GetGUID(); + + if( summoned->GetEntry() == ENTRY_RIGHT_HEAD ) + RightHead = summoned->GetGUID(); + + //summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + //summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + summoned->SetVisibility(VISIBILITY_OFF); + } + + void KilledUnit(Unit* victim) + { + if( LeftHead && RightHead ) + { + Unit *Left = Unit::GetUnit(*m_creature,LeftHead); + Unit *Right = Unit::GetUnit(*m_creature,RightHead); + + if( !Left && !Right ) + return; + + ikilling = rand()%2; + + Unit *source = (Left->GetEntry() == Killing[ikilling].creature ? Left : Right); + + switch(ikilling) + { + case 0: + source->MonsterYell(Killing[ikilling].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(source, Killing[ikilling].sound); + Delay_Timer = 3500; + KillingYell = true; + break; + case 1: + source->MonsterYell(Killing[ikilling].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(source, Killing[ikilling].sound); + KillingYell = false; + break; + } + } + } + + void JustDied(Unit* Killer) + { + if( LeftHead && RightHead ) + { + Unit *Left = Unit::GetUnit(*m_creature,LeftHead); + Unit *Right = Unit::GetUnit(*m_creature,RightHead); + + if( !Left && !Right ) + return; + + Left->MonsterYell(YELL_DIE_L, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(Left,SOUND_DIE_L); + + ((mob_omrogg_headsAI*)((Creature*)Right)->AI())->DoDeathYell(); + } + if( pInstance ) + pInstance->SetData(TYPE_OMROGG, DONE); + } + + void UpdateAI(const uint32 diff) + { + if( Delay_Timer < diff ) + { + Delay_Timer = 3500; + + if( !LeftHead && !RightHead ) + return; + + Unit *Left = Unit::GetUnit(*m_creature,LeftHead); + Unit *Right = Unit::GetUnit(*m_creature,RightHead); + + if( !Left && !Right ) + return; + + if( AggroYell ) + { + Right->MonsterYell(GoCombatDelay[iaggro].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(Right, GoCombatDelay[iaggro].sound); + AggroYell = false; + } + + if( ThreatYell2 ) + { + Unit *source = (Left->GetEntry() == ThreatDelay2[ithreat].creature ? Left : Right); + + source->MonsterYell(ThreatDelay2[ithreat].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(source, ThreatDelay2[ithreat].sound); + ThreatYell2 = false; + } + + if( ThreatYell ) + { + Unit *source = (Left->GetEntry() == ThreatDelay1[ithreat].creature ? Left : Right); + + source->MonsterYell(ThreatDelay1[ithreat].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(source, ThreatDelay1[ithreat].sound); + ThreatYell = false; + ThreatYell2 = true; + } + + if( KillingYell ) + { + Unit *source = (Left->GetEntry() == KillingDelay[ikilling].creature ? Left : Right); + + source->MonsterYell(KillingDelay[ikilling].text, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(source, KillingDelay[ikilling].sound); + KillingYell = false; + } + }else Delay_Timer -= diff; + + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( BlastCount && BlastWave_Timer <= diff ) + { + DoCast(m_creature,SPELL_BLAST_WAVE); + BlastWave_Timer = 5000; + ++BlastCount; + if( BlastCount == 3 ) + BlastCount = 0; + }else BlastWave_Timer -= diff; + + if( BurningMaul_Timer < diff ) + { + DoTextEmote(EMOTE_ENRAGE,NULL); + DoCast(m_creature,HeroicMode ? H_SPELL_BURNING_MAUL : SPELL_BURNING_MAUL); + BurningMaul_Timer = 40000; + BlastWave_Timer = 16000; + BlastCount = 1; + }else BurningMaul_Timer -= diff; + + if( ResetThreat_Timer < diff ) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + { + DoYellForThreat(); + DoResetThreat(); + m_creature->AddThreat(target, 0.0f); + } + ResetThreat_Timer = 35000+rand()%10000; + }else ResetThreat_Timer -= diff; + + if( Fear_Timer < diff ) + { + DoCast(m_creature,SPELL_FEAR); + Fear_Timer = 15000+rand()%25000; + }else Fear_Timer -= diff; + + if( ThunderClap_Timer < diff ) + { + DoCast(m_creature,SPELL_THUNDERCLAP); + ThunderClap_Timer = 25000+rand()%15000; + }else ThunderClap_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_warbringer_omrogg(Creature *_Creature) +{ + return new boss_warbringer_omroggAI (_Creature); +} + +CreatureAI* GetAI_mob_omrogg_heads(Creature *_Creature) +{ + return new mob_omrogg_headsAI (_Creature); +} + +void AddSC_boss_warbringer_omrogg() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_warbringer_omrogg"; + newscript->GetAI = GetAI_boss_warbringer_omrogg; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_omrogg_heads"; + newscript->GetAI = GetAI_mob_omrogg_heads; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/def_shattered_halls.h b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/def_shattered_halls.h index 602564d32f0..e7eef878481 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/def_shattered_halls.h +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/def_shattered_halls.h @@ -1,13 +1,13 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_SHATTERED_H -#define DEF_SHATTERED_H - -#define TYPE_NETHEKURSE 1 -#define DATA_NETHEKURSE 2 -#define DATA_NETHEKURSE_DOOR 3 - -#define TYPE_OMROGG 4 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_SHATTERED_H +#define DEF_SHATTERED_H + +#define TYPE_NETHEKURSE 1 +#define DATA_NETHEKURSE 2 +#define DATA_NETHEKURSE_DOOR 3 + +#define TYPE_OMROGG 4 +#endif diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp index 8d068a4bb40..8015101d41f 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp @@ -1,114 +1,114 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Shattered_Halls -SD%Complete: 50 -SDComment: currently missing info about door. instance not complete -SDCategory: Hellfire Citadel, Shattered Halls -EndScriptData */ - -#include "precompiled.h" -#include "def_shattered_halls.h" - -#define ENCOUNTERS 2 - -#define DOOR_NETHEKURSE 1 - -struct MANGOS_DLL_DECL instance_shattered_halls : public ScriptedInstance -{ - instance_shattered_halls(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint32 Encounter[ENCOUNTERS]; - uint64 nethekurseGUID; - uint64 nethekurseDoorGUID; - - void Initialize() - { - nethekurseGUID = 0; - nethekurseDoorGUID = 0; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounter[i] = NOT_STARTED; - } - - void OnObjectCreate(GameObject *go) - { - switch( go->GetEntry() ) - { - case DOOR_NETHEKURSE: nethekurseDoorGUID = go->GetGUID(); break; - } - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch( creature_entry ) - { - case 16807: nethekurseGUID = creature->GetGUID(); break; - } - } - - void SetData(uint32 type, uint32 data) - { - switch( type ) - { - case TYPE_NETHEKURSE: - Encounter[0] = data; - break; - case TYPE_OMROGG: - Encounter[1] = data; - break; - } - } - - uint32 GetData(uint32 type) - { - switch( type ) - { - case TYPE_NETHEKURSE: - return Encounter[0]; - case TYPE_OMROGG: - return Encounter[1]; - } - return 0; - } - - uint64 GetData64(uint32 data) - { - switch(data) - { - case DATA_NETHEKURSE: - return nethekurseGUID; - case DATA_NETHEKURSE_DOOR: - return nethekurseDoorGUID; - } - return 0; - } -}; - -InstanceData* GetInstanceData_instance_shattered_halls(Map* map) -{ - return new instance_shattered_halls(map); -} - -void AddSC_instance_shattered_halls() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_shattered_halls"; - newscript->GetInstanceData = GetInstanceData_instance_shattered_halls; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Shattered_Halls +SD%Complete: 50 +SDComment: currently missing info about door. instance not complete +SDCategory: Hellfire Citadel, Shattered Halls +EndScriptData */ + +#include "precompiled.h" +#include "def_shattered_halls.h" + +#define ENCOUNTERS 2 + +#define DOOR_NETHEKURSE 1 + +struct MANGOS_DLL_DECL instance_shattered_halls : public ScriptedInstance +{ + instance_shattered_halls(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 Encounter[ENCOUNTERS]; + uint64 nethekurseGUID; + uint64 nethekurseDoorGUID; + + void Initialize() + { + nethekurseGUID = 0; + nethekurseDoorGUID = 0; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounter[i] = NOT_STARTED; + } + + void OnObjectCreate(GameObject *go) + { + switch( go->GetEntry() ) + { + case DOOR_NETHEKURSE: nethekurseDoorGUID = go->GetGUID(); break; + } + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch( creature_entry ) + { + case 16807: nethekurseGUID = creature->GetGUID(); break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch( type ) + { + case TYPE_NETHEKURSE: + Encounter[0] = data; + break; + case TYPE_OMROGG: + Encounter[1] = data; + break; + } + } + + uint32 GetData(uint32 type) + { + switch( type ) + { + case TYPE_NETHEKURSE: + return Encounter[0]; + case TYPE_OMROGG: + return Encounter[1]; + } + return 0; + } + + uint64 GetData64(uint32 data) + { + switch(data) + { + case DATA_NETHEKURSE: + return nethekurseGUID; + case DATA_NETHEKURSE_DOOR: + return nethekurseDoorGUID; + } + return 0; + } +}; + +InstanceData* GetInstanceData_instance_shattered_halls(Map* map) +{ + return new instance_shattered_halls(map); +} + +void AddSC_instance_shattered_halls() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_shattered_halls"; + newscript->GetInstanceData = GetInstanceData_instance_shattered_halls; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_peninsula/boss_doomlord_kazzak.cpp b/src/bindings/scripts/scripts/zone/hellfire_peninsula/boss_doomlord_kazzak.cpp index ccb36f9f350..e70f233a12e 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_peninsula/boss_doomlord_kazzak.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_peninsula/boss_doomlord_kazzak.cpp @@ -1,141 +1,141 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Doomlord_Kazzak -SD%Complete: 70 -SDComment: Using incorrect spell for Mark of Kazzak -SDCategory: Hellfire Peninsula -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOWVOLLEY 32963 -#define SPELL_CLEAVE 31779 -#define SPELL_THUNDERCLAP 36706 -#define SPELL_VOIDBOLT 39329 -#define SPELL_MARKOFKAZZAK 32960 -#define SPELL_ENRAGE 32964 -#define SPELL_CAPTURESOUL 32966 -#define SPELL_TWISTEDREFLECTION 21063 - -struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI -{ - boss_doomlordkazzakAI(Creature *c) : ScriptedAI(c) {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() - { - ShadowVolley_Timer = 8000 + rand()%4000; - Cleave_Timer = 7000; - ThunderClap_Timer = 16000 + rand()%4000; - VoidBolt_Timer = 30000; - MarkOfKazzak_Timer = 25000; - Enrage_Timer = 60000; - Twisted_Reflection_Timer = 33000; // Timer may be incorrect - } - - void Aggro(Unit *who) {} - - void KilledUnit(Unit* victim) - { - // When Kazzak kills a player (not pets/totems), he regens some health - if(victim->GetTypeId() == TYPEID_PLAYER) - DoCast(m_creature,SPELL_CAPTURESOUL); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ShadowVolley_Timer - if (ShadowVolley_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SHADOWVOLLEY); - ShadowVolley_Timer = 4000 + rand()%2000; - }else ShadowVolley_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 8000 + rand()%4000; - }else Cleave_Timer -= diff; - - //ThunderClap_Timer - if (ThunderClap_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); - ThunderClap_Timer = 10000 + rand()%4000; - }else ThunderClap_Timer -= diff; - - //VoidBolt_Timer - if (VoidBolt_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_VOIDBOLT); - VoidBolt_Timer = 15000 + rand()%3000; - }else VoidBolt_Timer -= diff; - - //MarkOfKazzak_Timer - if (MarkOfKazzak_Timer < diff) - { - Unit* victim = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(victim->GetPower(POWER_MANA)) - { - DoCast(victim, SPELL_MARKOFKAZZAK); - MarkOfKazzak_Timer = 20000; - } - }else MarkOfKazzak_Timer -= diff; - - //Enrage_Timer - if (Enrage_Timer < diff) - { - DoCast(m_creature,SPELL_ENRAGE); - Enrage_Timer = 30000; - }else Enrage_Timer -= diff; - - if(Twisted_Reflection_Timer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_TWISTEDREFLECTION); - Twisted_Reflection_Timer = 15000; - }else Twisted_Reflection_Timer -= diff; - - DoMeleeAttackIfReady(); - } - -}; -CreatureAI* GetAI_boss_doomlordkazzak(Creature *_Creature) -{ - return new boss_doomlordkazzakAI (_Creature); -} - -void AddSC_boss_doomlordkazzak() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_doomlord_kazzak"; - newscript->GetAI = GetAI_boss_doomlordkazzak; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Doomlord_Kazzak +SD%Complete: 70 +SDComment: Using incorrect spell for Mark of Kazzak +SDCategory: Hellfire Peninsula +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SHADOWVOLLEY 32963 +#define SPELL_CLEAVE 31779 +#define SPELL_THUNDERCLAP 36706 +#define SPELL_VOIDBOLT 39329 +#define SPELL_MARKOFKAZZAK 32960 +#define SPELL_ENRAGE 32964 +#define SPELL_CAPTURESOUL 32966 +#define SPELL_TWISTEDREFLECTION 21063 + +struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI +{ + boss_doomlordkazzakAI(Creature *c) : ScriptedAI(c) {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() + { + ShadowVolley_Timer = 8000 + rand()%4000; + Cleave_Timer = 7000; + ThunderClap_Timer = 16000 + rand()%4000; + VoidBolt_Timer = 30000; + MarkOfKazzak_Timer = 25000; + Enrage_Timer = 60000; + Twisted_Reflection_Timer = 33000; // Timer may be incorrect + } + + void Aggro(Unit *who) {} + + void KilledUnit(Unit* victim) + { + // When Kazzak kills a player (not pets/totems), he regens some health + if(victim->GetTypeId() == TYPEID_PLAYER) + DoCast(m_creature,SPELL_CAPTURESOUL); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ShadowVolley_Timer + if (ShadowVolley_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SHADOWVOLLEY); + ShadowVolley_Timer = 4000 + rand()%2000; + }else ShadowVolley_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 8000 + rand()%4000; + }else Cleave_Timer -= diff; + + //ThunderClap_Timer + if (ThunderClap_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); + ThunderClap_Timer = 10000 + rand()%4000; + }else ThunderClap_Timer -= diff; + + //VoidBolt_Timer + if (VoidBolt_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_VOIDBOLT); + VoidBolt_Timer = 15000 + rand()%3000; + }else VoidBolt_Timer -= diff; + + //MarkOfKazzak_Timer + if (MarkOfKazzak_Timer < diff) + { + Unit* victim = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(victim->GetPower(POWER_MANA)) + { + DoCast(victim, SPELL_MARKOFKAZZAK); + MarkOfKazzak_Timer = 20000; + } + }else MarkOfKazzak_Timer -= diff; + + //Enrage_Timer + if (Enrage_Timer < diff) + { + DoCast(m_creature,SPELL_ENRAGE); + Enrage_Timer = 30000; + }else Enrage_Timer -= diff; + + if(Twisted_Reflection_Timer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_TWISTEDREFLECTION); + Twisted_Reflection_Timer = 15000; + }else Twisted_Reflection_Timer -= diff; + + DoMeleeAttackIfReady(); + } + +}; +CreatureAI* GetAI_boss_doomlordkazzak(Creature *_Creature) +{ + return new boss_doomlordkazzakAI (_Creature); +} + +void AddSC_boss_doomlordkazzak() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_doomlord_kazzak"; + newscript->GetAI = GetAI_boss_doomlordkazzak; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp b/src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp index ceedce42ea2..4123884d462 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp @@ -1,187 +1,187 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Hellfire_Peninsula -SD%Complete: 100 -SDComment: Quest support: 10129, 10146, 10162, 10163, 10340, 10346, 10347, 10382 (Special flight paths) -SDCategory: Hellfire Peninsula -EndScriptData */ - -/* ContentData -npc_wing_commander_dabiree -npc_gryphoneer_windbellow -npc_wing_commander_brack -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_wing_commander_dabiree -######*/ - -#define GOSSIP_ITEM1_DAB "Fly me to Murketh and Shaadraz Gateways" -#define GOSSIP_ITEM2_DAB "Fly me to Shatter Point" - -bool GossipHello_npc_wing_commander_dabiree(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - //Mission: The Murketh and Shaadraz Gateways - if (player->GetQuestStatus(10146) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM1_DAB, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - //Shatter Point - if (!player->GetQuestRewardStatus(10340)) - player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM2_DAB, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_wing_commander_dabiree(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,33768,true); //TaxiPath 585 (Gateways Murket and Shaadraz) - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,35069,true); //TaxiPath 612 (Taxi - Hellfire Peninsula - Expedition Point to Shatter Point) - } - return true; -} - -/*###### -## npc_gryphoneer_windbellow -######*/ - -#define GOSSIP_ITEM1_WIN "Fly me to The Abyssal Shelf" -#define GOSSIP_ITEM2_WIN "Fly me to Honor Point" - -bool GossipHello_npc_gryphoneer_windbellow(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - //Mission: The Abyssal Shelf || Return to the Abyssal Shelf - if (player->GetQuestStatus(10163) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10346) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM1_WIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - //Go to the Front - if (player->GetQuestStatus(10382) != QUEST_STATUS_NONE && !player->GetQuestRewardStatus(10382)) - player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM2_WIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_gryphoneer_windbellow(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,33899,true); //TaxiPath 589 (Aerial Assault Flight (Alliance)) - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,35065,true); //TaxiPath 607 (Taxi - Hellfire Peninsula - Shatter Point to Beach Head) - } - return true; -} - -/*###### -## npc_wing_commander_brack -######*/ - -#define GOSSIP_ITEM1_BRA "Fly me to Murketh and Shaadraz Gateways" -#define GOSSIP_ITEM2_BRA "Fly me to The Abyssal Shelf" -#define GOSSIP_ITEM3_BRA "Fly me to Spinebreaker Post" - -bool GossipHello_npc_wing_commander_brack(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - //Mission: The Murketh and Shaadraz Gateways - if (player->GetQuestStatus(10129) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM1_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - //Mission: The Abyssal Shelf || Return to the Abyssal Shelf - if (player->GetQuestStatus(10162) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10347) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM2_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - //Spinebreaker Post - if (player->GetQuestStatus(10242) == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(10242)) - player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM3_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_wing_commander_brack(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,33659,true); //TaxiPath 584 (Gateways Murket and Shaadraz) - } - if (action == GOSSIP_ACTION_INFO_DEF + 2) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,33825,true); //TaxiPath 587 (Aerial Assault Flight (Horde)) - } - if (action == GOSSIP_ACTION_INFO_DEF + 3) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,34578,true); //TaxiPath 604 (Taxi - Reaver's Fall to Spinebreaker Ridge) - } - return true; -} - -/*###### -## -######*/ - -void AddSC_hellfire_peninsula() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_wing_commander_dabiree"; - newscript->pGossipHello = &GossipHello_npc_wing_commander_dabiree; - newscript->pGossipSelect = &GossipSelect_npc_wing_commander_dabiree; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_gryphoneer_windbellow"; - newscript->pGossipHello = &GossipHello_npc_gryphoneer_windbellow; - newscript->pGossipSelect = &GossipSelect_npc_gryphoneer_windbellow; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_wing_commander_brack"; - newscript->pGossipHello = &GossipHello_npc_wing_commander_brack; - newscript->pGossipSelect = &GossipSelect_npc_wing_commander_brack; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Hellfire_Peninsula +SD%Complete: 100 +SDComment: Quest support: 10129, 10146, 10162, 10163, 10340, 10346, 10347, 10382 (Special flight paths) +SDCategory: Hellfire Peninsula +EndScriptData */ + +/* ContentData +npc_wing_commander_dabiree +npc_gryphoneer_windbellow +npc_wing_commander_brack +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_wing_commander_dabiree +######*/ + +#define GOSSIP_ITEM1_DAB "Fly me to Murketh and Shaadraz Gateways" +#define GOSSIP_ITEM2_DAB "Fly me to Shatter Point" + +bool GossipHello_npc_wing_commander_dabiree(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + //Mission: The Murketh and Shaadraz Gateways + if (player->GetQuestStatus(10146) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM1_DAB, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + //Shatter Point + if (!player->GetQuestRewardStatus(10340)) + player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM2_DAB, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_wing_commander_dabiree(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,33768,true); //TaxiPath 585 (Gateways Murket and Shaadraz) + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,35069,true); //TaxiPath 612 (Taxi - Hellfire Peninsula - Expedition Point to Shatter Point) + } + return true; +} + +/*###### +## npc_gryphoneer_windbellow +######*/ + +#define GOSSIP_ITEM1_WIN "Fly me to The Abyssal Shelf" +#define GOSSIP_ITEM2_WIN "Fly me to Honor Point" + +bool GossipHello_npc_gryphoneer_windbellow(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + //Mission: The Abyssal Shelf || Return to the Abyssal Shelf + if (player->GetQuestStatus(10163) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10346) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM1_WIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + //Go to the Front + if (player->GetQuestStatus(10382) != QUEST_STATUS_NONE && !player->GetQuestRewardStatus(10382)) + player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM2_WIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_gryphoneer_windbellow(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,33899,true); //TaxiPath 589 (Aerial Assault Flight (Alliance)) + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,35065,true); //TaxiPath 607 (Taxi - Hellfire Peninsula - Shatter Point to Beach Head) + } + return true; +} + +/*###### +## npc_wing_commander_brack +######*/ + +#define GOSSIP_ITEM1_BRA "Fly me to Murketh and Shaadraz Gateways" +#define GOSSIP_ITEM2_BRA "Fly me to The Abyssal Shelf" +#define GOSSIP_ITEM3_BRA "Fly me to Spinebreaker Post" + +bool GossipHello_npc_wing_commander_brack(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + //Mission: The Murketh and Shaadraz Gateways + if (player->GetQuestStatus(10129) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM1_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + //Mission: The Abyssal Shelf || Return to the Abyssal Shelf + if (player->GetQuestStatus(10162) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10347) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM2_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + + //Spinebreaker Post + if (player->GetQuestStatus(10242) == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(10242)) + player->ADD_GOSSIP_ITEM(2, GOSSIP_ITEM3_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_wing_commander_brack(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,33659,true); //TaxiPath 584 (Gateways Murket and Shaadraz) + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,33825,true); //TaxiPath 587 (Aerial Assault Flight (Horde)) + } + if (action == GOSSIP_ACTION_INFO_DEF + 3) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,34578,true); //TaxiPath 604 (Taxi - Reaver's Fall to Spinebreaker Ridge) + } + return true; +} + +/*###### +## +######*/ + +void AddSC_hellfire_peninsula() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_wing_commander_dabiree"; + newscript->pGossipHello = &GossipHello_npc_wing_commander_dabiree; + newscript->pGossipSelect = &GossipSelect_npc_wing_commander_dabiree; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_gryphoneer_windbellow"; + newscript->pGossipHello = &GossipHello_npc_gryphoneer_windbellow; + newscript->pGossipSelect = &GossipSelect_npc_gryphoneer_windbellow; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_wing_commander_brack"; + newscript->pGossipHello = &GossipHello_npc_wing_commander_brack; + newscript->pGossipSelect = &GossipSelect_npc_wing_commander_brack; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/ironforge/ironforge.cpp b/src/bindings/scripts/scripts/zone/ironforge/ironforge.cpp index 5ba9e4b3ae1..ff4d0cd6cc2 100644 --- a/src/bindings/scripts/scripts/zone/ironforge/ironforge.cpp +++ b/src/bindings/scripts/scripts/zone/ironforge/ironforge.cpp @@ -1,93 +1,93 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Ironforge -SD%Complete: 100 -SDComment: Quest support: 3702 -SDCategory: Ironforge -EndScriptData */ - -/* ContentData -npc_royal_historian_archesonus -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_royal_historian_archesonus -######*/ - -#define GOSSIP_ITEM_ROYAL "I am ready to listen" -#define GOSSIP_ITEM_ROYAL_1 "That is tragic. How did this happen?" -#define GOSSIP_ITEM_ROYAL_2 "Interesting, continue please." -#define GOSSIP_ITEM_ROYAL_3 "Unbelievable! How dare they??" -#define GOSSIP_ITEM_ROYAL_4 "Of course I will help!" - -bool GossipHello_npc_royal_historian_archesonus(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(3702) == QUEST_STATUS_INCOMPLETE) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(2235, _Creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_royal_historian_archesonus(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(2236, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(2237, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(2238, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(2239, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(3702); - break; - } - return true; -} - -void AddSC_ironforge() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_royal_historian_archesonus"; - newscript->pGossipHello = &GossipHello_npc_royal_historian_archesonus; - newscript->pGossipSelect = &GossipSelect_npc_royal_historian_archesonus; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Ironforge +SD%Complete: 100 +SDComment: Quest support: 3702 +SDCategory: Ironforge +EndScriptData */ + +/* ContentData +npc_royal_historian_archesonus +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_royal_historian_archesonus +######*/ + +#define GOSSIP_ITEM_ROYAL "I am ready to listen" +#define GOSSIP_ITEM_ROYAL_1 "That is tragic. How did this happen?" +#define GOSSIP_ITEM_ROYAL_2 "Interesting, continue please." +#define GOSSIP_ITEM_ROYAL_3 "Unbelievable! How dare they??" +#define GOSSIP_ITEM_ROYAL_4 "Of course I will help!" + +bool GossipHello_npc_royal_historian_archesonus(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(3702) == QUEST_STATUS_INCOMPLETE) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(2235, _Creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_royal_historian_archesonus(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(2236, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(2237, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(2238, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_ROYAL_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(2239, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(3702); + break; + } + return true; +} + +void AddSC_ironforge() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_royal_historian_archesonus"; + newscript->pGossipHello = &GossipHello_npc_royal_historian_archesonus; + newscript->pGossipSelect = &GossipSelect_npc_royal_historian_archesonus; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/isle_of_queldanas/isle_of_queldanas.cpp b/src/bindings/scripts/scripts/zone/isle_of_queldanas/isle_of_queldanas.cpp index 06baf994a18..732183f3a48 100644 --- a/src/bindings/scripts/scripts/zone/isle_of_queldanas/isle_of_queldanas.cpp +++ b/src/bindings/scripts/scripts/zone/isle_of_queldanas/isle_of_queldanas.cpp @@ -1,155 +1,155 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Queldanas -SD%Complete: 100 -SDComment: Quest support: 11524, 11525, 11532, 11533, 11542, 11543 -SDCategory: Isle Of Quel'Danas -EndScriptData */ - -/* ContentData -npc_ayren_cloudbreaker -npc_converted_sentry -npc_unrestrained_dragonhawk -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_ayren_cloudbreaker -######*/ - -bool GossipHello_npc_ayren_cloudbreaker(Player *player, Creature *_Creature) -{ - if( player->GetQuestStatus(11532) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(11533) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(0,"Speaking of action, I've been ordered to undertake an air strike.",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); - - if( player->GetQuestStatus(11542) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(11543) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(0,"I need to intercept the Dawnblade reinforcements.",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+2); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_ayren_cloudbreaker(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,45071,true); //TaxiPath 779 - } - if (action == GOSSIP_ACTION_INFO_DEF+2) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,45113,true); //TaxiPath 784 - } - return true; -} - -/*###### -## npc_converted_sentry -######*/ - -#define SAY_CONVERTED_1 "Deployment sucessful. Trespassers will be neutralized." -#define SAY_CONVERTED_2 "Objective acquired. Initiating security routines." - -#define SPELL_CONVERT_CREDIT 45009 - -struct MANGOS_DLL_DECL npc_converted_sentryAI : public ScriptedAI -{ - npc_converted_sentryAI(Creature *c) : ScriptedAI(c) { Reset(); } - - bool Credit; - uint32 Timer; - - void Reset() - { - Credit = false; - Timer = 2500; - } - - void MoveInLineOfSight(Unit *who) - { return; } - void Aggro(Unit* who) - { } - - void UpdateAI(const uint32 diff) - { - if( !Credit ) - { - if( Timer <= diff ) - { - uint32 i = urand(1,2); - if( i=1 ) DoSay(SAY_CONVERTED_1,LANG_UNIVERSAL,NULL); - else DoSay(SAY_CONVERTED_2,LANG_UNIVERSAL,NULL); - - DoCast(m_creature,SPELL_CONVERT_CREDIT); - ((Pet*)m_creature)->SetDuration(7500); - Credit = true; - }else Timer -= diff; - } - } -}; -CreatureAI* GetAI_npc_converted_sentry(Creature *_Creature) -{ - return new npc_converted_sentryAI (_Creature); -} - -/*###### -## npc_unrestrained_dragonhawk -######*/ - -bool GossipHello_npc_unrestrained_dragonhawk(Player *player, Creature *_Creature) -{ - if( player->GetQuestStatus(11542) == QUEST_STATUS_COMPLETE || player->GetQuestStatus(11543) == QUEST_STATUS_COMPLETE ) - player->ADD_GOSSIP_ITEM(0,"",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_unrestrained_dragonhawk(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,45353,true); //TaxiPath 788 - } - return true; -} - -void AddSC_isle_of_queldanas() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_ayren_cloudbreaker"; - newscript->pGossipHello = &GossipHello_npc_ayren_cloudbreaker; - newscript->pGossipSelect = &GossipSelect_npc_ayren_cloudbreaker; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_converted_sentry"; - newscript->GetAI = GetAI_npc_converted_sentry; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_unrestrained_dragonhawk"; - newscript->pGossipHello = &GossipHello_npc_unrestrained_dragonhawk; - newscript->pGossipSelect = &GossipSelect_npc_unrestrained_dragonhawk; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Queldanas +SD%Complete: 100 +SDComment: Quest support: 11524, 11525, 11532, 11533, 11542, 11543 +SDCategory: Isle Of Quel'Danas +EndScriptData */ + +/* ContentData +npc_ayren_cloudbreaker +npc_converted_sentry +npc_unrestrained_dragonhawk +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_ayren_cloudbreaker +######*/ + +bool GossipHello_npc_ayren_cloudbreaker(Player *player, Creature *_Creature) +{ + if( player->GetQuestStatus(11532) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(11533) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(0,"Speaking of action, I've been ordered to undertake an air strike.",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); + + if( player->GetQuestStatus(11542) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(11543) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(0,"I need to intercept the Dawnblade reinforcements.",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+2); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_ayren_cloudbreaker(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,45071,true); //TaxiPath 779 + } + if (action == GOSSIP_ACTION_INFO_DEF+2) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,45113,true); //TaxiPath 784 + } + return true; +} + +/*###### +## npc_converted_sentry +######*/ + +#define SAY_CONVERTED_1 "Deployment sucessful. Trespassers will be neutralized." +#define SAY_CONVERTED_2 "Objective acquired. Initiating security routines." + +#define SPELL_CONVERT_CREDIT 45009 + +struct MANGOS_DLL_DECL npc_converted_sentryAI : public ScriptedAI +{ + npc_converted_sentryAI(Creature *c) : ScriptedAI(c) { Reset(); } + + bool Credit; + uint32 Timer; + + void Reset() + { + Credit = false; + Timer = 2500; + } + + void MoveInLineOfSight(Unit *who) + { return; } + void Aggro(Unit* who) + { } + + void UpdateAI(const uint32 diff) + { + if( !Credit ) + { + if( Timer <= diff ) + { + uint32 i = urand(1,2); + if( i=1 ) DoSay(SAY_CONVERTED_1,LANG_UNIVERSAL,NULL); + else DoSay(SAY_CONVERTED_2,LANG_UNIVERSAL,NULL); + + DoCast(m_creature,SPELL_CONVERT_CREDIT); + ((Pet*)m_creature)->SetDuration(7500); + Credit = true; + }else Timer -= diff; + } + } +}; +CreatureAI* GetAI_npc_converted_sentry(Creature *_Creature) +{ + return new npc_converted_sentryAI (_Creature); +} + +/*###### +## npc_unrestrained_dragonhawk +######*/ + +bool GossipHello_npc_unrestrained_dragonhawk(Player *player, Creature *_Creature) +{ + if( player->GetQuestStatus(11542) == QUEST_STATUS_COMPLETE || player->GetQuestStatus(11543) == QUEST_STATUS_COMPLETE ) + player->ADD_GOSSIP_ITEM(0,"",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_unrestrained_dragonhawk(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,45353,true); //TaxiPath 788 + } + return true; +} + +void AddSC_isle_of_queldanas() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_ayren_cloudbreaker"; + newscript->pGossipHello = &GossipHello_npc_ayren_cloudbreaker; + newscript->pGossipSelect = &GossipSelect_npc_ayren_cloudbreaker; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_converted_sentry"; + newscript->GetAI = GetAI_npc_converted_sentry; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_unrestrained_dragonhawk"; + newscript->pGossipHello = &GossipHello_npc_unrestrained_dragonhawk; + newscript->pGossipSelect = &GossipSelect_npc_unrestrained_dragonhawk; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_curator.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_curator.cpp index b7c4af8dded..b6d04295399 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_curator.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_curator.cpp @@ -1,200 +1,200 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Curator -SD%Complete: 100 -SDComment: Evocation may cause client crash (Core related) -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO "The Menagerie is for guests only." -#define SOUND_AGGRO 9183 - -#define SAY_SUMMON1 "Gallery rules will be strictly enforced." -#define SOUND_SUMMON1 9188 - -#define SAY_SUMMON2 "This curator is equipped for gallery protection." -#define SOUND_SUMMON2 9309 - -#define SAY_EVOCATE "Your request cannot be processed." -#define SOUND_EVOCATE 9186 - -#define SAY_ENRAGE "Failure to comply will result in offensive action." -#define SOUND_ENRAGE 9185 - -#define SAY_KILL1 "Do not touch the displays." -#define SOUND_KILL1 9187 - -#define SAY_KILL2 "You are not a guest." -#define SOUND_KILL2 9308 - -#define SAY_DEATH "This Curator is no longer op... er... ation... al." -#define SOUND_DEATH 9184 - -//Flare spell info -#define SPELL_ASTRAL_FLARE_PASSIVE 30234 -#define SPELL_ASTRAL_FLARE_NE 30236 -#define SPELL_ASTRAL_FLARE_NW 30239 -#define SPELL_ASTRAL_FLARE_SE 30240 -#define SPELL_ASTRAL_FLARE_SW 30241 - -//Curator spell info -#define SPELL_HATEFUL_BOLT 30383 -#define SPELL_EVOCATION 30254 -#define SPELL_ENRAGE 28131 -#define SPELL_BERSERK 26662 - -struct MANGOS_DLL_DECL boss_curatorAI : public ScriptedAI -{ - boss_curatorAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 AddTimer; - uint32 HatefulBoltTimer; - uint32 BerserkTimer; - - bool Enraged; - bool Evocating; - - void Reset() - { - AddTimer = 10000; - HatefulBoltTimer = 15000; // This time is probably wrong - BerserkTimer = 720000; //12 minutes - Enraged = false; - Evocating = false; - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_KILL1); - break; - case 1: - DoYell(SAY_KILL2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_KILL2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(NULL, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if (Evocating && !m_creature->HasAura(SPELL_EVOCATION, 0)) - Evocating = false; - - if(m_creature->GetPower(POWER_MANA) <= 1000 && !Evocating) - { - DoYell(SAY_EVOCATE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_EVOCATE); - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature, SPELL_EVOCATION); - Evocating = true; - } - - if(!Enraged && !Evocating) - { - if(AddTimer < diff) - { - //Summon Astral Flare - Creature* AstralFlare = DoSpawnCreature(17096, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if (AstralFlare && target) - { - AstralFlare->CastSpell(AstralFlare, SPELL_ASTRAL_FLARE_PASSIVE, false); - AstralFlare->AI()->AttackStart(target); - } - - //Reduce Mana by 10% - int32 mana = (int32)(0.1f*(m_creature->GetMaxPower(POWER_MANA))); - m_creature->ModifyPower(POWER_MANA, -mana); - switch(rand()%4) - { - case 0: - DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON1); - break; - case 1: - DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON2); - break; - } - AddTimer = 10000; - }else AddTimer -= diff; - - if(HatefulBoltTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); - DoCast(target, SPELL_HATEFUL_BOLT); - - HatefulBoltTimer = 15000; - }else HatefulBoltTimer -= diff; - - if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 15) - { - Enraged = true; - DoCast(m_creature, SPELL_ENRAGE); - DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - } - } - - if(BerserkTimer < diff) - { - DoCast(m_creature, SPELL_BERSERK); - DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENRAGE); - }else BerserkTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_curator(Creature *_Creature) -{ - return new boss_curatorAI (_Creature); -} - -void AddSC_boss_curator() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_curator"; - newscript->GetAI = GetAI_boss_curator; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Curator +SD%Complete: 100 +SDComment: Evocation may cause client crash (Core related) +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO "The Menagerie is for guests only." +#define SOUND_AGGRO 9183 + +#define SAY_SUMMON1 "Gallery rules will be strictly enforced." +#define SOUND_SUMMON1 9188 + +#define SAY_SUMMON2 "This curator is equipped for gallery protection." +#define SOUND_SUMMON2 9309 + +#define SAY_EVOCATE "Your request cannot be processed." +#define SOUND_EVOCATE 9186 + +#define SAY_ENRAGE "Failure to comply will result in offensive action." +#define SOUND_ENRAGE 9185 + +#define SAY_KILL1 "Do not touch the displays." +#define SOUND_KILL1 9187 + +#define SAY_KILL2 "You are not a guest." +#define SOUND_KILL2 9308 + +#define SAY_DEATH "This Curator is no longer op... er... ation... al." +#define SOUND_DEATH 9184 + +//Flare spell info +#define SPELL_ASTRAL_FLARE_PASSIVE 30234 +#define SPELL_ASTRAL_FLARE_NE 30236 +#define SPELL_ASTRAL_FLARE_NW 30239 +#define SPELL_ASTRAL_FLARE_SE 30240 +#define SPELL_ASTRAL_FLARE_SW 30241 + +//Curator spell info +#define SPELL_HATEFUL_BOLT 30383 +#define SPELL_EVOCATION 30254 +#define SPELL_ENRAGE 28131 +#define SPELL_BERSERK 26662 + +struct MANGOS_DLL_DECL boss_curatorAI : public ScriptedAI +{ + boss_curatorAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 AddTimer; + uint32 HatefulBoltTimer; + uint32 BerserkTimer; + + bool Enraged; + bool Evocating; + + void Reset() + { + AddTimer = 10000; + HatefulBoltTimer = 15000; // This time is probably wrong + BerserkTimer = 720000; //12 minutes + Enraged = false; + Evocating = false; + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_KILL1); + break; + case 1: + DoYell(SAY_KILL2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_KILL2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(NULL, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if (Evocating && !m_creature->HasAura(SPELL_EVOCATION, 0)) + Evocating = false; + + if(m_creature->GetPower(POWER_MANA) <= 1000 && !Evocating) + { + DoYell(SAY_EVOCATE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_EVOCATE); + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_EVOCATION); + Evocating = true; + } + + if(!Enraged && !Evocating) + { + if(AddTimer < diff) + { + //Summon Astral Flare + Creature* AstralFlare = DoSpawnCreature(17096, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if (AstralFlare && target) + { + AstralFlare->CastSpell(AstralFlare, SPELL_ASTRAL_FLARE_PASSIVE, false); + AstralFlare->AI()->AttackStart(target); + } + + //Reduce Mana by 10% + int32 mana = (int32)(0.1f*(m_creature->GetMaxPower(POWER_MANA))); + m_creature->ModifyPower(POWER_MANA, -mana); + switch(rand()%4) + { + case 0: + DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON1); + break; + case 1: + DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON2); + break; + } + AddTimer = 10000; + }else AddTimer -= diff; + + if(HatefulBoltTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); + DoCast(target, SPELL_HATEFUL_BOLT); + + HatefulBoltTimer = 15000; + }else HatefulBoltTimer -= diff; + + if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 15) + { + Enraged = true; + DoCast(m_creature, SPELL_ENRAGE); + DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + } + } + + if(BerserkTimer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENRAGE); + }else BerserkTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_curator(Creature *_Creature) +{ + return new boss_curatorAI (_Creature); +} + +void AddSC_boss_curator() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_curator"; + newscript->GetAI = GetAI_boss_curator; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp index 45ee19c7999..53befd38365 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp @@ -1,176 +1,176 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Maiden_of_Virtue -SD%Complete: 100 -SDComment: -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_REPENTANCE 29511 -#define SPELL_HOLYFIRE 29522 -#define SPELL_HOLYWRATH 32445 -#define SPELL_HOLYGROUND 29512 - -#define SAY_AGGRO "Your behavior will not be tolerated!" -#define SAY_SLAY1 "Ah ah ah..." -#define SAY_SLAY2 "This is for the best." -#define SAY_SLAY3 "Impure thoughts lead to profane actions." -#define SAY_REPENTANCE1 "Cast out your corrupt thoughts." -#define SAY_REPENTANCE2 "Your impurity must be cleansed." -#define SAY_DEATH "Death comes. Will your conscience be clear?" - -#define SOUND_AGGRO 9204 -#define SOUND_SLAY1 9207 -#define SOUND_SLAY2 9312 -#define SOUND_SLAY3 9311 -#define SOUND_REPENTANCE1 9313 -#define SOUND_REPENTANCE2 9208 -#define SOUND_DEATH 9206 - -struct MANGOS_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI -{ - boss_maiden_of_virtueAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Repentance_Timer; - uint32 Holyfire_Timer; - uint32 Holywrath_Timer; - uint32 Holyground_Timer; - - void Reset() - { - Repentance_Timer = 30000+(rand()%15000); - Holyfire_Timer = 8000+(rand()%17000); - Holywrath_Timer = 20000+(rand()%10000); - Holyground_Timer = 3000; - } - - void KilledUnit(Unit* Victim) - { - if(rand()%2) return; - - switch(rand()%3) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,Victim); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,Victim); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - case 2: - DoYell(SAY_SLAY3,LANG_UNIVERSAL,Victim); - DoPlaySoundToSet(m_creature, SOUND_SLAY3); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if (Holyground_Timer < diff) - { - DoCast(m_creature, SPELL_HOLYGROUND, true); //Triggered so it doesn't interrupt her at all - Holyground_Timer = 3000; - }else Holyground_Timer -= diff; - - if (Repentance_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_REPENTANCE); - - switch(rand()%2) - { - case 0: - DoYell(SAY_REPENTANCE1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_REPENTANCE1); - break; - case 1: - DoYell(SAY_REPENTANCE2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_REPENTANCE2); - break; - } - Repentance_Timer = 30000 + rand()%15000; //A little randomness on that spell - }else Repentance_Timer -= diff; - - if (Holyfire_Timer < diff) - { - //Time for an omgwtfpwn code to make maiden cast holy fire only on units outside the holy ground's 18 yard range - Unit* target = NULL; - std::list t_list = m_creature->getThreatManager().getThreatList(); - std::vector target_list; - for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - if(target && target->GetDistance2d(m_creature) > 12 ) - target_list.push_back(target); - target = NULL; - } - if(target_list.size()) - target = *(target_list.begin()+rand()%target_list.size()); - - DoCast(target,SPELL_HOLYFIRE); - - Holyfire_Timer = 8000 + rand()%17000; //Anywhere from 8 to 25 seconds, good luck having several of those in a row! - }else Holyfire_Timer -= diff; - - if (Holywrath_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - if (target) - { - DoCast(target,SPELL_HOLYWRATH); - Holywrath_Timer = 20000+(rand()%10000); //20-30 secs sounds nice - } - }else Holywrath_Timer -= diff; - - DoMeleeAttackIfReady(); - } - -}; - -CreatureAI* GetAI_boss_maiden_of_virtue(Creature *_Creature) -{ - return new boss_maiden_of_virtueAI (_Creature); -} - -void AddSC_boss_maiden_of_virtue() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_maiden_of_virtue"; - newscript->GetAI = GetAI_boss_maiden_of_virtue; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Maiden_of_Virtue +SD%Complete: 100 +SDComment: +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_REPENTANCE 29511 +#define SPELL_HOLYFIRE 29522 +#define SPELL_HOLYWRATH 32445 +#define SPELL_HOLYGROUND 29512 + +#define SAY_AGGRO "Your behavior will not be tolerated!" +#define SAY_SLAY1 "Ah ah ah..." +#define SAY_SLAY2 "This is for the best." +#define SAY_SLAY3 "Impure thoughts lead to profane actions." +#define SAY_REPENTANCE1 "Cast out your corrupt thoughts." +#define SAY_REPENTANCE2 "Your impurity must be cleansed." +#define SAY_DEATH "Death comes. Will your conscience be clear?" + +#define SOUND_AGGRO 9204 +#define SOUND_SLAY1 9207 +#define SOUND_SLAY2 9312 +#define SOUND_SLAY3 9311 +#define SOUND_REPENTANCE1 9313 +#define SOUND_REPENTANCE2 9208 +#define SOUND_DEATH 9206 + +struct MANGOS_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI +{ + boss_maiden_of_virtueAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Repentance_Timer; + uint32 Holyfire_Timer; + uint32 Holywrath_Timer; + uint32 Holyground_Timer; + + void Reset() + { + Repentance_Timer = 30000+(rand()%15000); + Holyfire_Timer = 8000+(rand()%17000); + Holywrath_Timer = 20000+(rand()%10000); + Holyground_Timer = 3000; + } + + void KilledUnit(Unit* Victim) + { + if(rand()%2) return; + + switch(rand()%3) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,Victim); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,Victim); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + case 2: + DoYell(SAY_SLAY3,LANG_UNIVERSAL,Victim); + DoPlaySoundToSet(m_creature, SOUND_SLAY3); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if (Holyground_Timer < diff) + { + DoCast(m_creature, SPELL_HOLYGROUND, true); //Triggered so it doesn't interrupt her at all + Holyground_Timer = 3000; + }else Holyground_Timer -= diff; + + if (Repentance_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_REPENTANCE); + + switch(rand()%2) + { + case 0: + DoYell(SAY_REPENTANCE1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_REPENTANCE1); + break; + case 1: + DoYell(SAY_REPENTANCE2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_REPENTANCE2); + break; + } + Repentance_Timer = 30000 + rand()%15000; //A little randomness on that spell + }else Repentance_Timer -= diff; + + if (Holyfire_Timer < diff) + { + //Time for an omgwtfpwn code to make maiden cast holy fire only on units outside the holy ground's 18 yard range + Unit* target = NULL; + std::list t_list = m_creature->getThreatManager().getThreatList(); + std::vector target_list; + for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + if(target && target->GetDistance2d(m_creature) > 12 ) + target_list.push_back(target); + target = NULL; + } + if(target_list.size()) + target = *(target_list.begin()+rand()%target_list.size()); + + DoCast(target,SPELL_HOLYFIRE); + + Holyfire_Timer = 8000 + rand()%17000; //Anywhere from 8 to 25 seconds, good luck having several of those in a row! + }else Holyfire_Timer -= diff; + + if (Holywrath_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + if (target) + { + DoCast(target,SPELL_HOLYWRATH); + Holywrath_Timer = 20000+(rand()%10000); //20-30 secs sounds nice + } + }else Holywrath_Timer -= diff; + + DoMeleeAttackIfReady(); + } + +}; + +CreatureAI* GetAI_boss_maiden_of_virtue(Creature *_Creature) +{ + return new boss_maiden_of_virtueAI (_Creature); +} + +void AddSC_boss_maiden_of_virtue() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_maiden_of_virtue"; + newscript->GetAI = GetAI_boss_maiden_of_virtue; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_midnight.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_midnight.cpp index d70c25d15db..eb9c3b9ab72 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_midnight.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_midnight.cpp @@ -1,371 +1,371 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Midnight -SD%Complete: 100 -SDComment: -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" - -#define SAY_MIDNIGHT_KILL "Well done Midnight!" -#define SOUND_MIDNIGHT_KILL 9173 - -#define SAY_APPEAR1 "Cowards! Wretches!" -#define SOUND_APPEAR1 9167 -#define SAY_APPEAR2 "Who dares attack the steed of the Huntsman?" -#define SOUND_APPEAR2 9298 -#define SAY_APPEAR3 "Perhaps you would rather test yourselves against a more formidable opponent?! " -#define SOUND_APPEAR3 9299 - -#define SAY_MOUNT "Come, Midnight, let\'s disperse this petty rabble! " -#define SOUND_MOUNT 9168 - -#define SAY_KILL1 "It was... inevitable." -#define SOUND_KILL1 9169 -#define SAY_KILL2 "Another trophy to add to my collection!" -#define SOUND_KILL2 9300 - -#define SAY_DISARMED "Weapons are merely a convenience for a warrior of my skill!" -#define SOUND_DISARMED 9166 - -#define SAY_DEATH "I always knew... someday I would become... the hunted." -#define SOUND_DEATH 9165 - -#define SAY_RANDOM1 "Such easy sport." -#define SOUND_RANDOM1 9170 -#define SAY_RANDOM2 "Amateurs! Do not think you can best me! I kill for a living." -#define SOUND_RANDOM2 9304 - -#define SPELL_SHADOWCLEAVE 29832 -#define SPELL_INTANGIBLE_PRESENCE 29833 -#define SPELL_BERSERKER_CHARGE 26561 //Only when mounted - -#define MOUNTED_DISPLAYID 16040 - -//Attumen (TODO: Use the summoning spell instead of creature id. It works , but is not convenient for us) -#define SUMMON_ATTUMEN 15550 - -struct MANGOS_DLL_DECL boss_midnightAI : public ScriptedAI -{ - boss_midnightAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 Attumen; - uint8 Phase; - uint32 Mount_Timer; - - void Reset() - { - Phase = 1; - Attumen = 0; - Mount_Timer = 0; - - m_creature->SetVisibility(VISIBILITY_ON); - } - - void Aggro(Unit* who) {} - - void KilledUnit(Unit *victim) - { - if(Phase == 2) - { - Unit *pUnit = Unit::GetUnit(*m_creature, Attumen); - if(pUnit) - { - pUnit->MonsterYell(SAY_MIDNIGHT_KILL, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(pUnit, SOUND_MIDNIGHT_KILL); - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(Phase == 1 && (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 95) - { - Phase = 2; - Creature *pAttumen = DoSpawnCreature(SUMMON_ATTUMEN, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); - if(pAttumen) - { - Attumen = pAttumen->GetGUID(); - pAttumen->AI()->AttackStart(m_creature->getVictim()); - SetMidnight(pAttumen, m_creature->GetGUID()); - switch(rand()%3) - { - case 0: - pAttumen->Yell(SAY_APPEAR1, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(m_creature, SOUND_APPEAR1); - break; - case 1: - pAttumen->Yell(SAY_APPEAR2, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(m_creature, SOUND_APPEAR2); - break; - case 2: - pAttumen->Yell(SAY_APPEAR3, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(m_creature, SOUND_APPEAR3); - break; - } - } - } - else if(Phase == 2 && (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 25) - { - Unit *pAttumen = Unit::GetUnit(*m_creature, Attumen); - if(pAttumen) - Mount(pAttumen); - } - else if(Phase ==3) - { - if(Mount_Timer) - if(Mount_Timer <= diff) - { - Mount_Timer = 0; - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->GetMotionMaster()->MoveIdle(); - Unit *pAttumen = Unit::GetUnit(*m_creature, Attumen); - if(pAttumen) - { - pAttumen->SetUInt32Value(UNIT_FIELD_DISPLAYID, 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 Mount_Timer -= diff; - } - - if(Phase != 3) - DoMeleeAttackIfReady(); - } - - void Mount(Unit *pAttumen) - { - DoPlaySoundToSet(pAttumen, SOUND_MOUNT); - pAttumen->MonsterYell(SAY_MOUNT, LANG_UNIVERSAL, 0); - Phase = 3; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pAttumen->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - float angle = m_creature->GetAngle(pAttumen); - float distance = m_creature->GetDistance2d(pAttumen); - float newX = m_creature->GetPositionX() + cos(angle)*(distance/2) ; - float newY = m_creature->GetPositionY() + sin(angle)*(distance/2) ; - float newZ = 50; - //m_creature->Relocate(newX,newY,newZ,angle); - //m_creature->SendMonsterMove(newX, newY, newZ, 0, true, 1000); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MovePoint(0, newX, newY, newZ); - distance += 10; - newX = m_creature->GetPositionX() + cos(angle)*(distance/2) ; - newY = m_creature->GetPositionY() + sin(angle)*(distance/2) ; - pAttumen->GetMotionMaster()->Clear(); - pAttumen->GetMotionMaster()->MovePoint(0, newX, newY, newZ); - //pAttumen->Relocate(newX,newY,newZ,-angle); - //pAttumen->SendMonsterMove(newX, newY, newZ, 0, true, 1000); - Mount_Timer = 1000; - } - - void SetMidnight(Creature *, uint64); //Below .. -}; - -CreatureAI* GetAI_boss_midnight(Creature *_Creature) -{ - return new boss_midnightAI(_Creature); -} - -struct MANGOS_DLL_DECL boss_attumenAI : public ScriptedAI -{ - boss_attumenAI(Creature *c) : ScriptedAI(c) - { - Reset(); - Phase = 1; - - CleaveTimer = 10000 + (rand()%6)*1000; - CurseTimer = 30000; - RandomYellTimer = 30000 + (rand()%31)*1000; //Occasionally yell - ChargeTimer = 20000; - ResetTimer = 0; - } - - uint64 Midnight; - uint8 Phase; - uint32 CleaveTimer; - uint32 CurseTimer; - uint32 RandomYellTimer; - uint32 ChargeTimer; //only when mounted - uint32 ResetTimer; - - void Reset() - { - ResetTimer = 2000; - } - - void Aggro(Unit* who) {} - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL1); - case 1: - DoYell(SAY_KILL2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL2); - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - Unit *pMidnight = Unit::GetUnit(*m_creature, Midnight); - if(pMidnight) - { - pMidnight->DealDamage(pMidnight, pMidnight->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - } - - void UpdateAI(const uint32 diff) - { - if(ResetTimer) - if(ResetTimer <= diff) - { - ResetTimer = 0; - Unit *pMidnight = Unit::GetUnit(*m_creature, Midnight); - if(pMidnight) - { - pMidnight->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pMidnight->SetVisibility(VISIBILITY_ON); - } - Midnight = 0; - - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - else ResetTimer -= diff; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE )) - return; - - if(CleaveTimer < diff) - { - Unit *target = m_creature->getVictim(); - DoCast(target, SPELL_SHADOWCLEAVE); - CleaveTimer = 10000 + (rand()%6)*1000; - } else CleaveTimer -= diff; - - if(CurseTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_INTANGIBLE_PRESENCE); - CurseTimer = 30000; - } else CurseTimer -= diff; - - if(RandomYellTimer < diff) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_RANDOM1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_RANDOM1); - break; - case 1: - DoYell(SAY_RANDOM2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_RANDOM2); - break; - } - RandomYellTimer = 30000 + (rand()%31)*1000; - } else RandomYellTimer -= diff; - - if(m_creature->GetUInt32Value(UNIT_FIELD_DISPLAYID) == MOUNTED_DISPLAYID) - { - if(ChargeTimer < diff) - { - Unit *target; - std::list t_list = m_creature->getThreatManager().getThreatList(); - std::vector target_list; - for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - if(target && target->GetDistance2d(m_creature) > 5) - target_list.push_back(target); - target = NULL; - } - if(target_list.size()) - target = *(target_list.begin()+rand()%target_list.size()); - - DoCast(target, SPELL_BERSERKER_CHARGE); - ChargeTimer = 20000; - } else ChargeTimer -= diff; - } - else - { - if( (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 25) - { - Creature *pMidnight = (Creature*)Unit::GetUnit(*m_creature, Midnight); - if(pMidnight && pMidnight->GetTypeId() == TYPEID_UNIT) - { - ((boss_midnightAI*)(pMidnight->AI()))->Mount(m_creature); - m_creature->SetHealth(pMidnight->GetHealth()); - } - } - } - - DoMeleeAttackIfReady(); - } - - void SpellHit(Unit *source, const SpellEntry *spell) - { - if(spell->Mechanic == MECHANIC_DISARM) - { - DoYell(SAY_DISARMED, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DISARMED); - } - } -}; - -void boss_midnightAI::SetMidnight(Creature *pAttumen, uint64 value) -{ - ((boss_attumenAI*)pAttumen->AI())->Midnight = value; -} - -CreatureAI* GetAI_boss_attumen(Creature *_Creature) -{ - return new boss_attumenAI (_Creature); -} - -void AddSC_boss_attumen() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_attumen"; - newscript->GetAI = GetAI_boss_attumen; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_midnight"; - newscript->GetAI = GetAI_boss_midnight; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Midnight +SD%Complete: 100 +SDComment: +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" + +#define SAY_MIDNIGHT_KILL "Well done Midnight!" +#define SOUND_MIDNIGHT_KILL 9173 + +#define SAY_APPEAR1 "Cowards! Wretches!" +#define SOUND_APPEAR1 9167 +#define SAY_APPEAR2 "Who dares attack the steed of the Huntsman?" +#define SOUND_APPEAR2 9298 +#define SAY_APPEAR3 "Perhaps you would rather test yourselves against a more formidable opponent?! " +#define SOUND_APPEAR3 9299 + +#define SAY_MOUNT "Come, Midnight, let\'s disperse this petty rabble! " +#define SOUND_MOUNT 9168 + +#define SAY_KILL1 "It was... inevitable." +#define SOUND_KILL1 9169 +#define SAY_KILL2 "Another trophy to add to my collection!" +#define SOUND_KILL2 9300 + +#define SAY_DISARMED "Weapons are merely a convenience for a warrior of my skill!" +#define SOUND_DISARMED 9166 + +#define SAY_DEATH "I always knew... someday I would become... the hunted." +#define SOUND_DEATH 9165 + +#define SAY_RANDOM1 "Such easy sport." +#define SOUND_RANDOM1 9170 +#define SAY_RANDOM2 "Amateurs! Do not think you can best me! I kill for a living." +#define SOUND_RANDOM2 9304 + +#define SPELL_SHADOWCLEAVE 29832 +#define SPELL_INTANGIBLE_PRESENCE 29833 +#define SPELL_BERSERKER_CHARGE 26561 //Only when mounted + +#define MOUNTED_DISPLAYID 16040 + +//Attumen (TODO: Use the summoning spell instead of creature id. It works , but is not convenient for us) +#define SUMMON_ATTUMEN 15550 + +struct MANGOS_DLL_DECL boss_midnightAI : public ScriptedAI +{ + boss_midnightAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 Attumen; + uint8 Phase; + uint32 Mount_Timer; + + void Reset() + { + Phase = 1; + Attumen = 0; + Mount_Timer = 0; + + m_creature->SetVisibility(VISIBILITY_ON); + } + + void Aggro(Unit* who) {} + + void KilledUnit(Unit *victim) + { + if(Phase == 2) + { + Unit *pUnit = Unit::GetUnit(*m_creature, Attumen); + if(pUnit) + { + pUnit->MonsterYell(SAY_MIDNIGHT_KILL, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(pUnit, SOUND_MIDNIGHT_KILL); + } + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(Phase == 1 && (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 95) + { + Phase = 2; + Creature *pAttumen = DoSpawnCreature(SUMMON_ATTUMEN, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); + if(pAttumen) + { + Attumen = pAttumen->GetGUID(); + pAttumen->AI()->AttackStart(m_creature->getVictim()); + SetMidnight(pAttumen, m_creature->GetGUID()); + switch(rand()%3) + { + case 0: + pAttumen->Yell(SAY_APPEAR1, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(m_creature, SOUND_APPEAR1); + break; + case 1: + pAttumen->Yell(SAY_APPEAR2, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(m_creature, SOUND_APPEAR2); + break; + case 2: + pAttumen->Yell(SAY_APPEAR3, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(m_creature, SOUND_APPEAR3); + break; + } + } + } + else if(Phase == 2 && (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 25) + { + Unit *pAttumen = Unit::GetUnit(*m_creature, Attumen); + if(pAttumen) + Mount(pAttumen); + } + else if(Phase ==3) + { + if(Mount_Timer) + if(Mount_Timer <= diff) + { + Mount_Timer = 0; + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->GetMotionMaster()->MoveIdle(); + Unit *pAttumen = Unit::GetUnit(*m_creature, Attumen); + if(pAttumen) + { + pAttumen->SetUInt32Value(UNIT_FIELD_DISPLAYID, 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 Mount_Timer -= diff; + } + + if(Phase != 3) + DoMeleeAttackIfReady(); + } + + void Mount(Unit *pAttumen) + { + DoPlaySoundToSet(pAttumen, SOUND_MOUNT); + pAttumen->MonsterYell(SAY_MOUNT, LANG_UNIVERSAL, 0); + Phase = 3; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pAttumen->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + float angle = m_creature->GetAngle(pAttumen); + float distance = m_creature->GetDistance2d(pAttumen); + float newX = m_creature->GetPositionX() + cos(angle)*(distance/2) ; + float newY = m_creature->GetPositionY() + sin(angle)*(distance/2) ; + float newZ = 50; + //m_creature->Relocate(newX,newY,newZ,angle); + //m_creature->SendMonsterMove(newX, newY, newZ, 0, true, 1000); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(0, newX, newY, newZ); + distance += 10; + newX = m_creature->GetPositionX() + cos(angle)*(distance/2) ; + newY = m_creature->GetPositionY() + sin(angle)*(distance/2) ; + pAttumen->GetMotionMaster()->Clear(); + pAttumen->GetMotionMaster()->MovePoint(0, newX, newY, newZ); + //pAttumen->Relocate(newX,newY,newZ,-angle); + //pAttumen->SendMonsterMove(newX, newY, newZ, 0, true, 1000); + Mount_Timer = 1000; + } + + void SetMidnight(Creature *, uint64); //Below .. +}; + +CreatureAI* GetAI_boss_midnight(Creature *_Creature) +{ + return new boss_midnightAI(_Creature); +} + +struct MANGOS_DLL_DECL boss_attumenAI : public ScriptedAI +{ + boss_attumenAI(Creature *c) : ScriptedAI(c) + { + Reset(); + Phase = 1; + + CleaveTimer = 10000 + (rand()%6)*1000; + CurseTimer = 30000; + RandomYellTimer = 30000 + (rand()%31)*1000; //Occasionally yell + ChargeTimer = 20000; + ResetTimer = 0; + } + + uint64 Midnight; + uint8 Phase; + uint32 CleaveTimer; + uint32 CurseTimer; + uint32 RandomYellTimer; + uint32 ChargeTimer; //only when mounted + uint32 ResetTimer; + + void Reset() + { + ResetTimer = 2000; + } + + void Aggro(Unit* who) {} + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL1); + case 1: + DoYell(SAY_KILL2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL2); + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + Unit *pMidnight = Unit::GetUnit(*m_creature, Midnight); + if(pMidnight) + { + pMidnight->DealDamage(pMidnight, pMidnight->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + void UpdateAI(const uint32 diff) + { + if(ResetTimer) + if(ResetTimer <= diff) + { + ResetTimer = 0; + Unit *pMidnight = Unit::GetUnit(*m_creature, Midnight); + if(pMidnight) + { + pMidnight->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pMidnight->SetVisibility(VISIBILITY_ON); + } + Midnight = 0; + + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + else ResetTimer -= diff; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE )) + return; + + if(CleaveTimer < diff) + { + Unit *target = m_creature->getVictim(); + DoCast(target, SPELL_SHADOWCLEAVE); + CleaveTimer = 10000 + (rand()%6)*1000; + } else CleaveTimer -= diff; + + if(CurseTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_INTANGIBLE_PRESENCE); + CurseTimer = 30000; + } else CurseTimer -= diff; + + if(RandomYellTimer < diff) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_RANDOM1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_RANDOM1); + break; + case 1: + DoYell(SAY_RANDOM2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_RANDOM2); + break; + } + RandomYellTimer = 30000 + (rand()%31)*1000; + } else RandomYellTimer -= diff; + + if(m_creature->GetUInt32Value(UNIT_FIELD_DISPLAYID) == MOUNTED_DISPLAYID) + { + if(ChargeTimer < diff) + { + Unit *target; + std::list t_list = m_creature->getThreatManager().getThreatList(); + std::vector target_list; + for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + if(target && target->GetDistance2d(m_creature) > 5) + target_list.push_back(target); + target = NULL; + } + if(target_list.size()) + target = *(target_list.begin()+rand()%target_list.size()); + + DoCast(target, SPELL_BERSERKER_CHARGE); + ChargeTimer = 20000; + } else ChargeTimer -= diff; + } + else + { + if( (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 25) + { + Creature *pMidnight = (Creature*)Unit::GetUnit(*m_creature, Midnight); + if(pMidnight && pMidnight->GetTypeId() == TYPEID_UNIT) + { + ((boss_midnightAI*)(pMidnight->AI()))->Mount(m_creature); + m_creature->SetHealth(pMidnight->GetHealth()); + } + } + } + + DoMeleeAttackIfReady(); + } + + void SpellHit(Unit *source, const SpellEntry *spell) + { + if(spell->Mechanic == MECHANIC_DISARM) + { + DoYell(SAY_DISARMED, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DISARMED); + } + } +}; + +void boss_midnightAI::SetMidnight(Creature *pAttumen, uint64 value) +{ + ((boss_attumenAI*)pAttumen->AI())->Midnight = value; +} + +CreatureAI* GetAI_boss_attumen(Creature *_Creature) +{ + return new boss_attumenAI (_Creature); +} + +void AddSC_boss_attumen() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_attumen"; + newscript->GetAI = GetAI_boss_attumen; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_midnight"; + newscript->GetAI = GetAI_boss_midnight; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_moroes.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_moroes.cpp index 538de015315..1e90ff0c8a7 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_moroes.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_moroes.cpp @@ -1,868 +1,868 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Moroes -SD%Complete: 100 -SDComment: -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" -#include "def_karazhan.h" - -#define SAY_AGGRO "Hmm, unannounced visitors? Preparations must be made." -#define SOUND_AGGRO 9211 - -#define SAY_SPECIAL_1 "Now, where was I? Oh yes..." -#define SOUND_SPECIAL_1 9215 - -#define SAY_SPECIAL_2 "You rang?" -#define SOUND_SPECIAL_2 9316 - -#define SAY_KILL_1 "One more for dinner this evening" -#define SOUND_KILL_1 9214 - -#define SAY_KILL_2 "Time... Never enough time." -#define SOUND_KILL_2 9314 - -#define SAY_KILL_3 "I've gone and made a mess." -#define SOUND_KILL_3 9315 - -#define SAY_DEATH "How terribly clumsy of me..." -#define SOUND_DEATH 9213 - -#define SPELL_VANISH 24699 -#define SPELL_GARROTE 37066 -#define SPELL_BLIND 34654 -#define SPELL_GOUGE 28456 -#define SPELL_ENRAGE 37023 - -#define ORIENT 4.5784 -#define POS_Z 81.73 - -float Locations[4][2]= -{ - {-10976.2793, -1878.1736}, - {-10979.7587, -1877.8706}, - {-10985.6650, -1877.2458}, - {-10989.1367, -1876.8309}, -}; - -const uint32 Adds[6]= -{ - 17007, - 19872, - 19873, - 19874, - 19875, - 19876, -}; - -struct MANGOS_DLL_DECL boss_moroesAI : public ScriptedAI -{ - boss_moroesAI(Creature *c) : ScriptedAI(c) - { - FirstTime = true; - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint64 AddGUID[4]; - - uint32 Vanish_Timer; - uint32 Blind_Timer; - uint32 Gouge_Timer; - uint32 Wait_Timer; - uint32 CheckAdds_Timer; - uint32 AddId[4]; - - bool FirstTime; - bool InVanish; - bool Enrage; - - void Reset() - { - Vanish_Timer = 30000; - Blind_Timer = 35000; - Gouge_Timer = 23000; - Wait_Timer = 0; - CheckAdds_Timer = 5000; - - Enrage = false; - InVanish = 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(pInstance) - pInstance->SetData(DATA_MOROES_EVENT, NOT_STARTED); - } - - void StartEvent() - { - if(!pInstance) - return; - - if(pInstance) - pInstance->SetData(DATA_MOROES_EVENT, IN_PROGRESS); - } - - void Aggro(Unit* who) - { - StartEvent(); - - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - AddsAttack(); - } - - void KilledUnit(Unit* victim) - { - switch (rand()%3) - { - case 0: - DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL_2); - break; - case 2: - DoYell(SAY_KILL_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL_3); - break; - } - } - - void JustDied(Unit* victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if(pInstance) - pInstance->SetData(DATA_MOROES_EVENT, DONE); - - DeSpawnAdds(); - } - - uint8 CheckAdd(uint64 guid) - { - Unit* pUnit = Unit::GetUnit((*m_creature), guid); - if(pUnit) - { - if(!pUnit->isAlive()) - return 1; // Exists but is dead - else - return 2; // Exists and is alive - } - - return 0; // Does not exist - } - - void SpawnAdds() - { - Creature *pCreature = NULL; - - if(FirstTime) - { - std::vector AddList; - - for(uint8 i = 0; i < 6; ++i) - AddList.push_back(Adds[i]); - - while(AddList.size() > 4) - AddList.erase((AddList.begin())+(rand()%AddList.size())); - - uint8 j = 0; - for(std::vector::iterator itr = AddList.begin(); itr != AddList.end(); ++itr) - { - uint32 entry = *itr; - - pCreature = m_creature->SummonCreature(entry, Locations[j][0], Locations[j][1], POS_Z, ORIENT, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); - if(pCreature) - { - AddGUID[j] = pCreature->GetGUID(); - AddId[j] = entry; - } - ++j; - } - - FirstTime = false; - } - else - { - for(uint8 i = 0; i < 5; ++i) - { - switch(CheckAdd(AddGUID[i])) - { - case 0: - pCreature = m_creature->SummonCreature(AddId[i], Locations[i][0], Locations[i][1], POS_Z, ORIENT, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); - if(pCreature) - AddGUID[i] = pCreature->GetGUID(); - break; - case 1: - pCreature = ((Creature*)Unit::GetUnit((*m_creature), AddGUID[i])); - if(pCreature) - { - pCreature->Respawn(); - pCreature->AI()->EnterEvadeMode(); - } - break; - case 2: - pCreature = ((Creature*)Unit::GetUnit((*m_creature), AddGUID[i])); - if(!pCreature->IsInEvadeMode()) - pCreature->AI()->EnterEvadeMode(); - break; - } - } - } - } - - void DeSpawnAdds() - { - for(uint8 i = 0; i < 4 ; ++i) - { - Unit* Temp = NULL; - if(AddGUID[i]) - { - Temp = Unit::GetUnit((*m_creature),AddGUID[i]); - if(Temp && Temp->isAlive()) - Temp->DealDamage(Temp, Temp->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - } - } - - void AddsAttack() - { - for(uint8 i = 0; i < 4; ++i) - { - Unit* Temp = NULL; - if(AddGUID[i]) - { - Temp = Unit::GetUnit((*m_creature),AddGUID[i]); - if(Temp && Temp->isAlive()) - ((Creature*)Temp)->AI()->AttackStart(m_creature->getVictim()); - else - EnterEvadeMode(); - } - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(pInstance && !pInstance->GetData(DATA_MOROES_EVENT)) - EnterEvadeMode(); - - if(!Enrage && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30) - { - DoCast(m_creature, SPELL_ENRAGE); - Enrage = true; - } - - if(CheckAdds_Timer < diff) - { - for(uint8 i = 0; i < 4; ++i) - { - Unit* Temp = NULL; - if(AddGUID[i]) - { - Temp = Unit::GetUnit((*m_creature),AddGUID[i]); - if(Temp && Temp->isAlive()) - if(!Temp->SelectHostilTarget() || !Temp->getVictim() ) - ((Creature*)Temp)->AI()->AttackStart(m_creature->getVictim()); - } - } - CheckAdds_Timer = 5000; - }else CheckAdds_Timer -= diff; - - //Cast Vanish, then Garrote random victim - if(Vanish_Timer < diff) - { - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoCast(m_creature, SPELL_VANISH); - InVanish = true; - Vanish_Timer = 30000; - Wait_Timer = 5000; - }else Vanish_Timer -= diff; - - if(InVanish) - { - if(Wait_Timer < diff) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SPECIAL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SPECIAL_1); - break; - case 1: - DoYell(SAY_SPECIAL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SPECIAL_2); - break; - } - - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - target->CastSpell(target, 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()); - InVanish = false; - }else Wait_Timer -= diff; - } - - //Blind highest aggro, and attack second highest - if(Gouge_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_GOUGE); - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); - Gouge_Timer = 40000; - }else Gouge_Timer -= diff; - - if(Blind_Timer < diff) - { - Unit* target = NULL; - std::list t_list = m_creature->getThreatManager().getThreatList(); - - if(t_list.empty()) - return; - - std::vector target_list; - for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - if(target && target->GetDistance2d(m_creature) < 5) - target_list.push_back(target); - } - if(target_list.size()) - target = *(target_list.begin()+rand()%target_list.size()); - - if(target) - DoCast(target, SPELL_BLIND); - - Blind_Timer = 40000; - }else Blind_Timer -= diff; - - if(!InVanish) - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_moroes_guestAI : public ScriptedAI -{ - ScriptedInstance* pInstance; - - uint64 GuestGUID[4]; - - boss_moroes_guestAI(Creature* c) : ScriptedAI(c) - { - for(uint8 i = 0; i < 4; ++i) - GuestGUID[i] = 0; - - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - void Reset() - { - if(pInstance) - pInstance->SetData(DATA_MOROES_EVENT, NOT_STARTED); - } - - void Aggro(Unit* who) {} - - void AcquireGUID() - { - if(!pInstance) - return; - - GuestGUID[0] = pInstance->GetData64(DATA_MOROES); - Creature* Moroes = ((Creature*)Unit::GetUnit((*m_creature), GuestGUID[0])); - if(Moroes) - { - for(uint8 i = 0; i < 3; ++i) - { - uint64 GUID = ((boss_moroesAI*)Moroes->AI())->AddGUID[i]; - if(GUID && GUID != m_creature->GetGUID()) - GuestGUID[i+1] = GUID; - } - } - } - - Unit* SelectTarget() - { - uint64 TempGUID = GuestGUID[rand()%5]; - if(TempGUID) - { - Unit* pUnit = Unit::GetUnit((*m_creature), TempGUID); - if(pUnit && pUnit->isAlive()) - return pUnit; - } - - return m_creature; - } - - void UpdateAI(const uint32 diff) - { - if(pInstance && !pInstance->GetData(DATA_MOROES_EVENT)) - EnterEvadeMode(); - - DoMeleeAttackIfReady(); - } -}; - -#define SPELL_MANABURN 29405 -#define SPELL_MINDFLY 29570 -#define SPELL_SWPAIN 34441 -#define SPELL_SHADOWFORM 29406 - -struct MANGOS_DLL_DECL boss_baroness_dorothea_millstipeAI : public boss_moroes_guestAI -{ - //Shadow Priest - boss_baroness_dorothea_millstipeAI(Creature *c) : boss_moroes_guestAI(c) {} - - uint32 ManaBurn_Timer; - uint32 MindFlay_Timer; - uint32 ShadowWordPain_Timer; - - void Reset() - { - ManaBurn_Timer = 7000; - MindFlay_Timer = 1000; - ShadowWordPain_Timer = 6000; - - DoCast(m_creature,SPELL_SHADOWFORM, true); - - boss_moroes_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_moroes_guestAI::UpdateAI(diff); - - if(MindFlay_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MINDFLY); - MindFlay_Timer = 12000; //3sec channeled - }else MindFlay_Timer -= diff; - - if(ManaBurn_Timer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target && (target->getPowerType() == POWER_MANA)) - DoCast(target,SPELL_MANABURN); - ManaBurn_Timer = 5000; //3 sec cast - }else ManaBurn_Timer -= diff; - - if(ShadowWordPain_Timer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - DoCast(target,SPELL_SWPAIN); - ShadowWordPain_Timer = 7000; - } - }else ShadowWordPain_Timer -= diff; - } -}; - -#define SPELL_HAMMEROFJUSTICE 13005 -#define SPELL_JUDGEMENTOFCOMMAND 29386 -#define SPELL_SEALOFCOMMAND 29385 - -struct MANGOS_DLL_DECL boss_baron_rafe_dreugerAI : public boss_moroes_guestAI -{ - //Retr Pally - boss_baron_rafe_dreugerAI(Creature *c) : boss_moroes_guestAI(c){} - - uint32 HammerOfJustice_Timer; - uint32 SealOfCommand_Timer; - uint32 JudgementOfCommand_Timer; - - void Reset() - { - HammerOfJustice_Timer = 1000; - SealOfCommand_Timer = 7000; - JudgementOfCommand_Timer = SealOfCommand_Timer + 29000; - - boss_moroes_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_moroes_guestAI::UpdateAI(diff); - - if(SealOfCommand_Timer < diff) - { - DoCast(m_creature,SPELL_SEALOFCOMMAND); - SealOfCommand_Timer = 32000; - JudgementOfCommand_Timer = 29000; - }else SealOfCommand_Timer -= diff; - - if(JudgementOfCommand_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_JUDGEMENTOFCOMMAND); - JudgementOfCommand_Timer = SealOfCommand_Timer + 29000; - }else JudgementOfCommand_Timer -= diff; - - if(HammerOfJustice_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE); - HammerOfJustice_Timer = 12000; - }else HammerOfJustice_Timer -= diff; - } -}; - -#define SPELL_DISPELMAGIC 15090 //Self or other guest+Moroes -#define SPELL_GREATERHEAL 29564 //Self or other guest+Moroes -#define SPELL_HOLYFIRE 29563 -#define SPELL_PWSHIELD 29408 - -struct MANGOS_DLL_DECL boss_lady_catriona_von_indiAI : public boss_moroes_guestAI -{ - //Holy Priest - boss_lady_catriona_von_indiAI(Creature *c) : boss_moroes_guestAI(c) {} - - uint32 DispelMagic_Timer; - uint32 GreaterHeal_Timer; - uint32 HolyFire_Timer; - uint32 PowerWordShield_Timer; - - void Reset() - { - DispelMagic_Timer = 11000; - GreaterHeal_Timer = 1500; - HolyFire_Timer = 5000; - PowerWordShield_Timer = 1000; - - AcquireGUID(); - - boss_moroes_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_moroes_guestAI::UpdateAI(diff); - - if(PowerWordShield_Timer < diff) - { - DoCast(m_creature,SPELL_PWSHIELD); - PowerWordShield_Timer = 15000; - }else PowerWordShield_Timer -= diff; - - if(GreaterHeal_Timer < diff) - { - Unit* target = SelectTarget(); - - DoCast(target, SPELL_GREATERHEAL); - GreaterHeal_Timer = 17000; - }else GreaterHeal_Timer -= diff; - - if(HolyFire_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HOLYFIRE); - HolyFire_Timer = 22000; - }else HolyFire_Timer -= diff; - - if(DispelMagic_Timer < diff) - { - if(rand()%2) - { - Unit* target = SelectTarget(); - - DoCast(target, SPELL_DISPELMAGIC); - } - else - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DISPELMAGIC); - - DispelMagic_Timer = 25000; - }else DispelMagic_Timer -= diff; - } -}; - -#define SPELL_CLEANSE 29380 //Self or other guest+Moroes -#define SPELL_GREATERBLESSOFMIGHT 29381 //Self or other guest+Moroes -#define SPELL_HOLYLIGHT 29562 //Self or other guest+Moroes -#define SPELL_DIVINESHIELD 41367 - -struct MANGOS_DLL_DECL boss_lady_keira_berrybuckAI : public boss_moroes_guestAI -{ - //Holy Pally - boss_lady_keira_berrybuckAI(Creature *c) : boss_moroes_guestAI(c) {} - - uint32 Cleanse_Timer; - uint32 GreaterBless_Timer; - uint32 HolyLight_Timer; - uint32 DivineShield_Timer; - - void Reset() - { - Cleanse_Timer = 13000; - GreaterBless_Timer = 1000; - HolyLight_Timer = 7000; - DivineShield_Timer = 31000; - - AcquireGUID(); - - boss_moroes_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_moroes_guestAI::UpdateAI(diff); - - if(DivineShield_Timer < diff) - { - DoCast(m_creature,SPELL_DIVINESHIELD); - DivineShield_Timer = 31000; - }else DivineShield_Timer -= diff; - - if(HolyLight_Timer < diff) - { - Unit* target = SelectTarget(); - - DoCast(target, SPELL_HOLYLIGHT); - HolyLight_Timer = 10000; - }else HolyLight_Timer -= diff; - - if(GreaterBless_Timer < diff) - { - Unit* target = SelectTarget(); - - DoCast(target, SPELL_GREATERBLESSOFMIGHT); - - GreaterBless_Timer = 50000; - }else GreaterBless_Timer -= diff; - - if(Cleanse_Timer < diff) - { - Unit* target = SelectTarget(); - - DoCast(target, SPELL_CLEANSE); - - Cleanse_Timer = 10000; - }else Cleanse_Timer -= diff; - } -}; - -#define SPELL_HAMSTRING 9080 -#define SPELL_MORTALSTRIKE 29572 -#define SPELL_WHIRLWIND 29573 - -struct MANGOS_DLL_DECL boss_lord_robin_darisAI : public boss_moroes_guestAI -{ - //Arms Warr - boss_lord_robin_darisAI(Creature *c) : boss_moroes_guestAI(c) {} - - uint32 Hamstring_Timer; - uint32 MortalStrike_Timer; - uint32 WhirlWind_Timer; - - void Reset() - { - Hamstring_Timer = 7000; - MortalStrike_Timer = 10000; - WhirlWind_Timer = 21000; - - boss_moroes_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_moroes_guestAI::UpdateAI(diff); - - if(Hamstring_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMSTRING); - Hamstring_Timer = 12000; - }else Hamstring_Timer -= diff; - - if(MortalStrike_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_MORTALSTRIKE); - MortalStrike_Timer = 18000; - }else MortalStrike_Timer -= diff; - - if(WhirlWind_Timer < diff) - { - DoCast(m_creature,SPELL_WHIRLWIND); - WhirlWind_Timer = 21000; - }else WhirlWind_Timer -= diff; - } -}; - -#define SPELL_DISARM 8379 -#define SPELL_HEROICSTRIKE 29567 -#define SPELL_SHIELDBASH 11972 -#define SPELL_SHIELDWALL 29390 - -struct MANGOS_DLL_DECL boss_lord_crispin_ferenceAI : public boss_moroes_guestAI -{ - //Arms Warr - boss_lord_crispin_ferenceAI(Creature *c) : boss_moroes_guestAI(c) {} - - uint32 Disarm_Timer; - uint32 HeroicStrike_Timer; - uint32 ShieldBash_Timer; - uint32 ShieldWall_Timer; - - void Reset() - { - Disarm_Timer = 6000; - HeroicStrike_Timer = 10000; - ShieldBash_Timer = 8000; - ShieldWall_Timer = 4000; - - boss_moroes_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_moroes_guestAI::UpdateAI(diff); - - if(Disarm_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DISARM); - Disarm_Timer = 12000; - }else Disarm_Timer -= diff; - - if(HeroicStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HEROICSTRIKE); - HeroicStrike_Timer = 10000; - }else HeroicStrike_Timer -= diff; - - if(ShieldBash_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHIELDBASH); - ShieldBash_Timer = 13000; - }else ShieldBash_Timer -= diff; - - if(ShieldWall_Timer < diff) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall_Timer = 21000; - }else ShieldWall_Timer -= diff; - } -}; - -CreatureAI* GetAI_boss_moroes(Creature *_Creature) -{ - return new boss_moroesAI (_Creature); -} - -CreatureAI* GetAI_baroness_dorothea_millstipe(Creature *_Creature) -{ - return new boss_baroness_dorothea_millstipeAI (_Creature); -} - -CreatureAI* GetAI_baron_rafe_dreuger(Creature *_Creature) -{ - return new boss_baron_rafe_dreugerAI (_Creature); -} - -CreatureAI* GetAI_lady_catriona_von_indi(Creature *_Creature) -{ - return new boss_lady_catriona_von_indiAI (_Creature); -} - -CreatureAI* GetAI_lady_keira_berrybuck(Creature *_Creature) -{ - return new boss_lady_keira_berrybuckAI (_Creature); -} - -CreatureAI* GetAI_lord_robin_daris(Creature *_Creature) -{ - return new boss_lord_robin_darisAI (_Creature); -} - -CreatureAI* GetAI_lord_crispin_ference(Creature *_Creature) -{ - return new boss_lord_crispin_ferenceAI (_Creature); -} - -void AddSC_boss_moroes() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_moroes"; - newscript->GetAI = GetAI_boss_moroes; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_baroness_dorothea_millstipe"; - newscript->GetAI = GetAI_baroness_dorothea_millstipe; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_baron_rafe_dreuger"; - newscript->GetAI = GetAI_baron_rafe_dreuger; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_lady_catriona_von_indi"; - newscript->GetAI = GetAI_lady_catriona_von_indi; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_lady_keira_berrybuck"; - newscript->GetAI = GetAI_lady_keira_berrybuck; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_lord_robin_daris"; - newscript->GetAI = GetAI_lord_robin_daris; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_lord_crispin_ference"; - newscript->GetAI = GetAI_lord_crispin_ference; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Moroes +SD%Complete: 100 +SDComment: +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" +#include "def_karazhan.h" + +#define SAY_AGGRO "Hmm, unannounced visitors? Preparations must be made." +#define SOUND_AGGRO 9211 + +#define SAY_SPECIAL_1 "Now, where was I? Oh yes..." +#define SOUND_SPECIAL_1 9215 + +#define SAY_SPECIAL_2 "You rang?" +#define SOUND_SPECIAL_2 9316 + +#define SAY_KILL_1 "One more for dinner this evening" +#define SOUND_KILL_1 9214 + +#define SAY_KILL_2 "Time... Never enough time." +#define SOUND_KILL_2 9314 + +#define SAY_KILL_3 "I've gone and made a mess." +#define SOUND_KILL_3 9315 + +#define SAY_DEATH "How terribly clumsy of me..." +#define SOUND_DEATH 9213 + +#define SPELL_VANISH 24699 +#define SPELL_GARROTE 37066 +#define SPELL_BLIND 34654 +#define SPELL_GOUGE 28456 +#define SPELL_ENRAGE 37023 + +#define ORIENT 4.5784 +#define POS_Z 81.73 + +float Locations[4][2]= +{ + {-10976.2793, -1878.1736}, + {-10979.7587, -1877.8706}, + {-10985.6650, -1877.2458}, + {-10989.1367, -1876.8309}, +}; + +const uint32 Adds[6]= +{ + 17007, + 19872, + 19873, + 19874, + 19875, + 19876, +}; + +struct MANGOS_DLL_DECL boss_moroesAI : public ScriptedAI +{ + boss_moroesAI(Creature *c) : ScriptedAI(c) + { + FirstTime = true; + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint64 AddGUID[4]; + + uint32 Vanish_Timer; + uint32 Blind_Timer; + uint32 Gouge_Timer; + uint32 Wait_Timer; + uint32 CheckAdds_Timer; + uint32 AddId[4]; + + bool FirstTime; + bool InVanish; + bool Enrage; + + void Reset() + { + Vanish_Timer = 30000; + Blind_Timer = 35000; + Gouge_Timer = 23000; + Wait_Timer = 0; + CheckAdds_Timer = 5000; + + Enrage = false; + InVanish = 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(pInstance) + pInstance->SetData(DATA_MOROES_EVENT, NOT_STARTED); + } + + void StartEvent() + { + if(!pInstance) + return; + + if(pInstance) + pInstance->SetData(DATA_MOROES_EVENT, IN_PROGRESS); + } + + void Aggro(Unit* who) + { + StartEvent(); + + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + AddsAttack(); + } + + void KilledUnit(Unit* victim) + { + switch (rand()%3) + { + case 0: + DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL_2); + break; + case 2: + DoYell(SAY_KILL_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL_3); + break; + } + } + + void JustDied(Unit* victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if(pInstance) + pInstance->SetData(DATA_MOROES_EVENT, DONE); + + DeSpawnAdds(); + } + + uint8 CheckAdd(uint64 guid) + { + Unit* pUnit = Unit::GetUnit((*m_creature), guid); + if(pUnit) + { + if(!pUnit->isAlive()) + return 1; // Exists but is dead + else + return 2; // Exists and is alive + } + + return 0; // Does not exist + } + + void SpawnAdds() + { + Creature *pCreature = NULL; + + if(FirstTime) + { + std::vector AddList; + + for(uint8 i = 0; i < 6; ++i) + AddList.push_back(Adds[i]); + + while(AddList.size() > 4) + AddList.erase((AddList.begin())+(rand()%AddList.size())); + + uint8 i = 0; + for(std::vector::iterator itr = AddList.begin(); itr != AddList.end(); ++itr) + { + uint32 entry = *itr; + + pCreature = m_creature->SummonCreature(entry, Locations[i][0], Locations[i][1], POS_Z, ORIENT, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + if(pCreature) + { + AddGUID[i] = pCreature->GetGUID(); + AddId[i] = entry; + } + ++i; + } + + FirstTime = false; + } + else + { + for(uint8 i = 0; i < 5; ++i) + { + switch(CheckAdd(AddGUID[i])) + { + case 0: + pCreature = m_creature->SummonCreature(AddId[i], Locations[i][0], Locations[i][1], POS_Z, ORIENT, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + if(pCreature) + AddGUID[i] = pCreature->GetGUID(); + break; + case 1: + pCreature = ((Creature*)Unit::GetUnit((*m_creature), AddGUID[i])); + if(pCreature) + { + pCreature->Respawn(); + pCreature->AI()->EnterEvadeMode(); + } + break; + case 2: + pCreature = ((Creature*)Unit::GetUnit((*m_creature), AddGUID[i])); + if(!pCreature->IsInEvadeMode()) + pCreature->AI()->EnterEvadeMode(); + break; + } + } + } + } + + void DeSpawnAdds() + { + for(uint8 i = 0; i < 4 ; ++i) + { + Unit* Temp = NULL; + if(AddGUID[i]) + { + Temp = Unit::GetUnit((*m_creature),AddGUID[i]); + if(Temp && Temp->isAlive()) + Temp->DealDamage(Temp, Temp->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + } + + void AddsAttack() + { + for(uint8 i = 0; i < 4; ++i) + { + Unit* Temp = NULL; + if(AddGUID[i]) + { + Temp = Unit::GetUnit((*m_creature),AddGUID[i]); + if(Temp && Temp->isAlive()) + ((Creature*)Temp)->AI()->AttackStart(m_creature->getVictim()); + else + EnterEvadeMode(); + } + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(pInstance && !pInstance->GetData(DATA_MOROES_EVENT)) + EnterEvadeMode(); + + if(!Enrage && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30) + { + DoCast(m_creature, SPELL_ENRAGE); + Enrage = true; + } + + if(CheckAdds_Timer < diff) + { + for(uint8 i = 0; i < 4; ++i) + { + Unit* Temp = NULL; + if(AddGUID[i]) + { + Temp = Unit::GetUnit((*m_creature),AddGUID[i]); + if(Temp && Temp->isAlive()) + if(!Temp->SelectHostilTarget() || !Temp->getVictim() ) + ((Creature*)Temp)->AI()->AttackStart(m_creature->getVictim()); + } + } + CheckAdds_Timer = 5000; + }else CheckAdds_Timer -= diff; + + //Cast Vanish, then Garrote random victim + if(Vanish_Timer < diff) + { + m_creature->setFaction(35); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoCast(m_creature, SPELL_VANISH); + InVanish = true; + Vanish_Timer = 30000; + Wait_Timer = 5000; + }else Vanish_Timer -= diff; + + if(InVanish) + { + if(Wait_Timer < diff) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SPECIAL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SPECIAL_1); + break; + case 1: + DoYell(SAY_SPECIAL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SPECIAL_2); + break; + } + + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + target->CastSpell(target, 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()); + InVanish = false; + }else Wait_Timer -= diff; + } + + //Blind highest aggro, and attack second highest + if(Gouge_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_GOUGE); + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); + Gouge_Timer = 40000; + }else Gouge_Timer -= diff; + + if(Blind_Timer < diff) + { + Unit* target = NULL; + std::list t_list = m_creature->getThreatManager().getThreatList(); + + if(t_list.empty()) + return; + + std::vector target_list; + for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + if(target && target->GetDistance2d(m_creature) < 5) + target_list.push_back(target); + } + if(target_list.size()) + target = *(target_list.begin()+rand()%target_list.size()); + + if(target) + DoCast(target, SPELL_BLIND); + + Blind_Timer = 40000; + }else Blind_Timer -= diff; + + if(!InVanish) + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_moroes_guestAI : public ScriptedAI +{ + ScriptedInstance* pInstance; + + uint64 GuestGUID[4]; + + boss_moroes_guestAI(Creature* c) : ScriptedAI(c) + { + for(uint8 i = 0; i < 4; ++i) + GuestGUID[i] = 0; + + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + void Reset() + { + if(pInstance) + pInstance->SetData(DATA_MOROES_EVENT, NOT_STARTED); + } + + void Aggro(Unit* who) {} + + void AcquireGUID() + { + if(!pInstance) + return; + + GuestGUID[0] = pInstance->GetData64(DATA_MOROES); + Creature* Moroes = ((Creature*)Unit::GetUnit((*m_creature), GuestGUID[0])); + if(Moroes) + { + for(uint8 i = 0; i < 3; ++i) + { + uint64 GUID = ((boss_moroesAI*)Moroes->AI())->AddGUID[i]; + if(GUID && GUID != m_creature->GetGUID()) + GuestGUID[i+1] = GUID; + } + } + } + + Unit* SelectTarget() + { + uint64 TempGUID = GuestGUID[rand()%5]; + if(TempGUID) + { + Unit* pUnit = Unit::GetUnit((*m_creature), TempGUID); + if(pUnit && pUnit->isAlive()) + return pUnit; + } + + return m_creature; + } + + void UpdateAI(const uint32 diff) + { + if(pInstance && !pInstance->GetData(DATA_MOROES_EVENT)) + EnterEvadeMode(); + + DoMeleeAttackIfReady(); + } +}; + +#define SPELL_MANABURN 29405 +#define SPELL_MINDFLY 29570 +#define SPELL_SWPAIN 34441 +#define SPELL_SHADOWFORM 29406 + +struct MANGOS_DLL_DECL boss_baroness_dorothea_millstipeAI : public boss_moroes_guestAI +{ + //Shadow Priest + boss_baroness_dorothea_millstipeAI(Creature *c) : boss_moroes_guestAI(c) {} + + uint32 ManaBurn_Timer; + uint32 MindFlay_Timer; + uint32 ShadowWordPain_Timer; + + void Reset() + { + ManaBurn_Timer = 7000; + MindFlay_Timer = 1000; + ShadowWordPain_Timer = 6000; + + DoCast(m_creature,SPELL_SHADOWFORM, true); + + boss_moroes_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_moroes_guestAI::UpdateAI(diff); + + if(MindFlay_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MINDFLY); + MindFlay_Timer = 12000; //3sec channeled + }else MindFlay_Timer -= diff; + + if(ManaBurn_Timer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target && (target->getPowerType() == POWER_MANA)) + DoCast(target,SPELL_MANABURN); + ManaBurn_Timer = 5000; //3 sec cast + }else ManaBurn_Timer -= diff; + + if(ShadowWordPain_Timer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + DoCast(target,SPELL_SWPAIN); + ShadowWordPain_Timer = 7000; + } + }else ShadowWordPain_Timer -= diff; + } +}; + +#define SPELL_HAMMEROFJUSTICE 13005 +#define SPELL_JUDGEMENTOFCOMMAND 29386 +#define SPELL_SEALOFCOMMAND 29385 + +struct MANGOS_DLL_DECL boss_baron_rafe_dreugerAI : public boss_moroes_guestAI +{ + //Retr Pally + boss_baron_rafe_dreugerAI(Creature *c) : boss_moroes_guestAI(c){} + + uint32 HammerOfJustice_Timer; + uint32 SealOfCommand_Timer; + uint32 JudgementOfCommand_Timer; + + void Reset() + { + HammerOfJustice_Timer = 1000; + SealOfCommand_Timer = 7000; + JudgementOfCommand_Timer = SealOfCommand_Timer + 29000; + + boss_moroes_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_moroes_guestAI::UpdateAI(diff); + + if(SealOfCommand_Timer < diff) + { + DoCast(m_creature,SPELL_SEALOFCOMMAND); + SealOfCommand_Timer = 32000; + JudgementOfCommand_Timer = 29000; + }else SealOfCommand_Timer -= diff; + + if(JudgementOfCommand_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_JUDGEMENTOFCOMMAND); + JudgementOfCommand_Timer = SealOfCommand_Timer + 29000; + }else JudgementOfCommand_Timer -= diff; + + if(HammerOfJustice_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE); + HammerOfJustice_Timer = 12000; + }else HammerOfJustice_Timer -= diff; + } +}; + +#define SPELL_DISPELMAGIC 15090 //Self or other guest+Moroes +#define SPELL_GREATERHEAL 29564 //Self or other guest+Moroes +#define SPELL_HOLYFIRE 29563 +#define SPELL_PWSHIELD 29408 + +struct MANGOS_DLL_DECL boss_lady_catriona_von_indiAI : public boss_moroes_guestAI +{ + //Holy Priest + boss_lady_catriona_von_indiAI(Creature *c) : boss_moroes_guestAI(c) {} + + uint32 DispelMagic_Timer; + uint32 GreaterHeal_Timer; + uint32 HolyFire_Timer; + uint32 PowerWordShield_Timer; + + void Reset() + { + DispelMagic_Timer = 11000; + GreaterHeal_Timer = 1500; + HolyFire_Timer = 5000; + PowerWordShield_Timer = 1000; + + AcquireGUID(); + + boss_moroes_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_moroes_guestAI::UpdateAI(diff); + + if(PowerWordShield_Timer < diff) + { + DoCast(m_creature,SPELL_PWSHIELD); + PowerWordShield_Timer = 15000; + }else PowerWordShield_Timer -= diff; + + if(GreaterHeal_Timer < diff) + { + Unit* target = SelectTarget(); + + DoCast(target, SPELL_GREATERHEAL); + GreaterHeal_Timer = 17000; + }else GreaterHeal_Timer -= diff; + + if(HolyFire_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HOLYFIRE); + HolyFire_Timer = 22000; + }else HolyFire_Timer -= diff; + + if(DispelMagic_Timer < diff) + { + if(rand()%2) + { + Unit* target = SelectTarget(); + + DoCast(target, SPELL_DISPELMAGIC); + } + else + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DISPELMAGIC); + + DispelMagic_Timer = 25000; + }else DispelMagic_Timer -= diff; + } +}; + +#define SPELL_CLEANSE 29380 //Self or other guest+Moroes +#define SPELL_GREATERBLESSOFMIGHT 29381 //Self or other guest+Moroes +#define SPELL_HOLYLIGHT 29562 //Self or other guest+Moroes +#define SPELL_DIVINESHIELD 41367 + +struct MANGOS_DLL_DECL boss_lady_keira_berrybuckAI : public boss_moroes_guestAI +{ + //Holy Pally + boss_lady_keira_berrybuckAI(Creature *c) : boss_moroes_guestAI(c) {} + + uint32 Cleanse_Timer; + uint32 GreaterBless_Timer; + uint32 HolyLight_Timer; + uint32 DivineShield_Timer; + + void Reset() + { + Cleanse_Timer = 13000; + GreaterBless_Timer = 1000; + HolyLight_Timer = 7000; + DivineShield_Timer = 31000; + + AcquireGUID(); + + boss_moroes_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_moroes_guestAI::UpdateAI(diff); + + if(DivineShield_Timer < diff) + { + DoCast(m_creature,SPELL_DIVINESHIELD); + DivineShield_Timer = 31000; + }else DivineShield_Timer -= diff; + + if(HolyLight_Timer < diff) + { + Unit* target = SelectTarget(); + + DoCast(target, SPELL_HOLYLIGHT); + HolyLight_Timer = 10000; + }else HolyLight_Timer -= diff; + + if(GreaterBless_Timer < diff) + { + Unit* target = SelectTarget(); + + DoCast(target, SPELL_GREATERBLESSOFMIGHT); + + GreaterBless_Timer = 50000; + }else GreaterBless_Timer -= diff; + + if(Cleanse_Timer < diff) + { + Unit* target = SelectTarget(); + + DoCast(target, SPELL_CLEANSE); + + Cleanse_Timer = 10000; + }else Cleanse_Timer -= diff; + } +}; + +#define SPELL_HAMSTRING 9080 +#define SPELL_MORTALSTRIKE 29572 +#define SPELL_WHIRLWIND 29573 + +struct MANGOS_DLL_DECL boss_lord_robin_darisAI : public boss_moroes_guestAI +{ + //Arms Warr + boss_lord_robin_darisAI(Creature *c) : boss_moroes_guestAI(c) {} + + uint32 Hamstring_Timer; + uint32 MortalStrike_Timer; + uint32 WhirlWind_Timer; + + void Reset() + { + Hamstring_Timer = 7000; + MortalStrike_Timer = 10000; + WhirlWind_Timer = 21000; + + boss_moroes_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_moroes_guestAI::UpdateAI(diff); + + if(Hamstring_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HAMSTRING); + Hamstring_Timer = 12000; + }else Hamstring_Timer -= diff; + + if(MortalStrike_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_MORTALSTRIKE); + MortalStrike_Timer = 18000; + }else MortalStrike_Timer -= diff; + + if(WhirlWind_Timer < diff) + { + DoCast(m_creature,SPELL_WHIRLWIND); + WhirlWind_Timer = 21000; + }else WhirlWind_Timer -= diff; + } +}; + +#define SPELL_DISARM 8379 +#define SPELL_HEROICSTRIKE 29567 +#define SPELL_SHIELDBASH 11972 +#define SPELL_SHIELDWALL 29390 + +struct MANGOS_DLL_DECL boss_lord_crispin_ferenceAI : public boss_moroes_guestAI +{ + //Arms Warr + boss_lord_crispin_ferenceAI(Creature *c) : boss_moroes_guestAI(c) {} + + uint32 Disarm_Timer; + uint32 HeroicStrike_Timer; + uint32 ShieldBash_Timer; + uint32 ShieldWall_Timer; + + void Reset() + { + Disarm_Timer = 6000; + HeroicStrike_Timer = 10000; + ShieldBash_Timer = 8000; + ShieldWall_Timer = 4000; + + boss_moroes_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_moroes_guestAI::UpdateAI(diff); + + if(Disarm_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DISARM); + Disarm_Timer = 12000; + }else Disarm_Timer -= diff; + + if(HeroicStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HEROICSTRIKE); + HeroicStrike_Timer = 10000; + }else HeroicStrike_Timer -= diff; + + if(ShieldBash_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHIELDBASH); + ShieldBash_Timer = 13000; + }else ShieldBash_Timer -= diff; + + if(ShieldWall_Timer < diff) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall_Timer = 21000; + }else ShieldWall_Timer -= diff; + } +}; + +CreatureAI* GetAI_boss_moroes(Creature *_Creature) +{ + return new boss_moroesAI (_Creature); +} + +CreatureAI* GetAI_baroness_dorothea_millstipe(Creature *_Creature) +{ + return new boss_baroness_dorothea_millstipeAI (_Creature); +} + +CreatureAI* GetAI_baron_rafe_dreuger(Creature *_Creature) +{ + return new boss_baron_rafe_dreugerAI (_Creature); +} + +CreatureAI* GetAI_lady_catriona_von_indi(Creature *_Creature) +{ + return new boss_lady_catriona_von_indiAI (_Creature); +} + +CreatureAI* GetAI_lady_keira_berrybuck(Creature *_Creature) +{ + return new boss_lady_keira_berrybuckAI (_Creature); +} + +CreatureAI* GetAI_lord_robin_daris(Creature *_Creature) +{ + return new boss_lord_robin_darisAI (_Creature); +} + +CreatureAI* GetAI_lord_crispin_ference(Creature *_Creature) +{ + return new boss_lord_crispin_ferenceAI (_Creature); +} + +void AddSC_boss_moroes() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_moroes"; + newscript->GetAI = GetAI_boss_moroes; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_baroness_dorothea_millstipe"; + newscript->GetAI = GetAI_baroness_dorothea_millstipe; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_baron_rafe_dreuger"; + newscript->GetAI = GetAI_baron_rafe_dreuger; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_lady_catriona_von_indi"; + newscript->GetAI = GetAI_lady_catriona_von_indi; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_lady_keira_berrybuck"; + newscript->GetAI = GetAI_lady_keira_berrybuck; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_lord_robin_daris"; + newscript->GetAI = GetAI_lord_robin_daris; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_lord_crispin_ference"; + newscript->GetAI = GetAI_lord_crispin_ference; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_netherspite.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_netherspite.cpp index dfddad46aff..079ce619ab9 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_netherspite.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_netherspite.cpp @@ -1,37 +1,37 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Netherspite -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_NETHERBURN_AURA 30522 -#define SPELL_VOIDZONE 37014 //Probably won't work -#define SPELL_BERSERK 26662 -#define SPELL_NETHERBREATH 36631 - -//Beams (no idea how these are going to work in Mangos) -#define SPELL_DOMINANCE_ENEMY 30423 -#define SPELL_DOMINANCE_SELF 30468 -#define SPELL_PERSEVERANCE_ENEMY 30421 -#define SPELL_PERSEVERANCE_SELF 30466 -#define SPELL_SERENITY_ENEMY 30422 -#define SPELL_SERENITY_SELF 30467 +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Netherspite +SD%Complete: 0 +SDComment: Place Holder +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_NETHERBURN_AURA 30522 +#define SPELL_VOIDZONE 37014 //Probably won't work +#define SPELL_BERSERK 26662 +#define SPELL_NETHERBREATH 36631 + +//Beams (no idea how these are going to work in Mangos) +#define SPELL_DOMINANCE_ENEMY 30423 +#define SPELL_DOMINANCE_SELF 30468 +#define SPELL_PERSEVERANCE_ENEMY 30421 +#define SPELL_PERSEVERANCE_SELF 30466 +#define SPELL_SERENITY_ENEMY 30422 +#define SPELL_SERENITY_SELF 30467 diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_nightbane.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_nightbane.cpp index 8b84df3a7fd..d29e7a2a6f4 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_nightbane.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_nightbane.cpp @@ -1,33 +1,33 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Nightbane -SD%Complete: 0 -SDComment: Place holder -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_BELLOWING_ROAR 39427 -#define SPELL_CHARRED_EARTH 30129 //Also 30209 (Target Charred Earth) triggers this -#define SPELL_DISTRACTING_ASH 30130 -#define SPELL_SMOLDERING_BREATH 30210 -#define SPELL_TAIL_SWEEP 25653 -#define SPELL_RAIN_OF_BONES 37098 -#define SPELL_SMOKING_BLAST 37057 -#define SPELL_FIREBALL_BARRAGE 30282 +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Nightbane +SD%Complete: 0 +SDComment: Place holder +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_BELLOWING_ROAR 39427 +#define SPELL_CHARRED_EARTH 30129 //Also 30209 (Target Charred Earth) triggers this +#define SPELL_DISTRACTING_ASH 30130 +#define SPELL_SMOLDERING_BREATH 30210 +#define SPELL_TAIL_SWEEP 25653 +#define SPELL_RAIN_OF_BONES 37098 +#define SPELL_SMOKING_BLAST 37057 +#define SPELL_FIREBALL_BARRAGE 30282 diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_prince_malchezaar.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_prince_malchezaar.cpp index 842321cfbff..b9f24610e8c 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_prince_malchezaar.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_prince_malchezaar.cpp @@ -1,646 +1,646 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Prince_Malchezzar -SD%Complete: 100 -SDComment: -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO "Madness has brought you here to me. I shall be your undoing!" -#define SOUND_AGGRO 9218 -#define SAY_SUMMON1 "You face not Malchezaar alone, but the legions I command!" -#define SOUND_SUMMON1 9322 -#define SAY_SUMMON2 "All realities, all dimensions are open to me!" -#define SOUND_SUMMON2 9224 -#define SAY_PHASE2 "Simple fools! Time is the fire in which you'll burn!" -#define SOUND_PHASE2 9220 -#define SAY_PHASE3 "How can you hope to withstand against such overwhelming power?" -#define SOUND_PHASE3 9321 -#define SAY_PDEATH1 "You are, but a plaything, unfit even to amuse." -#define SOUND_PDEATH1 9319 -#define SAY_PDEATH2 "Your greed, your foolishness has brought you to this end." -#define SOUND_PDEATH2 9318 -#define SAY_PDEATH3 "Surely you did not think you could win." -#define SOUND_PDEATH3 9222 -#define SAY_DEATH "I refuse to concede defeat. I am a prince of the Eredar! I am..." -#define SOUND_DEATH 9221 - -// 19 Coordinates for Infernal spawns -struct InfernalPoint -{ - float x,y; -}; - -#define INFERNAL_Z 275.5 - -static InfernalPoint InfernalPoints[] = -{ - {-10922.8, -1985.2}, - {-10916.2, -1996.2}, - {-10932.2, -2008.1}, - {-10948.8, -2022.1}, - {-10958.7, -1997.7}, - {-10971.5, -1997.5}, - {-10990.8, -1995.1}, - {-10989.8, -1976.5}, - {-10971.6, -1973.0}, - {-10955.5, -1974.0}, - {-10939.6, -1969.8}, - {-10958.0, -1952.2}, - {-10941.7, -1954.8}, - {-10943.1, -1988.5}, - {-10948.8, -2005.1}, - {-10984.0, -2019.3}, - {-10932.8, -1979.6}, - {-10932.8, -1979.6}, - {-10935.7, -1996.0} -}; - -#define TOTAL_INFERNAL_POINTS 19 - -//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 3417 //Passive proc chance for thrash -#define SPELL_EQUIP_AXES 30857 //Visual for axe equiping -#define SPELL_AMPLIFY_DAMAGE 12738 //Amplifiy during phase 3 -#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 AXE_EQUIP_MODEL 40066 //Axes info -#define AXE_EQUIP_INFO 33448898 - -//---------Infernal code first -struct MANGOS_DLL_DECL netherspite_infernalAI : public ScriptedAI -{ - netherspite_infernalAI(Creature *c) : ScriptedAI(c) , - malchezaar(0), HellfireTimer(0), CleanupTimer(0), point(NULL) {Reset();} - - uint32 HellfireTimer; - uint32 CleanupTimer; - uint32 malchezaar; - InfernalPoint *point; - - void Reset() {} - void Aggro(Unit *who) {} - void MoveInLineOfSight(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(HellfireTimer) - if(HellfireTimer <= diff) - { - DoCast(m_creature, SPELL_HELLFIRE); - HellfireTimer = 0; - } - else HellfireTimer -= diff; - - if(CleanupTimer) - if(CleanupTimer <= diff) - { - Cleanup(); - CleanupTimer = 0; - } else CleanupTimer -= diff; - } - - void KilledUnit(Unit *who) - { - Unit *pMalchezaar = Unit::GetUnit(*m_creature, malchezaar); - if(pMalchezaar) - ((Creature*)pMalchezaar)->AI()->KilledUnit(who); - } - - void SpellHit(Unit *who, const SpellEntry *spell) - { - if(spell->Id == SPELL_INFERNAL_RELAY) - { - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 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 ... -}; - -struct MANGOS_DLL_DECL boss_malchezaarAI : public ScriptedAI -{ - boss_malchezaarAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 EnfeebleTimer; - uint32 EnfeebleResetTimer; - uint32 ShadowNovaTimer; - uint32 SWPainTimer; - uint32 SunderArmorTimer; - uint32 AmplifyDamageTimer; - uint32 InfernalTimer; - uint32 AxesTargetSwitchTimer; - uint32 InfernalCleanupTimer; - - std::vector infernals; - std::vector positions; - - uint64 axes[2]; - uint64 enfeeble_targets[5]; - uint64 enfeeble_health[5]; - - uint32 phase; - - void Reset() - { - AxesCleanup(); - ClearWeapons(); - InfernalCleanup(); - positions.clear(); - - for(int i =0; i < 5; ++i) - enfeeble_targets[i] = 0; - - for(int i = 0; i < TOTAL_INFERNAL_POINTS; ++i) - positions.push_back(&InfernalPoints[i]); - - EnfeebleTimer = 30000; - EnfeebleResetTimer = 38000; - ShadowNovaTimer = 35000; - SWPainTimer = 20000; - AmplifyDamageTimer = 10000; - InfernalTimer = 45000; - InfernalCleanupTimer = 47000; - AxesTargetSwitchTimer = 7500 + rand()%12500; - phase = 1; - } - - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_PDEATH1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_PDEATH1); - break; - case 1: - DoYell(SAY_PDEATH2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_PDEATH2); - break; - case 2: - DoYell(SAY_PDEATH3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_PDEATH3); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - AxesCleanup(); - ClearWeapons(); - InfernalCleanup(); - positions.clear(); - - for(int i = 0; i < TOTAL_INFERNAL_POINTS; ++i) - positions.push_back(&InfernalPoints[i]); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void InfernalCleanup() - { - //Infernal Cleanup - for(std::vector::iterator itr = infernals.begin(); itr!= infernals.end(); ++itr) - { - Unit *pInfernal = Unit::GetUnit(*m_creature, *itr); - if(pInfernal && pInfernal->isAlive()) - { - pInfernal->SetVisibility(VISIBILITY_OFF); - pInfernal->setDeathState(JUST_DIED); - } - } - infernals.clear(); - } - - void AxesCleanup() - { - for(int i=0; i<2;++i) - { - Unit *axe = Unit::GetUnit(*m_creature, 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() - { - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, 0); - - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+2, 0); - - //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); - } - - void EnfeebleHealthEffect() - { - const SpellEntry *info = GetSpellStore()->LookupEntry(SPELL_ENFEEBLE_EFFECT); - if(!info) - return; - - std::list t_list = m_creature->getThreatManager().getThreatList(); - std::vector targets; - - if(!t_list.size()) - return; - - //begin + 1 , so we don't target the one with the highest threat - std::list::iterator itr = t_list.begin(); - std::advance(itr, 1); - for( ; itr!= t_list.end(); ++itr) //store the threat list in a different container - { - Unit *target = Unit::GetUnit(*m_creature, (*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 itr = targets.begin(); itr!= targets.end(); ++itr, ++i) - { - Unit *target = *itr; - 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); - } - } - - } - - void EnfeebleResetHealth() - { - for(int i = 0; i < 5; ++i) - { - Unit *target = Unit::GetUnit(*m_creature, enfeeble_targets[i]); - if(target && target->isAlive()) - target->SetHealth(enfeeble_health[i]); - enfeeble_targets[i] = 0; - enfeeble_health[i] = 0; - } - } - - void SummonInfernal(const uint32 diff) - { - InfernalPoint *point = NULL; - float posX,posY,posZ; - if( (m_creature->GetMapId() != 532) || positions.empty()) - { - 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; - } - - Creature *Infernal = m_creature->SummonCreature(NETHERSPITE_INFERNAL, posX, posY, posZ, 0, TEMPSUMMON_TIMED_DESPAWN, 180000); - - if (Infernal) - { - Infernal->SetUInt32Value(UNIT_FIELD_DISPLAYID, INFERNAL_MODEL_INVISIBLE); - Infernal->setFaction(m_creature->getFaction()); - if(point) - ((netherspite_infernalAI*)Infernal->AI())->point=point; - ((netherspite_infernalAI*)Infernal->AI())->malchezaar=m_creature->GetGUID(); - - infernals.push_back(Infernal->GetGUID()); - DoCast(Infernal, SPELL_INFERNAL_RELAY); - } - - switch(rand()%2) - { - case 0: - DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON1); - break; - case 1: - DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON2); - break; - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !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_STUNDED)) //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) - { - if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 60) - { - m_creature->InterruptNonMeleeSpells(false); - - phase = 2; - - //animation - DoCast(m_creature, SPELL_EQUIP_AXES); - - //text - DoYell(SAY_PHASE2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE2); - - //passive thrash aura - m_creature->CastSpell(m_creature, SPELL_THRASH_AURA, true); - - //models - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, AXE_EQUIP_MODEL); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, AXE_EQUIP_INFO); - - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, AXE_EQUIP_MODEL); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+2, AXE_EQUIP_INFO); - - //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); - - m_creature->SetAttackTime(OFF_ATTACK, (((uint32)m_creature->GetAttackTime(BASE_ATTACK)/1.5))); - } - } - else if(phase == 2) - { - if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 30) - { - InfernalTimer = 15000; - - phase = 3; - - ClearWeapons(); - - //remove thrash - m_creature->RemoveAurasDueToSpell(SPELL_THRASH_AURA); - - DoYell(SAY_PHASE3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE3); - - Unit *target = SelectUnit(SELECT_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->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, AXE_EQUIP_MODEL); - axe->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, AXE_EQUIP_INFO); - - 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); - } - } - } - - if(ShadowNovaTimer > 35000) - ShadowNovaTimer = EnfeebleTimer + 5000; - - return; - } - - if(SunderArmorTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SUNDER_ARMOR); - SunderArmorTimer = 15000; - - }else SunderArmorTimer -= diff; - } - else - { - if(AxesTargetSwitchTimer < diff) - { - AxesTargetSwitchTimer = 7500 + rand()%12500 ; - - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - for(int i = 0; i < 2; ++i) - { - Unit *axe = Unit::GetUnit(*m_creature, 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) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_AMPLIFY_DAMAGE); - AmplifyDamageTimer = 20000 + rand()%10000; - }else AmplifyDamageTimer -= diff; - } - - //Time for global and double timers - if(InfernalTimer < diff) - { - SummonInfernal(diff); - InfernalTimer = phase == 3 ? 15000 : 45000; //15 secs in phase 3, 45 otherwise - }else InfernalTimer -= diff; - - if(ShadowNovaTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SHADOWNOVA); - ShadowNovaTimer = phase == 3 ? 35000 : -1; - }else ShadowNovaTimer -= diff; - - if(phase != 2) - { - if(SWPainTimer < diff) - { - Unit *target; - if(phase == 1) - target = m_creature->getVictim(); // the tank - else //anyone but the tank - target = SelectUnit(SELECT_TARGET_RANDOM, 1); - - DoCast(target, SPELL_SW_PAIN); - SWPainTimer = 20000; - }else SWPainTimer -= diff; - } - - if(phase != 3) - { - if(EnfeebleTimer < diff) - { - EnfeebleHealthEffect(); - EnfeebleTimer = 30000; - ShadowNovaTimer = 5000; - EnfeebleResetTimer = 9000; - }else EnfeebleTimer -= diff; - } - - if(phase==2) - DoMeleeAttacksIfReady(); - else - DoMeleeAttackIfReady(); - } - - void DoMeleeAttacksIfReady() - { - if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE) && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Check for base attack - if( m_creature->isAttackReady()) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - //Check for offhand attack - if( m_creature->isAttackReady(OFF_ATTACK)) - { - m_creature->AttackerStateUpdate(m_creature->getVictim(), OFF_ATTACK); - m_creature->resetAttackTimer(OFF_ATTACK); - } - } - } - - void Cleanup(Creature *infernal, InfernalPoint *point) - { - for(std::vector::iterator itr = infernals.begin(); itr!= infernals.end(); ++itr) - if(*itr == infernal->GetGUID()) - { - infernals.erase(itr); - break; - } - - positions.push_back(point); - } -}; - -void netherspite_infernalAI::Cleanup() -{ - Unit *pMalchezaar = Unit::GetUnit(*m_creature, malchezaar); - - if(pMalchezaar && pMalchezaar->isAlive()) - ((boss_malchezaarAI*)((Creature*)pMalchezaar)->AI())->Cleanup(m_creature, point); -} - -CreatureAI* GetAI_netherspite_infernal(Creature *_Creature) -{ - return new netherspite_infernalAI (_Creature); -} - -CreatureAI* GetAI_boss_malchezaar(Creature *_Creature) -{ - return new boss_malchezaarAI (_Creature); -} - -void AddSC_netherspite_infernal() -{ - Script *newscript; - newscript = new Script; - newscript->Name="netherspite_infernal"; - newscript->GetAI = GetAI_netherspite_infernal; - m_scripts[nrscripts++] = newscript; -} - -void AddSC_boss_malchezaar() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_malchezaar"; - newscript->GetAI = GetAI_boss_malchezaar; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Prince_Malchezzar +SD%Complete: 100 +SDComment: +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO "Madness has brought you here to me. I shall be your undoing!" +#define SOUND_AGGRO 9218 +#define SAY_SUMMON1 "You face not Malchezaar alone, but the legions I command!" +#define SOUND_SUMMON1 9322 +#define SAY_SUMMON2 "All realities, all dimensions are open to me!" +#define SOUND_SUMMON2 9224 +#define SAY_PHASE2 "Simple fools! Time is the fire in which you'll burn!" +#define SOUND_PHASE2 9220 +#define SAY_PHASE3 "How can you hope to withstand against such overwhelming power?" +#define SOUND_PHASE3 9321 +#define SAY_PDEATH1 "You are, but a plaything, unfit even to amuse." +#define SOUND_PDEATH1 9319 +#define SAY_PDEATH2 "Your greed, your foolishness has brought you to this end." +#define SOUND_PDEATH2 9318 +#define SAY_PDEATH3 "Surely you did not think you could win." +#define SOUND_PDEATH3 9222 +#define SAY_DEATH "I refuse to concede defeat. I am a prince of the Eredar! I am..." +#define SOUND_DEATH 9221 + +// 19 Coordinates for Infernal spawns +struct InfernalPoint +{ + float x,y; +}; + +#define INFERNAL_Z 275.5 + +static InfernalPoint InfernalPoints[] = +{ + {-10922.8, -1985.2}, + {-10916.2, -1996.2}, + {-10932.2, -2008.1}, + {-10948.8, -2022.1}, + {-10958.7, -1997.7}, + {-10971.5, -1997.5}, + {-10990.8, -1995.1}, + {-10989.8, -1976.5}, + {-10971.6, -1973.0}, + {-10955.5, -1974.0}, + {-10939.6, -1969.8}, + {-10958.0, -1952.2}, + {-10941.7, -1954.8}, + {-10943.1, -1988.5}, + {-10948.8, -2005.1}, + {-10984.0, -2019.3}, + {-10932.8, -1979.6}, + {-10932.8, -1979.6}, + {-10935.7, -1996.0} +}; + +#define TOTAL_INFERNAL_POINTS 19 + +//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 3417 //Passive proc chance for thrash +#define SPELL_EQUIP_AXES 30857 //Visual for axe equiping +#define SPELL_AMPLIFY_DAMAGE 12738 //Amplifiy during phase 3 +#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 AXE_EQUIP_MODEL 40066 //Axes info +#define AXE_EQUIP_INFO 33448898 + +//---------Infernal code first +struct MANGOS_DLL_DECL netherspite_infernalAI : public ScriptedAI +{ + netherspite_infernalAI(Creature *c) : ScriptedAI(c) , + malchezaar(0), HellfireTimer(0), CleanupTimer(0), point(NULL) {Reset();} + + uint32 HellfireTimer; + uint32 CleanupTimer; + uint32 malchezaar; + InfernalPoint *point; + + void Reset() {} + void Aggro(Unit *who) {} + void MoveInLineOfSight(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(HellfireTimer) + if(HellfireTimer <= diff) + { + DoCast(m_creature, SPELL_HELLFIRE); + HellfireTimer = 0; + } + else HellfireTimer -= diff; + + if(CleanupTimer) + if(CleanupTimer <= diff) + { + Cleanup(); + CleanupTimer = 0; + } else CleanupTimer -= diff; + } + + void KilledUnit(Unit *who) + { + Unit *pMalchezaar = Unit::GetUnit(*m_creature, malchezaar); + if(pMalchezaar) + ((Creature*)pMalchezaar)->AI()->KilledUnit(who); + } + + void SpellHit(Unit *who, const SpellEntry *spell) + { + if(spell->Id == SPELL_INFERNAL_RELAY) + { + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 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 ... +}; + +struct MANGOS_DLL_DECL boss_malchezaarAI : public ScriptedAI +{ + boss_malchezaarAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 EnfeebleTimer; + uint32 EnfeebleResetTimer; + uint32 ShadowNovaTimer; + uint32 SWPainTimer; + uint32 SunderArmorTimer; + uint32 AmplifyDamageTimer; + uint32 InfernalTimer; + uint32 AxesTargetSwitchTimer; + uint32 InfernalCleanupTimer; + + std::vector infernals; + std::vector positions; + + uint64 axes[2]; + uint64 enfeeble_targets[5]; + uint64 enfeeble_health[5]; + + uint32 phase; + + void Reset() + { + AxesCleanup(); + ClearWeapons(); + InfernalCleanup(); + positions.clear(); + + for(int i =0; i < 5; ++i) + enfeeble_targets[i] = 0; + + for(int i = 0; i < TOTAL_INFERNAL_POINTS; ++i) + positions.push_back(&InfernalPoints[i]); + + EnfeebleTimer = 30000; + EnfeebleResetTimer = 38000; + ShadowNovaTimer = 35000; + SWPainTimer = 20000; + AmplifyDamageTimer = 10000; + InfernalTimer = 45000; + InfernalCleanupTimer = 47000; + AxesTargetSwitchTimer = 7500 + rand()%12500; + phase = 1; + } + + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_PDEATH1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_PDEATH1); + break; + case 1: + DoYell(SAY_PDEATH2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_PDEATH2); + break; + case 2: + DoYell(SAY_PDEATH3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_PDEATH3); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + AxesCleanup(); + ClearWeapons(); + InfernalCleanup(); + positions.clear(); + + for(int i = 0; i < TOTAL_INFERNAL_POINTS; ++i) + positions.push_back(&InfernalPoints[i]); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void InfernalCleanup() + { + //Infernal Cleanup + for(std::vector::iterator itr = infernals.begin(); itr!= infernals.end(); ++itr) + { + Unit *pInfernal = Unit::GetUnit(*m_creature, *itr); + if(pInfernal && pInfernal->isAlive()) + { + pInfernal->SetVisibility(VISIBILITY_OFF); + pInfernal->setDeathState(JUST_DIED); + } + } + infernals.clear(); + } + + void AxesCleanup() + { + for(int i=0; i<2;++i) + { + Unit *axe = Unit::GetUnit(*m_creature, 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() + { + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, 0); + + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+2, 0); + + //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); + } + + void EnfeebleHealthEffect() + { + const SpellEntry *info = GetSpellStore()->LookupEntry(SPELL_ENFEEBLE_EFFECT); + if(!info) + return; + + std::list t_list = m_creature->getThreatManager().getThreatList(); + std::vector targets; + + if(!t_list.size()) + return; + + //begin + 1 , so we don't target the one with the highest threat + std::list::iterator itr = t_list.begin(); + std::advance(itr, 1); + for( ; itr!= t_list.end(); ++itr) //store the threat list in a different container + { + Unit *target = Unit::GetUnit(*m_creature, (*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 itr = targets.begin(); itr!= targets.end(); ++itr, ++i) + { + Unit *target = *itr; + 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); + } + } + + } + + void EnfeebleResetHealth() + { + for(int i = 0; i < 5; ++i) + { + Unit *target = Unit::GetUnit(*m_creature, enfeeble_targets[i]); + if(target && target->isAlive()) + target->SetHealth(enfeeble_health[i]); + enfeeble_targets[i] = 0; + enfeeble_health[i] = 0; + } + } + + void SummonInfernal(const uint32 diff) + { + InfernalPoint *point = NULL; + float posX,posY,posZ; + if( (m_creature->GetMapId() != 532) || positions.empty()) + { + 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; + } + + Creature *Infernal = m_creature->SummonCreature(NETHERSPITE_INFERNAL, posX, posY, posZ, 0, TEMPSUMMON_TIMED_DESPAWN, 180000); + + if (Infernal) + { + Infernal->SetUInt32Value(UNIT_FIELD_DISPLAYID, INFERNAL_MODEL_INVISIBLE); + Infernal->setFaction(m_creature->getFaction()); + if(point) + ((netherspite_infernalAI*)Infernal->AI())->point=point; + ((netherspite_infernalAI*)Infernal->AI())->malchezaar=m_creature->GetGUID(); + + infernals.push_back(Infernal->GetGUID()); + DoCast(Infernal, SPELL_INFERNAL_RELAY); + } + + switch(rand()%2) + { + case 0: + DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON1); + break; + case 1: + DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON2); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !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_STUNDED)) //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) + { + if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 60) + { + m_creature->InterruptNonMeleeSpells(false); + + phase = 2; + + //animation + DoCast(m_creature, SPELL_EQUIP_AXES); + + //text + DoYell(SAY_PHASE2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE2); + + //passive thrash aura + m_creature->CastSpell(m_creature, SPELL_THRASH_AURA, true); + + //models + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, AXE_EQUIP_MODEL); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, AXE_EQUIP_INFO); + + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, AXE_EQUIP_MODEL); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO+2, AXE_EQUIP_INFO); + + //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); + + m_creature->SetAttackTime(OFF_ATTACK, (((uint32)m_creature->GetAttackTime(BASE_ATTACK)/1.5))); + } + } + else if(phase == 2) + { + if( (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 30) + { + InfernalTimer = 15000; + + phase = 3; + + ClearWeapons(); + + //remove thrash + m_creature->RemoveAurasDueToSpell(SPELL_THRASH_AURA); + + DoYell(SAY_PHASE3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE3); + + Unit *target = SelectUnit(SELECT_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->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, AXE_EQUIP_MODEL); + axe->SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO, AXE_EQUIP_INFO); + + 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); + } + } + } + + if(ShadowNovaTimer > 35000) + ShadowNovaTimer = EnfeebleTimer + 5000; + + return; + } + + if(SunderArmorTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SUNDER_ARMOR); + SunderArmorTimer = 15000; + + }else SunderArmorTimer -= diff; + } + else + { + if(AxesTargetSwitchTimer < diff) + { + AxesTargetSwitchTimer = 7500 + rand()%12500 ; + + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + for(int i = 0; i < 2; ++i) + { + Unit *axe = Unit::GetUnit(*m_creature, 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) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_AMPLIFY_DAMAGE); + AmplifyDamageTimer = 20000 + rand()%10000; + }else AmplifyDamageTimer -= diff; + } + + //Time for global and double timers + if(InfernalTimer < diff) + { + SummonInfernal(diff); + InfernalTimer = phase == 3 ? 15000 : 45000; //15 secs in phase 3, 45 otherwise + }else InfernalTimer -= diff; + + if(ShadowNovaTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SHADOWNOVA); + ShadowNovaTimer = phase == 3 ? 35000 : -1; + }else ShadowNovaTimer -= diff; + + if(phase != 2) + { + if(SWPainTimer < diff) + { + Unit *target; + if(phase == 1) + target = m_creature->getVictim(); // the tank + else //anyone but the tank + target = SelectUnit(SELECT_TARGET_RANDOM, 1); + + DoCast(target, SPELL_SW_PAIN); + SWPainTimer = 20000; + }else SWPainTimer -= diff; + } + + if(phase != 3) + { + if(EnfeebleTimer < diff) + { + EnfeebleHealthEffect(); + EnfeebleTimer = 30000; + ShadowNovaTimer = 5000; + EnfeebleResetTimer = 9000; + }else EnfeebleTimer -= diff; + } + + if(phase==2) + DoMeleeAttacksIfReady(); + else + DoMeleeAttackIfReady(); + } + + void DoMeleeAttacksIfReady() + { + if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE) && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Check for base attack + if( m_creature->isAttackReady()) + { + m_creature->AttackerStateUpdate(m_creature->getVictim()); + m_creature->resetAttackTimer(); + } + //Check for offhand attack + if( m_creature->isAttackReady(OFF_ATTACK)) + { + m_creature->AttackerStateUpdate(m_creature->getVictim(), OFF_ATTACK); + m_creature->resetAttackTimer(OFF_ATTACK); + } + } + } + + void Cleanup(Creature *infernal, InfernalPoint *point) + { + for(std::vector::iterator itr = infernals.begin(); itr!= infernals.end(); ++itr) + if(*itr == infernal->GetGUID()) + { + infernals.erase(itr); + break; + } + + positions.push_back(point); + } +}; + +void netherspite_infernalAI::Cleanup() +{ + Unit *pMalchezaar = Unit::GetUnit(*m_creature, malchezaar); + + if(pMalchezaar && pMalchezaar->isAlive()) + ((boss_malchezaarAI*)((Creature*)pMalchezaar)->AI())->Cleanup(m_creature, point); +} + +CreatureAI* GetAI_netherspite_infernal(Creature *_Creature) +{ + return new netherspite_infernalAI (_Creature); +} + +CreatureAI* GetAI_boss_malchezaar(Creature *_Creature) +{ + return new boss_malchezaarAI (_Creature); +} + +void AddSC_netherspite_infernal() +{ + Script *newscript; + newscript = new Script; + newscript->Name="netherspite_infernal"; + newscript->GetAI = GetAI_netherspite_infernal; + m_scripts[nrscripts++] = newscript; +} + +void AddSC_boss_malchezaar() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_malchezaar"; + newscript->GetAI = GetAI_boss_malchezaar; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_shade_of_aran.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_shade_of_aran.cpp index c90620f04a7..f3733c955c1 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_shade_of_aran.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_shade_of_aran.cpp @@ -1,673 +1,673 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Shade_of_Aran -SD%Complete: 95 -SDComment: Flame wreath missing cast animation, mods won't triggere. Drinking may cause client crash (core related) -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" -#include "../../creature/simple_ai.h" -#include "def_karazhan.h" -#include "GameObject.h" - -//Aggro -#define SAY_AGGRO1 "Please, no more. My son... he's gone mad!" -#define SOUND_AGGRO1 9241 - -#define SAY_AGGRO2 "I'll not be tortured again!" -#define SOUND_AGGRO2 9323 - -#define SAY_AGGRO3 "Who are you? What do you want? Stay away from me!" -#define SOUND_AGGRO3 9324 - -//Flame Wreath -#define SAY_FLAMEWREATH1 "I'll show you this beaten dog still has some teeth!" -#define SOUND_FLAMEWREATH1 9245 -#define SAY_FLAMEWREATH2 "Burn you hellish fiends!" -#define SOUND_FLAMEWREATH2 9326 - -//Blizzard -#define SAY_BLIZZARD1 "I'll freeze you all!" -#define SOUND_BLIZZARD1 9246 -#define SAY_BLIZZARD2 "Back to the cold dark with you!" -#define SOUND_BLIZZARD2 9327 - -//Arcane Explosion -#define SAY_EXPLOSION1 "Yes, yes, my son is quite powerful... but I have powers of my own!" -#define SOUND_EXPLOSION1 9242 -#define SAY_EXPLOSION2 "I am not some simple jester! I am Nielas Aran!" -#define SOUND_EXPLOSION2 9325 - -//Low Mana / AoE Pyroblast -#define SAY_DRINK "Surely you would not deny an old man a replenishing drink? No, no I thought not." -#define SOUND_DRINK 9248 - -//Summon Water Elementals -#define SAY_ELEMENTALS "I'm not finished yet! No, I have a few more tricks up me sleeve." -#define SOUND_ELEMENTALS 9251 - -//Player Death -#define SAY_KILL1 "I want this nightmare to be over!" -#define SOUND_KILL1 9250 - -#define SAY_KILL2 "Torment me no more!" -#define SOUND_KILL2 9328 - -//Time over -#define SAY_TIMEOVER "You've wasted enough of my time. Let these games be finished!" -#define SOUND_TIMEOVER 9247 - -//Aran's death -#define SAY_DEATH "At last... The nightmare is.. over..." -#define SOUND_DEATH 9244 - -//Atiesh is equipped by a raid member -#define SAY_ATIESH "Where did you get that?! Did HE send you?!" -#define SOUND_ATIESH 9249 - -//Spells -#define SPELL_FROSTBOLT 29954 -#define SPELL_FIREBALL 29953 -#define SPELL_ARCMISSLE 29955 -#define SPELL_CHAINSOFICE 29991 -#define SPELL_DRAGONSBREATH 29964 -#define SPELL_MASSSLOW 30035 -#define SPELL_FLAME_WREATH 29946 -#define SPELL_AOE_CS 29961 -#define SPELL_PLAYERPULL 32265 -#define SPELL_AEXPLOSION 29973 -#define SPELL_MASS_POLY 29963 -#define SPELL_BLINK_CENTER 29967 -#define SPELL_ELEMENTALS 29962 -#define SPELL_CONJURE 29975 -#define SPELL_DRINK 30024 -#define SPELL_POTION 32453 -#define SPELL_AOE_PYROBLAST 29978 - -//Creature Spells -#define SPELL_CIRCULAR_BLIZZARD 29951 //29952 is the REAL circular blizzard that leaves persistant blizzards that last for 10 seconds -#define SPELL_WATERBOLT 31012 -#define SPELL_SHADOW_PYRO 29978 - -//Creatures -#define CREATURE_WATER_ELEMENTAL 17167 -#define CREATURE_SHADOW_OF_ARAN 18254 -#define CREATURE_ARAN_BLIZZARD 17161 - -enum SuperSpell -{ - SUPER_FLAME = 0, - SUPER_BLIZZARD, - SUPER_AE, -}; - -struct MANGOS_DLL_DECL boss_aranAI : public ScriptedAI -{ - boss_aranAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 SecondarySpellTimer; - uint32 NormalCastTimer; - uint32 SuperCastTimer; - uint32 BerserkTimer; - uint32 CloseDoorTimer; // Don't close the door right on aggro in case some people are still entering. - - uint8 LastSuperSpell; - - uint32 FlameWreathTimer; - uint32 FlameWreathCheckTime; - uint64 FlameWreathTarget[3]; - float FWTargPosX[3]; - float FWTargPosY[3]; - - uint32 CurrentNormalSpell; - uint32 ArcaneCooldown; - uint32 FireCooldown; - uint32 FrostCooldown; - - uint32 DrinkInturruptTimer; - - bool ElementalsSpawned; - bool Drinking; - bool DrinkInturrupted; - - void Reset() - { - SecondarySpellTimer = 5000; - NormalCastTimer = 0; - SuperCastTimer = 35000; - BerserkTimer = 720000; - CloseDoorTimer = 15000; - - LastSuperSpell = rand()%3; - - FlameWreathTimer = 0; - FlameWreathCheckTime = 0; - - CurrentNormalSpell = 0; - ArcaneCooldown = 0; - FireCooldown = 0; - FrostCooldown = 0; - - DrinkInturruptTimer = 10000; - - ElementalsSpawned = false; - Drinking = false; - DrinkInturrupted = false; - - if(pInstance) - { - // Not in progress - pInstance->SetData(DATA_SHADEOFARAN_EVENT, NOT_STARTED); - - if(GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_LIBRARY_DOOR))) - Door->SetGoState(0); - } - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_KILL1); - break; - case 1: - DoYell(SAY_KILL2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_KILL2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(NULL, SOUND_DEATH); - - if(pInstance) - { - pInstance->SetData(DATA_SHADEOFARAN_EVENT, DONE); - if(GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_LIBRARY_DOOR))) - Door->SetGoState(0); - } - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - break; - } - - if(pInstance) - pInstance->SetData(DATA_SHADEOFARAN_EVENT, IN_PROGRESS); - } - - void FlameWreathEffect() - { - std::vector targets; - std::list t_list = m_creature->getThreatManager().getThreatList(); - - if(!t_list.size()) - return; - - //store the threat list in a different container - for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - Unit *target = Unit::GetUnit(*m_creature, (*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 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) - { - if(*itr) - { - FlameWreathTarget[i] = (*itr)->GetGUID(); - FWTargPosX[i] = (*itr)->GetPositionX(); - FWTargPosY[i] = (*itr)->GetPositionY(); - m_creature->CastSpell((*itr), SPELL_FLAME_WREATH, true); - i++; - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(CloseDoorTimer) - if(CloseDoorTimer <= diff) - { - if(pInstance) - if(GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_LIBRARY_DOOR))) - Door->SetGoState(1); - CloseDoorTimer = 0; - } - else CloseDoorTimer -= diff; - - //Cooldowns for casts - if (ArcaneCooldown) - if (ArcaneCooldown >= diff) - ArcaneCooldown -= diff; - else ArcaneCooldown = 0; - - if (FireCooldown) - if (FireCooldown >= diff) - FireCooldown -= diff; - else FireCooldown = 0; - - if (FrostCooldown) - if (FrostCooldown >= diff) - FrostCooldown -= diff; - else FrostCooldown = 0; - - if(!Drinking && m_creature->GetMaxPower(POWER_MANA) && (m_creature->GetPower(POWER_MANA)*100 / m_creature->GetMaxPower(POWER_MANA)) < 20) - { - Drinking = true; - m_creature->InterruptNonMeleeSpells(false); - - DoYell(SAY_DRINK, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DRINK); - - if (!DrinkInturrupted) - { - 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); - //Sitting down - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 1); - DrinkInturruptTimer = 10000; - } - } - - //Drink Inturrupt - if (Drinking && DrinkInturrupted) - { - Drinking = false; - m_creature->RemoveAurasDueToSpell(SPELL_DRINK); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - m_creature->SetPower(POWER_MANA, m_creature->GetMaxPower(POWER_MANA)-32000); - m_creature->CastSpell(m_creature, SPELL_POTION, false); - } - - //Drink Inturrupt Timer - if (Drinking && !DrinkInturrupted) - if (DrinkInturruptTimer >= diff) - DrinkInturruptTimer -= diff; - else - { - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - m_creature->CastSpell(m_creature, SPELL_POTION, true); - m_creature->CastSpell(m_creature, SPELL_AOE_PYROBLAST, false); - DrinkInturrupted = true; - Drinking = false; - } - - //Don't execute any more code if we are drinking - if (Drinking) - return; - - //Normal casts - if(NormalCastTimer < diff) - { - if (!m_creature->IsNonMeleeSpellCasted(false)) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (!target) - return; - - uint32 Spells[3]; - uint8 AvailableSpells = 0; - - //Check for what spells are not on cooldown - if (!ArcaneCooldown) - { - Spells[AvailableSpells] = SPELL_ARCMISSLE; - AvailableSpells++; - } - if (!FireCooldown) - { - Spells[AvailableSpells] = SPELL_FIREBALL; - AvailableSpells++; - } - if (!FrostCooldown) - { - Spells[AvailableSpells] = SPELL_FROSTBOLT; - AvailableSpells++; - } - - //If no available spells wait 1 second and try again - if (AvailableSpells) - { - CurrentNormalSpell = Spells[rand() % AvailableSpells]; - DoCast(target, CurrentNormalSpell); - } - } - NormalCastTimer = 1000; - }else NormalCastTimer -= diff; - - if(SecondarySpellTimer < diff) - { - switch (rand()%2) - { - - case 0: - DoCast(m_creature, SPELL_AOE_CS); - break; - case 1: - Unit* pUnit; - pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (pUnit) - DoCast(pUnit, SPELL_CHAINSOFICE); - break; - } - SecondarySpellTimer = 5000 + (rand()%15000); - }else SecondarySpellTimer -= diff; - - if(SuperCastTimer < diff) - { - uint8 Available[2]; - - switch (LastSuperSpell) - { - case SUPER_AE: - Available[0] = SUPER_FLAME; - Available[1] = SUPER_BLIZZARD; - break; - case SUPER_FLAME: - Available[0] = SUPER_AE; - Available[1] = SUPER_BLIZZARD; - break; - case SUPER_BLIZZARD: - Available[0] = SUPER_FLAME; - Available[1] = SUPER_AE; - break; - } - - LastSuperSpell = Available[rand()%2]; - - switch (LastSuperSpell) - { - case SUPER_AE: - - if (rand()%2) - { - DoYell(SAY_EXPLOSION1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_EXPLOSION1); - }else - { - DoYell(SAY_EXPLOSION2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_EXPLOSION2); - } - - m_creature->CastSpell(m_creature, SPELL_BLINK_CENTER, true); - m_creature->CastSpell(m_creature, SPELL_PLAYERPULL, true); - m_creature->CastSpell(m_creature, SPELL_MASSSLOW, true); - m_creature->CastSpell(m_creature, SPELL_AEXPLOSION, false); - break; - - case SUPER_FLAME: - if (rand()%2) - { - DoYell(SAY_FLAMEWREATH1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_FLAMEWREATH1); - }else - { - DoYell(SAY_FLAMEWREATH2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_FLAMEWREATH2); - } - - FlameWreathTimer = 20000; - FlameWreathCheckTime = 500; - - FlameWreathTarget[0] = 0; - FlameWreathTarget[1] = 0; - FlameWreathTarget[2] = 0; - - FlameWreathEffect(); - break; - - case SUPER_BLIZZARD: - - if (rand()%2) - { - DoYell(SAY_BLIZZARD1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_BLIZZARD1); - }else - { - DoYell(SAY_BLIZZARD2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_BLIZZARD2); - } - - Creature* Spawn = NULL; - Spawn = DoSpawnCreature(CREATURE_ARAN_BLIZZARD, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 25000); - if (Spawn) - { - Spawn->setFaction(m_creature->getFaction()); - Spawn->CastSpell(Spawn, SPELL_CIRCULAR_BLIZZARD, false); - } - break; - } - - SuperCastTimer = 35000 + (rand()%5000); - }else SuperCastTimer -= diff; - - if(!ElementalsSpawned && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 40) - { - ElementalsSpawned = true; - - for (uint32 i = 0; i < 4; i++) - { - Creature* pUnit = DoSpawnCreature(CREATURE_WATER_ELEMENTAL, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 90000); - if (pUnit) - { - pUnit->Attack(m_creature->getVictim(), true); - pUnit->setFaction(m_creature->getFaction()); - } - } - - DoYell(SAY_ELEMENTALS, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ELEMENTALS); - } - - if(BerserkTimer < diff) - { - for (uint32 i = 0; i < 5; i++) - { - Creature* pUnit = DoSpawnCreature(CREATURE_SHADOW_OF_ARAN, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - if (pUnit) - { - pUnit->Attack(m_creature->getVictim(), true); - pUnit->setFaction(m_creature->getFaction()); - } - } - - DoYell(SAY_TIMEOVER, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TIMEOVER); - - BerserkTimer = 60000; - }else BerserkTimer -= diff; - - //Flame Wreath check - if (FlameWreathTimer) - { - if (FlameWreathTimer >= diff) - FlameWreathTimer -= diff; - else FlameWreathTimer = 0; - - if (FlameWreathCheckTime < diff) - { - for (uint32 i = 0; i < 3; i++) - { - if (!FlameWreathTarget[i]) - continue; - - Unit* pUnit = Unit::GetUnit(*m_creature, FlameWreathTarget[i]); - if (pUnit && pUnit->GetDistance2d(FWTargPosX[i], FWTargPosY[i]) > 3) - { - pUnit->CastSpell(pUnit, 20476, true, 0, 0, m_creature->GetGUID()); - pUnit->CastSpell(pUnit, 11027, true); - FlameWreathTarget[i] = 0; - } - } - FlameWreathCheckTime = 500; - }else FlameWreathCheckTime -= diff; - } - - if (ArcaneCooldown && FireCooldown && FrostCooldown) - DoMeleeAttackIfReady(); - } - - void DamageTaken(Unit* pAttacker, uint32 &damage) - { - if (!DrinkInturrupted && Drinking && damage) - DrinkInturrupted = 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 (CurrentNormalSpell) - { - case SPELL_ARCMISSLE: - ArcaneCooldown = 5000; - break; - case SPELL_FIREBALL: - FireCooldown = 5000; - break; - case SPELL_FROSTBOLT: - FrostCooldown = 5000; - break; - } - } -}; - -struct MANGOS_DLL_DECL water_elementalAI : public ScriptedAI -{ - water_elementalAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 CastTimer; - - void Reset() - { - CastTimer = 2000 + (rand()%3000); - } - - void Aggro(Unit* who) {} - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(CastTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_WATERBOLT); - CastTimer = 2000 + (rand()%3000); - }else CastTimer -= diff; - } -}; - -CreatureAI* GetAI_boss_aran(Creature *_Creature) -{ - return new boss_aranAI (_Creature); -} - -CreatureAI* GetAI_water_elemental(Creature *_Creature) -{ - return new water_elementalAI (_Creature); -} - -// CONVERT TO ACID -CreatureAI* GetAI_shadow_of_aran(Creature *_Creature) -{ - outstring_log("SD2: Convert simpleAI script for Creature Entry %u to ACID", _Creature->GetEntry()); - SimpleAI* ai = new SimpleAI (_Creature); - - ai->Spell[0].Enabled = true; - ai->Spell[0].Spell_Id = SPELL_SHADOW_PYRO; - ai->Spell[0].Cooldown = 5000; - ai->Spell[0].First_Cast = 1000; - ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; - - ai->EnterEvadeMode(); - - return ai; -} - -void AddSC_boss_shade_of_aran() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_shade_of_aran"; - newscript->GetAI = GetAI_boss_aran; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_shadow_of_aran"; - newscript->GetAI = GetAI_shadow_of_aran; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_aran_elemental"; - newscript->GetAI = GetAI_water_elemental; - m_scripts[nrscripts++] = newscript; - - //newscript = new Script; - //newscript->Name="mob_aran_blizzard"; - //newscript->GetAI = GetAI_boss_aran; - //m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Shade_of_Aran +SD%Complete: 95 +SDComment: Flame wreath missing cast animation, mods won't triggere. Drinking may cause client crash (core related) +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" +#include "../../creature/simple_ai.h" +#include "def_karazhan.h" +#include "GameObject.h" + +//Aggro +#define SAY_AGGRO1 "Please, no more. My son... he's gone mad!" +#define SOUND_AGGRO1 9241 + +#define SAY_AGGRO2 "I'll not be tortured again!" +#define SOUND_AGGRO2 9323 + +#define SAY_AGGRO3 "Who are you? What do you want? Stay away from me!" +#define SOUND_AGGRO3 9324 + +//Flame Wreath +#define SAY_FLAMEWREATH1 "I'll show you this beaten dog still has some teeth!" +#define SOUND_FLAMEWREATH1 9245 +#define SAY_FLAMEWREATH2 "Burn you hellish fiends!" +#define SOUND_FLAMEWREATH2 9326 + +//Blizzard +#define SAY_BLIZZARD1 "I'll freeze you all!" +#define SOUND_BLIZZARD1 9246 +#define SAY_BLIZZARD2 "Back to the cold dark with you!" +#define SOUND_BLIZZARD2 9327 + +//Arcane Explosion +#define SAY_EXPLOSION1 "Yes, yes, my son is quite powerful... but I have powers of my own!" +#define SOUND_EXPLOSION1 9242 +#define SAY_EXPLOSION2 "I am not some simple jester! I am Nielas Aran!" +#define SOUND_EXPLOSION2 9325 + +//Low Mana / AoE Pyroblast +#define SAY_DRINK "Surely you would not deny an old man a replenishing drink? No, no I thought not." +#define SOUND_DRINK 9248 + +//Summon Water Elementals +#define SAY_ELEMENTALS "I'm not finished yet! No, I have a few more tricks up me sleeve." +#define SOUND_ELEMENTALS 9251 + +//Player Death +#define SAY_KILL1 "I want this nightmare to be over!" +#define SOUND_KILL1 9250 + +#define SAY_KILL2 "Torment me no more!" +#define SOUND_KILL2 9328 + +//Time over +#define SAY_TIMEOVER "You've wasted enough of my time. Let these games be finished!" +#define SOUND_TIMEOVER 9247 + +//Aran's death +#define SAY_DEATH "At last... The nightmare is.. over..." +#define SOUND_DEATH 9244 + +//Atiesh is equipped by a raid member +#define SAY_ATIESH "Where did you get that?! Did HE send you?!" +#define SOUND_ATIESH 9249 + +//Spells +#define SPELL_FROSTBOLT 29954 +#define SPELL_FIREBALL 29953 +#define SPELL_ARCMISSLE 29955 +#define SPELL_CHAINSOFICE 29991 +#define SPELL_DRAGONSBREATH 29964 +#define SPELL_MASSSLOW 30035 +#define SPELL_FLAME_WREATH 29946 +#define SPELL_AOE_CS 29961 +#define SPELL_PLAYERPULL 32265 +#define SPELL_AEXPLOSION 29973 +#define SPELL_MASS_POLY 29963 +#define SPELL_BLINK_CENTER 29967 +#define SPELL_ELEMENTALS 29962 +#define SPELL_CONJURE 29975 +#define SPELL_DRINK 30024 +#define SPELL_POTION 32453 +#define SPELL_AOE_PYROBLAST 29978 + +//Creature Spells +#define SPELL_CIRCULAR_BLIZZARD 29951 //29952 is the REAL circular blizzard that leaves persistant blizzards that last for 10 seconds +#define SPELL_WATERBOLT 31012 +#define SPELL_SHADOW_PYRO 29978 + +//Creatures +#define CREATURE_WATER_ELEMENTAL 17167 +#define CREATURE_SHADOW_OF_ARAN 18254 +#define CREATURE_ARAN_BLIZZARD 17161 + +enum SuperSpell +{ + SUPER_FLAME = 0, + SUPER_BLIZZARD, + SUPER_AE, +}; + +struct MANGOS_DLL_DECL boss_aranAI : public ScriptedAI +{ + boss_aranAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 SecondarySpellTimer; + uint32 NormalCastTimer; + uint32 SuperCastTimer; + uint32 BerserkTimer; + uint32 CloseDoorTimer; // Don't close the door right on aggro in case some people are still entering. + + uint8 LastSuperSpell; + + uint32 FlameWreathTimer; + uint32 FlameWreathCheckTime; + uint64 FlameWreathTarget[3]; + float FWTargPosX[3]; + float FWTargPosY[3]; + + uint32 CurrentNormalSpell; + uint32 ArcaneCooldown; + uint32 FireCooldown; + uint32 FrostCooldown; + + uint32 DrinkInturruptTimer; + + bool ElementalsSpawned; + bool Drinking; + bool DrinkInturrupted; + + void Reset() + { + SecondarySpellTimer = 5000; + NormalCastTimer = 0; + SuperCastTimer = 35000; + BerserkTimer = 720000; + CloseDoorTimer = 15000; + + LastSuperSpell = rand()%3; + + FlameWreathTimer = 0; + FlameWreathCheckTime = 0; + + CurrentNormalSpell = 0; + ArcaneCooldown = 0; + FireCooldown = 0; + FrostCooldown = 0; + + DrinkInturruptTimer = 10000; + + ElementalsSpawned = false; + Drinking = false; + DrinkInturrupted = false; + + if(pInstance) + { + // Not in progress + pInstance->SetData(DATA_SHADEOFARAN_EVENT, NOT_STARTED); + + if(GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_LIBRARY_DOOR))) + Door->SetGoState(0); + } + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_KILL1); + break; + case 1: + DoYell(SAY_KILL2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_KILL2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(NULL, SOUND_DEATH); + + if(pInstance) + { + pInstance->SetData(DATA_SHADEOFARAN_EVENT, DONE); + if(GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_LIBRARY_DOOR))) + Door->SetGoState(0); + } + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO3); + break; + } + + if(pInstance) + pInstance->SetData(DATA_SHADEOFARAN_EVENT, IN_PROGRESS); + } + + void FlameWreathEffect() + { + std::vector targets; + std::list t_list = m_creature->getThreatManager().getThreatList(); + + if(!t_list.size()) + return; + + //store the threat list in a different container + for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + Unit *target = Unit::GetUnit(*m_creature, (*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 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) + { + if(*itr) + { + FlameWreathTarget[i] = (*itr)->GetGUID(); + FWTargPosX[i] = (*itr)->GetPositionX(); + FWTargPosY[i] = (*itr)->GetPositionY(); + m_creature->CastSpell((*itr), SPELL_FLAME_WREATH, true); + i++; + } + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(CloseDoorTimer) + if(CloseDoorTimer <= diff) + { + if(pInstance) + if(GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_LIBRARY_DOOR))) + Door->SetGoState(1); + CloseDoorTimer = 0; + } + else CloseDoorTimer -= diff; + + //Cooldowns for casts + if (ArcaneCooldown) + if (ArcaneCooldown >= diff) + ArcaneCooldown -= diff; + else ArcaneCooldown = 0; + + if (FireCooldown) + if (FireCooldown >= diff) + FireCooldown -= diff; + else FireCooldown = 0; + + if (FrostCooldown) + if (FrostCooldown >= diff) + FrostCooldown -= diff; + else FrostCooldown = 0; + + if(!Drinking && m_creature->GetMaxPower(POWER_MANA) && (m_creature->GetPower(POWER_MANA)*100 / m_creature->GetMaxPower(POWER_MANA)) < 20) + { + Drinking = true; + m_creature->InterruptNonMeleeSpells(false); + + DoYell(SAY_DRINK, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DRINK); + + if (!DrinkInturrupted) + { + 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); + //Sitting down + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 1); + DrinkInturruptTimer = 10000; + } + } + + //Drink Inturrupt + if (Drinking && DrinkInturrupted) + { + Drinking = false; + m_creature->RemoveAurasDueToSpell(SPELL_DRINK); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + m_creature->SetPower(POWER_MANA, m_creature->GetMaxPower(POWER_MANA)-32000); + m_creature->CastSpell(m_creature, SPELL_POTION, false); + } + + //Drink Inturrupt Timer + if (Drinking && !DrinkInturrupted) + if (DrinkInturruptTimer >= diff) + DrinkInturruptTimer -= diff; + else + { + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + m_creature->CastSpell(m_creature, SPELL_POTION, true); + m_creature->CastSpell(m_creature, SPELL_AOE_PYROBLAST, false); + DrinkInturrupted = true; + Drinking = false; + } + + //Don't execute any more code if we are drinking + if (Drinking) + return; + + //Normal casts + if(NormalCastTimer < diff) + { + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (!target) + return; + + uint32 Spells[3]; + uint8 AvailableSpells = 0; + + //Check for what spells are not on cooldown + if (!ArcaneCooldown) + { + Spells[AvailableSpells] = SPELL_ARCMISSLE; + AvailableSpells++; + } + if (!FireCooldown) + { + Spells[AvailableSpells] = SPELL_FIREBALL; + AvailableSpells++; + } + if (!FrostCooldown) + { + Spells[AvailableSpells] = SPELL_FROSTBOLT; + AvailableSpells++; + } + + //If no available spells wait 1 second and try again + if (AvailableSpells) + { + CurrentNormalSpell = Spells[rand() % AvailableSpells]; + DoCast(target, CurrentNormalSpell); + } + } + NormalCastTimer = 1000; + }else NormalCastTimer -= diff; + + if(SecondarySpellTimer < diff) + { + switch (rand()%2) + { + + case 0: + DoCast(m_creature, SPELL_AOE_CS); + break; + case 1: + Unit* pUnit; + pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (pUnit) + DoCast(pUnit, SPELL_CHAINSOFICE); + break; + } + SecondarySpellTimer = 5000 + (rand()%15000); + }else SecondarySpellTimer -= diff; + + if(SuperCastTimer < diff) + { + uint8 Available[2]; + + switch (LastSuperSpell) + { + case SUPER_AE: + Available[0] = SUPER_FLAME; + Available[1] = SUPER_BLIZZARD; + break; + case SUPER_FLAME: + Available[0] = SUPER_AE; + Available[1] = SUPER_BLIZZARD; + break; + case SUPER_BLIZZARD: + Available[0] = SUPER_FLAME; + Available[1] = SUPER_AE; + break; + } + + LastSuperSpell = Available[rand()%2]; + + switch (LastSuperSpell) + { + case SUPER_AE: + + if (rand()%2) + { + DoYell(SAY_EXPLOSION1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_EXPLOSION1); + }else + { + DoYell(SAY_EXPLOSION2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_EXPLOSION2); + } + + m_creature->CastSpell(m_creature, SPELL_BLINK_CENTER, true); + m_creature->CastSpell(m_creature, SPELL_PLAYERPULL, true); + m_creature->CastSpell(m_creature, SPELL_MASSSLOW, true); + m_creature->CastSpell(m_creature, SPELL_AEXPLOSION, false); + break; + + case SUPER_FLAME: + if (rand()%2) + { + DoYell(SAY_FLAMEWREATH1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_FLAMEWREATH1); + }else + { + DoYell(SAY_FLAMEWREATH2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_FLAMEWREATH2); + } + + FlameWreathTimer = 20000; + FlameWreathCheckTime = 500; + + FlameWreathTarget[0] = 0; + FlameWreathTarget[1] = 0; + FlameWreathTarget[2] = 0; + + FlameWreathEffect(); + break; + + case SUPER_BLIZZARD: + + if (rand()%2) + { + DoYell(SAY_BLIZZARD1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_BLIZZARD1); + }else + { + DoYell(SAY_BLIZZARD2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_BLIZZARD2); + } + + Creature* Spawn = NULL; + Spawn = DoSpawnCreature(CREATURE_ARAN_BLIZZARD, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 25000); + if (Spawn) + { + Spawn->setFaction(m_creature->getFaction()); + Spawn->CastSpell(Spawn, SPELL_CIRCULAR_BLIZZARD, false); + } + break; + } + + SuperCastTimer = 35000 + (rand()%5000); + }else SuperCastTimer -= diff; + + if(!ElementalsSpawned && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 40) + { + ElementalsSpawned = true; + + for (uint32 i = 0; i < 4; i++) + { + Creature* pUnit = DoSpawnCreature(CREATURE_WATER_ELEMENTAL, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 90000); + if (pUnit) + { + pUnit->Attack(m_creature->getVictim(), true); + pUnit->setFaction(m_creature->getFaction()); + } + } + + DoYell(SAY_ELEMENTALS, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ELEMENTALS); + } + + if(BerserkTimer < diff) + { + for (uint32 i = 0; i < 5; i++) + { + Creature* pUnit = DoSpawnCreature(CREATURE_SHADOW_OF_ARAN, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + if (pUnit) + { + pUnit->Attack(m_creature->getVictim(), true); + pUnit->setFaction(m_creature->getFaction()); + } + } + + DoYell(SAY_TIMEOVER, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TIMEOVER); + + BerserkTimer = 60000; + }else BerserkTimer -= diff; + + //Flame Wreath check + if (FlameWreathTimer) + { + if (FlameWreathTimer >= diff) + FlameWreathTimer -= diff; + else FlameWreathTimer = 0; + + if (FlameWreathCheckTime < diff) + { + for (uint32 i = 0; i < 3; i++) + { + if (!FlameWreathTarget[i]) + continue; + + Unit* pUnit = Unit::GetUnit(*m_creature, FlameWreathTarget[i]); + if (pUnit && pUnit->GetDistance2d(FWTargPosX[i], FWTargPosY[i]) > 3) + { + pUnit->CastSpell(pUnit, 20476, true, 0, 0, m_creature->GetGUID()); + pUnit->CastSpell(pUnit, 11027, true); + FlameWreathTarget[i] = 0; + } + } + FlameWreathCheckTime = 500; + }else FlameWreathCheckTime -= diff; + } + + if (ArcaneCooldown && FireCooldown && FrostCooldown) + DoMeleeAttackIfReady(); + } + + void DamageTaken(Unit* pAttacker, uint32 &damage) + { + if (!DrinkInturrupted && Drinking && damage) + DrinkInturrupted = 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 (CurrentNormalSpell) + { + case SPELL_ARCMISSLE: + ArcaneCooldown = 5000; + break; + case SPELL_FIREBALL: + FireCooldown = 5000; + break; + case SPELL_FROSTBOLT: + FrostCooldown = 5000; + break; + } + } +}; + +struct MANGOS_DLL_DECL water_elementalAI : public ScriptedAI +{ + water_elementalAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 CastTimer; + + void Reset() + { + CastTimer = 2000 + (rand()%3000); + } + + void Aggro(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(CastTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_WATERBOLT); + CastTimer = 2000 + (rand()%3000); + }else CastTimer -= diff; + } +}; + +CreatureAI* GetAI_boss_aran(Creature *_Creature) +{ + return new boss_aranAI (_Creature); +} + +CreatureAI* GetAI_water_elemental(Creature *_Creature) +{ + return new water_elementalAI (_Creature); +} + +// CONVERT TO ACID +CreatureAI* GetAI_shadow_of_aran(Creature *_Creature) +{ + outstring_log("SD2: Convert simpleAI script for Creature Entry %u to ACID", _Creature->GetEntry()); + SimpleAI* ai = new SimpleAI (_Creature); + + ai->Spell[0].Enabled = true; + ai->Spell[0].Spell_Id = SPELL_SHADOW_PYRO; + ai->Spell[0].Cooldown = 5000; + ai->Spell[0].First_Cast = 1000; + ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; + + ai->EnterEvadeMode(); + + return ai; +} + +void AddSC_boss_shade_of_aran() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_shade_of_aran"; + newscript->GetAI = GetAI_boss_aran; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_shadow_of_aran"; + newscript->GetAI = GetAI_shadow_of_aran; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_aran_elemental"; + newscript->GetAI = GetAI_water_elemental; + m_scripts[nrscripts++] = newscript; + + //newscript = new Script; + //newscript->Name="mob_aran_blizzard"; + //newscript->GetAI = GetAI_boss_aran; + //m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_terestian_illhoof.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_terestian_illhoof.cpp index 2fa5b3860a0..771d839925f 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_terestian_illhoof.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_terestian_illhoof.cpp @@ -1,454 +1,454 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Terestian_Illhoof -SD%Complete: 100 -SDComment: Complete! -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" -#include "def_karazhan.h" - -#define SPELL_SUMMON_DEMONCHAINS 30120 // Summons demonic chains that maintain the ritual of sacrifice. -#define SPELL_DEMON_CHAINS 30206 // Instant - Visual Effect -#define SPELL_ENRAGE 23537 // Increases the caster's attack speed by 50% and the Physical damage it deals by 219 to 281 for 10 min. -#define SPELL_SHADOW_BOLT 30055 // Hurls a bolt of dark magic at an enemy, inflicting Shadow damage. -#define SPELL_SACRIFICE 30115 // Teleports and adds the debuff -#define SPELL_BERSERK 32965 // Increases attack speed by 75%. Periodically casts Shadow Bolt Volley. - -#define SPELL_FIREBOLT 18086 // Blasts a target for 150 Fire damage. - -#define SPELL_BROKEN_PACT 30065 // All damage taken increased by 25%. -#define SPELL_AMPLIFY_FLAMES 30053 // Increases the Fire damage taken by an enemy by 500 for 25 sec. -#define SPELL_FIREBOLT 18086 // Blasts a target for 150 Fire damage. - -#define SAY_SLAY1 "Your blood will anoint my circle." -#define SOUND_SLAY1 9264 -#define SAY_SLAY2 "The great one will be pleased." -#define SOUND_SLAY2 9329 - -#define SAY_DEATH "My life, is yours. Oh great one." -#define SOUND_DEATH 9262 - -#define SAY_AGGRO "Ah, you're just in time. The rituals are about to begin." -#define SOUND_AGGRO 9260 - -#define SAY_SACRIFICE1 "Please, accept this humble offering, oh great one." -#define SOUND_SACRIFICE1 9263 -#define SAY_SACRIFICE2 "Let the sacrifice serve his testament to my fealty." -#define SOUND_SACRIFICE2 9330 - -#define SAY_SUMMON1 "Come, you dwellers in the dark. Rally to my call!" -#define SOUND_SUMMON1 9265 -#define SAY_SUMMON2 "Gather, my pets. There is plenty for all." -#define SOUND_SUMMON2 9331 - -#define CREATURE_DEMONCHAINS 17248 -#define CREATURE_FIENDISHIMP 17267 -#define CREATURE_PORTAL 17265 - -#define SACRIFICE_X -11240.599 -#define SACRIFICE_Y -1694.2700 -#define SACRIFICE_Z 179.720007 - -#define PORTAL_Z 179.434 - -float PortalLocations[2][2]= -{ - {-11249.6933, -1704.61023}, - {-11242.1160, -1713.33325}, -}; - -struct MANGOS_DLL_DECL mob_kilrekAI : public ScriptedAI -{ - mob_kilrekAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 TerestianGUID; - - uint32 AmplifyTimer; - - void Reset() - { - TerestianGUID = 0; - - AmplifyTimer = 0; - } - - void Aggro(Unit *who) - { - if(!pInstance) - { - ERROR_INST_DATA(m_creature); - return; - } - - Creature* Terestian = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_TERESTIAN))); - if(Terestian && (!Terestian->SelectHostilTarget() && !Terestian->getVictim())) - Terestian->AddThreat(who, 1.0f); - } - - void JustDied(Unit* Killer) - { - if(pInstance) - { - uint64 TerestianGUID = pInstance->GetData64(DATA_TERESTIAN); - if(TerestianGUID) - { - Unit* Terestian = Unit::GetUnit((*m_creature), TerestianGUID); - if(Terestian && Terestian->isAlive()) - DoCast(Terestian, SPELL_BROKEN_PACT, true); - } - }else ERROR_INST_DATA(m_creature); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if (AmplifyTimer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature->getVictim(),SPELL_AMPLIFY_FLAMES); - - AmplifyTimer = 20000; - }else AmplifyTimer -= diff; - - //Chain cast - if (!m_creature->IsNonMeleeSpellCasted(false) && m_creature->IsWithinDistInMap(m_creature->getVictim(), 30)) - DoCast(m_creature->getVictim(),SPELL_FIREBOLT); - else DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_demon_chainAI : public ScriptedAI -{ - mob_demon_chainAI(Creature *c) : ScriptedAI(c) - { - Reset(); - } - - uint64 SacrificeGUID; - - void Reset() - { - SacrificeGUID = 0; - } - - void Aggro(Unit* who) {} - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - - void JustDied(Unit *killer) - { - if(SacrificeGUID) - { - Unit* Sacrifice = Unit::GetUnit((*m_creature),SacrificeGUID); - if(Sacrifice) - Sacrifice->RemoveAurasDueToSpell(SPELL_SACRIFICE); - } - } -}; - -struct MANGOS_DLL_DECL boss_terestianAI : public ScriptedAI -{ - boss_terestianAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint64 KilrekGUID; - uint64 PortalGUID[2]; - - uint32 CheckKilrekTimer; - uint32 SacrificeTimer; - uint32 ShadowboltTimer; - uint32 SummonTimer; - uint32 BerserkTimer; - - bool SummonKilrek; - bool SummonedPortals; - bool Berserk; - - void Reset() - { - for(uint8 i = 0; i < 2; ++i) - { - if(PortalGUID[i]) - { - Unit* Portal = Unit::GetUnit((*m_creature), PortalGUID[i]); - if(Portal) - Portal->DealDamage(Portal, Portal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - PortalGUID[i] = 0; - } - } - - CheckKilrekTimer = 5000; - SacrificeTimer = 30000; - ShadowboltTimer = 5000; - SummonTimer = 10000; - BerserkTimer = 600000; - - SummonedPortals = false; - Berserk = false; - - if(pInstance) - pInstance->SetData(DATA_TERESTIAN_EVENT, NOT_STARTED); - } - - void Aggro(Unit* who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - - if(pInstance) - { - // Put Kil'rek in combat against our target so players don't skip him - Creature* Kilrek = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_KILREK))); - if(Kilrek && (!Kilrek->SelectHostilTarget() && !Kilrek->getVictim())) - Kilrek->AddThreat(who, 1.0f); - - pInstance->SetData(DATA_TERESTIAN_EVENT, IN_PROGRESS); - }else ERROR_INST_DATA(m_creature); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit *killer) - { - for(uint8 i = 0; i < 2; ++i) - { - if(PortalGUID[i]) - { - Unit* Portal = Unit::GetUnit((*m_creature), PortalGUID[i]); - if(Portal) - Portal->DealDamage(Portal, Portal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - PortalGUID[i] = 0; - } - } - - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if(pInstance) - pInstance->SetData(DATA_TERESTIAN_EVENT, DONE); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->getVictim() && !m_creature->SelectHostilTarget()) - return; - - if(CheckKilrekTimer < diff) - { - CheckKilrekTimer = 5000; - - if(pInstance) - uint64 KilrekGUID = pInstance->GetData64(DATA_KILREK); - else ERROR_INST_DATA(m_creature); - - Creature* Kilrek = ((Creature*)Unit::GetUnit((*m_creature), KilrekGUID)); - if(SummonKilrek && Kilrek) - { - Kilrek->Respawn(); - Kilrek->AI()->AttackStart(m_creature->getVictim()); - - SummonKilrek = false; - } - - if(!Kilrek || !Kilrek->isAlive()) - { - SummonKilrek = true; - CheckKilrekTimer = 45000; - } - }else CheckKilrekTimer -= diff; - - if(SacrificeTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) - { - DoCast(target, SPELL_SACRIFICE, true); - Creature* Chains = m_creature->SummonCreature(CREATURE_DEMONCHAINS, SACRIFICE_X, SACRIFICE_Y, SACRIFICE_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 21000); - if(Chains) - { - ((mob_demon_chainAI*)Chains->AI())->SacrificeGUID = target->GetGUID(); - Chains->CastSpell(Chains, SPELL_DEMON_CHAINS, true); - switch(rand()%2) - { - case 0: - DoYell(SAY_SACRIFICE1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SACRIFICE1); - break; - case 1: - DoYell(SAY_SACRIFICE2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SACRIFICE2); - break; - } - SacrificeTimer = 30000; - } - } - }else SacrificeTimer -= diff; - - if(ShadowboltTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_TOPAGGRO, 0), SPELL_SHADOW_BOLT); - ShadowboltTimer = 10000; - }else ShadowboltTimer -= diff; - - if(SummonTimer < diff) - { - if(!SummonedPortals) - { - for(uint8 i = 0; i < 2; ++i) - { - Creature* Portal = m_creature->SummonCreature(CREATURE_PORTAL, PortalLocations[i][0], PortalLocations[i][1], PORTAL_Z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - if(Portal) - PortalGUID[i] = Portal->GetGUID(); - } - SummonedPortals = true; - switch(rand()%2) - { - case 0: - DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON1); - break; - case 1: - DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON2); - break; - } - } - uint32 random = rand()%2; - Creature* Imp = m_creature->SummonCreature(CREATURE_FIENDISHIMP, PortalLocations[random][0], PortalLocations[random][1], PORTAL_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 15000); - if(Imp) - { - Imp->AddThreat(m_creature->getVictim(), 1.0f); - Imp->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM, 1)); - } - SummonTimer = 5000; - }else SummonTimer -= diff; - - if(!Berserk) - if(BerserkTimer < diff) - { - DoCast(m_creature, SPELL_BERSERK); - Berserk = true; - }else BerserkTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_karazhan_impAI : public ScriptedAI -{ - mob_karazhan_impAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FireboltTimer; - - void Reset() - { - FireboltTimer = 3000; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(FireboltTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FIREBOLT); - FireboltTimer = 1500; - }else FireboltTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_kilrek(Creature *_Creature) -{ - return new mob_kilrekAI (_Creature); -} - -CreatureAI* GetAI_mob_karazhan_imp(Creature *_Creature) -{ - return new mob_karazhan_impAI (_Creature); -} - -CreatureAI* GetAI_mob_demon_chain(Creature *_Creature) -{ - return new mob_demon_chainAI(_Creature); -} - -CreatureAI* GetAI_boss_terestian_illhoof(Creature *_Creature) -{ - return new boss_terestianAI (_Creature); -} - -void AddSC_boss_terestian_illhoof() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_terestian_illhoof"; - newscript->GetAI = GetAI_boss_terestian_illhoof; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_karazhan_imp"; - newscript->GetAI = GetAI_mob_karazhan_imp; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_kilrek"; - newscript->GetAI = GetAI_mob_kilrek; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_demon_chain"; - newscript->GetAI = GetAI_mob_demon_chain; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Terestian_Illhoof +SD%Complete: 100 +SDComment: Complete! +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" +#include "def_karazhan.h" + +#define SPELL_SUMMON_DEMONCHAINS 30120 // Summons demonic chains that maintain the ritual of sacrifice. +#define SPELL_DEMON_CHAINS 30206 // Instant - Visual Effect +#define SPELL_ENRAGE 23537 // Increases the caster's attack speed by 50% and the Physical damage it deals by 219 to 281 for 10 min. +#define SPELL_SHADOW_BOLT 30055 // Hurls a bolt of dark magic at an enemy, inflicting Shadow damage. +#define SPELL_SACRIFICE 30115 // Teleports and adds the debuff +#define SPELL_BERSERK 32965 // Increases attack speed by 75%. Periodically casts Shadow Bolt Volley. + +#define SPELL_FIREBOLT 18086 // Blasts a target for 150 Fire damage. + +#define SPELL_BROKEN_PACT 30065 // All damage taken increased by 25%. +#define SPELL_AMPLIFY_FLAMES 30053 // Increases the Fire damage taken by an enemy by 500 for 25 sec. +#define SPELL_FIREBOLT 18086 // Blasts a target for 150 Fire damage. + +#define SAY_SLAY1 "Your blood will anoint my circle." +#define SOUND_SLAY1 9264 +#define SAY_SLAY2 "The great one will be pleased." +#define SOUND_SLAY2 9329 + +#define SAY_DEATH "My life, is yours. Oh great one." +#define SOUND_DEATH 9262 + +#define SAY_AGGRO "Ah, you're just in time. The rituals are about to begin." +#define SOUND_AGGRO 9260 + +#define SAY_SACRIFICE1 "Please, accept this humble offering, oh great one." +#define SOUND_SACRIFICE1 9263 +#define SAY_SACRIFICE2 "Let the sacrifice serve his testament to my fealty." +#define SOUND_SACRIFICE2 9330 + +#define SAY_SUMMON1 "Come, you dwellers in the dark. Rally to my call!" +#define SOUND_SUMMON1 9265 +#define SAY_SUMMON2 "Gather, my pets. There is plenty for all." +#define SOUND_SUMMON2 9331 + +#define CREATURE_DEMONCHAINS 17248 +#define CREATURE_FIENDISHIMP 17267 +#define CREATURE_PORTAL 17265 + +#define SACRIFICE_X -11240.599 +#define SACRIFICE_Y -1694.2700 +#define SACRIFICE_Z 179.720007 + +#define PORTAL_Z 179.434 + +float PortalLocations[2][2]= +{ + {-11249.6933, -1704.61023}, + {-11242.1160, -1713.33325}, +}; + +struct MANGOS_DLL_DECL mob_kilrekAI : public ScriptedAI +{ + mob_kilrekAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 TerestianGUID; + + uint32 AmplifyTimer; + + void Reset() + { + TerestianGUID = 0; + + AmplifyTimer = 0; + } + + void Aggro(Unit *who) + { + if(!pInstance) + { + ERROR_INST_DATA(m_creature); + return; + } + + Creature* Terestian = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_TERESTIAN))); + if(Terestian && (!Terestian->SelectHostilTarget() && !Terestian->getVictim())) + Terestian->AddThreat(who, 1.0f); + } + + void JustDied(Unit* Killer) + { + if(pInstance) + { + uint64 TerestianGUID = pInstance->GetData64(DATA_TERESTIAN); + if(TerestianGUID) + { + Unit* Terestian = Unit::GetUnit((*m_creature), TerestianGUID); + if(Terestian && Terestian->isAlive()) + DoCast(Terestian, SPELL_BROKEN_PACT, true); + } + }else ERROR_INST_DATA(m_creature); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if (AmplifyTimer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature->getVictim(),SPELL_AMPLIFY_FLAMES); + + AmplifyTimer = 20000; + }else AmplifyTimer -= diff; + + //Chain cast + if (!m_creature->IsNonMeleeSpellCasted(false) && m_creature->IsWithinDistInMap(m_creature->getVictim(), 30)) + DoCast(m_creature->getVictim(),SPELL_FIREBOLT); + else DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_demon_chainAI : public ScriptedAI +{ + mob_demon_chainAI(Creature *c) : ScriptedAI(c) + { + Reset(); + } + + uint64 SacrificeGUID; + + void Reset() + { + SacrificeGUID = 0; + } + + void Aggro(Unit* who) {} + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + + void JustDied(Unit *killer) + { + if(SacrificeGUID) + { + Unit* Sacrifice = Unit::GetUnit((*m_creature),SacrificeGUID); + if(Sacrifice) + Sacrifice->RemoveAurasDueToSpell(SPELL_SACRIFICE); + } + } +}; + +struct MANGOS_DLL_DECL boss_terestianAI : public ScriptedAI +{ + boss_terestianAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint64 KilrekGUID; + uint64 PortalGUID[2]; + + uint32 CheckKilrekTimer; + uint32 SacrificeTimer; + uint32 ShadowboltTimer; + uint32 SummonTimer; + uint32 BerserkTimer; + + bool SummonKilrek; + bool SummonedPortals; + bool Berserk; + + void Reset() + { + for(uint8 i = 0; i < 2; ++i) + { + if(PortalGUID[i]) + { + Unit* Portal = Unit::GetUnit((*m_creature), PortalGUID[i]); + if(Portal) + Portal->DealDamage(Portal, Portal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + PortalGUID[i] = 0; + } + } + + CheckKilrekTimer = 5000; + SacrificeTimer = 30000; + ShadowboltTimer = 5000; + SummonTimer = 10000; + BerserkTimer = 600000; + + SummonedPortals = false; + Berserk = false; + + if(pInstance) + pInstance->SetData(DATA_TERESTIAN_EVENT, NOT_STARTED); + } + + void Aggro(Unit* who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + + if(pInstance) + { + // Put Kil'rek in combat against our target so players don't skip him + Creature* Kilrek = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_KILREK))); + if(Kilrek && (!Kilrek->SelectHostilTarget() && !Kilrek->getVictim())) + Kilrek->AddThreat(who, 1.0f); + + pInstance->SetData(DATA_TERESTIAN_EVENT, IN_PROGRESS); + }else ERROR_INST_DATA(m_creature); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit *killer) + { + for(uint8 i = 0; i < 2; ++i) + { + if(PortalGUID[i]) + { + Unit* Portal = Unit::GetUnit((*m_creature), PortalGUID[i]); + if(Portal) + Portal->DealDamage(Portal, Portal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + PortalGUID[i] = 0; + } + } + + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if(pInstance) + pInstance->SetData(DATA_TERESTIAN_EVENT, DONE); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->getVictim() && !m_creature->SelectHostilTarget()) + return; + + if(CheckKilrekTimer < diff) + { + CheckKilrekTimer = 5000; + + if(pInstance) + uint64 KilrekGUID = pInstance->GetData64(DATA_KILREK); + else ERROR_INST_DATA(m_creature); + + Creature* Kilrek = ((Creature*)Unit::GetUnit((*m_creature), KilrekGUID)); + if(SummonKilrek && Kilrek) + { + Kilrek->Respawn(); + Kilrek->AI()->AttackStart(m_creature->getVictim()); + + SummonKilrek = false; + } + + if(!Kilrek || !Kilrek->isAlive()) + { + SummonKilrek = true; + CheckKilrekTimer = 45000; + } + }else CheckKilrekTimer -= diff; + + if(SacrificeTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) + { + DoCast(target, SPELL_SACRIFICE, true); + Creature* Chains = m_creature->SummonCreature(CREATURE_DEMONCHAINS, SACRIFICE_X, SACRIFICE_Y, SACRIFICE_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 21000); + if(Chains) + { + ((mob_demon_chainAI*)Chains->AI())->SacrificeGUID = target->GetGUID(); + Chains->CastSpell(Chains, SPELL_DEMON_CHAINS, true); + switch(rand()%2) + { + case 0: + DoYell(SAY_SACRIFICE1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SACRIFICE1); + break; + case 1: + DoYell(SAY_SACRIFICE2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SACRIFICE2); + break; + } + SacrificeTimer = 30000; + } + } + }else SacrificeTimer -= diff; + + if(ShadowboltTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_TOPAGGRO, 0), SPELL_SHADOW_BOLT); + ShadowboltTimer = 10000; + }else ShadowboltTimer -= diff; + + if(SummonTimer < diff) + { + if(!SummonedPortals) + { + for(uint8 i = 0; i < 2; ++i) + { + Creature* Portal = m_creature->SummonCreature(CREATURE_PORTAL, PortalLocations[i][0], PortalLocations[i][1], PORTAL_Z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + if(Portal) + PortalGUID[i] = Portal->GetGUID(); + } + SummonedPortals = true; + switch(rand()%2) + { + case 0: + DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON1); + break; + case 1: + DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON2); + break; + } + } + uint32 random = rand()%2; + Creature* Imp = m_creature->SummonCreature(CREATURE_FIENDISHIMP, PortalLocations[random][0], PortalLocations[random][1], PORTAL_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 15000); + if(Imp) + { + Imp->AddThreat(m_creature->getVictim(), 1.0f); + Imp->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM, 1)); + } + SummonTimer = 5000; + }else SummonTimer -= diff; + + if(!Berserk) + if(BerserkTimer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + Berserk = true; + }else BerserkTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_karazhan_impAI : public ScriptedAI +{ + mob_karazhan_impAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FireboltTimer; + + void Reset() + { + FireboltTimer = 3000; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(FireboltTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FIREBOLT); + FireboltTimer = 1500; + }else FireboltTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_kilrek(Creature *_Creature) +{ + return new mob_kilrekAI (_Creature); +} + +CreatureAI* GetAI_mob_karazhan_imp(Creature *_Creature) +{ + return new mob_karazhan_impAI (_Creature); +} + +CreatureAI* GetAI_mob_demon_chain(Creature *_Creature) +{ + return new mob_demon_chainAI(_Creature); +} + +CreatureAI* GetAI_boss_terestian_illhoof(Creature *_Creature) +{ + return new boss_terestianAI (_Creature); +} + +void AddSC_boss_terestian_illhoof() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_terestian_illhoof"; + newscript->GetAI = GetAI_boss_terestian_illhoof; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_karazhan_imp"; + newscript->GetAI = GetAI_mob_karazhan_imp; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_kilrek"; + newscript->GetAI = GetAI_mob_kilrek; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_demon_chain"; + newscript->GetAI = GetAI_mob_demon_chain; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/bosses_opera.cpp b/src/bindings/scripts/scripts/zone/karazhan/bosses_opera.cpp index 3caedb2dafa..2cd3f9d3c56 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/bosses_opera.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/bosses_opera.cpp @@ -1,1471 +1,1471 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Opera -SD%Complete: 90 -SDComment: Oz, Hood, and RAJ event implemented. RAJ event requires more testing. -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" -#include "def_karazhan.h" - -/***********************************/ -/*** OPERA WIZARD OF OZ EVENT *****/ -/*********************************/ - -/**** 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 - -/***** Speech and Sound *****/ -#define SAY_DOROTHEE_DEATH "Oh at last, at last. I can go home." -#define SOUND_DOROTHEE_DEATH 9190 -#define SAY_DOROTHEE_SUMMON "Don't let them hurt us, Tito! Oh, you won't, will you?" -#define SOUND_DOROTHEE_SUMMON 9191 -#define SAY_DOROTHEE_TITO_DEATH "Tito, oh Tito, no!" -#define SOUND_DOROTHEE_TITO_DEATH 9192 -#define SAY_DOROTHEE_AGGRO "Oh dear, we simply must find a way home! The old wizard could be our only hope! Strawman, Roar, Tinhead, will you... wait! Oh golly, look! We have visitors!" -#define SOUND_DOROTHEE_AGGRO 9195 - -#define SAY_ROAR_AGGRO "Wanna fight? Huh? Do ya? C'mon, I'll fight you with both claws behind my back!" -#define SOUND_ROAR_AGGRO 9227 -#define SAY_ROAR_DEATH "You didn't have to go and do that." -#define SOUND_ROAR_DEATH 9229 -#define SAY_ROAR_SLAY "I think I'm going to go take fourty winks" -#define SOUND_ROAR_SLAY 9230 - -#define SAY_STRAWMAN_AGGRO "Now what should I do with you? I simply can't make up my mind." -#define SOUND_STRAWMAN_AGGRO 9254 -#define SAY_STRAWMAN_DEATH "Don't let them make a mattress... out of me." -#define SOUND_STRAWMAN_DEATH 9256 -#define SAY_STRAWMAN_SLAY "I guess I'm not a failure after all." -#define SOUND_STRAWMAN_SLAY 9257 - -#define SAY_TINHEAD_AGGRO "I could really use a heart. Say, can I have yours?" -#define SOUND_TINHEAD_AGGRO 9268 -#define SAY_TINHEAD_DEATH "Back to being an old rustbucket." -#define SOUND_TINHEAD_DEATH 9270 -#define SAY_TINHEAD_SLAY "Guess I'm not so rusty, after all." -#define SOUND_TINHEAD_SLAY 9271 - -#define SAY_CRONE_AGGRO "Woe to each and every one of you my pretties!" -#define SOUND_CRONE_AGGRO 9179 -#define SAY_CRONE_AGGRO2 "It will all be over soon!" -#define SOUND_CRONE_AGGRO2 9307 -#define SAY_CRONE_DEATH "How could you? What a cruel, cruel world!" -#define SOUND_CRONE_DEATH 9178 -#define SAY_CRONE_SLAY "Fixed you, didn't I?" -#define SOUND_CRONE_SLAY 9180 - -void SummonCroneIfReady(ScriptedInstance* pInstance, Creature *_Creature) -{ - pInstance->SetData(DATA_OPERA_OZ_DEATHCOUNT, 0); // Increment DeathCount - if(pInstance->GetData(DATA_OPERA_OZ_DEATHCOUNT) == 4) - { - Creature* Crone = _Creature->SummonCreature(CREATURE_CRONE, -10891.96, -1755.95, _Creature->GetPositionZ(), 4.64, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); - if(Crone) - { - if(_Creature->getVictim()) - Crone->AI()->AttackStart(_Creature->getVictim()); - - Crone->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - } -}; - -struct MANGOS_DLL_DECL boss_dorotheeAI : public ScriptedAI -{ - boss_dorotheeAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 AggroTimer; - - uint32 WaterBoltTimer; - uint32 FearTimer; - uint32 SummonTitoTimer; - - bool SummonedTito; - bool TitoDied; - bool InCombat; - - void Reset() - { - AggroTimer = 500; - - WaterBoltTimer = 5000; - FearTimer = 15000; - SummonTitoTimer = 47500; - - SummonedTito = false; - TitoDied = false; - InCombat = false; - } - - void Aggro(Unit* who) - { - DoYell(SAY_DOROTHEE_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DOROTHEE_AGGRO); - } - - void SummonTito(); // See below - - void JustDied(Unit* killer) - { - DoYell(SAY_DOROTHEE_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DOROTHEE_DEATH); - - if(pInstance) - SummonCroneIfReady(pInstance, m_creature); - } - - void AttackStart(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void UpdateAI(const uint32 diff) - { - if(AggroTimer) - if(AggroTimer <= diff) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - AggroTimer = 0; - }else AggroTimer -= diff; - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(WaterBoltTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_WATERBOLT); - WaterBoltTimer = TitoDied ? 1500 : 5000; - }else WaterBoltTimer -= diff; - - if(FearTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SCREAM); - FearTimer = 30000; - }else FearTimer -= diff; - - if(!SummonedTito) - { - if(SummonTitoTimer < diff) - SummonTito(); - else SummonTitoTimer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_titoAI : public ScriptedAI -{ - mob_titoAI(Creature* c) : ScriptedAI(c) - { - Reset(); - } - - uint64 DorotheeGUID; - - uint32 YipTimer; - - void Reset() - { - DorotheeGUID = 0; - - YipTimer = 10000; - } - - void Aggro(Unit* who) {} - - void JustDied(Unit* killer) - { - if(DorotheeGUID) - { - Creature* Dorothee = ((Creature*)Unit::GetUnit((*m_creature), DorotheeGUID)); - if(Dorothee && Dorothee->isAlive()) - { - ((boss_dorotheeAI*)Dorothee->AI())->TitoDied = true; - Dorothee->MonsterYell(SAY_DOROTHEE_TITO_DEATH, LANG_UNIVERSAL, 0); - DoPlaySoundToSet(Dorothee, SOUND_DOROTHEE_TITO_DEATH); - } - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(YipTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_YIPPING); - YipTimer = 10000; - }else YipTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -void boss_dorotheeAI::SummonTito() -{ - Creature* Tito = DoSpawnCreature(CREATURE_TITO, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); - if(Tito) - { - DoYell(SAY_DOROTHEE_SUMMON, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DOROTHEE_SUMMON); - ((mob_titoAI*)Tito->AI())->DorotheeGUID = m_creature->GetGUID(); - Tito->AI()->AttackStart(m_creature->getVictim()); - SummonedTito = true; - TitoDied = false; - } -} - -struct MANGOS_DLL_DECL boss_strawmanAI : public ScriptedAI -{ - boss_strawmanAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 AggroTimer; - uint32 BrainBashTimer; - uint32 BrainWipeTimer; - - void Reset() - { - AggroTimer = 13000; - BrainBashTimer = 5000; - BrainWipeTimer = 7000; - } - - void AttackStart(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void Aggro(Unit* who) - { - DoYell(SAY_STRAWMAN_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_STRAWMAN_AGGRO); - } - - void SpellHit(Unit* caster, const SpellEntry *Spell) - { - if((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && (!(rand()%10))) - DoCast(m_creature, SPELL_BURNING_STRAW, true); - } - - void JustDied(Unit* killer) - { - DoYell(SAY_STRAWMAN_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_STRAWMAN_DEATH); - - if(pInstance) - SummonCroneIfReady(pInstance, m_creature); - } - - void KilledUnit(Unit* victim) - { - DoYell(SAY_STRAWMAN_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_STRAWMAN_SLAY); - } - - void UpdateAI(const uint32 diff) - { - if(AggroTimer) - if(AggroTimer <= diff) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - AggroTimer = 0; - }else AggroTimer -= diff; - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(BrainBashTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_BRAIN_BASH); - BrainBashTimer = 15000; - }else BrainBashTimer -= diff; - - if(BrainWipeTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_BRAIN_WIPE); - BrainWipeTimer = 20000; - }else BrainWipeTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_tinheadAI : public ScriptedAI -{ - boss_tinheadAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 AggroTimer; - uint32 CleaveTimer; - uint32 RustTimer; - - uint8 RustCount; - - void Reset() - { - AggroTimer = 15000; - CleaveTimer = 5000; - RustTimer = 30000; - - RustCount = 0; - } - - void Aggro(Unit* who) - { - DoYell(SAY_TINHEAD_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TINHEAD_AGGRO); - } - - void AttackStart(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void JustDied(Unit* killer) - { - DoYell(SAY_TINHEAD_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TINHEAD_DEATH); - - if(pInstance) - SummonCroneIfReady(pInstance, m_creature); - } - - void KilledUnit(Unit* victim) - { - DoYell(SAY_TINHEAD_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TINHEAD_SLAY); - } - - void UpdateAI(const uint32 diff) - { - if(AggroTimer) - if(AggroTimer < diff) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - AggroTimer = 0; - }else AggroTimer -= diff; - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(CleaveTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CLEAVE); - CleaveTimer = 5000; - }else CleaveTimer -= diff; - - if(RustCount < 8) - { - if(RustTimer < diff) - { - RustCount++; - DoTextEmote("begins to rust", NULL); - DoCast(m_creature, SPELL_RUST); - RustTimer = 6000; - }else RustTimer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_roarAI : public ScriptedAI -{ - boss_roarAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 AggroTimer; - uint32 MangleTimer; - uint32 ShredTimer; - uint32 ScreamTimer; - - void Reset() - { - AggroTimer = 20000; - MangleTimer = 5000; - ShredTimer = 10000; - ScreamTimer = 15000; - } - - void MoveInLineOfSight(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void AttackStart(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void Aggro(Unit* who) - { - DoYell(SAY_ROAR_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ROAR_AGGRO); - } - - void JustDied(Unit* killer) - { - DoYell(SAY_ROAR_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ROAR_DEATH); - - if(pInstance) - SummonCroneIfReady(pInstance, m_creature); - } - - void KilledUnit(Unit* victim) - { - DoYell(SAY_ROAR_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ROAR_SLAY); - } - - void UpdateAI(const uint32 diff) - { - if(AggroTimer) - if(AggroTimer <= diff) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - AggroTimer = 0; - }else AggroTimer -= diff; - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(MangleTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_MANGLE); - MangleTimer = 5000 + rand()%3000; - }else MangleTimer -= diff; - - if(ShredTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SHRED); - ShredTimer = 10000 + rand()%5000; - }else ShredTimer -= diff; - - if(ScreamTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FRIGHTENED_SCREAM); - ScreamTimer = 20000 + rand()%10000; - }else ScreamTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_croneAI : public ScriptedAI -{ - boss_croneAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 CycloneTimer; - uint32 ChainLightningTimer; - - void Reset() - { - CycloneTimer = 30000; - ChainLightningTimer = 10000; - } - - void Aggro(Unit* who) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_CRONE_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CRONE_AGGRO); - break; - case 1: - DoYell(SAY_CRONE_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CRONE_AGGRO2); - break; - } - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - void JustDied(Unit* killer) - { - DoYell(SAY_CRONE_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CRONE_DEATH); - - if(pInstance) - { - pInstance->SetData(DATA_OPERA_EVENT, DONE); - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORRIGHT)); - if(Door) - Door->UseDoorOrButton(); - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !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) - { - DoCast(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING); - ChainLightningTimer = 15000; - }else ChainLightningTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_cycloneAI : public ScriptedAI -{ - mob_cycloneAI(Creature* c) : ScriptedAI(c) - { - Reset(); - } - - uint32 MoveTimer; - - void Reset() - { - MoveTimer = 1000; - } - - void Aggro(Unit* who) {} - - void MoveInLineOfSight(Unit* who) - { - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->HasAura(SPELL_KNOCKBACK, 0)) - DoCast(m_creature, SPELL_KNOCKBACK, true); - - 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 = 5000 + rand()%3000; - }else MoveTimer -= diff; - } -}; - -CreatureAI* GetAI_boss_dorothee(Creature* _Creature) -{ - return new boss_dorotheeAI(_Creature); -} - -CreatureAI* GetAI_boss_strawman(Creature* _Creature) -{ - return new boss_strawmanAI(_Creature); -} - -CreatureAI* GetAI_boss_tinhead(Creature* _Creature) -{ - return new boss_tinheadAI(_Creature); -} - -CreatureAI* GetAI_boss_roar(Creature* _Creature) -{ - return new boss_roarAI(_Creature); -} - -CreatureAI* GetAI_boss_crone(Creature* _Creature) -{ - return new boss_croneAI(_Creature); -} - -CreatureAI* GetAI_mob_tito(Creature* _Creature) -{ - return new mob_titoAI(_Creature); -} - -CreatureAI* GetAI_mob_cyclone(Creature* _Creature) -{ - return new mob_cycloneAI(_Creature); -} - -/**************************************/ -/**** Opera Red Riding Hood Event ****/ -/************************************/ - -#define GOSSIP_GRANDMA "What phat lewtz you have grandmother?" - -/**** Spells For The Wolf ****/ -#define SPELL_LITTLE_RED_RIDING_HOOD 30768 -#define SPELL_TERRIFYING_HOWL 30752 -#define SPELL_WIDE_SWIPE 30761 - -/**** Yells for the Wolf ****/ -#define SAY_WOLF_AGGRO "All the better to own you with!" -#define SOUND_WOLF_AGGRO 9276 -#define SOUND_WOLF_DEATH 9275 // No speech -#define SAY_WOLF_SLAY "Mmmm... delicious." -#define SOUND_WOLF_SLAY 9277 -#define SAY_WOLF_HOOD "Run away little girl, run away!" -#define SOUND_WOLF_HOOD 9278 - -/**** The Wolf's Entry ****/ -#define CREATURE_BIG_BAD_WOLF 17521 - -bool GossipHello_npc_grandmother(Player* player, Creature* _Creature) -{ - player->ADD_GOSSIP_ITEM(0, GOSSIP_GRANDMA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(8990, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_grandmother(Player* player, Creature* _Creature, uint32 sender, uint32 action) -{ - if(action == GOSSIP_ACTION_INFO_DEF) - { - _Creature->SetVisibility(VISIBILITY_OFF); - float x,y,z; - _Creature->GetPosition(x,y,z); - Creature* BigBadWolf = _Creature->SummonCreature(CREATURE_BIG_BAD_WOLF, x, y, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); - if(BigBadWolf) - { - BigBadWolf->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - BigBadWolf->AI()->AttackStart(player); - } - - _Creature->setDeathState(JUST_DIED); - } - - return true; -} - -struct MANGOS_DLL_DECL boss_bigbadwolfAI : public ScriptedAI -{ - boss_bigbadwolfAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 ChaseTimer; - uint32 FearTimer; - uint32 SwipeTimer; - - uint64 HoodGUID; - float TempThreat; - - bool IsChasing; - - void Reset() - { - ChaseTimer = 30000; - FearTimer = 25000 + rand()%10000; - SwipeTimer = 5000; - - HoodGUID = 0; - TempThreat = 0; - - IsChasing = false; - } - - void Aggro(Unit* who) - { - DoYell(SAY_WOLF_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_WOLF_AGGRO); - } - - void JustDied(Unit* killer) - { - DoPlaySoundToSet(m_creature, SOUND_WOLF_DEATH); - - if(pInstance) - { - pInstance->SetData(DATA_OPERA_EVENT, DONE); - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORRIGHT)); - if(Door) - Door->UseDoorOrButton(); - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - - if(ChaseTimer < diff) - { - if(!IsChasing) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target && target->GetTypeId() == TYPEID_PLAYER) - { - DoYell(SAY_WOLF_HOOD, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_WOLF_HOOD); - - DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true); - 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; - } - } - else - { - IsChasing = false; - Unit* target = Unit::GetUnit((*m_creature), HoodGUID); - if(target) - { - 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; - - if(FearTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_TERRIFYING_HOWL); - FearTimer = 25000 + rand()%35000; - }else FearTimer -= diff; - - if(SwipeTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_WIDE_SWIPE); - SwipeTimer = 25000 + rand()%5000; - }else SwipeTimer -= diff; - - } -}; - -CreatureAI* GetAI_boss_bigbadwolf(Creature* _Creature) -{ - return new boss_bigbadwolfAI(_Creature); -} - -/**********************************************/ -/******** Opera Romeo and Juliet Event *******/ -/********************************************/ - -/***** 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 - -/**** Speech and Text *****/ -/****** Julianne *******/ -#define SAY_JULIANNE_AGGRO "What devil art thou, that dost torment me thus?" -#define SOUND_JULIANNE_AGGRO 9196 -#define SAY_JULIANNE_ENTER "Where is my lord? Where is my Romulo?" -#define SOUND_JULIANNE_ENTER 9199 -#define SAY_JULIANNE_DEATH01 "Romulo, I come! Oh... this do I drink to thee!" -#define SOUND_JULIANNE_DEATH01 9198 -#define SAY_JULIANNE_DEATH02 "Where is my Lord? Where is my Romulo? Ohh, happy dagger! This is thy sheath! There rust, and let me die!" -#define SOUND_JULIANNE_DEATH02 9310 -#define SAY_JULIANNE_RESURRECT "Come, gentle night; and give me back my Romulo!" -#define SOUND_JULIANNE_RESURRECT 9200 -#define SAY_JULIANNE_SLAY "Parting is such sweet sorrow." -#define SOUND_JULIANNE_SLAY 9201 - -/****** Romulo *******/ -#define SAY_ROMULO_AGGRO "Wilt thou provoke me? Then have at thee, boy!" -#define SOUND_ROMULO_AGGRO 9233 -#define SAY_ROMULO_DEATH "Thou smilest... upon the stroke that... murders me." -#define SOUND_ROMULO_DEATH 9235 -#define SAY_ROMULO_ENTER "This day's black fate on more days doth depend. This but begins the woe. Others must end." -#define SOUND_ROMULO_ENTER 9236 -#define SAY_ROMULO_RESURRECT "Thou detestable maw, thou womb of death; I enforce thy rotten jaws to open!" -#define SOUND_ROMULO_RESURRECT 9237 -#define SAY_ROMULO_SLAY "How well my comfort is revived by this!" -#define SOUND_ROMULO_SLAY 9238 - -/*** Misc. Information ****/ -#define CREATURE_ROMULO 17533 -#define ROMULO_X -10900 -#define ROMULO_Y -1758 - -enum RAJPhase -{ - PHASE_JULIANNE = 0, - PHASE_ROMULO = 1, - PHASE_BOTH = 2, -}; - -void PretendToDie(Creature* _Creature) -{ - _Creature->InterruptNonMeleeSpells(false); - _Creature->SetHealth(0); - _Creature->StopMoving(); - _Creature->ClearComboPointHolders(); - _Creature->RemoveAllAurasOnDeath(); - _Creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); - _Creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); - _Creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - _Creature->ClearAllReactives(); - _Creature->SetUInt64Value(UNIT_FIELD_TARGET,0); - _Creature->GetMotionMaster()->Clear(); - _Creature->GetMotionMaster()->MoveIdle(); - _Creature->SetUInt32Value(UNIT_FIELD_BYTES_1,PLAYER_STATE_DEAD); -}; - -void Resurrect(Creature* target) -{ - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - target->SetHealth(target->GetMaxHealth()); - target->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - target->CastSpell(target, SPELL_RES_VISUAL, true); - if(target->getVictim()) - { - target->SetUInt64Value(UNIT_FIELD_TARGET, target->getVictim()->GetGUID()); - target->GetMotionMaster()->MoveChase(target->getVictim()); - target->AI()->AttackStart(target->getVictim()); - } -}; - -struct MANGOS_DLL_DECL boss_julianneAI : public ScriptedAI -{ - boss_julianneAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - EntryYellTimer = 1000; - AggroYellTimer = 10000; - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 RomuloGUID; - - uint32 Phase; - - uint32 EntryYellTimer; - uint32 AggroYellTimer; - uint32 BlindingPassionTimer; - uint32 DevotionTimer; - uint32 EternalAffectionTimer; - uint32 PowerfulAttractionTimer; - uint32 SummonRomuloTimer; - uint32 ResurrectTimer; - - bool IsFakingDeath; - bool SummonedRomulo; - bool RomuloDead; - - void Reset() - { - if(RomuloGUID) - { - if(Unit* Romulo = Unit::GetUnit(*m_creature, RomuloGUID)) - { - Romulo->SetVisibility(VISIBILITY_OFF); - Romulo->DealDamage(Romulo, Romulo->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - - RomuloGUID = 0; - } - - Phase = PHASE_JULIANNE; - - BlindingPassionTimer = 30000; - DevotionTimer = 15000; - EternalAffectionTimer = 25000; - PowerfulAttractionTimer = 5000; - - if(IsFakingDeath) - Resurrect(m_creature); - - IsFakingDeath = false; - SummonedRomulo = false; - RomuloDead = false; - } - - void Aggro(Unit* who) {} - - void AttackStart(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void DamageTaken(Unit* done_by, uint32 &damage); - - void JustDied(Unit* killer) - { - DoYell(SAY_JULIANNE_DEATH02, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_JULIANNE_DEATH02); - - if(pInstance) - { - pInstance->SetData(DATA_OPERA_EVENT, DONE); - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORRIGHT)); - if(Door) - Door->UseDoorOrButton(); - } - } - - void KilledUnit(Unit* victim) - { - DoYell(SAY_JULIANNE_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_JULIANNE_SLAY); - } - - void UpdateAI(const uint32 diff); -}; - -struct MANGOS_DLL_DECL boss_romuloAI : public ScriptedAI -{ - boss_romuloAI(Creature* c) : ScriptedAI(c) - { - Reset(); - EntryYellTimer = 8000; - AggroYellTimer = 15000; - } - - uint64 JulianneGUID; - - uint32 Phase; - - uint32 EntryYellTimer; - uint32 AggroYellTimer; - uint32 BackwardLungeTimer; - uint32 DaringTimer; - uint32 DeadlySwatheTimer; - uint32 PoisonThrustTimer; - uint32 ResurrectTimer; - - bool JulianneDead; - bool IsFakingDeath; - - void Reset() - { - JulianneGUID = 0; - - Phase = PHASE_ROMULO; - - BackwardLungeTimer = 15000; - DaringTimer = 20000; - DeadlySwatheTimer = 25000; - PoisonThrustTimer = 10000; - - if(IsFakingDeath) - Resurrect(m_creature); - - IsFakingDeath = false; - JulianneDead = false; - } - - void DamageTaken(Unit* done_by, uint32 &damage); - - void Aggro(Unit* who) - { - DoYell(SAY_ROMULO_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ROMULO_AGGRO); - if(JulianneGUID) - { - Creature* Julianne = ((Creature*)Unit::GetUnit((*m_creature), JulianneGUID)); - if(Julianne && Julianne->getVictim()) - { - m_creature->AddThreat(Julianne->getVictim(), 1.0f); - DoStartAttackAndMovement(Julianne->getVictim()); - } - } - } - - void MoveInLineOfSight(Unit* who) - { - if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void JustDied(Unit* killer) - { - DoYell(SAY_ROMULO_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ROMULO_DEATH); - } - - void KilledUnit(Unit* victim) - { - DoYell(SAY_ROMULO_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ROMULO_SLAY); - } - - void UpdateAI(const uint32 diff); -}; - -void boss_julianneAI::DamageTaken(Unit* done_by, uint32 &damage) -{ - if(damage < m_creature->GetHealth() || done_by == m_creature || done_by->GetGUID() == RomuloGUID) - return; - - if(Phase == PHASE_JULIANNE) - { - DoYell(SAY_JULIANNE_DEATH01, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_JULIANNE_DEATH01); - m_creature->InterruptNonMeleeSpells(true); - DoCast(m_creature, SPELL_DRINK_POISON); - PretendToDie(m_creature); - Phase = PHASE_ROMULO; - damage = 0; - IsFakingDeath = true; - SummonRomuloTimer = 10000; - return; - } - - if(!IsFakingDeath) - { - Creature* Romulo = ((Creature*)Unit::GetUnit((*m_creature), RomuloGUID)); - if(Romulo && Romulo->isAlive() && !((boss_romuloAI*)Romulo->AI())->IsFakingDeath) - { - ((boss_romuloAI*)Romulo->AI())->ResurrectTimer = 10000; - ((boss_romuloAI*)Romulo->AI())->JulianneDead = true; - } - else - { - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - if(Romulo) - { - Romulo->DealDamage(Romulo, Romulo->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - Romulo->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - JustDied(done_by); - } - - IsFakingDeath = true; - PretendToDie(m_creature); - damage = 0; - } - else - damage = 0; -} - -void boss_romuloAI::DamageTaken(Unit* done_by, uint32 &damage) -{ - if(damage < m_creature->GetHealth() || done_by == m_creature || done_by->GetGUID() == JulianneGUID) - return; - - if(!IsFakingDeath) - { - IsFakingDeath = true; - PretendToDie(m_creature); - - if(Phase == PHASE_BOTH) - { - Creature* Julianne = ((Creature*)Unit::GetUnit((*m_creature), JulianneGUID)); - if(Julianne && Julianne->isAlive() && !((boss_julianneAI*)Julianne->AI())->IsFakingDeath) - { - ((boss_julianneAI*)Julianne->AI())->ResurrectTimer = 10000; - ((boss_julianneAI*)Julianne->AI())->RomuloDead = true; - } - else - { - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - if(Julianne) - { - Julianne->DealDamage(Julianne, Julianne->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - Julianne->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - JustDied(done_by); - } - } - else - { - Creature* Julianne = ((Creature*)Unit::GetUnit((*m_creature), JulianneGUID)); - if(Julianne) - { - Resurrect(Julianne); - m_creature->SetHealth(m_creature->GetMaxHealth()); - ((boss_julianneAI*)Julianne->AI())->ResurrectTimer = 4000; - ((boss_julianneAI*)Julianne->AI())->RomuloDead = true; - ((boss_julianneAI*)Julianne->AI())->Phase = PHASE_BOTH; - ((boss_julianneAI*)Julianne->AI())->IsFakingDeath = false; - } - Phase = PHASE_BOTH; - } - - damage = 0; - } - - if(IsFakingDeath) damage = 0; -} - -void boss_julianneAI::UpdateAI(const uint32 diff) -{ - if(EntryYellTimer) - if(EntryYellTimer < diff) - { - DoYell(SAY_JULIANNE_ENTER, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_JULIANNE_ENTER); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - EntryYellTimer = 0; - }else EntryYellTimer -= diff; - - if(AggroYellTimer) - if(AggroYellTimer < diff) - { - DoYell(SAY_JULIANNE_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_JULIANNE_AGGRO); - AggroYellTimer = 0; - }else AggroYellTimer -= diff; - - if(Phase == PHASE_ROMULO && !SummonedRomulo) - { - if(SummonRomuloTimer < diff) - { - Creature* Romulo = m_creature->SummonCreature(CREATURE_ROMULO, ROMULO_X, ROMULO_Y, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); - if(Romulo) - { - RomuloGUID = Romulo->GetGUID(); - ((boss_romuloAI*)Romulo->AI())->JulianneGUID = m_creature->GetGUID(); - ((boss_romuloAI*)Romulo->AI())->Phase = PHASE_ROMULO; - if(m_creature->getVictim()) - { - Romulo->AI()->AttackStart(m_creature->getVictim()); - Romulo->AddThreat(m_creature->getVictim(), 50.0f); - } - DoZoneInCombat(Romulo); - } - SummonedRomulo = true; - }else SummonRomuloTimer -= diff; - } - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ||IsFakingDeath) - return; - - if(RomuloDead) - if(ResurrectTimer < diff) - { - Creature* Romulo = ((Creature*)Unit::GetUnit((*m_creature), RomuloGUID)); - if(Romulo && ((boss_romuloAI*)Romulo->AI())->IsFakingDeath) - { - DoYell(SAY_JULIANNE_RESURRECT, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_JULIANNE_RESURRECT); - Resurrect(Romulo); - ((boss_romuloAI*)Romulo->AI())->IsFakingDeath = false; - ResurrectTimer = 10000; - } - RomuloDead = false; - }else ResurrectTimer -= diff; - - if(BlindingPassionTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_BLINDING_PASSION); - BlindingPassionTimer = 30000 + rand()%15000; - }else BlindingPassionTimer -= diff; - - if(DevotionTimer < diff) - { - DoCast(m_creature, SPELL_DEVOTION); - DevotionTimer = 15000 + rand()%30000; - }else DevotionTimer -= diff; - - if(PowerfulAttractionTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_POWERFUL_ATTRACTION); - PowerfulAttractionTimer = 5000 + rand()%25000; - }else PowerfulAttractionTimer -= diff; - - if(EternalAffectionTimer < diff) - { - if(rand()%2 == 1 && SummonedRomulo) - { - Creature* Romulo = ((Creature*)Unit::GetUnit((*m_creature), RomuloGUID)); - if(Romulo && Romulo->isAlive() && !((boss_romuloAI*)Romulo->AI())->IsFakingDeath) - DoCast(Romulo, SPELL_ETERNAL_AFFECTION); - else - return; - } - else DoCast(m_creature, SPELL_ETERNAL_AFFECTION); - - EternalAffectionTimer = 45000 + rand()%15000; - }else EternalAffectionTimer -= diff; - - DoMeleeAttackIfReady(); -} - -void boss_romuloAI::UpdateAI(const uint32 diff) -{ - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsFakingDeath) - return; - - if(JulianneDead) - if(ResurrectTimer < diff) - { - Creature* Julianne = ((Creature*)Unit::GetUnit((*m_creature), JulianneGUID)); - if(Julianne && ((boss_julianneAI*)Julianne->AI())->IsFakingDeath) - { - DoYell(SAY_ROMULO_RESURRECT, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ROMULO_RESURRECT); - Resurrect(Julianne); - ((boss_julianneAI*)Julianne->AI())->IsFakingDeath = false; - ResurrectTimer = 10000; - } - JulianneDead = false; - }else ResurrectTimer -= diff; - - if(BackwardLungeTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(target && !m_creature->HasInArc(M_PI, target)) - { - DoCast(target, SPELL_BACKWARD_LUNGE); - BackwardLungeTimer = 15000 + rand()%15000; - } - }else BackwardLungeTimer -= diff; - - if(DaringTimer < diff) - { - DoCast(m_creature, SPELL_DARING); - DaringTimer = 20000 + rand()%20000; - }else DaringTimer -= diff; - - if(DeadlySwatheTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DEADLY_SWATHE); - DeadlySwatheTimer = 15000 + rand()%10000; - }else DeadlySwatheTimer -= diff; - - if(PoisonThrustTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_POISON_THRUST); - PoisonThrustTimer = 10000 + rand()%10000; - }else PoisonThrustTimer -= diff; - - DoMeleeAttackIfReady(); -} - -CreatureAI* GetAI_boss_julianne(Creature* _Creature) -{ - return new boss_julianneAI(_Creature); -} - -CreatureAI* GetAI_boss_romulo(Creature* _Creature) -{ - return new boss_romuloAI(_Creature); -} - -void AddSC_bosses_opera() -{ - Script* newscript; - - // Oz - newscript = new Script; - newscript->GetAI = GetAI_boss_dorothee; - newscript->Name = "boss_dorothee"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_strawman; - newscript->Name = "boss_strawman"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_tinhead; - newscript->Name = "boss_tinhead"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_roar; - newscript->Name = "boss_roar"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_crone; - newscript->Name = "boss_crone"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_mob_tito; - newscript->Name = "mob_tito"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_mob_cyclone; - newscript->Name = "mob_cyclone"; - m_scripts[nrscripts++] = newscript; - - // Hood - newscript = new Script; - newscript->pGossipHello = GossipHello_npc_grandmother; - newscript->pGossipSelect = GossipSelect_npc_grandmother; - newscript->Name = "npc_grandmother"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_bigbadwolf; - newscript->Name = "boss_bigbadwolf"; - m_scripts[nrscripts++] = newscript; - - // Romeo And Juliet - newscript = new Script; - newscript->GetAI = GetAI_boss_julianne; - newscript->Name = "boss_julianne"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_romulo; - newscript->Name = "boss_romulo"; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Opera +SD%Complete: 90 +SDComment: Oz, Hood, and RAJ event implemented. RAJ event requires more testing. +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" +#include "def_karazhan.h" + +/***********************************/ +/*** OPERA WIZARD OF OZ EVENT *****/ +/*********************************/ + +/**** 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 + +/***** Speech and Sound *****/ +#define SAY_DOROTHEE_DEATH "Oh at last, at last. I can go home." +#define SOUND_DOROTHEE_DEATH 9190 +#define SAY_DOROTHEE_SUMMON "Don't let them hurt us, Tito! Oh, you won't, will you?" +#define SOUND_DOROTHEE_SUMMON 9191 +#define SAY_DOROTHEE_TITO_DEATH "Tito, oh Tito, no!" +#define SOUND_DOROTHEE_TITO_DEATH 9192 +#define SAY_DOROTHEE_AGGRO "Oh dear, we simply must find a way home! The old wizard could be our only hope! Strawman, Roar, Tinhead, will you... wait! Oh golly, look! We have visitors!" +#define SOUND_DOROTHEE_AGGRO 9195 + +#define SAY_ROAR_AGGRO "Wanna fight? Huh? Do ya? C'mon, I'll fight you with both claws behind my back!" +#define SOUND_ROAR_AGGRO 9227 +#define SAY_ROAR_DEATH "You didn't have to go and do that." +#define SOUND_ROAR_DEATH 9229 +#define SAY_ROAR_SLAY "I think I'm going to go take fourty winks" +#define SOUND_ROAR_SLAY 9230 + +#define SAY_STRAWMAN_AGGRO "Now what should I do with you? I simply can't make up my mind." +#define SOUND_STRAWMAN_AGGRO 9254 +#define SAY_STRAWMAN_DEATH "Don't let them make a mattress... out of me." +#define SOUND_STRAWMAN_DEATH 9256 +#define SAY_STRAWMAN_SLAY "I guess I'm not a failure after all." +#define SOUND_STRAWMAN_SLAY 9257 + +#define SAY_TINHEAD_AGGRO "I could really use a heart. Say, can I have yours?" +#define SOUND_TINHEAD_AGGRO 9268 +#define SAY_TINHEAD_DEATH "Back to being an old rustbucket." +#define SOUND_TINHEAD_DEATH 9270 +#define SAY_TINHEAD_SLAY "Guess I'm not so rusty, after all." +#define SOUND_TINHEAD_SLAY 9271 + +#define SAY_CRONE_AGGRO "Woe to each and every one of you my pretties!" +#define SOUND_CRONE_AGGRO 9179 +#define SAY_CRONE_AGGRO2 "It will all be over soon!" +#define SOUND_CRONE_AGGRO2 9307 +#define SAY_CRONE_DEATH "How could you? What a cruel, cruel world!" +#define SOUND_CRONE_DEATH 9178 +#define SAY_CRONE_SLAY "Fixed you, didn't I?" +#define SOUND_CRONE_SLAY 9180 + +void SummonCroneIfReady(ScriptedInstance* pInstance, Creature *_Creature) +{ + pInstance->SetData(DATA_OPERA_OZ_DEATHCOUNT, 0); // Increment DeathCount + if(pInstance->GetData(DATA_OPERA_OZ_DEATHCOUNT) == 4) + { + Creature* Crone = _Creature->SummonCreature(CREATURE_CRONE, -10891.96, -1755.95, _Creature->GetPositionZ(), 4.64, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); + if(Crone) + { + if(_Creature->getVictim()) + Crone->AI()->AttackStart(_Creature->getVictim()); + + Crone->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } +}; + +struct MANGOS_DLL_DECL boss_dorotheeAI : public ScriptedAI +{ + boss_dorotheeAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 AggroTimer; + + uint32 WaterBoltTimer; + uint32 FearTimer; + uint32 SummonTitoTimer; + + bool SummonedTito; + bool TitoDied; + bool InCombat; + + void Reset() + { + AggroTimer = 500; + + WaterBoltTimer = 5000; + FearTimer = 15000; + SummonTitoTimer = 47500; + + SummonedTito = false; + TitoDied = false; + InCombat = false; + } + + void Aggro(Unit* who) + { + DoYell(SAY_DOROTHEE_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DOROTHEE_AGGRO); + } + + void SummonTito(); // See below + + void JustDied(Unit* killer) + { + DoYell(SAY_DOROTHEE_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DOROTHEE_DEATH); + + if(pInstance) + SummonCroneIfReady(pInstance, m_creature); + } + + void AttackStart(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void UpdateAI(const uint32 diff) + { + if(AggroTimer) + if(AggroTimer <= diff) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + AggroTimer = 0; + }else AggroTimer -= diff; + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(WaterBoltTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_WATERBOLT); + WaterBoltTimer = TitoDied ? 1500 : 5000; + }else WaterBoltTimer -= diff; + + if(FearTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SCREAM); + FearTimer = 30000; + }else FearTimer -= diff; + + if(!SummonedTito) + { + if(SummonTitoTimer < diff) + SummonTito(); + else SummonTitoTimer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_titoAI : public ScriptedAI +{ + mob_titoAI(Creature* c) : ScriptedAI(c) + { + Reset(); + } + + uint64 DorotheeGUID; + + uint32 YipTimer; + + void Reset() + { + DorotheeGUID = 0; + + YipTimer = 10000; + } + + void Aggro(Unit* who) {} + + void JustDied(Unit* killer) + { + if(DorotheeGUID) + { + Creature* Dorothee = ((Creature*)Unit::GetUnit((*m_creature), DorotheeGUID)); + if(Dorothee && Dorothee->isAlive()) + { + ((boss_dorotheeAI*)Dorothee->AI())->TitoDied = true; + Dorothee->MonsterYell(SAY_DOROTHEE_TITO_DEATH, LANG_UNIVERSAL, 0); + DoPlaySoundToSet(Dorothee, SOUND_DOROTHEE_TITO_DEATH); + } + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(YipTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_YIPPING); + YipTimer = 10000; + }else YipTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +void boss_dorotheeAI::SummonTito() +{ + Creature* Tito = DoSpawnCreature(CREATURE_TITO, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); + if(Tito) + { + DoYell(SAY_DOROTHEE_SUMMON, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DOROTHEE_SUMMON); + ((mob_titoAI*)Tito->AI())->DorotheeGUID = m_creature->GetGUID(); + Tito->AI()->AttackStart(m_creature->getVictim()); + SummonedTito = true; + TitoDied = false; + } +} + +struct MANGOS_DLL_DECL boss_strawmanAI : public ScriptedAI +{ + boss_strawmanAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 AggroTimer; + uint32 BrainBashTimer; + uint32 BrainWipeTimer; + + void Reset() + { + AggroTimer = 13000; + BrainBashTimer = 5000; + BrainWipeTimer = 7000; + } + + void AttackStart(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void Aggro(Unit* who) + { + DoYell(SAY_STRAWMAN_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_STRAWMAN_AGGRO); + } + + void SpellHit(Unit* caster, const SpellEntry *Spell) + { + if((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && (!(rand()%10))) + DoCast(m_creature, SPELL_BURNING_STRAW, true); + } + + void JustDied(Unit* killer) + { + DoYell(SAY_STRAWMAN_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_STRAWMAN_DEATH); + + if(pInstance) + SummonCroneIfReady(pInstance, m_creature); + } + + void KilledUnit(Unit* victim) + { + DoYell(SAY_STRAWMAN_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_STRAWMAN_SLAY); + } + + void UpdateAI(const uint32 diff) + { + if(AggroTimer) + if(AggroTimer <= diff) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + AggroTimer = 0; + }else AggroTimer -= diff; + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(BrainBashTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_BRAIN_BASH); + BrainBashTimer = 15000; + }else BrainBashTimer -= diff; + + if(BrainWipeTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_BRAIN_WIPE); + BrainWipeTimer = 20000; + }else BrainWipeTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_tinheadAI : public ScriptedAI +{ + boss_tinheadAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 AggroTimer; + uint32 CleaveTimer; + uint32 RustTimer; + + uint8 RustCount; + + void Reset() + { + AggroTimer = 15000; + CleaveTimer = 5000; + RustTimer = 30000; + + RustCount = 0; + } + + void Aggro(Unit* who) + { + DoYell(SAY_TINHEAD_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TINHEAD_AGGRO); + } + + void AttackStart(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void JustDied(Unit* killer) + { + DoYell(SAY_TINHEAD_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TINHEAD_DEATH); + + if(pInstance) + SummonCroneIfReady(pInstance, m_creature); + } + + void KilledUnit(Unit* victim) + { + DoYell(SAY_TINHEAD_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TINHEAD_SLAY); + } + + void UpdateAI(const uint32 diff) + { + if(AggroTimer) + if(AggroTimer < diff) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + AggroTimer = 0; + }else AggroTimer -= diff; + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(CleaveTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + CleaveTimer = 5000; + }else CleaveTimer -= diff; + + if(RustCount < 8) + { + if(RustTimer < diff) + { + RustCount++; + DoTextEmote("begins to rust", NULL); + DoCast(m_creature, SPELL_RUST); + RustTimer = 6000; + }else RustTimer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_roarAI : public ScriptedAI +{ + boss_roarAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 AggroTimer; + uint32 MangleTimer; + uint32 ShredTimer; + uint32 ScreamTimer; + + void Reset() + { + AggroTimer = 20000; + MangleTimer = 5000; + ShredTimer = 10000; + ScreamTimer = 15000; + } + + void MoveInLineOfSight(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void AttackStart(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void Aggro(Unit* who) + { + DoYell(SAY_ROAR_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ROAR_AGGRO); + } + + void JustDied(Unit* killer) + { + DoYell(SAY_ROAR_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ROAR_DEATH); + + if(pInstance) + SummonCroneIfReady(pInstance, m_creature); + } + + void KilledUnit(Unit* victim) + { + DoYell(SAY_ROAR_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ROAR_SLAY); + } + + void UpdateAI(const uint32 diff) + { + if(AggroTimer) + if(AggroTimer <= diff) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + AggroTimer = 0; + }else AggroTimer -= diff; + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(MangleTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_MANGLE); + MangleTimer = 5000 + rand()%3000; + }else MangleTimer -= diff; + + if(ShredTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SHRED); + ShredTimer = 10000 + rand()%5000; + }else ShredTimer -= diff; + + if(ScreamTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FRIGHTENED_SCREAM); + ScreamTimer = 20000 + rand()%10000; + }else ScreamTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_croneAI : public ScriptedAI +{ + boss_croneAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 CycloneTimer; + uint32 ChainLightningTimer; + + void Reset() + { + CycloneTimer = 30000; + ChainLightningTimer = 10000; + } + + void Aggro(Unit* who) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_CRONE_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CRONE_AGGRO); + break; + case 1: + DoYell(SAY_CRONE_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CRONE_AGGRO2); + break; + } + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void JustDied(Unit* killer) + { + DoYell(SAY_CRONE_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CRONE_DEATH); + + if(pInstance) + { + pInstance->SetData(DATA_OPERA_EVENT, DONE); + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORRIGHT)); + if(Door) + Door->UseDoorOrButton(); + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !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) + { + DoCast(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING); + ChainLightningTimer = 15000; + }else ChainLightningTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_cycloneAI : public ScriptedAI +{ + mob_cycloneAI(Creature* c) : ScriptedAI(c) + { + Reset(); + } + + uint32 MoveTimer; + + void Reset() + { + MoveTimer = 1000; + } + + void Aggro(Unit* who) {} + + void MoveInLineOfSight(Unit* who) + { + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->HasAura(SPELL_KNOCKBACK, 0)) + DoCast(m_creature, SPELL_KNOCKBACK, true); + + 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 = 5000 + rand()%3000; + }else MoveTimer -= diff; + } +}; + +CreatureAI* GetAI_boss_dorothee(Creature* _Creature) +{ + return new boss_dorotheeAI(_Creature); +} + +CreatureAI* GetAI_boss_strawman(Creature* _Creature) +{ + return new boss_strawmanAI(_Creature); +} + +CreatureAI* GetAI_boss_tinhead(Creature* _Creature) +{ + return new boss_tinheadAI(_Creature); +} + +CreatureAI* GetAI_boss_roar(Creature* _Creature) +{ + return new boss_roarAI(_Creature); +} + +CreatureAI* GetAI_boss_crone(Creature* _Creature) +{ + return new boss_croneAI(_Creature); +} + +CreatureAI* GetAI_mob_tito(Creature* _Creature) +{ + return new mob_titoAI(_Creature); +} + +CreatureAI* GetAI_mob_cyclone(Creature* _Creature) +{ + return new mob_cycloneAI(_Creature); +} + +/**************************************/ +/**** Opera Red Riding Hood Event ****/ +/************************************/ + +#define GOSSIP_GRANDMA "What phat lewtz you have grandmother?" + +/**** Spells For The Wolf ****/ +#define SPELL_LITTLE_RED_RIDING_HOOD 30768 +#define SPELL_TERRIFYING_HOWL 30752 +#define SPELL_WIDE_SWIPE 30761 + +/**** Yells for the Wolf ****/ +#define SAY_WOLF_AGGRO "All the better to own you with!" +#define SOUND_WOLF_AGGRO 9276 +#define SOUND_WOLF_DEATH 9275 // No speech +#define SAY_WOLF_SLAY "Mmmm... delicious." +#define SOUND_WOLF_SLAY 9277 +#define SAY_WOLF_HOOD "Run away little girl, run away!" +#define SOUND_WOLF_HOOD 9278 + +/**** The Wolf's Entry ****/ +#define CREATURE_BIG_BAD_WOLF 17521 + +bool GossipHello_npc_grandmother(Player* player, Creature* _Creature) +{ + player->ADD_GOSSIP_ITEM(0, GOSSIP_GRANDMA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(8990, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_grandmother(Player* player, Creature* _Creature, uint32 sender, uint32 action) +{ + if(action == GOSSIP_ACTION_INFO_DEF) + { + _Creature->SetVisibility(VISIBILITY_OFF); + float x,y,z; + _Creature->GetPosition(x,y,z); + Creature* BigBadWolf = _Creature->SummonCreature(CREATURE_BIG_BAD_WOLF, x, y, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); + if(BigBadWolf) + { + BigBadWolf->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + BigBadWolf->AI()->AttackStart(player); + } + + _Creature->setDeathState(JUST_DIED); + } + + return true; +} + +struct MANGOS_DLL_DECL boss_bigbadwolfAI : public ScriptedAI +{ + boss_bigbadwolfAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 ChaseTimer; + uint32 FearTimer; + uint32 SwipeTimer; + + uint64 HoodGUID; + float TempThreat; + + bool IsChasing; + + void Reset() + { + ChaseTimer = 30000; + FearTimer = 25000 + rand()%10000; + SwipeTimer = 5000; + + HoodGUID = 0; + TempThreat = 0; + + IsChasing = false; + } + + void Aggro(Unit* who) + { + DoYell(SAY_WOLF_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_WOLF_AGGRO); + } + + void JustDied(Unit* killer) + { + DoPlaySoundToSet(m_creature, SOUND_WOLF_DEATH); + + if(pInstance) + { + pInstance->SetData(DATA_OPERA_EVENT, DONE); + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORRIGHT)); + if(Door) + Door->UseDoorOrButton(); + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + + if(ChaseTimer < diff) + { + if(!IsChasing) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target && target->GetTypeId() == TYPEID_PLAYER) + { + DoYell(SAY_WOLF_HOOD, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_WOLF_HOOD); + + DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true); + 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; + } + } + else + { + IsChasing = false; + Unit* target = Unit::GetUnit((*m_creature), HoodGUID); + if(target) + { + 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; + + if(FearTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_TERRIFYING_HOWL); + FearTimer = 25000 + rand()%35000; + }else FearTimer -= diff; + + if(SwipeTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_WIDE_SWIPE); + SwipeTimer = 25000 + rand()%5000; + }else SwipeTimer -= diff; + + } +}; + +CreatureAI* GetAI_boss_bigbadwolf(Creature* _Creature) +{ + return new boss_bigbadwolfAI(_Creature); +} + +/**********************************************/ +/******** Opera Romeo and Juliet Event *******/ +/********************************************/ + +/***** 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 + +/**** Speech and Text *****/ +/****** Julianne *******/ +#define SAY_JULIANNE_AGGRO "What devil art thou, that dost torment me thus?" +#define SOUND_JULIANNE_AGGRO 9196 +#define SAY_JULIANNE_ENTER "Where is my lord? Where is my Romulo?" +#define SOUND_JULIANNE_ENTER 9199 +#define SAY_JULIANNE_DEATH01 "Romulo, I come! Oh... this do I drink to thee!" +#define SOUND_JULIANNE_DEATH01 9198 +#define SAY_JULIANNE_DEATH02 "Where is my Lord? Where is my Romulo? Ohh, happy dagger! This is thy sheath! There rust, and let me die!" +#define SOUND_JULIANNE_DEATH02 9310 +#define SAY_JULIANNE_RESURRECT "Come, gentle night; and give me back my Romulo!" +#define SOUND_JULIANNE_RESURRECT 9200 +#define SAY_JULIANNE_SLAY "Parting is such sweet sorrow." +#define SOUND_JULIANNE_SLAY 9201 + +/****** Romulo *******/ +#define SAY_ROMULO_AGGRO "Wilt thou provoke me? Then have at thee, boy!" +#define SOUND_ROMULO_AGGRO 9233 +#define SAY_ROMULO_DEATH "Thou smilest... upon the stroke that... murders me." +#define SOUND_ROMULO_DEATH 9235 +#define SAY_ROMULO_ENTER "This day's black fate on more days doth depend. This but begins the woe. Others must end." +#define SOUND_ROMULO_ENTER 9236 +#define SAY_ROMULO_RESURRECT "Thou detestable maw, thou womb of death; I enforce thy rotten jaws to open!" +#define SOUND_ROMULO_RESURRECT 9237 +#define SAY_ROMULO_SLAY "How well my comfort is revived by this!" +#define SOUND_ROMULO_SLAY 9238 + +/*** Misc. Information ****/ +#define CREATURE_ROMULO 17533 +#define ROMULO_X -10900 +#define ROMULO_Y -1758 + +enum RAJPhase +{ + PHASE_JULIANNE = 0, + PHASE_ROMULO = 1, + PHASE_BOTH = 2, +}; + +void PretendToDie(Creature* _Creature) +{ + _Creature->InterruptNonMeleeSpells(false); + _Creature->SetHealth(0); + _Creature->StopMoving(); + _Creature->ClearComboPointHolders(); + _Creature->RemoveAllAurasOnDeath(); + _Creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + _Creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + _Creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + _Creature->ClearAllReactives(); + _Creature->SetUInt64Value(UNIT_FIELD_TARGET,0); + _Creature->GetMotionMaster()->Clear(); + _Creature->GetMotionMaster()->MoveIdle(); + _Creature->SetUInt32Value(UNIT_FIELD_BYTES_1,PLAYER_STATE_DEAD); +}; + +void Resurrect(Creature* target) +{ + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + target->SetHealth(target->GetMaxHealth()); + target->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + target->CastSpell(target, SPELL_RES_VISUAL, true); + if(target->getVictim()) + { + target->SetUInt64Value(UNIT_FIELD_TARGET, target->getVictim()->GetGUID()); + target->GetMotionMaster()->MoveChase(target->getVictim()); + target->AI()->AttackStart(target->getVictim()); + } +}; + +struct MANGOS_DLL_DECL boss_julianneAI : public ScriptedAI +{ + boss_julianneAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + EntryYellTimer = 1000; + AggroYellTimer = 10000; + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 RomuloGUID; + + uint32 Phase; + + uint32 EntryYellTimer; + uint32 AggroYellTimer; + uint32 BlindingPassionTimer; + uint32 DevotionTimer; + uint32 EternalAffectionTimer; + uint32 PowerfulAttractionTimer; + uint32 SummonRomuloTimer; + uint32 ResurrectTimer; + + bool IsFakingDeath; + bool SummonedRomulo; + bool RomuloDead; + + void Reset() + { + if(RomuloGUID) + { + if(Unit* Romulo = Unit::GetUnit(*m_creature, RomuloGUID)) + { + Romulo->SetVisibility(VISIBILITY_OFF); + Romulo->DealDamage(Romulo, Romulo->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + RomuloGUID = 0; + } + + Phase = PHASE_JULIANNE; + + BlindingPassionTimer = 30000; + DevotionTimer = 15000; + EternalAffectionTimer = 25000; + PowerfulAttractionTimer = 5000; + + if(IsFakingDeath) + Resurrect(m_creature); + + IsFakingDeath = false; + SummonedRomulo = false; + RomuloDead = false; + } + + void Aggro(Unit* who) {} + + void AttackStart(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void DamageTaken(Unit* done_by, uint32 &damage); + + void JustDied(Unit* killer) + { + DoYell(SAY_JULIANNE_DEATH02, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_JULIANNE_DEATH02); + + if(pInstance) + { + pInstance->SetData(DATA_OPERA_EVENT, DONE); + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORRIGHT)); + if(Door) + Door->UseDoorOrButton(); + } + } + + void KilledUnit(Unit* victim) + { + DoYell(SAY_JULIANNE_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_JULIANNE_SLAY); + } + + void UpdateAI(const uint32 diff); +}; + +struct MANGOS_DLL_DECL boss_romuloAI : public ScriptedAI +{ + boss_romuloAI(Creature* c) : ScriptedAI(c) + { + Reset(); + EntryYellTimer = 8000; + AggroYellTimer = 15000; + } + + uint64 JulianneGUID; + + uint32 Phase; + + uint32 EntryYellTimer; + uint32 AggroYellTimer; + uint32 BackwardLungeTimer; + uint32 DaringTimer; + uint32 DeadlySwatheTimer; + uint32 PoisonThrustTimer; + uint32 ResurrectTimer; + + bool JulianneDead; + bool IsFakingDeath; + + void Reset() + { + JulianneGUID = 0; + + Phase = PHASE_ROMULO; + + BackwardLungeTimer = 15000; + DaringTimer = 20000; + DeadlySwatheTimer = 25000; + PoisonThrustTimer = 10000; + + if(IsFakingDeath) + Resurrect(m_creature); + + IsFakingDeath = false; + JulianneDead = false; + } + + void DamageTaken(Unit* done_by, uint32 &damage); + + void Aggro(Unit* who) + { + DoYell(SAY_ROMULO_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ROMULO_AGGRO); + if(JulianneGUID) + { + Creature* Julianne = ((Creature*)Unit::GetUnit((*m_creature), JulianneGUID)); + if(Julianne && Julianne->getVictim()) + { + m_creature->AddThreat(Julianne->getVictim(), 1.0f); + DoStartAttackAndMovement(Julianne->getVictim()); + } + } + } + + void MoveInLineOfSight(Unit* who) + { + if(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void JustDied(Unit* killer) + { + DoYell(SAY_ROMULO_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ROMULO_DEATH); + } + + void KilledUnit(Unit* victim) + { + DoYell(SAY_ROMULO_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ROMULO_SLAY); + } + + void UpdateAI(const uint32 diff); +}; + +void boss_julianneAI::DamageTaken(Unit* done_by, uint32 &damage) +{ + if(damage < m_creature->GetHealth() || done_by == m_creature || done_by->GetGUID() == RomuloGUID) + return; + + if(Phase == PHASE_JULIANNE) + { + DoYell(SAY_JULIANNE_DEATH01, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_JULIANNE_DEATH01); + m_creature->InterruptNonMeleeSpells(true); + DoCast(m_creature, SPELL_DRINK_POISON); + PretendToDie(m_creature); + Phase = PHASE_ROMULO; + damage = 0; + IsFakingDeath = true; + SummonRomuloTimer = 10000; + return; + } + + if(!IsFakingDeath) + { + Creature* Romulo = ((Creature*)Unit::GetUnit((*m_creature), RomuloGUID)); + if(Romulo && Romulo->isAlive() && !((boss_romuloAI*)Romulo->AI())->IsFakingDeath) + { + ((boss_romuloAI*)Romulo->AI())->ResurrectTimer = 10000; + ((boss_romuloAI*)Romulo->AI())->JulianneDead = true; + } + else + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if(Romulo) + { + Romulo->DealDamage(Romulo, Romulo->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + Romulo->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + JustDied(done_by); + } + + IsFakingDeath = true; + PretendToDie(m_creature); + damage = 0; + } + else + damage = 0; +} + +void boss_romuloAI::DamageTaken(Unit* done_by, uint32 &damage) +{ + if(damage < m_creature->GetHealth() || done_by == m_creature || done_by->GetGUID() == JulianneGUID) + return; + + if(!IsFakingDeath) + { + IsFakingDeath = true; + PretendToDie(m_creature); + + if(Phase == PHASE_BOTH) + { + Creature* Julianne = ((Creature*)Unit::GetUnit((*m_creature), JulianneGUID)); + if(Julianne && Julianne->isAlive() && !((boss_julianneAI*)Julianne->AI())->IsFakingDeath) + { + ((boss_julianneAI*)Julianne->AI())->ResurrectTimer = 10000; + ((boss_julianneAI*)Julianne->AI())->RomuloDead = true; + } + else + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if(Julianne) + { + Julianne->DealDamage(Julianne, Julianne->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + Julianne->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + JustDied(done_by); + } + } + else + { + Creature* Julianne = ((Creature*)Unit::GetUnit((*m_creature), JulianneGUID)); + if(Julianne) + { + Resurrect(Julianne); + m_creature->SetHealth(m_creature->GetMaxHealth()); + ((boss_julianneAI*)Julianne->AI())->ResurrectTimer = 4000; + ((boss_julianneAI*)Julianne->AI())->RomuloDead = true; + ((boss_julianneAI*)Julianne->AI())->Phase = PHASE_BOTH; + ((boss_julianneAI*)Julianne->AI())->IsFakingDeath = false; + } + Phase = PHASE_BOTH; + } + + damage = 0; + } + + if(IsFakingDeath) damage = 0; +} + +void boss_julianneAI::UpdateAI(const uint32 diff) +{ + if(EntryYellTimer) + if(EntryYellTimer < diff) + { + DoYell(SAY_JULIANNE_ENTER, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_JULIANNE_ENTER); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + EntryYellTimer = 0; + }else EntryYellTimer -= diff; + + if(AggroYellTimer) + if(AggroYellTimer < diff) + { + DoYell(SAY_JULIANNE_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_JULIANNE_AGGRO); + AggroYellTimer = 0; + }else AggroYellTimer -= diff; + + if(Phase == PHASE_ROMULO && !SummonedRomulo) + { + if(SummonRomuloTimer < diff) + { + Creature* Romulo = m_creature->SummonCreature(CREATURE_ROMULO, ROMULO_X, ROMULO_Y, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); + if(Romulo) + { + RomuloGUID = Romulo->GetGUID(); + ((boss_romuloAI*)Romulo->AI())->JulianneGUID = m_creature->GetGUID(); + ((boss_romuloAI*)Romulo->AI())->Phase = PHASE_ROMULO; + if(m_creature->getVictim()) + { + Romulo->AI()->AttackStart(m_creature->getVictim()); + Romulo->AddThreat(m_creature->getVictim(), 50.0f); + } + DoZoneInCombat(Romulo); + } + SummonedRomulo = true; + }else SummonRomuloTimer -= diff; + } + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ||IsFakingDeath) + return; + + if(RomuloDead) + if(ResurrectTimer < diff) + { + Creature* Romulo = ((Creature*)Unit::GetUnit((*m_creature), RomuloGUID)); + if(Romulo && ((boss_romuloAI*)Romulo->AI())->IsFakingDeath) + { + DoYell(SAY_JULIANNE_RESURRECT, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_JULIANNE_RESURRECT); + Resurrect(Romulo); + ((boss_romuloAI*)Romulo->AI())->IsFakingDeath = false; + ResurrectTimer = 10000; + } + RomuloDead = false; + }else ResurrectTimer -= diff; + + if(BlindingPassionTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_BLINDING_PASSION); + BlindingPassionTimer = 30000 + rand()%15000; + }else BlindingPassionTimer -= diff; + + if(DevotionTimer < diff) + { + DoCast(m_creature, SPELL_DEVOTION); + DevotionTimer = 15000 + rand()%30000; + }else DevotionTimer -= diff; + + if(PowerfulAttractionTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_POWERFUL_ATTRACTION); + PowerfulAttractionTimer = 5000 + rand()%25000; + }else PowerfulAttractionTimer -= diff; + + if(EternalAffectionTimer < diff) + { + if(rand()%2 == 1 && SummonedRomulo) + { + Creature* Romulo = ((Creature*)Unit::GetUnit((*m_creature), RomuloGUID)); + if(Romulo && Romulo->isAlive() && !((boss_romuloAI*)Romulo->AI())->IsFakingDeath) + DoCast(Romulo, SPELL_ETERNAL_AFFECTION); + else + return; + } + else DoCast(m_creature, SPELL_ETERNAL_AFFECTION); + + EternalAffectionTimer = 45000 + rand()%15000; + }else EternalAffectionTimer -= diff; + + DoMeleeAttackIfReady(); +} + +void boss_romuloAI::UpdateAI(const uint32 diff) +{ + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsFakingDeath) + return; + + if(JulianneDead) + if(ResurrectTimer < diff) + { + Creature* Julianne = ((Creature*)Unit::GetUnit((*m_creature), JulianneGUID)); + if(Julianne && ((boss_julianneAI*)Julianne->AI())->IsFakingDeath) + { + DoYell(SAY_ROMULO_RESURRECT, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ROMULO_RESURRECT); + Resurrect(Julianne); + ((boss_julianneAI*)Julianne->AI())->IsFakingDeath = false; + ResurrectTimer = 10000; + } + JulianneDead = false; + }else ResurrectTimer -= diff; + + if(BackwardLungeTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(target && !m_creature->HasInArc(M_PI, target)) + { + DoCast(target, SPELL_BACKWARD_LUNGE); + BackwardLungeTimer = 15000 + rand()%15000; + } + }else BackwardLungeTimer -= diff; + + if(DaringTimer < diff) + { + DoCast(m_creature, SPELL_DARING); + DaringTimer = 20000 + rand()%20000; + }else DaringTimer -= diff; + + if(DeadlySwatheTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DEADLY_SWATHE); + DeadlySwatheTimer = 15000 + rand()%10000; + }else DeadlySwatheTimer -= diff; + + if(PoisonThrustTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_POISON_THRUST); + PoisonThrustTimer = 10000 + rand()%10000; + }else PoisonThrustTimer -= diff; + + DoMeleeAttackIfReady(); +} + +CreatureAI* GetAI_boss_julianne(Creature* _Creature) +{ + return new boss_julianneAI(_Creature); +} + +CreatureAI* GetAI_boss_romulo(Creature* _Creature) +{ + return new boss_romuloAI(_Creature); +} + +void AddSC_bosses_opera() +{ + Script* newscript; + + // Oz + newscript = new Script; + newscript->GetAI = GetAI_boss_dorothee; + newscript->Name = "boss_dorothee"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_strawman; + newscript->Name = "boss_strawman"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_tinhead; + newscript->Name = "boss_tinhead"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_roar; + newscript->Name = "boss_roar"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_crone; + newscript->Name = "boss_crone"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_mob_tito; + newscript->Name = "mob_tito"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_mob_cyclone; + newscript->Name = "mob_cyclone"; + m_scripts[nrscripts++] = newscript; + + // Hood + newscript = new Script; + newscript->pGossipHello = GossipHello_npc_grandmother; + newscript->pGossipSelect = GossipSelect_npc_grandmother; + newscript->Name = "npc_grandmother"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_bigbadwolf; + newscript->Name = "boss_bigbadwolf"; + m_scripts[nrscripts++] = newscript; + + // Romeo And Juliet + newscript = new Script; + newscript->GetAI = GetAI_boss_julianne; + newscript->Name = "boss_julianne"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_romulo; + newscript->Name = "boss_romulo"; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/def_karazhan.h b/src/bindings/scripts/scripts/zone/karazhan/def_karazhan.h index 938c0131b9c..86db3e86f6d 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/def_karazhan.h +++ b/src/bindings/scripts/scripts/zone/karazhan/def_karazhan.h @@ -1,40 +1,40 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_KARAZHAN_H -#define DEF_KARAZHAN_H - -#define DATA_ATTUMEN_EVENT 1 -#define DATA_MOROES_EVENT 2 -#define DATA_MAIDENOFVIRTUE_EVENT 3 -#define DATA_OPTIONAL_BOSS_EVENT 4 -#define DATA_OPERA_EVENT 5 -#define DATA_CURATOR_EVENT 6 -#define DATA_SHADEOFARAN_EVENT 7 -#define DATA_TERESTIAN_EVENT 8 -#define DATA_NETHERSPITE_EVENT 9 -#define DATA_CHESS_EVENT 10 -#define DATA_MALCHEZZAR_EVENT 11 -#define DATA_NETHERBANE_EVENT 12 -#define DATA_OPERA_PERFORMANCE 13 -#define DATA_OPERA_OZ_DEATHCOUNT 14 -#define DATA_KILREK 15 -#define DATA_TERESTIAN 16 -#define DATA_MOROES 17 -#define DATA_GAMEOBJECT_CURTAINS 18 -#define DATA_GAMEOBJECT_STAGEDOORLEFT 19 -#define DATA_GAMEOBJECT_STAGEDOORRIGHT 20 -#define DATA_GAMEOBJECT_LIBRARY_DOOR 21 -#define DATA_GAMEOBJECT_MASSIVE_DOOR 22 -#define DATA_GAMEOBJECT_NETHER_DOOR 23 -#define DATA_GAMEOBJECT_GAME_DOOR 24 -#define DATA_GAMEOBJECT_GAME_EXIT_DOOR 25 - -// Opera Performances -#define EVENT_OZ 1 -#define EVENT_HOOD 2 -#define EVENT_RAJ 3 - -#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()); -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_KARAZHAN_H +#define DEF_KARAZHAN_H + +#define DATA_ATTUMEN_EVENT 1 +#define DATA_MOROES_EVENT 2 +#define DATA_MAIDENOFVIRTUE_EVENT 3 +#define DATA_OPTIONAL_BOSS_EVENT 4 +#define DATA_OPERA_EVENT 5 +#define DATA_CURATOR_EVENT 6 +#define DATA_SHADEOFARAN_EVENT 7 +#define DATA_TERESTIAN_EVENT 8 +#define DATA_NETHERSPITE_EVENT 9 +#define DATA_CHESS_EVENT 10 +#define DATA_MALCHEZZAR_EVENT 11 +#define DATA_NETHERBANE_EVENT 12 +#define DATA_OPERA_PERFORMANCE 13 +#define DATA_OPERA_OZ_DEATHCOUNT 14 +#define DATA_KILREK 15 +#define DATA_TERESTIAN 16 +#define DATA_MOROES 17 +#define DATA_GAMEOBJECT_CURTAINS 18 +#define DATA_GAMEOBJECT_STAGEDOORLEFT 19 +#define DATA_GAMEOBJECT_STAGEDOORRIGHT 20 +#define DATA_GAMEOBJECT_LIBRARY_DOOR 21 +#define DATA_GAMEOBJECT_MASSIVE_DOOR 22 +#define DATA_GAMEOBJECT_NETHER_DOOR 23 +#define DATA_GAMEOBJECT_GAME_DOOR 24 +#define DATA_GAMEOBJECT_GAME_EXIT_DOOR 25 + +// Opera Performances +#define EVENT_OZ 1 +#define EVENT_HOOD 2 +#define EVENT_RAJ 3 + +#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()); +#endif diff --git a/src/bindings/scripts/scripts/zone/karazhan/instance_karazhan.cpp b/src/bindings/scripts/scripts/zone/karazhan/instance_karazhan.cpp index f7b2be1978f..88a11739651 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/instance_karazhan.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/instance_karazhan.cpp @@ -1,253 +1,253 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Karazhan -SD%Complete: 70 -SDComment: Instance Script for Karazhan to help in various encounters. TODO: GameObject visibility for Opera event. -SDCategory: Karazhan -EndScriptData */ - -#include "precompiled.h" -#include "def_karazhan.h" - -#define ENCOUNTERS 11 - -/* -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 -6 - Shade of Aran (optional) -7 - Terestian Illhoof (optional) -8 - Netherspite (optional) -9 - Chess Event -10 - Prince Malchezzar -11 - Netherbane -*/ -struct MANGOS_DLL_DECL instance_karazhan : public ScriptedInstance -{ - instance_karazhan(Map* map) : ScriptedInstance(map) - { - Initialize(); - } - - uint32 Encounters[ENCOUNTERS]; - - uint32 OperaEvent; // 0 - OZ, 1 - HOOD, 2 - RAJ - uint32 OzDeathCount; - - uint64 CurtainGUID; - uint64 StageDoorLeftGUID; - uint64 StageDoorRightGUID; - uint64 KilrekGUID; - uint64 TerestianGUID; - uint64 MoroesGUID; - uint64 LibraryDoor; // Door at Shade of Aran - uint64 MassiveDoor; // Door at Netherspite - uint64 GamesmansDoor; // Door before Chess - uint64 GamesmansExitDoor; // Door after Chess - uint64 NetherspaceDoor; // Door at Malchezaar - - void Initialize() - { - for (uint8 i = 0; i < ENCOUNTERS; ++i) - Encounters[i] = NOT_STARTED; - - OperaEvent = rand()%3; // This never gets altered. - OzDeathCount = 0; - - CurtainGUID = 0; - StageDoorLeftGUID = 0; - StageDoorRightGUID = 0; - - KilrekGUID = 0; - TerestianGUID = 0; - MoroesGUID = 0; - - LibraryDoor = 0; - MassiveDoor = 0; - GamesmansDoor = 0; - GamesmansExitDoor = 0; - NetherspaceDoor = 0; - } - - bool IsEncounterInProgress() const - { - for (uint8 i = 0; i < ENCOUNTERS; ++i) - if (Encounters[i] == IN_PROGRESS) return true; - - return false; - } - - uint32 GetData(uint32 identifier) - { - switch (identifier) - { - case DATA_ATTUMEN_EVENT: return Encounters[0]; - case DATA_MOROES_EVENT: return Encounters[1]; - case DATA_MAIDENOFVIRTUE_EVENT: return Encounters[2]; - case DATA_OPTIONAL_BOSS_EVENT: return Encounters[3]; - case DATA_OPERA_EVENT: return Encounters[4]; - case DATA_CURATOR_EVENT: return Encounters[5]; - case DATA_SHADEOFARAN_EVENT: return Encounters[6]; - case DATA_TERESTIAN_EVENT: return Encounters[7]; - case DATA_NETHERSPITE_EVENT: return Encounters[8]; - case DATA_CHESS_EVENT: return Encounters[9]; - case DATA_MALCHEZZAR_EVENT: return Encounters[10]; - case DATA_NETHERBANE_EVENT: return Encounters[11]; - case DATA_OPERA_PERFORMANCE: return OperaEvent; - case DATA_OPERA_OZ_DEATHCOUNT: return OzDeathCount; - } - - return 0; - } - - void OnCreatureCreate(Creature *creature, uint32 entry) - { - switch (entry) - { - case 17229: KilrekGUID = creature->GetGUID(); break; - case 15688: TerestianGUID = creature->GetGUID(); break; - case 15687: MoroesGUID = creature->GetGUID(); break; - } - } - - uint64 GetData64(uint32 identifier) - { - switch (identifier) - { - case DATA_KILREK: return KilrekGUID; - case DATA_TERESTIAN: return TerestianGUID; - case DATA_MOROES: return MoroesGUID; - case DATA_GAMEOBJECT_STAGEDOORLEFT: return StageDoorLeftGUID; - case DATA_GAMEOBJECT_STAGEDOORRIGHT: return StageDoorRightGUID; - case DATA_GAMEOBJECT_CURTAINS: return CurtainGUID; - case DATA_GAMEOBJECT_LIBRARY_DOOR: return LibraryDoor; - case DATA_GAMEOBJECT_MASSIVE_DOOR: return MassiveDoor; - case DATA_GAMEOBJECT_GAME_DOOR: return GamesmansDoor; - case DATA_GAMEOBJECT_GAME_EXIT_DOOR: return GamesmansExitDoor; - case DATA_GAMEOBJECT_NETHER_DOOR: return NetherspaceDoor; - } - - return 0; - } - - void SetData(uint32 identifier, uint32 data) - { - switch (identifier) - { - case DATA_ATTUMEN_EVENT: Encounters[0] = data; break; - case DATA_MOROES_EVENT: Encounters[1] = data; break; - case DATA_MAIDENOFVIRTUE_EVENT: Encounters[2] = data; break; - case DATA_OPTIONAL_BOSS_EVENT: Encounters[3] = data; break; - case DATA_OPERA_EVENT: Encounters[4] = data; break; - case DATA_CURATOR_EVENT: Encounters[5] = data; break; - case DATA_SHADEOFARAN_EVENT: Encounters[6] = data; break; - case DATA_TERESTIAN_EVENT: Encounters[7] = data; break; - case DATA_NETHERSPITE_EVENT: Encounters[8] = data; break; - case DATA_CHESS_EVENT: Encounters[9] = data; break; - case DATA_MALCHEZZAR_EVENT: Encounters[10] = data; break; - case DATA_NETHERBANE_EVENT: Encounters[11] = data; break; - - case DATA_OPERA_OZ_DEATHCOUNT: ++OzDeathCount; break; - } - - if(data == DONE) - SaveToDB(); - } - - void OnObjectCreate(GameObject* go) - { - switch(go->GetEntry()) - { - case 183932: CurtainGUID = go->GetGUID(); break; - case 184278: StageDoorLeftGUID = go->GetGUID(); break; - case 184279: StageDoorRightGUID = go->GetGUID(); break; - case 184517: LibraryDoor = go->GetGUID(); break; - case 185521: MassiveDoor = go->GetGUID(); break; - case 184276: GamesmansDoor = go->GetGUID(); break; - case 184277: GamesmansExitDoor = go->GetGUID(); break; - case 185134: NetherspaceDoor = go->GetGUID(); break; - } - - switch(OperaEvent) - { - //TODO: Set Object visibilities for Opera based on performance - case EVENT_OZ: - break; - - case EVENT_HOOD: - break; - - case EVENT_RAJ: - break; - } - } - - const char* Save() - { - OUT_SAVE_INST_DATA; - std::ostringstream stream; - stream << Encounters[0] << " " << Encounters[1] << " " << Encounters[2] << " " << Encounters[3] << " " - << Encounters[4] << " " << Encounters[5] << " " << Encounters[6] << " " << Encounters[7] << " " - << Encounters[8] << " " << Encounters[9] << " " << Encounters[10]; - char* out = new char[stream.str().length() + 1]; - strcpy(out, stream.str().c_str()); - if(out) - { - OUT_SAVE_INST_DATA_COMPLETE; - return out; - } - - return NULL; - } - - void Load(const char* in) - { - if(!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); - std::istringstream stream(in); - stream >> Encounters[0] >> Encounters[1] >> Encounters[2] >> Encounters[3] - >> Encounters[4] >> Encounters[5] >> Encounters[6] >> Encounters[7] - >> Encounters[8] >> Encounters[9] >> Encounters[10]; - for(uint8 i = 0; i < ENCOUNTERS; ++i) - if(Encounters[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. - Encounters[i] = NOT_STARTED; - OUT_LOAD_INST_DATA_COMPLETE; - } -}; - -InstanceData* GetInstanceData_instance_karazhan(Map* map) -{ - return new instance_karazhan(map); -} - -void AddSC_instance_karazhan() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_karazhan"; - newscript->GetInstanceData = GetInstanceData_instance_karazhan; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Karazhan +SD%Complete: 70 +SDComment: Instance Script for Karazhan to help in various encounters. TODO: GameObject visibility for Opera event. +SDCategory: Karazhan +EndScriptData */ + +#include "precompiled.h" +#include "def_karazhan.h" + +#define ENCOUNTERS 11 + +/* +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 +6 - Shade of Aran (optional) +7 - Terestian Illhoof (optional) +8 - Netherspite (optional) +9 - Chess Event +10 - Prince Malchezzar +11 - Netherbane +*/ +struct MANGOS_DLL_DECL instance_karazhan : public ScriptedInstance +{ + instance_karazhan(Map* map) : ScriptedInstance(map) + { + Initialize(); + } + + uint32 Encounters[ENCOUNTERS]; + + uint32 OperaEvent; // 0 - OZ, 1 - HOOD, 2 - RAJ + uint32 OzDeathCount; + + uint64 CurtainGUID; + uint64 StageDoorLeftGUID; + uint64 StageDoorRightGUID; + uint64 KilrekGUID; + uint64 TerestianGUID; + uint64 MoroesGUID; + uint64 LibraryDoor; // Door at Shade of Aran + uint64 MassiveDoor; // Door at Netherspite + uint64 GamesmansDoor; // Door before Chess + uint64 GamesmansExitDoor; // Door after Chess + uint64 NetherspaceDoor; // Door at Malchezaar + + void Initialize() + { + for (uint8 i = 0; i < ENCOUNTERS; ++i) + Encounters[i] = NOT_STARTED; + + OperaEvent = rand()%3; // This never gets altered. + OzDeathCount = 0; + + CurtainGUID = 0; + StageDoorLeftGUID = 0; + StageDoorRightGUID = 0; + + KilrekGUID = 0; + TerestianGUID = 0; + MoroesGUID = 0; + + LibraryDoor = 0; + MassiveDoor = 0; + GamesmansDoor = 0; + GamesmansExitDoor = 0; + NetherspaceDoor = 0; + } + + bool IsEncounterInProgress() const + { + for (uint8 i = 0; i < ENCOUNTERS; ++i) + if (Encounters[i] == IN_PROGRESS) return true; + + return false; + } + + uint32 GetData(uint32 identifier) + { + switch (identifier) + { + case DATA_ATTUMEN_EVENT: return Encounters[0]; + case DATA_MOROES_EVENT: return Encounters[1]; + case DATA_MAIDENOFVIRTUE_EVENT: return Encounters[2]; + case DATA_OPTIONAL_BOSS_EVENT: return Encounters[3]; + case DATA_OPERA_EVENT: return Encounters[4]; + case DATA_CURATOR_EVENT: return Encounters[5]; + case DATA_SHADEOFARAN_EVENT: return Encounters[6]; + case DATA_TERESTIAN_EVENT: return Encounters[7]; + case DATA_NETHERSPITE_EVENT: return Encounters[8]; + case DATA_CHESS_EVENT: return Encounters[9]; + case DATA_MALCHEZZAR_EVENT: return Encounters[10]; + case DATA_NETHERBANE_EVENT: return Encounters[11]; + case DATA_OPERA_PERFORMANCE: return OperaEvent; + case DATA_OPERA_OZ_DEATHCOUNT: return OzDeathCount; + } + + return 0; + } + + void OnCreatureCreate(Creature *creature, uint32 entry) + { + switch (entry) + { + case 17229: KilrekGUID = creature->GetGUID(); break; + case 15688: TerestianGUID = creature->GetGUID(); break; + case 15687: MoroesGUID = creature->GetGUID(); break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch (identifier) + { + case DATA_KILREK: return KilrekGUID; + case DATA_TERESTIAN: return TerestianGUID; + case DATA_MOROES: return MoroesGUID; + case DATA_GAMEOBJECT_STAGEDOORLEFT: return StageDoorLeftGUID; + case DATA_GAMEOBJECT_STAGEDOORRIGHT: return StageDoorRightGUID; + case DATA_GAMEOBJECT_CURTAINS: return CurtainGUID; + case DATA_GAMEOBJECT_LIBRARY_DOOR: return LibraryDoor; + case DATA_GAMEOBJECT_MASSIVE_DOOR: return MassiveDoor; + case DATA_GAMEOBJECT_GAME_DOOR: return GamesmansDoor; + case DATA_GAMEOBJECT_GAME_EXIT_DOOR: return GamesmansExitDoor; + case DATA_GAMEOBJECT_NETHER_DOOR: return NetherspaceDoor; + } + + return 0; + } + + void SetData(uint32 identifier, uint32 data) + { + switch (identifier) + { + case DATA_ATTUMEN_EVENT: Encounters[0] = data; break; + case DATA_MOROES_EVENT: Encounters[1] = data; break; + case DATA_MAIDENOFVIRTUE_EVENT: Encounters[2] = data; break; + case DATA_OPTIONAL_BOSS_EVENT: Encounters[3] = data; break; + case DATA_OPERA_EVENT: Encounters[4] = data; break; + case DATA_CURATOR_EVENT: Encounters[5] = data; break; + case DATA_SHADEOFARAN_EVENT: Encounters[6] = data; break; + case DATA_TERESTIAN_EVENT: Encounters[7] = data; break; + case DATA_NETHERSPITE_EVENT: Encounters[8] = data; break; + case DATA_CHESS_EVENT: Encounters[9] = data; break; + case DATA_MALCHEZZAR_EVENT: Encounters[10] = data; break; + case DATA_NETHERBANE_EVENT: Encounters[11] = data; break; + + case DATA_OPERA_OZ_DEATHCOUNT: ++OzDeathCount; break; + } + + if(data == DONE) + SaveToDB(); + } + + void OnObjectCreate(GameObject* go) + { + switch(go->GetEntry()) + { + case 183932: CurtainGUID = go->GetGUID(); break; + case 184278: StageDoorLeftGUID = go->GetGUID(); break; + case 184279: StageDoorRightGUID = go->GetGUID(); break; + case 184517: LibraryDoor = go->GetGUID(); break; + case 185521: MassiveDoor = go->GetGUID(); break; + case 184276: GamesmansDoor = go->GetGUID(); break; + case 184277: GamesmansExitDoor = go->GetGUID(); break; + case 185134: NetherspaceDoor = go->GetGUID(); break; + } + + switch(OperaEvent) + { + //TODO: Set Object visibilities for Opera based on performance + case EVENT_OZ: + break; + + case EVENT_HOOD: + break; + + case EVENT_RAJ: + break; + } + } + + const char* Save() + { + OUT_SAVE_INST_DATA; + std::ostringstream stream; + stream << Encounters[0] << " " << Encounters[1] << " " << Encounters[2] << " " << Encounters[3] << " " + << Encounters[4] << " " << Encounters[5] << " " << Encounters[6] << " " << Encounters[7] << " " + << Encounters[8] << " " << Encounters[9] << " " << Encounters[10]; + char* out = new char[stream.str().length() + 1]; + strcpy(out, stream.str().c_str()); + if(out) + { + OUT_SAVE_INST_DATA_COMPLETE; + return out; + } + + return NULL; + } + + void Load(const char* in) + { + if(!in) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(in); + std::istringstream stream(in); + stream >> Encounters[0] >> Encounters[1] >> Encounters[2] >> Encounters[3] + >> Encounters[4] >> Encounters[5] >> Encounters[6] >> Encounters[7] + >> Encounters[8] >> Encounters[9] >> Encounters[10]; + for(uint8 i = 0; i < ENCOUNTERS; ++i) + if(Encounters[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. + Encounters[i] = NOT_STARTED; + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +InstanceData* GetInstanceData_instance_karazhan(Map* map) +{ + return new instance_karazhan(map); +} + +void AddSC_instance_karazhan() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_karazhan"; + newscript->GetInstanceData = GetInstanceData_instance_karazhan; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/karazhan/karazhan.cpp b/src/bindings/scripts/scripts/zone/karazhan/karazhan.cpp index b12c3280f58..b7b4e8a6b9a 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/karazhan.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/karazhan.cpp @@ -1,470 +1,470 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Karazhan -SD%Complete: 100 -SDComment: Support for Barnes (Opera controller) and Berthold (Doorman). -SDCategory: Karazhan -EndScriptData */ - -/* ContentData -npc_barnes -npc_berthold -EndContentData */ - -#include "precompiled.h" -#include "def_karazhan.h" -#include "../../npc/npc_escortAI.h" - -/*###### -# 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." - -struct Dialogue -{ - char* text; - uint32 soundid, timer; -}; - -static Dialogue OzDialogue[]= -{ - {"Welcome Ladies and Gentlemen, to this evening's presentation!", 9174, 6000}, - {"Tonight we plumb the depths of the human soul as we join a lost, lonely girl trying desperately -- with the help of her loyal companions -- to find her way home!", 9338, 18000}, - {"But she is pursued... by a wicked malevolent crone!", 9339, 9000}, - {"Will she survive? Will she prevail? Only time will tell. And now ... on with the show!", 9340, 15000} -}; - -static Dialogue HoodDialogue[]= -{ - {"Good evening, Ladies and Gentlemen! Welcome to this evening's presentation!", 9175, 6000}, - {"Tonight, things are not what they seem. For tonight, your eyes may not be trusted", 9335, 10000}, - {"Take for instance, this quiet, elderly woman, waiting for a visit from her granddaughter. Surely there is nothing to fear from this sweet, grey-haired, old lady.", 9336, 14000}, - {"But don't let me pull the wool over your eyes. See for yourself what lies beneath those covers! And now... on with the show!", 9337, 15000} -}; - -static Dialogue RAJDialogue[]= -{ - {"Welcome, Ladies and Gentlemen, to this evening's presentation!", 9176, 5000}, - {"Tonight, we explore a tale of forbidden love!", 9341, 7000}, - {"But beware, for not all love stories end happily, as you may find out. Sometimes, love pricks like a thorn.", 9342, 14000}, - {"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, 14000} -}; - -// Entries and spawn locations for creatures in Oz event -float Spawns[6][2]= -{ - {17535, -10896}, // Dorothee - {17546, -10891}, // Roar - {17547, -10884}, // Tinhead - {17543, -10902}, // Strawman - {17603, -10892}, // Grandmother - {17534, -10900}, // Julianne -}; - -float StageLocations[6][2]= -{ - {-10866.711, -1779.816}, // Open door, begin walking (0) - {-10894.917, -1775.467}, // (1) - {-10896.044, -1782.619}, // Begin Speech after this (2) - {-10894.917, -1775.467}, // Resume walking (back to spawn point now) after speech (3) - {-10866.711, -1779.816}, // (4) - {-10866.700, -1781.030} // Summon mobs, open curtains, close door (5) -}; - -#define CREATURE_SPOTLIGHT 19525 - -#define SPELL_SPOTLIGHT 25824 -#define SPELL_TUXEDO 32616 - -#define SPAWN_Z 90.5 -#define SPAWN_Y -1758 -#define SPAWN_O 4.738 - -struct MANGOS_DLL_DECL npc_barnesAI : public npc_escortAI -{ - npc_barnesAI(Creature* c) : npc_escortAI(c) - { - RaidWiped = false; - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 SpotlightGUID; - - uint32 TalkCount; - uint32 TalkTimer; - uint32 CurtainTimer; - uint32 WipeTimer; - uint32 Event; - - bool PerformanceReady; - bool RaidWiped; - bool IsTalking; - - void Reset() - { - TalkCount = 0; - TalkTimer = 2000; - CurtainTimer = 5000; - WipeTimer = 5000; - - PerformanceReady = false; - IsTalking = false; - - if(pInstance) - { - pInstance->SetData(DATA_OPERA_EVENT, NOT_STARTED); - - Event = pInstance->GetData(DATA_OPERA_PERFORMANCE); - - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORLEFT)); - if(Door) - Door->SetGoState(1); - - GameObject* Curtain = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_CURTAINS)); - if(Curtain) - Curtain->SetGoState(1); - } - } - - void Aggro(Unit* who) {} - - void WaypointReached(uint32 i) - { - switch(i) - { - case 2: - IsBeingEscorted = false; - TalkCount = 0; - IsTalking = true; - - float x,y,z; - m_creature->GetPosition(x, y, z); - Creature* Spotlight; - Spotlight = m_creature->SummonCreature(CREATURE_SPOTLIGHT, x, y, z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 50000); - if(Spotlight) - { - Spotlight->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Spotlight->CastSpell(Spotlight, SPELL_SPOTLIGHT, false); - SpotlightGUID = Spotlight->GetGUID(); - } - break; - - case 5: - if(pInstance) - { - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORLEFT)); - if(Door) - Door->SetGoState(1); - } - IsBeingEscorted = false; - PerformanceReady = true; - break; - } - } - - void Talk(uint32 count) - { - char* text = NULL; - uint32 sound = 0; - - switch(Event) - { - case EVENT_OZ: - if(OzDialogue[count].text) - text = OzDialogue[count].text; - if(OzDialogue[count].soundid) - sound = OzDialogue[count].soundid; - if(OzDialogue[count].timer) - TalkTimer = OzDialogue[count].timer; - break; - - case EVENT_HOOD: - if(HoodDialogue[count].text) - text = HoodDialogue[count].text; - if(HoodDialogue[count].soundid) - sound = HoodDialogue[count].soundid; - if(HoodDialogue[count].timer) - TalkTimer = HoodDialogue[count].timer; - break; - - case EVENT_RAJ: - if(RAJDialogue[count].text) - text = RAJDialogue[count].text; - if(RAJDialogue[count].soundid) - sound = RAJDialogue[count].soundid; - if(RAJDialogue[count].timer) - TalkTimer = RAJDialogue[count].timer; - break; - } - - if(text) - DoYell(text, LANG_UNIVERSAL, 0); - if(sound) - DoPlaySoundToSet(m_creature, sound); - } - - void UpdateAI(const uint32 diff) - { - npc_escortAI::UpdateAI(diff); - - if(IsTalking) - { - if(TalkTimer < diff) - { - if(TalkCount > 3) - { - Unit* Spotlight = Unit::GetUnit((*m_creature), SpotlightGUID); - if(Spotlight) - { - Spotlight->RemoveAllAuras(); - Spotlight->SetVisibility(VISIBILITY_OFF); - } - - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); - IsTalking = false; - IsBeingEscorted = true; - return; - } - - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); - Talk(TalkCount); - ++TalkCount; - } - else TalkTimer -= diff; - } - - if(PerformanceReady) - { - if(CurtainTimer) - if(CurtainTimer <= diff) - { - PrepareEncounter(); - - if(!pInstance) - return; - - GameObject* Curtain = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_CURTAINS)); - if(Curtain) - Curtain->SetGoState(0); - - CurtainTimer = 0; - }else CurtainTimer -= diff; - - if(!RaidWiped) - { - if(WipeTimer < diff) - { - Map *map = m_creature->GetMap(); - if(!map->IsDungeon()) return; - - InstanceMap::PlayerList const &PlayerList = ((InstanceMap*)map)->GetPlayers(); - if(PlayerList.empty()) - return; - - RaidWiped = true; - for(InstanceMap::PlayerList::const_iterator i = PlayerList.begin();i != PlayerList.end(); ++i) - { - if((*i)->isAlive() && !(*i)->isGameMaster()) - { - RaidWiped = false; - break; - } - } - - if(RaidWiped) - { - RaidWiped = true; - EnterEvadeMode(); - } - - WipeTimer = 15000; - }else WipeTimer -= diff; - } - - } - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } - - void StartEvent() - { - if(!pInstance) - return; - - pInstance->SetData(DATA_OPERA_EVENT, IN_PROGRESS); - - GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORLEFT)); - if(Door) - Door->SetGoState(0); - - m_creature->CastSpell(m_creature, SPELL_TUXEDO, true); - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - Start(false, false, false); - } - - void PrepareEncounter() - { - debug_log("SD2: Barnes Opera Event - Introduction complete - preparing encounter %d", Event); - uint8 index = 0; - uint8 count = 0; - switch(Event) - { - case EVENT_OZ: - index = 0; - count = 4; - break; - - case EVENT_HOOD: - index = 4; - count = index+1; - break; - - case EVENT_RAJ: - index = 5; - count = index+1; - break; - } - - for( ; index < count; ++index) - { - uint32 entry = ((uint32)Spawns[index][0]); - float PosX = Spawns[index][1]; - Creature* pCreature = m_creature->SummonCreature(entry, PosX, SPAWN_Y, SPAWN_Z, SPAWN_O, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); - if(pCreature) - { - // In case database has bad flags - pCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0); - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - } - - CurtainTimer = 10000; - PerformanceReady = true; - RaidWiped = false; - } -}; - -CreatureAI* GetAI_npc_barnesAI(Creature* _Creature) -{ - npc_barnesAI* Barnes_AI = new npc_barnesAI(_Creature); - - for(uint8 i = 0; i < 6; ++i) - Barnes_AI->AddWaypoint(i, StageLocations[i][0], StageLocations[i][1], 90.465); - - return ((CreatureAI*)Barnes_AI); -} - -bool GossipHello_npc_barnes(Player* player, Creature* _Creature) -{ - // Check for death of Moroes. - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - if(pInstance && (pInstance->GetData(DATA_MOROES_EVENT) >= DONE)) - { - player->ADD_GOSSIP_ITEM(0, OZ_GOSSIP1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if(!((npc_barnesAI*)_Creature->AI())->RaidWiped) - player->SEND_GOSSIP_MENU(8970, _Creature->GetGUID()); - else - player->SEND_GOSSIP_MENU(8975, _Creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(8978, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_barnes(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch(action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, OZ_GOSSIP2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(8971, _Creature->GetGUID()); - break; - - case GOSSIP_ACTION_INFO_DEF+2: - player->CLOSE_GOSSIP_MENU(); - ((npc_barnesAI*)_Creature->AI())->StartEvent(); - break; - } - - return true; -} - -/*### -# npc_berthold -####*/ - -#define SPELL_TELEPORT 39567 - -#define GOSSIP_ITEM_TELEPORT "Teleport me to the Guardian's Library" - -bool GossipHello_npc_berthold(Player* player, Creature* _Creature) -{ - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - // Check if Shade of Aran is dead or not - if(pInstance && (pInstance->GetData(DATA_SHADEOFARAN_EVENT) >= DONE)) - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_berthold(Player* player, Creature* _Creature, uint32 sender, uint32 action) -{ - if(action == GOSSIP_ACTION_INFO_DEF + 1) - player->CastSpell(player, SPELL_TELEPORT, true); - - player->CLOSE_GOSSIP_MENU(); - return true; -} - -void AddSC_karazhan() -{ - Script* newscript; - - newscript = new Script; - newscript->GetAI = GetAI_npc_barnesAI; - newscript->Name = "npc_barnes"; - newscript->pGossipHello = GossipHello_npc_barnes; - newscript->pGossipSelect = GossipSelect_npc_barnes; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "npc_berthold"; - newscript->pGossipHello = GossipHello_npc_berthold; - newscript->pGossipSelect = GossipSelect_npc_berthold; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Karazhan +SD%Complete: 100 +SDComment: Support for Barnes (Opera controller) and Berthold (Doorman). +SDCategory: Karazhan +EndScriptData */ + +/* ContentData +npc_barnes +npc_berthold +EndContentData */ + +#include "precompiled.h" +#include "def_karazhan.h" +#include "../../npc/npc_escortAI.h" + +/*###### +# 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." + +struct Dialogue +{ + char* text; + uint32 soundid, timer; +}; + +static Dialogue OzDialogue[]= +{ + {"Welcome Ladies and Gentlemen, to this evening's presentation!", 9174, 6000}, + {"Tonight we plumb the depths of the human soul as we join a lost, lonely girl trying desperately -- with the help of her loyal companions -- to find her way home!", 9338, 18000}, + {"But she is pursued... by a wicked malevolent crone!", 9339, 9000}, + {"Will she survive? Will she prevail? Only time will tell. And now ... on with the show!", 9340, 15000} +}; + +static Dialogue HoodDialogue[]= +{ + {"Good evening, Ladies and Gentlemen! Welcome to this evening's presentation!", 9175, 6000}, + {"Tonight, things are not what they seem. For tonight, your eyes may not be trusted", 9335, 10000}, + {"Take for instance, this quiet, elderly woman, waiting for a visit from her granddaughter. Surely there is nothing to fear from this sweet, grey-haired, old lady.", 9336, 14000}, + {"But don't let me pull the wool over your eyes. See for yourself what lies beneath those covers! And now... on with the show!", 9337, 15000} +}; + +static Dialogue RAJDialogue[]= +{ + {"Welcome, Ladies and Gentlemen, to this evening's presentation!", 9176, 5000}, + {"Tonight, we explore a tale of forbidden love!", 9341, 7000}, + {"But beware, for not all love stories end happily, as you may find out. Sometimes, love pricks like a thorn.", 9342, 14000}, + {"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, 14000} +}; + +// Entries and spawn locations for creatures in Oz event +float Spawns[6][2]= +{ + {17535, -10896}, // Dorothee + {17546, -10891}, // Roar + {17547, -10884}, // Tinhead + {17543, -10902}, // Strawman + {17603, -10892}, // Grandmother + {17534, -10900}, // Julianne +}; + +float StageLocations[6][2]= +{ + {-10866.711, -1779.816}, // Open door, begin walking (0) + {-10894.917, -1775.467}, // (1) + {-10896.044, -1782.619}, // Begin Speech after this (2) + {-10894.917, -1775.467}, // Resume walking (back to spawn point now) after speech (3) + {-10866.711, -1779.816}, // (4) + {-10866.700, -1781.030} // Summon mobs, open curtains, close door (5) +}; + +#define CREATURE_SPOTLIGHT 19525 + +#define SPELL_SPOTLIGHT 25824 +#define SPELL_TUXEDO 32616 + +#define SPAWN_Z 90.5 +#define SPAWN_Y -1758 +#define SPAWN_O 4.738 + +struct MANGOS_DLL_DECL npc_barnesAI : public npc_escortAI +{ + npc_barnesAI(Creature* c) : npc_escortAI(c) + { + RaidWiped = false; + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 SpotlightGUID; + + uint32 TalkCount; + uint32 TalkTimer; + uint32 CurtainTimer; + uint32 WipeTimer; + uint32 Event; + + bool PerformanceReady; + bool RaidWiped; + bool IsTalking; + + void Reset() + { + TalkCount = 0; + TalkTimer = 2000; + CurtainTimer = 5000; + WipeTimer = 5000; + + PerformanceReady = false; + IsTalking = false; + + if(pInstance) + { + pInstance->SetData(DATA_OPERA_EVENT, NOT_STARTED); + + Event = pInstance->GetData(DATA_OPERA_PERFORMANCE); + + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORLEFT)); + if(Door) + Door->SetGoState(1); + + GameObject* Curtain = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_CURTAINS)); + if(Curtain) + Curtain->SetGoState(1); + } + } + + void Aggro(Unit* who) {} + + void WaypointReached(uint32 i) + { + switch(i) + { + case 2: + IsBeingEscorted = false; + TalkCount = 0; + IsTalking = true; + + float x,y,z; + m_creature->GetPosition(x, y, z); + Creature* Spotlight; + Spotlight = m_creature->SummonCreature(CREATURE_SPOTLIGHT, x, y, z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 50000); + if(Spotlight) + { + Spotlight->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Spotlight->CastSpell(Spotlight, SPELL_SPOTLIGHT, false); + SpotlightGUID = Spotlight->GetGUID(); + } + break; + + case 5: + if(pInstance) + { + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORLEFT)); + if(Door) + Door->SetGoState(1); + } + IsBeingEscorted = false; + PerformanceReady = true; + break; + } + } + + void Talk(uint32 count) + { + char* text = NULL; + uint32 sound = 0; + + switch(Event) + { + case EVENT_OZ: + if(OzDialogue[count].text) + text = OzDialogue[count].text; + if(OzDialogue[count].soundid) + sound = OzDialogue[count].soundid; + if(OzDialogue[count].timer) + TalkTimer = OzDialogue[count].timer; + break; + + case EVENT_HOOD: + if(HoodDialogue[count].text) + text = HoodDialogue[count].text; + if(HoodDialogue[count].soundid) + sound = HoodDialogue[count].soundid; + if(HoodDialogue[count].timer) + TalkTimer = HoodDialogue[count].timer; + break; + + case EVENT_RAJ: + if(RAJDialogue[count].text) + text = RAJDialogue[count].text; + if(RAJDialogue[count].soundid) + sound = RAJDialogue[count].soundid; + if(RAJDialogue[count].timer) + TalkTimer = RAJDialogue[count].timer; + break; + } + + if(text) + DoYell(text, LANG_UNIVERSAL, 0); + if(sound) + DoPlaySoundToSet(m_creature, sound); + } + + void UpdateAI(const uint32 diff) + { + npc_escortAI::UpdateAI(diff); + + if(IsTalking) + { + if(TalkTimer < diff) + { + if(TalkCount > 3) + { + Unit* Spotlight = Unit::GetUnit((*m_creature), SpotlightGUID); + if(Spotlight) + { + Spotlight->RemoveAllAuras(); + Spotlight->SetVisibility(VISIBILITY_OFF); + } + + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); + IsTalking = false; + IsBeingEscorted = true; + return; + } + + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); + Talk(TalkCount); + ++TalkCount; + } + else TalkTimer -= diff; + } + + if(PerformanceReady) + { + if(CurtainTimer) + if(CurtainTimer <= diff) + { + PrepareEncounter(); + + if(!pInstance) + return; + + GameObject* Curtain = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_CURTAINS)); + if(Curtain) + Curtain->SetGoState(0); + + CurtainTimer = 0; + }else CurtainTimer -= diff; + + if(!RaidWiped) + { + if(WipeTimer < diff) + { + Map *map = m_creature->GetMap(); + if(!map->IsDungeon()) return; + + InstanceMap::PlayerList const &PlayerList = ((InstanceMap*)map)->GetPlayers(); + if(PlayerList.empty()) + return; + + RaidWiped = true; + for(InstanceMap::PlayerList::const_iterator i = PlayerList.begin();i != PlayerList.end(); ++i) + { + if((*i)->isAlive() && !(*i)->isGameMaster()) + { + RaidWiped = false; + break; + } + } + + if(RaidWiped) + { + RaidWiped = true; + EnterEvadeMode(); + } + + WipeTimer = 15000; + }else WipeTimer -= diff; + } + + } + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } + + void StartEvent() + { + if(!pInstance) + return; + + pInstance->SetData(DATA_OPERA_EVENT, IN_PROGRESS); + + GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_STAGEDOORLEFT)); + if(Door) + Door->SetGoState(0); + + m_creature->CastSpell(m_creature, SPELL_TUXEDO, true); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + Start(false, false, false); + } + + void PrepareEncounter() + { + debug_log("SD2: Barnes Opera Event - Introduction complete - preparing encounter %d", Event); + uint8 index = 0; + uint8 count = 0; + switch(Event) + { + case EVENT_OZ: + index = 0; + count = 4; + break; + + case EVENT_HOOD: + index = 4; + count = index+1; + break; + + case EVENT_RAJ: + index = 5; + count = index+1; + break; + } + + for( ; index < count; ++index) + { + uint32 entry = ((uint32)Spawns[index][0]); + float PosX = Spawns[index][1]; + Creature* pCreature = m_creature->SummonCreature(entry, PosX, SPAWN_Y, SPAWN_Z, SPAWN_O, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); + if(pCreature) + { + // In case database has bad flags + pCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + + CurtainTimer = 10000; + PerformanceReady = true; + RaidWiped = false; + } +}; + +CreatureAI* GetAI_npc_barnesAI(Creature* _Creature) +{ + npc_barnesAI* Barnes_AI = new npc_barnesAI(_Creature); + + for(uint8 i = 0; i < 6; ++i) + Barnes_AI->AddWaypoint(i, StageLocations[i][0], StageLocations[i][1], 90.465); + + return ((CreatureAI*)Barnes_AI); +} + +bool GossipHello_npc_barnes(Player* player, Creature* _Creature) +{ + // Check for death of Moroes. + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + if(pInstance && (pInstance->GetData(DATA_MOROES_EVENT) >= DONE)) + { + player->ADD_GOSSIP_ITEM(0, OZ_GOSSIP1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + if(!((npc_barnesAI*)_Creature->AI())->RaidWiped) + player->SEND_GOSSIP_MENU(8970, _Creature->GetGUID()); + else + player->SEND_GOSSIP_MENU(8975, _Creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(8978, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_barnes(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch(action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, OZ_GOSSIP2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(8971, _Creature->GetGUID()); + break; + + case GOSSIP_ACTION_INFO_DEF+2: + player->CLOSE_GOSSIP_MENU(); + ((npc_barnesAI*)_Creature->AI())->StartEvent(); + break; + } + + return true; +} + +/*### +# npc_berthold +####*/ + +#define SPELL_TELEPORT 39567 + +#define GOSSIP_ITEM_TELEPORT "Teleport me to the Guardian's Library" + +bool GossipHello_npc_berthold(Player* player, Creature* _Creature) +{ + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + // Check if Shade of Aran is dead or not + if(pInstance && (pInstance->GetData(DATA_SHADEOFARAN_EVENT) >= DONE)) + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_berthold(Player* player, Creature* _Creature, uint32 sender, uint32 action) +{ + if(action == GOSSIP_ACTION_INFO_DEF + 1) + player->CastSpell(player, SPELL_TELEPORT, true); + + player->CLOSE_GOSSIP_MENU(); + return true; +} + +void AddSC_karazhan() +{ + Script* newscript; + + newscript = new Script; + newscript->GetAI = GetAI_npc_barnesAI; + newscript->Name = "npc_barnes"; + newscript->pGossipHello = GossipHello_npc_barnes; + newscript->pGossipSelect = GossipSelect_npc_barnes; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "npc_berthold"; + newscript->pGossipHello = GossipHello_npc_berthold; + newscript->pGossipSelect = GossipSelect_npc_berthold; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/loch_modan/loch_modan.cpp b/src/bindings/scripts/scripts/zone/loch_modan/loch_modan.cpp index af335dba05f..929f0b3e92d 100644 --- a/src/bindings/scripts/scripts/zone/loch_modan/loch_modan.cpp +++ b/src/bindings/scripts/scripts/zone/loch_modan/loch_modan.cpp @@ -1,91 +1,91 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Loch_Modan -SD%Complete: 100 -SDComment: Quest support: 3181 (only to argue with pebblebitty to get to searing gorge, before quest rewarded) -SDCategory: Loch Modan -EndScriptData */ - -/* ContentData -npc_mountaineer_pebblebitty -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_mountaineer_pebblebitty -######*/ - -bool GossipHello_npc_mountaineer_pebblebitty(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (!player->GetQuestRewardStatus(3181) == 1) - player->ADD_GOSSIP_ITEM( 0, "Open the gate please, i need to get to Searing Gorge", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_mountaineer_pebblebitty(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "But i need to get there, now open the gate!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(1833, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "Ok, so what is this other way?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(1834, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "Doesn't matter, i'm invulnerable.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(1835, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM( 0, "Yes...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(1836, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM( 0, "Ok, i'll try to remember that.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(1837, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM( 0, "A key? Ok!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(1838, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - player->CLOSE_GOSSIP_MENU(); - break; - } - return true; -} - -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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Loch_Modan +SD%Complete: 100 +SDComment: Quest support: 3181 (only to argue with pebblebitty to get to searing gorge, before quest rewarded) +SDCategory: Loch Modan +EndScriptData */ + +/* ContentData +npc_mountaineer_pebblebitty +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_mountaineer_pebblebitty +######*/ + +bool GossipHello_npc_mountaineer_pebblebitty(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (!player->GetQuestRewardStatus(3181) == 1) + player->ADD_GOSSIP_ITEM( 0, "Open the gate please, i need to get to Searing Gorge", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_mountaineer_pebblebitty(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "But i need to get there, now open the gate!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(1833, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "Ok, so what is this other way?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(1834, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "Doesn't matter, i'm invulnerable.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(1835, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM( 0, "Yes...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(1836, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM( 0, "Ok, i'll try to remember that.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(1837, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + player->ADD_GOSSIP_ITEM( 0, "A key? Ok!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(1838, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+7: + player->CLOSE_GOSSIP_MENU(); + break; + } + return true; +} + +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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_felblood_kaelthas.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_felblood_kaelthas.cpp index 5783d1ac441..0b448dbb047 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_felblood_kaelthas.cpp +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_felblood_kaelthas.cpp @@ -1,591 +1,591 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: boss_felblood_kaelthas -SD%Complete: 80 -SDComment: Normal and Heroic Support. Issues: Arcane Spheres do not initially follow targets. TODO: Convert Phoenix to ACID. -SDCategory: Magisters' Terrace -EndScriptData */ - -#include "precompiled.h" -#include "def_magisters_terrace.h" -#include "WorldPacket.h" - -/*** 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 44198 // A spell Phoenix uses to damage everything around - -#define SPELL_FLAMESTRIKE1_NORMAL 44190 // Damage part -#define SPELL_FLAMESTRIKE1_HEROIC 46163 // Heroic damage part -#define SPELL_FLAMESTRIKE2 44191 // Flamestrike indicator before the damage -#define SPELL_FLAMESTRIKE3 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 CREATURE_PHOENIX 24674 -#define CREATURE_PHOENIX_EGG 24675 -#define CREATURE_ARCANE_SPHERE 24708 - -/*** Dialogues ***/ -#define SAY_AGGRO "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!" -#define SOUND_AGGRO 12413 // This yell should be done when the room is cleared. For now, set it as aggro yell. - -#define SAY_PHOENIX "Vengeance burns!" -#define SOUND_PHOENIX 12415 - -#define SAY_FLAMESTRIKE "Felomin ashal!" -#define SOUND_FLAMESTRIKE 12417 - -#define SAY_GRAVITY_LAPSE "I'll turn your world... upside... down..." -#define SOUND_GRAVITY_LAPSE 12418 - -#define SAY_TIRED "Master... grant me strength." -#define SOUND_TIRED 12419 - -#define SAY_RECAST_GRAVITY "Do not... get too comfortable." -#define SOUND_RECAST_GRAVITY 12420 - -#define SAY_DEATH "My demise accomplishes nothing! The Master will have you! You will drown in your own blood! This world shall burn! Aaaghh!" -#define SOUND_DEATH 12421 - -/** Locations **/ -float KaelLocations[3][2]= -{ - {148.744659, 181.377426}, - {140.823883, 195.403046}, - {156.574188, 195.650482}, -}; -#define LOCATION_Z -16.727455 - -struct MANGOS_DLL_DECL boss_felblood_kaelthasAI : public ScriptedAI -{ - boss_felblood_kaelthasAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - Heroic = c->GetMap()->IsHeroic() ? true : false; - } - - ScriptedInstance* pInstance; - - uint32 FireballTimer; - uint32 PhoenixTimer; - uint32 FlameStrikeTimer; - uint32 CombatPulseTimer; - - //Heroic only - uint32 PyroblastTimer; - - 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. - - bool FirstGravityLapse; - bool Heroic; - - uint8 Phase; - // 0 = Not started - // 1 = Fireball; Summon Phoenix; Flamestrike - // 2 = Gravity Lapses - - void Reset() - { - // TODO: Timers - FireballTimer = 0; - PhoenixTimer = 30000; - FlameStrikeTimer = 25000; - CombatPulseTimer = 0; - - PyroblastTimer = 60000; - - GravityLapseTimer = 0; - GravityLapsePhase = 0; - - FirstGravityLapse = true; - - Phase = 0; - - if(pInstance) - pInstance->SetData(DATA_KAELTHAS_EVENT, 0); - } - - void JustDied(Unit *killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void DamageTaken(Unit* done_by, uint32 &damage) - { - if(damage > m_creature->GetHealth()) - RemoveGravityLapse(); // Remove Gravity Lapse so that players fall to ground if they kill him when in air. - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void SetThreatList(Creature* SummonedUnit) - { - if(!SummonedUnit) return; - - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list::iterator i = m_threatlist.begin(); - for(i = m_threatlist.begin(); i != m_threatlist.end(); i++) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && pUnit->isAlive()) - { - float threat = m_creature->getThreatManager().getThreat(pUnit); - SummonedUnit->AddThreat(pUnit, threat); - } - } - } - - void TeleportPlayersToSelf() - { - float x = KaelLocations[0][0]; - float y = KaelLocations[0][1]; - m_creature->Relocate(x, y, LOCATION_Z, 0); - //m_creature->SendMonsterMove(x, y, LOCATION_Z, 0, 0, 0); // causes some issues... - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) - pUnit->CastSpell(pUnit, SPELL_TELEPORT_CENTER, true); - } - DoCast(m_creature, SPELL_TELEPORT_CENTER, true); - } - - void CastGravityLapseKnockUp() - { - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) - // Knockback into the air - pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE_DOT, true, 0, 0, m_creature->GetGUID()); - } - } - - void CastGravityLapseFly() // Use Fly Packet hack for now as players can't cast "fly" spells unless in map 530. Has to be done a while after they get knocked into the air... - { - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) - { - // Also needs an exception in spell system. - pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE_FLY, true, 0, 0, m_creature->GetGUID()); - // Use packet hack - WorldPacket data(12); - data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); - data.append(pUnit->GetPackGUID()); - data << uint32(0); - pUnit->SendMessageToSet(&data, true); - } - } - } - - void RemoveGravityLapse() - { - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) - { - pUnit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY); - pUnit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DOT); - WorldPacket data(12); - data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); - data.append(pUnit->GetPackGUID()); - data << uint32(0); - pUnit->SendMessageToSet(&data, true); - } - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->getVictim() && !m_creature->SelectHostilTarget()) - return; - - switch(Phase) - { - case 0: - { - // *Heroic mode only: - if(Heroic) - if(PyroblastTimer < diff) - { - DoCast(m_creature, SPELL_SHOCK_BARRIER, true); - DoCast(m_creature->getVictim(), SPELL_PYROBLAST); - PyroblastTimer = 60000; - }else PyroblastTimer -= diff; - - if(FireballTimer < diff) - { - // *Normal/Heroic mode support - if(Heroic) DoCast(m_creature->getVictim(), SPELL_FIREBALL_HEROIC); - else DoCast(m_creature->getVictim(), SPELL_FIREBALL_NORMAL); - FireballTimer = 2000 + rand()%4000; - }else FireballTimer -= diff; - - if(PhoenixTimer < diff) - { - uint32 random = rand()%2 + 1; - float x = KaelLocations[random][0]; - float y = KaelLocations[random][1]; - Creature* Phoenix = m_creature->SummonCreature(CREATURE_PHOENIX, x, y, LOCATION_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - if(Phoenix) - { - Phoenix->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - SetThreatList(Phoenix); - } - - DoYell(SAY_PHOENIX, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_PHOENIX); - - PhoenixTimer = 40000; - }else PhoenixTimer -= diff; - - if(FlameStrikeTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - DoCast(target, SPELL_FLAMESTRIKE3, true); - FlameStrikeTimer = 20000 + rand()%5000; - - DoYell(SAY_FLAMESTRIKE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_FLAMESTRIKE); - } - }else FlameStrikeTimer -= diff; - - // Below 50% - if(m_creature->GetMaxHealth() * 0.5 > m_creature->GetHealth()) - { - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); - m_creature->StopMoving(); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - GravityLapseTimer = 0; - GravityLapsePhase = 0; - Phase = 1; - } - DoMeleeAttackIfReady(); - } - break; - - case 1: - { - if(GravityLapseTimer < diff) - { - switch(GravityLapsePhase) - { - case 0: - if(FirstGravityLapse) // Different yells at 50%, and at every following Gravity Lapse - { - DoYell(SAY_GRAVITY_LAPSE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_GRAVITY_LAPSE); - FirstGravityLapse = false; - if(pInstance) - { - GameObject* KaelLeft = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_KAEL_STATUE_LEFT)); - if(KaelLeft) KaelLeft->SetGoState(0); - GameObject* KaelRight = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_KAEL_STATUE_RIGHT)); - if(KaelRight) KaelRight->SetGoState(0); - } - }else - { - DoYell(SAY_RECAST_GRAVITY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RECAST_GRAVITY); - } - DoCast(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) - { - Creature* Orb = DoSpawnCreature(CREATURE_ARCANE_SPHERE, 5, 5, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); - if(Orb) SetThreatList(Orb); - } - DoCast(m_creature, SPELL_GRAVITY_LAPSE_CHANNEL); - break; - - case 4: - m_creature->InterruptNonMeleeSpells(false); - DoYell(SAY_TIRED,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_TIRED); - DoCast(m_creature, SPELL_POWER_FEEDBACK); - RemoveGravityLapse(); - GravityLapseTimer = 10000; - GravityLapsePhase = 0; - break; - } - }else GravityLapseTimer -= diff; - } - break; - } - } -}; - -struct MANGOS_DLL_DECL mob_felkael_flamestrikeAI : public ScriptedAI -{ - mob_felkael_flamestrikeAI(Creature *c) : ScriptedAI(c) - { - Reset(); - Heroic = c->GetMap()->IsHeroic() ? true : false; - } - - uint32 FlameStrikeTimer; - bool Heroic; - - void Reset() - { - FlameStrikeTimer = 5000; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(14); - - DoCast(m_creature, SPELL_FLAMESTRIKE2, true); - } - - void Aggro(Unit *who) {} - void MoveInLineOfSight(Unit *who) {} - void UpdateAI(const uint32 diff) - { - if(FlameStrikeTimer < diff) - { - // *Normal/Heroic mode support - if(Heroic) DoCast(m_creature, SPELL_FLAMESTRIKE1_HEROIC, true); - else DoCast(m_creature, SPELL_FLAMESTRIKE1_NORMAL, true); - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - }else FlameStrikeTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL mob_felkael_phoenixAI : public ScriptedAI -{ - mob_felkael_phoenixAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 BurnTimer; - - void Reset() - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - BurnTimer = 2000; - } - - void Aggro(Unit* who) {} - - void JustDied(Unit* slayer) - { - DoSpawnCreature(CREATURE_PHOENIX_EGG, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (BurnTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_PHOENIX_BURN); - BurnTimer = 2000; - }else BurnTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_felkael_phoenix_eggAI : public ScriptedAI -{ - mob_felkael_phoenix_eggAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 HatchTimer; - - void Reset() { HatchTimer = 15000; } - - void Aggro(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - - void UpdateAI(const uint32 diff) - { - if(HatchTimer < diff) - { - DoSpawnCreature(CREATURE_PHOENIX, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - }else HatchTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL mob_arcane_sphereAI : public ScriptedAI -{ - mob_arcane_sphereAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 DespawnTimer; - uint32 ChangeTargetTimer; - - bool TargetLocked; - - void Reset() - { - DespawnTimer = 30000; - ChangeTargetTimer = 5000; - TargetLocked = false; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(14); - DoCast(m_creature, SPELL_ARCANE_SPHERE_PASSIVE, true); - } - - void MoveInLineOfSight(Unit* who) - { - if(TargetLocked) - return; - if(who && who->IsHostileTo(m_creature) && (m_creature->IsWithinDistInMap(who, 25))) - StalkTarget(who); - } - - void Aggro(Unit* who) {} - - void StalkTarget(Unit* target) - { - if(!target) - return; - - m_creature->GetMotionMaster()->MoveChase(target); - TargetLocked = true; - } - - void UpdateAI(const uint32 diff) - { - if(DespawnTimer < diff) - 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->SelectHostilTarget()) - return; - - if(ChangeTargetTimer < diff) - { - TargetLocked = false; - ChangeTargetTimer = 10000; - }else ChangeTargetTimer -= diff; - } -}; - -CreatureAI* GetAI_boss_felblood_kaelthas(Creature* c) -{ - return new boss_felblood_kaelthasAI(c); -} - -CreatureAI* GetAI_mob_arcane_sphere(Creature* c) -{ - return new mob_arcane_sphereAI(c); -} - -CreatureAI* GetAI_mob_felkael_phoenix(Creature* c) -{ - return new mob_felkael_phoenixAI(c); -} - -CreatureAI* GetAI_mob_felkael_phoenix_egg(Creature* c) -{ - return new mob_felkael_phoenix_eggAI(c); -} - -CreatureAI* GetAI_mob_felkael_flamestrike(Creature* c) -{ - return new mob_felkael_flamestrikeAI(c); -} - -void AddSC_boss_felblood_kaelthas() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_felblood_kaelthas"; - newscript->GetAI = GetAI_boss_felblood_kaelthas; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_arcane_sphere"; - newscript->GetAI = GetAI_mob_arcane_sphere; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_felkael_phoenix"; - newscript->GetAI = GetAI_mob_felkael_phoenix; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_felkael_phoenix_egg"; - newscript->GetAI = GetAI_mob_felkael_phoenix_egg; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_felkael_flamestrike"; - newscript->GetAI = GetAI_mob_felkael_flamestrike; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_felblood_kaelthas +SD%Complete: 80 +SDComment: Normal and Heroic Support. Issues: Arcane Spheres do not initially follow targets. TODO: Convert Phoenix to ACID. +SDCategory: Magisters' Terrace +EndScriptData */ + +#include "precompiled.h" +#include "def_magisters_terrace.h" +#include "WorldPacket.h" + +/*** 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 44198 // A spell Phoenix uses to damage everything around + +#define SPELL_FLAMESTRIKE1_NORMAL 44190 // Damage part +#define SPELL_FLAMESTRIKE1_HEROIC 46163 // Heroic damage part +#define SPELL_FLAMESTRIKE2 44191 // Flamestrike indicator before the damage +#define SPELL_FLAMESTRIKE3 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 CREATURE_PHOENIX 24674 +#define CREATURE_PHOENIX_EGG 24675 +#define CREATURE_ARCANE_SPHERE 24708 + +/*** Dialogues ***/ +#define SAY_AGGRO "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!" +#define SOUND_AGGRO 12413 // This yell should be done when the room is cleared. For now, set it as aggro yell. + +#define SAY_PHOENIX "Vengeance burns!" +#define SOUND_PHOENIX 12415 + +#define SAY_FLAMESTRIKE "Felomin ashal!" +#define SOUND_FLAMESTRIKE 12417 + +#define SAY_GRAVITY_LAPSE "I'll turn your world... upside... down..." +#define SOUND_GRAVITY_LAPSE 12418 + +#define SAY_TIRED "Master... grant me strength." +#define SOUND_TIRED 12419 + +#define SAY_RECAST_GRAVITY "Do not... get too comfortable." +#define SOUND_RECAST_GRAVITY 12420 + +#define SAY_DEATH "My demise accomplishes nothing! The Master will have you! You will drown in your own blood! This world shall burn! Aaaghh!" +#define SOUND_DEATH 12421 + +/** Locations **/ +float KaelLocations[3][2]= +{ + {148.744659, 181.377426}, + {140.823883, 195.403046}, + {156.574188, 195.650482}, +}; +#define LOCATION_Z -16.727455 + +struct MANGOS_DLL_DECL boss_felblood_kaelthasAI : public ScriptedAI +{ + boss_felblood_kaelthasAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + Heroic = c->GetMap()->IsHeroic() ? true : false; + } + + ScriptedInstance* pInstance; + + uint32 FireballTimer; + uint32 PhoenixTimer; + uint32 FlameStrikeTimer; + uint32 CombatPulseTimer; + + //Heroic only + uint32 PyroblastTimer; + + 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. + + bool FirstGravityLapse; + bool Heroic; + + uint8 Phase; + // 0 = Not started + // 1 = Fireball; Summon Phoenix; Flamestrike + // 2 = Gravity Lapses + + void Reset() + { + // TODO: Timers + FireballTimer = 0; + PhoenixTimer = 30000; + FlameStrikeTimer = 25000; + CombatPulseTimer = 0; + + PyroblastTimer = 60000; + + GravityLapseTimer = 0; + GravityLapsePhase = 0; + + FirstGravityLapse = true; + + Phase = 0; + + if(pInstance) + pInstance->SetData(DATA_KAELTHAS_EVENT, 0); + } + + void JustDied(Unit *killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void DamageTaken(Unit* done_by, uint32 &damage) + { + if(damage > m_creature->GetHealth()) + RemoveGravityLapse(); // Remove Gravity Lapse so that players fall to ground if they kill him when in air. + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void SetThreatList(Creature* SummonedUnit) + { + if(!SummonedUnit) return; + + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + std::list::iterator i = m_threatlist.begin(); + for(i = m_threatlist.begin(); i != m_threatlist.end(); i++) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && pUnit->isAlive()) + { + float threat = m_creature->getThreatManager().getThreat(pUnit); + SummonedUnit->AddThreat(pUnit, threat); + } + } + } + + void TeleportPlayersToSelf() + { + float x = KaelLocations[0][0]; + float y = KaelLocations[0][1]; + m_creature->Relocate(x, y, LOCATION_Z, 0); + //m_creature->SendMonsterMove(x, y, LOCATION_Z, 0, 0, 0); // causes some issues... + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) + pUnit->CastSpell(pUnit, SPELL_TELEPORT_CENTER, true); + } + DoCast(m_creature, SPELL_TELEPORT_CENTER, true); + } + + void CastGravityLapseKnockUp() + { + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) + // Knockback into the air + pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE_DOT, true, 0, 0, m_creature->GetGUID()); + } + } + + void CastGravityLapseFly() // Use Fly Packet hack for now as players can't cast "fly" spells unless in map 530. Has to be done a while after they get knocked into the air... + { + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) + { + // Also needs an exception in spell system. + pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE_FLY, true, 0, 0, m_creature->GetGUID()); + // Use packet hack + WorldPacket data(12); + data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); + data.append(pUnit->GetPackGUID()); + data << uint32(0); + pUnit->SendMessageToSet(&data, true); + } + } + } + + void RemoveGravityLapse() + { + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) + { + pUnit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY); + pUnit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DOT); + WorldPacket data(12); + data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); + data.append(pUnit->GetPackGUID()); + data << uint32(0); + pUnit->SendMessageToSet(&data, true); + } + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->getVictim() && !m_creature->SelectHostilTarget()) + return; + + switch(Phase) + { + case 0: + { + // *Heroic mode only: + if(Heroic) + if(PyroblastTimer < diff) + { + DoCast(m_creature, SPELL_SHOCK_BARRIER, true); + DoCast(m_creature->getVictim(), SPELL_PYROBLAST); + PyroblastTimer = 60000; + }else PyroblastTimer -= diff; + + if(FireballTimer < diff) + { + // *Normal/Heroic mode support + if(Heroic) DoCast(m_creature->getVictim(), SPELL_FIREBALL_HEROIC); + else DoCast(m_creature->getVictim(), SPELL_FIREBALL_NORMAL); + FireballTimer = 2000 + rand()%4000; + }else FireballTimer -= diff; + + if(PhoenixTimer < diff) + { + uint32 random = rand()%2 + 1; + float x = KaelLocations[random][0]; + float y = KaelLocations[random][1]; + Creature* Phoenix = m_creature->SummonCreature(CREATURE_PHOENIX, x, y, LOCATION_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); + if(Phoenix) + { + Phoenix->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + SetThreatList(Phoenix); + } + + DoYell(SAY_PHOENIX, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_PHOENIX); + + PhoenixTimer = 40000; + }else PhoenixTimer -= diff; + + if(FlameStrikeTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + DoCast(target, SPELL_FLAMESTRIKE3, true); + FlameStrikeTimer = 20000 + rand()%5000; + + DoYell(SAY_FLAMESTRIKE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_FLAMESTRIKE); + } + }else FlameStrikeTimer -= diff; + + // Below 50% + if(m_creature->GetMaxHealth() * 0.5 > m_creature->GetHealth()) + { + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); + m_creature->StopMoving(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + GravityLapseTimer = 0; + GravityLapsePhase = 0; + Phase = 1; + } + DoMeleeAttackIfReady(); + } + break; + + case 1: + { + if(GravityLapseTimer < diff) + { + switch(GravityLapsePhase) + { + case 0: + if(FirstGravityLapse) // Different yells at 50%, and at every following Gravity Lapse + { + DoYell(SAY_GRAVITY_LAPSE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_GRAVITY_LAPSE); + FirstGravityLapse = false; + if(pInstance) + { + GameObject* KaelLeft = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_KAEL_STATUE_LEFT)); + if(KaelLeft) KaelLeft->SetGoState(0); + GameObject* KaelRight = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_KAEL_STATUE_RIGHT)); + if(KaelRight) KaelRight->SetGoState(0); + } + }else + { + DoYell(SAY_RECAST_GRAVITY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RECAST_GRAVITY); + } + DoCast(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) + { + Creature* Orb = DoSpawnCreature(CREATURE_ARCANE_SPHERE, 5, 5, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + if(Orb) SetThreatList(Orb); + } + DoCast(m_creature, SPELL_GRAVITY_LAPSE_CHANNEL); + break; + + case 4: + m_creature->InterruptNonMeleeSpells(false); + DoYell(SAY_TIRED,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_TIRED); + DoCast(m_creature, SPELL_POWER_FEEDBACK); + RemoveGravityLapse(); + GravityLapseTimer = 10000; + GravityLapsePhase = 0; + break; + } + }else GravityLapseTimer -= diff; + } + break; + } + } +}; + +struct MANGOS_DLL_DECL mob_felkael_flamestrikeAI : public ScriptedAI +{ + mob_felkael_flamestrikeAI(Creature *c) : ScriptedAI(c) + { + Reset(); + Heroic = c->GetMap()->IsHeroic() ? true : false; + } + + uint32 FlameStrikeTimer; + bool Heroic; + + void Reset() + { + FlameStrikeTimer = 5000; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->setFaction(14); + + DoCast(m_creature, SPELL_FLAMESTRIKE2, true); + } + + void Aggro(Unit *who) {} + void MoveInLineOfSight(Unit *who) {} + void UpdateAI(const uint32 diff) + { + if(FlameStrikeTimer < diff) + { + // *Normal/Heroic mode support + if(Heroic) DoCast(m_creature, SPELL_FLAMESTRIKE1_HEROIC, true); + else DoCast(m_creature, SPELL_FLAMESTRIKE1_NORMAL, true); + m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + }else FlameStrikeTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL mob_felkael_phoenixAI : public ScriptedAI +{ + mob_felkael_phoenixAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 BurnTimer; + + void Reset() + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); + BurnTimer = 2000; + } + + void Aggro(Unit* who) {} + + void JustDied(Unit* slayer) + { + DoSpawnCreature(CREATURE_PHOENIX_EGG, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (BurnTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_PHOENIX_BURN); + BurnTimer = 2000; + }else BurnTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_felkael_phoenix_eggAI : public ScriptedAI +{ + mob_felkael_phoenix_eggAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 HatchTimer; + + void Reset() { HatchTimer = 15000; } + + void Aggro(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if(HatchTimer < diff) + { + DoSpawnCreature(CREATURE_PHOENIX, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + }else HatchTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL mob_arcane_sphereAI : public ScriptedAI +{ + mob_arcane_sphereAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 DespawnTimer; + uint32 ChangeTargetTimer; + + bool TargetLocked; + + void Reset() + { + DespawnTimer = 30000; + ChangeTargetTimer = 5000; + TargetLocked = false; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->setFaction(14); + DoCast(m_creature, SPELL_ARCANE_SPHERE_PASSIVE, true); + } + + void MoveInLineOfSight(Unit* who) + { + if(TargetLocked) + return; + if(who && who->IsHostileTo(m_creature) && (m_creature->IsWithinDistInMap(who, 25))) + StalkTarget(who); + } + + void Aggro(Unit* who) {} + + void StalkTarget(Unit* target) + { + if(!target) + return; + + m_creature->GetMotionMaster()->MoveChase(target); + TargetLocked = true; + } + + void UpdateAI(const uint32 diff) + { + if(DespawnTimer < diff) + 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->SelectHostilTarget()) + return; + + if(ChangeTargetTimer < diff) + { + TargetLocked = false; + ChangeTargetTimer = 10000; + }else ChangeTargetTimer -= diff; + } +}; + +CreatureAI* GetAI_boss_felblood_kaelthas(Creature* c) +{ + return new boss_felblood_kaelthasAI(c); +} + +CreatureAI* GetAI_mob_arcane_sphere(Creature* c) +{ + return new mob_arcane_sphereAI(c); +} + +CreatureAI* GetAI_mob_felkael_phoenix(Creature* c) +{ + return new mob_felkael_phoenixAI(c); +} + +CreatureAI* GetAI_mob_felkael_phoenix_egg(Creature* c) +{ + return new mob_felkael_phoenix_eggAI(c); +} + +CreatureAI* GetAI_mob_felkael_flamestrike(Creature* c) +{ + return new mob_felkael_flamestrikeAI(c); +} + +void AddSC_boss_felblood_kaelthas() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_felblood_kaelthas"; + newscript->GetAI = GetAI_boss_felblood_kaelthas; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_arcane_sphere"; + newscript->GetAI = GetAI_mob_arcane_sphere; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_felkael_phoenix"; + newscript->GetAI = GetAI_mob_felkael_phoenix; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_felkael_phoenix_egg"; + newscript->GetAI = GetAI_mob_felkael_phoenix_egg; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_felkael_flamestrike"; + newscript->GetAI = GetAI_mob_felkael_flamestrike; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp index 94b13cd5cd5..a37069542cc 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp @@ -1,1367 +1,1367 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Delrissa -SD%Complete: 45 -SDComment: No Heroic support yet. Needs further testing. Several scripts for pets disabled, not seem to require any special script. -SDCategory: Magister's Terrace -EndScriptData */ - -#include "precompiled.h" -#include "def_magisters_terrace.h" - -#define SAY_AGGRO "Annihilate them!" -#define SOUND_AGGRO 12395 - -struct Speech -{ - const char* text; - uint32 sound; -}; - -static Speech LackeyDeath[]= -{ - {"Oh, the horror.", 12398}, - {"Well, aren't you lucky?", 12400}, - {"Now I'm getting annoyed.", 12401}, - {"Lackies be damned! I'll finish you myself!", 12403}, -}; - -static Speech PlayerDeath[]= -{ - {"I call that a good start.", 12405}, - {"I could have sworn there were more of you.", 12407}, - {"Not really much of a group, anymore, is it?", 12409}, - {"One is such a lonely number", 12410}, - {"It's been a kick, really", 12411}, -}; - -#define SAY_DEATH "Not what I had... planned..." -#define SOUND_DEATH 12397 - -#define SPELL_DISPEL_MAGIC 27609 -#define SPELL_FLASH_HEAL 17843 -#define SPELL_SW_PAIN_NORMAL 14032 -#define SPELL_SW_PAIN_HEROIC 15654 -#define SPELL_SHIELD 44291 -#define SPELL_RENEW_NORMAL 44174 -#define SPELL_RENEW_HEROIC 46192 - -#define ORIENT 4.98 -#define POS_Z -19.9215 - -float LackeyLocations[4][2]= -{ - {123.77, 17.6007}, - {131.731, 15.0827}, - {121.563, 15.6213}, - {129.988, 17.2355}, -}; - -const uint32 AddEntry[8]= -{ - 24557, //Kagani Nightstrike - 24558, //Elris Duskhallow - 24554, //Eramas Brightblaze - 24561, //Yazzaj - 24559, //Warlord Salaris - 24555, //Garaxxas - 24553, //Apoko - 24556, //Zelfan -}; - -struct Add -{ - Add(uint32 _entry, uint64 _guid) - { - entry = _entry; - guid = _guid; - } - - uint32 entry; - uint64 guid; -}; - -struct MANGOS_DLL_DECL boss_priestess_delrissaAI : public ScriptedAI -{ - boss_priestess_delrissaAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Adds.clear(); - Reset(); - SummonAdds(); - Heroic = c->GetMap()->IsHeroic(); - } - - ScriptedInstance* pInstance; - - std::vector Adds; - - uint8 LackeysKilled; - uint8 PlayersKilled; - - uint32 HealTimer; - uint32 RenewTimer; - uint32 ShieldTimer; - uint32 SWPainTimer; - uint32 DispelTimer; - - uint32 CombatPulseTimer; // Periodically puts all players in the instance in combat - - bool Heroic; - - void Reset() - { - LackeysKilled = 0; - PlayersKilled = 0; - - HealTimer = 15000; - RenewTimer = 10000; - ShieldTimer = 2000; - SWPainTimer = 5000; - DispelTimer = 7500; - - CombatPulseTimer = 5000; - - CheckAdds(); - - if(pInstance) - { - pInstance->SetData(DATA_DELRISSA_EVENT, NOT_STARTED); - pInstance->SetData(DATA_DELRISSA_DEATH_COUNT, 0); - } - else error_log(ERROR_INST_DATA); - } - - void Aggro(Unit* who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - - for(uint8 i = 0; i < Adds.size(); ++i) - if(Unit* pAdd = Unit::GetUnit(*m_creature, Adds[i]->guid)) - pAdd->AddThreat(who, 1.0f); - } - - void SummonAdds() - { - std::vector AddList; - for(uint8 i = 0; i < 8; ++i) - AddList.push_back(AddEntry[i]); - - while(AddList.size() > 4) - AddList.erase(AddList.begin() + rand()%AddList.size()); - - for(uint8 i = 0; i < AddList.size(); ++i) - { - Creature* pAdd = m_creature->SummonCreature(AddList[i], LackeyLocations[i][0], LackeyLocations[i][1], POS_Z, ORIENT, TEMPSUMMON_DEAD_DESPAWN, 0); - if(pAdd) - { - Add* nAdd = new Add(AddList[i], pAdd->GetGUID()); - Adds.push_back(nAdd); - } - } - } - - void CheckAdds() - { - if(Adds.empty()) - return; - - for(uint8 i = 0; i < Adds.size(); ++i) - { - bool resummon = true; - Creature* pAdd = ((Creature*)Unit::GetUnit(*m_creature, Adds[i]->guid)); - if(pAdd && pAdd->isAlive()) - { - pAdd->AI()->EnterEvadeMode(); // Force them out of combat and reset if they are in combat. - resummon = false; - } - if(resummon) - { - pAdd = m_creature->SummonCreature(Adds[i]->entry, LackeyLocations[i][0], LackeyLocations[i][1], POS_Z, ORIENT, TEMPSUMMON_DEAD_DESPAWN, 0); - Add* nAdd = new Add(Adds[i]->entry, pAdd->GetGUID()); - Adds.erase(Adds.begin() + i); - Adds.push_back(nAdd); - } - } - } - - void KilledUnit(Unit* victim) - { - if(victim->GetTypeId() != TYPEID_PLAYER) - return; - - DoYell(PlayerDeath[PlayersKilled].text, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, PlayerDeath[PlayersKilled].sound); - if( PlayersKilled < 4 ) - ++PlayersKilled; - } - - void KilledLackey() - { - DoYell(LackeyDeath[LackeysKilled].text, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, LackeyDeath[LackeysKilled].sound); - if( LackeysKilled < 3 ) - ++LackeysKilled; - } - - void JustDied(Unit* killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - CheckLootable(); - - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - pInstance->SetData(DATA_DELRISSA_DEATH_COUNT, 1); - pInstance->SetData(DATA_DELRISSA_EVENT, DONE); - if(GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_DELRISSA_DOOR))) - Door->SetGoState(0); - } - - void CheckLootable() - { - if(LackeysKilled > 4) - m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - else - m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(HealTimer < diff) - { - uint32 health = m_creature->GetHealth(); - Unit* target = m_creature; - for(uint8 i = 0; i < Adds.size(); ++i) - if(Unit* pAdd = Unit::GetUnit(*m_creature, Adds[i]->guid)) - if(pAdd->isAlive() && pAdd->GetHealth() < health) - target = pAdd; - - DoCast(target, SPELL_FLASH_HEAL); - HealTimer = 15000; - }else HealTimer -= diff; - - if(RenewTimer < diff) - { - Unit* target = m_creature; - if(rand()%2 == 1) - { - std::vector::iterator itr = Adds.begin() + rand()%Adds.size(); - Unit* pAdd = Unit::GetUnit(*m_creature, (*itr)->guid); - if(pAdd && pAdd->isAlive()) - target = pAdd; - } - DoCast(target,Heroic ? SPELL_RENEW_HEROIC : SPELL_RENEW_NORMAL); - RenewTimer = 5000; - }else RenewTimer -= diff; - - if(ShieldTimer < diff) - { - Unit* target = m_creature; - if(rand()%2 == 1) - { - std::vector::iterator itr = Adds.begin() + rand()%Adds.size(); - if(Unit* pAdd = Unit::GetUnit(*m_creature, (*itr)->guid)) - if(!pAdd->HasAura(SPELL_SHIELD, 0) && pAdd->isAlive()) - target = pAdd; - } - DoCast(target, SPELL_SHIELD); - ShieldTimer = 7500; - }else ShieldTimer -= diff; - - if(DispelTimer < diff) - { - Unit* target = NULL; - bool friendly = false; - if(rand()%2 == 1) - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - else - { - friendly = true; - if(rand()%2 == 1) - target = m_creature; - else - { - std::vector::iterator itr = Adds.begin() + rand()%Adds.size(); - Unit* pAdd = Unit::GetUnit(*m_creature, (*itr)->guid); - if(pAdd && pAdd->isAlive()) - target = pAdd; - } - } - if(target) - { - DoCast(target, SPELL_DISPEL_MAGIC); - DispelTimer = 12000; - } - }else DispelTimer -= diff; - - if(SWPainTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0),Heroic ? SPELL_SW_PAIN_HEROIC : SPELL_SW_PAIN_NORMAL); - SWPainTimer = 10000; - }else SWPainTimer -= diff; - - /* - if(CombatPulseTimer < diff) - { - DoZoneInCombat(); - for(uint8 i = 0; i < Adds.size(); ++i) - { - if(Unit* pAdd = Unit::GetUnit(*m_creature, Add[i]->guid)) - if(pAdd->isAlive()) - DoZoneInCombat(pAdd); - } - - CombatPulseTimer = 10000; - }else CombatPulseTimer -= diff;*/ - - DoMeleeAttackIfReady(); - } -}; - -#define SPELL_HEALING_POTION 15503 - -struct MANGOS_DLL_DECL boss_priestess_guestAI : public ScriptedAI -{ - boss_priestess_guestAI(Creature* c) : ScriptedAI(c) - { - Group.clear(); - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - AcquireGUIDs(); - } - - ScriptedInstance* pInstance; - - std::vector Group; - - uint32 ResetThreatTimer; - - bool UsedPotion; - - void Reset() - { - UsedPotion = false; - - ResetThreatTimer = 5000 + rand()%15000; // These guys like to switch targets often, and are not meant to be tanked. - } - - void Aggro(Unit* who) {} - - void JustDied(Unit* killer) - { - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - Creature* Delrissa = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA))); - if(Delrissa) - { - ((boss_priestess_delrissaAI*)Delrissa->AI())->KilledLackey(); - if(!Delrissa->isAlive() && pInstance->GetData(DATA_DELRISSA_DEATH_COUNT) > 3) - ((boss_priestess_delrissaAI*)Delrissa->AI())->CheckLootable(); - - pInstance->SetData(DATA_DELRISSA_DEATH_COUNT, 1); - } - } - - void KilledUnit(Unit* victim) - { - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - Creature* Delrissa = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA))); - if(Delrissa) - Delrissa->AI()->KilledUnit(victim); - } - - void AcquireGUIDs() - { - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - Creature* Delrissa = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA))); - if(Delrissa) - { - Group = ((boss_priestess_delrissaAI*)Delrissa->AI())->Adds; - Add* dAdd = new Add(Delrissa->GetEntry(), Delrissa->GetGUID()); - Group.push_back(dAdd); - } - } - - void UpdateAI(const uint32 diff) - { - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) && !UsedPotion) - { - DoCast(m_creature, SPELL_HEALING_POTION, true); - UsedPotion = true; - } - - if(ResetThreatTimer < diff) - { - DoResetThreat(); - ResetThreatTimer = 5000 + rand()%15000; - }else ResetThreatTimer -= diff; - } -}; - -#define SPELL_KIDNEY_SHOT 27615 -#define SPELL_GOUGE 12540 -#define SPELL_KICK 27613 -#define SPELL_VANISH 44290 -#define SPELL_BACKSTAB 15657 -#define SPELL_EVISCERATE 27611 - -struct MANGOS_DLL_DECL boss_kagani_nightstrikeAI : public boss_priestess_guestAI -{ - //Rogue - boss_kagani_nightstrikeAI(Creature *c) : boss_priestess_guestAI(c) {} - - uint32 Gouge_Timer; - uint32 Kick_Timer; - uint32 Vanish_Timer; - uint32 Eviscerate_Timer; - uint32 Wait_Timer; - bool InVanish; - - 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_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_priestess_guestAI::UpdateAI(diff); - - if(Vanish_Timer < diff) - { - m_creature->SetVisibility(VISIBILITY_OFF); // ...? Hacklike - DoCast(m_creature, SPELL_VANISH); - InVanish = true; - Vanish_Timer = 30000; - Wait_Timer = 10000; - DoResetThreat(); - m_creature->AddThreat(SelectUnit(SELECT_TARGET_RANDOM, 0), 1000.0f); - }else Vanish_Timer -= diff; - - if(InVanish) - if(Wait_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_BACKSTAB, true); - DoCast(m_creature->getVictim(), SPELL_KIDNEY_SHOT, true); - m_creature->SetVisibility(VISIBILITY_ON); // ...? Hacklike - InVanish = false; - }else Wait_Timer -= diff; - - if(Gouge_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_GOUGE); - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); - Gouge_Timer = 5500; - }else Gouge_Timer -= diff; - - if(Kick_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_KICK); - Kick_Timer = 7000; - }else Kick_Timer -= diff; - - if(Eviscerate_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_EVISCERATE); - Eviscerate_Timer = 4000; - }else Eviscerate_Timer -= diff; - - if(!InVanish) - DoMeleeAttackIfReady(); - } -}; - -#define SPELL_IMMOLATE 44267 -#define SPELL_SHADOW_BOLT 12471 -#define SPELL_SEED_OF_CORRUPTION 44141 -#define SPELL_CURSE_OF_AGONY 14875 -#define SPELL_FEAR 38595 -#define SPELL_IMP_FIREBALL 44164 -#define SPELL_SUMMON_IMP 44163 - -//#define CREATURE_IMP 44163 -//#define CREATURE_FIZZLE 24656 - -/*struct MANGOS_DLL_DECL mob_fizzleAI : public ScriptedAI -{ - mob_fizzleAI(Creature *c) : ScriptedAI(c) - { - Reset(); - } - - uint64 EllrisGUID; - uint32 Firebal_Timer; - - void Reset() { EllrisGUID = 0; } - - void KilledUnit(Unit* victim); - void JustDied(Unit* killer); - - void Aggro(Unit* who){} - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Chain cast - if (!m_creature->IsNonMeleeSpellCasted(false)) - DoCast(m_creature->getVictim(),SPELL_IMP_FIREBALL); - else DoMeleeAttackIfReady(); - } -};*/ - -struct MANGOS_DLL_DECL boss_ellris_duskhallowAI : public boss_priestess_guestAI -{ - //Warlock - boss_ellris_duskhallowAI(Creature *c) : boss_priestess_guestAI(c) - { - } - - bool HasSummonedImp; - - uint32 Immolate_Timer; - uint32 Shadow_Bolt_Timer; - uint32 Seed_of_Corruption_Timer; - uint32 Curse_of_Agony_Timer; - uint32 Fear_Timer; - - void Reset() - { - //HasSummonedImp = false; - - Immolate_Timer = 6000; - Shadow_Bolt_Timer = 3000; - Seed_of_Corruption_Timer = 2000; - Curse_of_Agony_Timer = 1000; - Fear_Timer = 10000; - - boss_priestess_guestAI::Reset(); - } - - void JustDied(Unit* killer) - { - boss_priestess_guestAI::JustDied(killer); - } - - void UpdateAI(const uint32 diff) - { - if(!HasSummonedImp) - { - //Imp will not despawn unless it's killed, even if owner dies, this is correct way. - DoCast(m_creature,SPELL_SUMMON_IMP); - HasSummonedImp = true; - } - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_priestess_guestAI::UpdateAI(diff); - - if(Immolate_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_IMMOLATE); - Immolate_Timer = 6000; - }else Immolate_Timer -= diff; - - if(Shadow_Bolt_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOW_BOLT); - Shadow_Bolt_Timer = 5000; - }else Shadow_Bolt_Timer -= diff; - - if(Seed_of_Corruption_Timer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_SEED_OF_CORRUPTION); - Seed_of_Corruption_Timer = 10000; - }else Seed_of_Corruption_Timer -= diff; - - if(Curse_of_Agony_Timer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_CURSE_OF_AGONY); - Curse_of_Agony_Timer = 13000; - }else Curse_of_Agony_Timer -= diff; - - if(Fear_Timer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FEAR); - Fear_Timer = 10000; - }else Fear_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -/*void mob_fizzleAI::JustDied(Unit* killer) -{ - if(Creature* Ellris = ((Creature*)Unit::GetUnit(*m_creature, EllrisGUID))) - ((boss_ellris_duskhallowAI*)Ellris->AI())->ImpGUID = 0; -} - -void mob_fizzleAI::KilledUnit(Unit* victim) -{ - if(Creature* Ellris = ((Creature*)Unit::GetUnit(*m_creature, EllrisGUID))) - ((boss_ellris_duskhallowAI*)Ellris->AI())->KilledUnit(victim); -}*/ - -#define SPELL_KNOCKDOWN 11428 -#define SPELL_SNAP_KICK 46182 - -struct MANGOS_DLL_DECL boss_eramas_brightblazeAI : public boss_priestess_guestAI -{ - //Monk - boss_eramas_brightblazeAI(Creature *c) : boss_priestess_guestAI(c) {} - - uint32 Knockdown_Timer; - uint32 Snap_Kick_Timer; - - void Reset() - { - Knockdown_Timer = 6000; - Snap_Kick_Timer = 4500; - - boss_priestess_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_priestess_guestAI::UpdateAI(diff); - - if(Knockdown_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKDOWN); - Knockdown_Timer = 6000; - }else Knockdown_Timer -= diff; - - if(Snap_Kick_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SNAP_KICK); - Snap_Kick_Timer = 4500; - }else Snap_Kick_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -#define SPELL_POLYMORPH 13323 -#define SPELL_ICE_BLOCK 27619 -#define SPELL_BLIZZARD 44178 -#define SPELL_ICE_LANCE 46194 -#define SPELL_CONE_OF_COLD 38384 -#define SPELL_FROSTBOLT 15043 -#define SPELL_BLINK 14514 - -struct MANGOS_DLL_DECL boss_yazzaiAI : public boss_priestess_guestAI -{ - //Mage - boss_yazzaiAI(Creature *c) : boss_priestess_guestAI(c) {} - - bool HasIceBlocked; - - 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; - - 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_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_priestess_guestAI::UpdateAI(diff); - - if(Polymorph_Timer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - DoCast(target, SPELL_POLYMORPH); - m_creature->getThreatManager().modifyThreatPercent(target,-100); - Polymorph_Timer = 20000; - } - }else Polymorph_Timer -= diff; - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 35) && !HasIceBlocked) - { - DoCast(m_creature, SPELL_ICE_BLOCK); - HasIceBlocked = true; - } - - if(Blizzard_Timer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_BLIZZARD); - Blizzard_Timer = 8000; - }else Blizzard_Timer -= diff; - - if(Ice_Lance_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ICE_LANCE); - Ice_Lance_Timer = 12000; - }else Ice_Lance_Timer -= diff; - - if(Cone_of_Cold_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CONE_OF_COLD); - Cone_of_Cold_Timer = 10000; - }else Cone_of_Cold_Timer -= diff; - - if(Frostbolt_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FROSTBOLT); - Frostbolt_Timer = 8000; - }else Frostbolt_Timer -= diff; - - if(Blink_Timer < diff) - { - bool InMeleeRange = false; - std::list& t_list = m_creature->getThreatManager().getThreatList(); - for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - if(Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid())) - //if in melee range - if (target->IsWithinDistInMap(m_creature, 5)) - { - InMeleeRange = true; - break; - } - } - //if anybody is in melee range than escape by blink - if(InMeleeRange) - DoCast(m_creature, SPELL_BLINK); - - Blink_Timer = 8000; - }else Blink_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -#define SPELL_INTERCEPT_STUN 27577 -#define SPELL_DISARM 27581 -#define SPELL_PIERCING_HOWL 23600 -#define SPELL_FRIGHTENING_SHOUT 19134 -#define SPELL_HAMSTRING 27584 -#define SPELL_BATTLE_SHOUT 27578 -#define SPELL_MORTAL_STRIKE 44268 - -struct MANGOS_DLL_DECL boss_warlord_salarisAI : public boss_priestess_guestAI -{ - //Warrior - boss_warlord_salarisAI(Creature *c) : boss_priestess_guestAI(c) {} - - uint32 Intercept_Stun_Timer; - uint32 Disarm_Timer; - uint32 Piercing_Howl_Timer; - uint32 Frightening_Shout_Timer; - uint32 Hamstring_Timer; - uint32 Mortal_Strike_Timer; - - void Reset() - { - Intercept_Stun_Timer = 500; - Disarm_Timer = 6000; - Piercing_Howl_Timer = 10000; - Frightening_Shout_Timer = 18000; - Hamstring_Timer = 4500; - Mortal_Strike_Timer = 8000; - DoCast(m_creature, SPELL_BATTLE_SHOUT); - boss_priestess_guestAI::Reset(); - } - - void Aggro(Unit* who) - { - DoCast(m_creature, SPELL_BATTLE_SHOUT); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_priestess_guestAI::UpdateAI(diff); - - if(Intercept_Stun_Timer < diff) - { - bool InMeleeRange = false; - std::list& t_list = m_creature->getThreatManager().getThreatList(); - for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - if(Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid())) - //if in melee range - if (target->IsWithinDistInMap(m_creature, 5)) - { - InMeleeRange = true; - break; - } - } - //if nobody is in melee range than try to use Intercept - if(!InMeleeRange) - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_INTERCEPT_STUN); - Intercept_Stun_Timer = 10000; - }else Intercept_Stun_Timer -= diff; - - if(Disarm_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DISARM); - Disarm_Timer = 6000; - }else Disarm_Timer -= diff; - - if(Hamstring_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_HAMSTRING); - Hamstring_Timer = 4500; - }else Hamstring_Timer -= diff; - - if(Mortal_Strike_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); - Mortal_Strike_Timer = 4500; - }else Mortal_Strike_Timer -= diff; - - if(Piercing_Howl_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_PIERCING_HOWL); - Piercing_Howl_Timer = 10000; - }else Piercing_Howl_Timer -= diff; - - if(Frightening_Shout_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FRIGHTENING_SHOUT); - Frightening_Shout_Timer = 18000; - }else Frightening_Shout_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -#define SPELL_AIMED_SHOT 44271 -#define SPELL_SHOOT 15620 -#define SPELL_CONCUSSIVE_SHOT 27634 -#define TRIGGER_CONCUSSIVE_SHOT 19410 -#define SPELL_MULTI_SHOT 31942 -#define SPELL_WING_CLIP 44286 -#define SPELL_FREEZING_TRAP 44136 - -#define CREATURE_SLIVER 24552 - -/*struct MANGOS_DLL_DECL mob_sliverAI : public ScriptedAI -{ - mob_sliverAI(Creature *c) : ScriptedAI(c) - { - Reset(); - } - - uint64 GaraxxasGUID; - - void Reset() { GaraxxasGUID = 0; } - - void KilledUnit(Unit* victim); - void JustDied(Unit* killer); - - void Aggro(Unit* who){} - -};*/ - -struct MANGOS_DLL_DECL boss_garaxxasAI : public boss_priestess_guestAI -{ - //Hunter - boss_garaxxasAI(Creature *c) : boss_priestess_guestAI(c) {} - - //uint64 SliverGUID; - bool HasSummonedSliver; - - uint32 Aimed_Shot_Timer; - uint32 Shoot_Timer; - uint32 Concussive_Shot_Timer; - uint32 Multi_Shot_Timer; - uint32 Wing_Clip_Timer; - uint32 Freezing_Trap_Timer; - - void Reset() - { - //SliverGUID = 0; - //HasSummonedSliver = false; - - Aimed_Shot_Timer = 6000; - Shoot_Timer = 2500; - Concussive_Shot_Timer = 8000; - Multi_Shot_Timer = 10000; - Wing_Clip_Timer = 4000; - Freezing_Trap_Timer = 15000; - - boss_priestess_guestAI::Reset(); - } - - void JustDied(Unit* killer) - { - boss_priestess_guestAI::JustDied(killer); - } - - void UpdateAI(const uint32 diff) - { - if(!HasSummonedSliver) - { - Creature* Sliver = m_creature->SummonCreature(CREATURE_SLIVER, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - if(Sliver) - { - //((mob_sliverAI*)Sliver->AI())->GaraxxasGUID = m_creature->GetGUID(); - //SliverGUID = Sliver->GetGUID(); - HasSummonedSliver = true; - } - } - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_priestess_guestAI::UpdateAI(diff); - - if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 5)) - { - if(Wing_Clip_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_WING_CLIP); - Wing_Clip_Timer = 4000; - }else Wing_Clip_Timer -= diff; - - if(Freezing_Trap_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FREEZING_TRAP); - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); - Freezing_Trap_Timer = 30000; - }else Freezing_Trap_Timer -= diff; - - if(!m_creature->getVictim()->hasUnitState(UNIT_STAT_STUNDED | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED | UNIT_STAT_DISTRACTED)) - DoMeleeAttackIfReady(); - }else - { - if(Concussive_Shot_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CONCUSSIVE_SHOT); - Concussive_Shot_Timer = 8000; - }else Concussive_Shot_Timer -= diff; - - if(Multi_Shot_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_MULTI_SHOT); - Multi_Shot_Timer = 10000; - }else Multi_Shot_Timer -= diff; - - if(Aimed_Shot_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_AIMED_SHOT); - Aimed_Shot_Timer = 6000; - }else Aimed_Shot_Timer -= diff; - - if(Shoot_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SHOOT); - Shoot_Timer = 2500; - }else Shoot_Timer -= diff; - } - } -}; - -/*void mob_sliverAI::JustDied(Unit* killer) -{ - if(Creature* Garaxxas = ((Creature*)Unit::GetUnit(*m_creature, GaraxxasGUID))) - ((boss_garaxxasAI*)Garaxxas->AI())->SliverGUID = 0; -} - -void mob_sliverAI::KilledUnit(Unit* victim) -{ - if(Creature* Garaxxas = ((Creature*)Unit::GetUnit(*m_creature, GaraxxasGUID))) - ((boss_garaxxasAI*)Garaxxas->AI())->KilledUnit(victim); -}*/ - -#define SPELL_WINDFURY_TOTEM 27621 -#define SPELL_WAR_STOMP 46026 -#define SPELL_PURGE 27626 -#define SPELL_LESSER_HEALING_WAVE 44256 -#define SPELL_FROST_SHOCK 21401 -#define SPELL_FIRE_NOVA_TOTEM 44257 -#define SPELL_EARTHBIND_TOTEM 15786 - -struct MANGOS_DLL_DECL boss_apokoAI : public boss_priestess_guestAI -{ - //Shaman - boss_apokoAI(Creature *c) : boss_priestess_guestAI(c) {} - - uint32 Totem_Timer; - uint8 Totem_Amount; - uint32 War_Stomp_Timer; - uint32 Purge_Timer; - uint32 Healing_Wave_Timer; - uint32 Frost_Shock_Timer; - - 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_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_priestess_guestAI::UpdateAI(diff); - - if(Totem_Timer < diff) - { - switch(rand()%3) - { - case 0: - DoCast(m_creature, SPELL_WINDFURY_TOTEM); - break; - case 1: - DoCast(m_creature, SPELL_FIRE_NOVA_TOTEM); - break; - case 2: - DoCast(m_creature, SPELL_EARTHBIND_TOTEM); - break; - } - ++Totem_Amount; - Totem_Timer = Totem_Amount*2000; - }else Totem_Timer -= diff; - - if(War_Stomp_Timer < diff) - { - DoCast(m_creature, SPELL_WAR_STOMP); - War_Stomp_Timer = 10000; - }else War_Stomp_Timer -= diff; - - if(Purge_Timer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_PURGE); - Purge_Timer = 15000; - }else Purge_Timer -= diff; - - if(Frost_Shock_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FROST_SHOCK); - Frost_Shock_Timer = 7000; - }else Frost_Shock_Timer -= diff; - - if(Healing_Wave_Timer < diff) - { - // std::vector::iterator itr = Group.begin() + rand()%Group.size(); - // uint64 guid = (*itr)->guid; - // if(guid) - // { - // Unit* pAdd = Unit::GetUnit(*m_creature, (*itr)->guid); - // if(pAdd && pAdd->isAlive()) - // { - DoCast(m_creature, SPELL_LESSER_HEALING_WAVE); - Healing_Wave_Timer = 5000; - // } - // } - }else Healing_Wave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -#define SPELL_GOBLIN_DRAGON_GUN 44272 -#define SPELL_ROCKET_LAUNCH 44137 -#define SPELL_RECOMBOBULATE 44274 -#define SPELL_HIGH_EXPLOSIVE_SHEEP 44276 -#define SPELL_FEL_IRON_BOMB 46024 -#define SPELL_SHEEP_EXPLOSION 44279 - -#define CREATURE_EXPLOSIVE_SHEEP 24715 - -struct MANGOS_DLL_DECL boss_zelfanAI : public boss_priestess_guestAI -{ - //Engineer - boss_zelfanAI(Creature *c) : boss_priestess_guestAI(c) {} - - uint32 Goblin_Dragon_Gun_Timer; - uint32 Rocket_Launch_Timer; - uint32 Recombobulate_Timer; - uint32 High_Explosive_Sheep_Timer; - uint32 Fel_Iron_Bomb_Timer; - - void Reset() - { - Goblin_Dragon_Gun_Timer = 20000; - Rocket_Launch_Timer = 7000; - Recombobulate_Timer = 4000; - High_Explosive_Sheep_Timer = 10000; - Fel_Iron_Bomb_Timer = 15000; - - boss_priestess_guestAI::Reset(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - boss_priestess_guestAI::UpdateAI(diff); - - if(Goblin_Dragon_Gun_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_GOBLIN_DRAGON_GUN); - Goblin_Dragon_Gun_Timer = 10000; - }else Goblin_Dragon_Gun_Timer -= diff; - - if(Rocket_Launch_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ROCKET_LAUNCH); - Rocket_Launch_Timer = 9000; - }else Rocket_Launch_Timer -= diff; - - if(Fel_Iron_Bomb_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FEL_IRON_BOMB); - Fel_Iron_Bomb_Timer = 15000; - }else Fel_Iron_Bomb_Timer -= diff; - - if(Recombobulate_Timer < diff) - { - for(uint8 i = 0; i < Group.size(); ++i) - if(Unit* pAdd = Unit::GetUnit(*m_creature, Group[i]->guid)) - if(pAdd->IsPolymorphed()) - { - DoCast(pAdd, SPELL_RECOMBOBULATE); - break; - } - }else Recombobulate_Timer -= diff; - - if(High_Explosive_Sheep_Timer < diff) - { - DoCast(m_creature, SPELL_HIGH_EXPLOSIVE_SHEEP); - High_Explosive_Sheep_Timer = 65000; - }else High_Explosive_Sheep_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//struct MANGOS_DLL_DECL mob_high_explosive_sheepAI : public ScriptedAI -//{ -// mob_high_explosive_sheepAI(Creature *c) : ScriptedAI(c) {Reset();} -// -// uint32 Explosion_Timer; -// -// void Reset() -// { -// Explosion_Timer = 60000; -// } -// -// void JustDied(Unit *Killer){} -// -// void Aggro(Unit *who){} -// -// void UpdateAI(const uint32 diff) -// { -// if(Explosion_Timer < diff) -// { -// DoCast(m_creature->getVictim(), SPELL_SHEEP_EXPLOSION); -// }else -// Explosion_Timer -= diff; -// } -//}; - -/*CreatureAI* GetAI_mob_sliver(Creature *_Creature) -{ - return new mob_sliverAI (_Creature); -};*/ - -//CreatureAI* GetAI_mob_high_explosive_sheep(Creature *_Creature) -//{ -// return new mob_high_explosive_sheepAI (_Creature); -//}; - -/*CreatureAI* GetAI_mob_fizzle(Creature *_Creature) -{ - return new mob_fizzleAI (_Creature); -};*/ - -CreatureAI* GetAI_boss_priestess_delrissa(Creature *_Creature) -{ - return new boss_priestess_delrissaAI (_Creature); -} - -CreatureAI* GetAI_boss_kagani_nightstrike(Creature *_Creature) -{ - return new boss_kagani_nightstrikeAI (_Creature); -} - -CreatureAI* GetAI_ellris_duskhallow(Creature *_Creature) -{ - return new boss_ellris_duskhallowAI (_Creature); -} - -CreatureAI* GetAI_eramas_brightblaze(Creature *_Creature) -{ - return new boss_eramas_brightblazeAI (_Creature); -} - -CreatureAI* GetAI_yazzai(Creature *_Creature) -{ - return new boss_yazzaiAI (_Creature); -} - -CreatureAI* GetAI_warlord_salaris(Creature *_Creature) -{ - return new boss_warlord_salarisAI (_Creature); -} - -CreatureAI* GetAI_garaxxas(Creature *_Creature) -{ - return new boss_garaxxasAI (_Creature); -} - -CreatureAI* GetAI_apoko(Creature *_Creature) -{ - return new boss_apokoAI (_Creature); -} - -CreatureAI* GetAI_zelfan(Creature *_Creature) -{ - return new boss_zelfanAI (_Creature); -} - -void AddSC_boss_priestess_delrissa() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_priestess_delrissa"; - newscript->GetAI = GetAI_boss_priestess_delrissa; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_kagani_nightstrike"; - newscript->GetAI = GetAI_boss_kagani_nightstrike; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_ellris_duskhallow"; - newscript->GetAI = GetAI_ellris_duskhallow; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_eramas_brightblaze"; - newscript->GetAI = GetAI_eramas_brightblaze; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_yazzai"; - newscript->GetAI = GetAI_yazzai; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_warlord_salaris"; - newscript->GetAI = GetAI_warlord_salaris; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_garaxxas"; - newscript->GetAI = GetAI_garaxxas; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_apoko"; - newscript->GetAI = GetAI_apoko; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_zelfan"; - newscript->GetAI = GetAI_zelfan; - m_scripts[nrscripts++] = newscript; - - /*newscript = new Script; - newscript->Name="mob_high_explosive_sheep"; - newscript->GetAI = GetAI_mob_high_explosive_sheep; - m_scripts[nrscripts++] = newscript;*/ - - /*newscript = new Script; - newscript->Name="mob_fizzle"; - newscript->GetAI = GetAI_mob_fizzle; - m_scripts[nrscripts++] = newscript;*/ - - /*newscript = new Script; - newscript->Name="mob_sliver"; - newscript->GetAI = GetAI_mob_sliver; - m_scripts[nrscripts++] = newscript;*/ -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Delrissa +SD%Complete: 45 +SDComment: No Heroic support yet. Needs further testing. Several scripts for pets disabled, not seem to require any special script. +SDCategory: Magister's Terrace +EndScriptData */ + +#include "precompiled.h" +#include "def_magisters_terrace.h" + +#define SAY_AGGRO "Annihilate them!" +#define SOUND_AGGRO 12395 + +struct Speech +{ + const char* text; + uint32 sound; +}; + +static Speech LackeyDeath[]= +{ + {"Oh, the horror.", 12398}, + {"Well, aren't you lucky?", 12400}, + {"Now I'm getting annoyed.", 12401}, + {"Lackies be damned! I'll finish you myself!", 12403}, +}; + +static Speech PlayerDeath[]= +{ + {"I call that a good start.", 12405}, + {"I could have sworn there were more of you.", 12407}, + {"Not really much of a group, anymore, is it?", 12409}, + {"One is such a lonely number", 12410}, + {"It's been a kick, really", 12411}, +}; + +#define SAY_DEATH "Not what I had... planned..." +#define SOUND_DEATH 12397 + +#define SPELL_DISPEL_MAGIC 27609 +#define SPELL_FLASH_HEAL 17843 +#define SPELL_SW_PAIN_NORMAL 14032 +#define SPELL_SW_PAIN_HEROIC 15654 +#define SPELL_SHIELD 44291 +#define SPELL_RENEW_NORMAL 44174 +#define SPELL_RENEW_HEROIC 46192 + +#define ORIENT 4.98 +#define POS_Z -19.9215 + +float LackeyLocations[4][2]= +{ + {123.77, 17.6007}, + {131.731, 15.0827}, + {121.563, 15.6213}, + {129.988, 17.2355}, +}; + +const uint32 AddEntry[8]= +{ + 24557, //Kagani Nightstrike + 24558, //Elris Duskhallow + 24554, //Eramas Brightblaze + 24561, //Yazzaj + 24559, //Warlord Salaris + 24555, //Garaxxas + 24553, //Apoko + 24556, //Zelfan +}; + +struct Add +{ + Add(uint32 _entry, uint64 _guid) + { + entry = _entry; + guid = _guid; + } + + uint32 entry; + uint64 guid; +}; + +struct MANGOS_DLL_DECL boss_priestess_delrissaAI : public ScriptedAI +{ + boss_priestess_delrissaAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Adds.clear(); + Reset(); + SummonAdds(); + Heroic = c->GetMap()->IsHeroic(); + } + + ScriptedInstance* pInstance; + + std::vector Adds; + + uint8 LackeysKilled; + uint8 PlayersKilled; + + uint32 HealTimer; + uint32 RenewTimer; + uint32 ShieldTimer; + uint32 SWPainTimer; + uint32 DispelTimer; + + uint32 CombatPulseTimer; // Periodically puts all players in the instance in combat + + bool Heroic; + + void Reset() + { + LackeysKilled = 0; + PlayersKilled = 0; + + HealTimer = 15000; + RenewTimer = 10000; + ShieldTimer = 2000; + SWPainTimer = 5000; + DispelTimer = 7500; + + CombatPulseTimer = 5000; + + CheckAdds(); + + if(pInstance) + { + pInstance->SetData(DATA_DELRISSA_EVENT, NOT_STARTED); + pInstance->SetData(DATA_DELRISSA_DEATH_COUNT, 0); + } + else error_log(ERROR_INST_DATA); + } + + void Aggro(Unit* who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + + for(uint8 i = 0; i < Adds.size(); ++i) + if(Unit* pAdd = Unit::GetUnit(*m_creature, Adds[i]->guid)) + pAdd->AddThreat(who, 1.0f); + } + + void SummonAdds() + { + std::vector AddList; + for(uint8 i = 0; i < 8; ++i) + AddList.push_back(AddEntry[i]); + + while(AddList.size() > 4) + AddList.erase(AddList.begin() + rand()%AddList.size()); + + for(uint8 i = 0; i < AddList.size(); ++i) + { + Creature* pAdd = m_creature->SummonCreature(AddList[i], LackeyLocations[i][0], LackeyLocations[i][1], POS_Z, ORIENT, TEMPSUMMON_DEAD_DESPAWN, 0); + if(pAdd) + { + Add* nAdd = new Add(AddList[i], pAdd->GetGUID()); + Adds.push_back(nAdd); + } + } + } + + void CheckAdds() + { + if(Adds.empty()) + return; + + for(uint8 i = 0; i < Adds.size(); ++i) + { + bool resummon = true; + Creature* pAdd = ((Creature*)Unit::GetUnit(*m_creature, Adds[i]->guid)); + if(pAdd && pAdd->isAlive()) + { + pAdd->AI()->EnterEvadeMode(); // Force them out of combat and reset if they are in combat. + resummon = false; + } + if(resummon) + { + pAdd = m_creature->SummonCreature(Adds[i]->entry, LackeyLocations[i][0], LackeyLocations[i][1], POS_Z, ORIENT, TEMPSUMMON_DEAD_DESPAWN, 0); + Add* nAdd = new Add(Adds[i]->entry, pAdd->GetGUID()); + Adds.erase(Adds.begin() + i); + Adds.push_back(nAdd); + } + } + } + + void KilledUnit(Unit* victim) + { + if(victim->GetTypeId() != TYPEID_PLAYER) + return; + + DoYell(PlayerDeath[PlayersKilled].text, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, PlayerDeath[PlayersKilled].sound); + if( PlayersKilled < 4 ) + ++PlayersKilled; + } + + void KilledLackey() + { + DoYell(LackeyDeath[LackeysKilled].text, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, LackeyDeath[LackeysKilled].sound); + if( LackeysKilled < 3 ) + ++LackeysKilled; + } + + void JustDied(Unit* killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + CheckLootable(); + + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + pInstance->SetData(DATA_DELRISSA_DEATH_COUNT, 1); + pInstance->SetData(DATA_DELRISSA_EVENT, DONE); + if(GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_DELRISSA_DOOR))) + Door->SetGoState(0); + } + + void CheckLootable() + { + if(LackeysKilled > 4) + m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + else + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(HealTimer < diff) + { + uint32 health = m_creature->GetHealth(); + Unit* target = m_creature; + for(uint8 i = 0; i < Adds.size(); ++i) + if(Unit* pAdd = Unit::GetUnit(*m_creature, Adds[i]->guid)) + if(pAdd->isAlive() && pAdd->GetHealth() < health) + target = pAdd; + + DoCast(target, SPELL_FLASH_HEAL); + HealTimer = 15000; + }else HealTimer -= diff; + + if(RenewTimer < diff) + { + Unit* target = m_creature; + if(rand()%2 == 1) + { + std::vector::iterator itr = Adds.begin() + rand()%Adds.size(); + Unit* pAdd = Unit::GetUnit(*m_creature, (*itr)->guid); + if(pAdd && pAdd->isAlive()) + target = pAdd; + } + DoCast(target,Heroic ? SPELL_RENEW_HEROIC : SPELL_RENEW_NORMAL); + RenewTimer = 5000; + }else RenewTimer -= diff; + + if(ShieldTimer < diff) + { + Unit* target = m_creature; + if(rand()%2 == 1) + { + std::vector::iterator itr = Adds.begin() + rand()%Adds.size(); + if(Unit* pAdd = Unit::GetUnit(*m_creature, (*itr)->guid)) + if(!pAdd->HasAura(SPELL_SHIELD, 0) && pAdd->isAlive()) + target = pAdd; + } + DoCast(target, SPELL_SHIELD); + ShieldTimer = 7500; + }else ShieldTimer -= diff; + + if(DispelTimer < diff) + { + Unit* target = NULL; + bool friendly = false; + if(rand()%2 == 1) + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + else + { + friendly = true; + if(rand()%2 == 1) + target = m_creature; + else + { + std::vector::iterator itr = Adds.begin() + rand()%Adds.size(); + Unit* pAdd = Unit::GetUnit(*m_creature, (*itr)->guid); + if(pAdd && pAdd->isAlive()) + target = pAdd; + } + } + if(target) + { + DoCast(target, SPELL_DISPEL_MAGIC); + DispelTimer = 12000; + } + }else DispelTimer -= diff; + + if(SWPainTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0),Heroic ? SPELL_SW_PAIN_HEROIC : SPELL_SW_PAIN_NORMAL); + SWPainTimer = 10000; + }else SWPainTimer -= diff; + + /* + if(CombatPulseTimer < diff) + { + DoZoneInCombat(); + for(uint8 i = 0; i < Adds.size(); ++i) + { + if(Unit* pAdd = Unit::GetUnit(*m_creature, Add[i]->guid)) + if(pAdd->isAlive()) + DoZoneInCombat(pAdd); + } + + CombatPulseTimer = 10000; + }else CombatPulseTimer -= diff;*/ + + DoMeleeAttackIfReady(); + } +}; + +#define SPELL_HEALING_POTION 15503 + +struct MANGOS_DLL_DECL boss_priestess_guestAI : public ScriptedAI +{ + boss_priestess_guestAI(Creature* c) : ScriptedAI(c) + { + Group.clear(); + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + AcquireGUIDs(); + } + + ScriptedInstance* pInstance; + + std::vector Group; + + uint32 ResetThreatTimer; + + bool UsedPotion; + + void Reset() + { + UsedPotion = false; + + ResetThreatTimer = 5000 + rand()%15000; // These guys like to switch targets often, and are not meant to be tanked. + } + + void Aggro(Unit* who) {} + + void JustDied(Unit* killer) + { + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + Creature* Delrissa = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA))); + if(Delrissa) + { + ((boss_priestess_delrissaAI*)Delrissa->AI())->KilledLackey(); + if(!Delrissa->isAlive() && pInstance->GetData(DATA_DELRISSA_DEATH_COUNT) > 3) + ((boss_priestess_delrissaAI*)Delrissa->AI())->CheckLootable(); + + pInstance->SetData(DATA_DELRISSA_DEATH_COUNT, 1); + } + } + + void KilledUnit(Unit* victim) + { + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + Creature* Delrissa = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA))); + if(Delrissa) + Delrissa->AI()->KilledUnit(victim); + } + + void AcquireGUIDs() + { + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + Creature* Delrissa = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA))); + if(Delrissa) + { + Group = ((boss_priestess_delrissaAI*)Delrissa->AI())->Adds; + Add* dAdd = new Add(Delrissa->GetEntry(), Delrissa->GetGUID()); + Group.push_back(dAdd); + } + } + + void UpdateAI(const uint32 diff) + { + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) && !UsedPotion) + { + DoCast(m_creature, SPELL_HEALING_POTION, true); + UsedPotion = true; + } + + if(ResetThreatTimer < diff) + { + DoResetThreat(); + ResetThreatTimer = 5000 + rand()%15000; + }else ResetThreatTimer -= diff; + } +}; + +#define SPELL_KIDNEY_SHOT 27615 +#define SPELL_GOUGE 12540 +#define SPELL_KICK 27613 +#define SPELL_VANISH 44290 +#define SPELL_BACKSTAB 15657 +#define SPELL_EVISCERATE 27611 + +struct MANGOS_DLL_DECL boss_kagani_nightstrikeAI : public boss_priestess_guestAI +{ + //Rogue + boss_kagani_nightstrikeAI(Creature *c) : boss_priestess_guestAI(c) {} + + uint32 Gouge_Timer; + uint32 Kick_Timer; + uint32 Vanish_Timer; + uint32 Eviscerate_Timer; + uint32 Wait_Timer; + bool InVanish; + + 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_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_priestess_guestAI::UpdateAI(diff); + + if(Vanish_Timer < diff) + { + m_creature->SetVisibility(VISIBILITY_OFF); // ...? Hacklike + DoCast(m_creature, SPELL_VANISH); + InVanish = true; + Vanish_Timer = 30000; + Wait_Timer = 10000; + DoResetThreat(); + m_creature->AddThreat(SelectUnit(SELECT_TARGET_RANDOM, 0), 1000.0f); + }else Vanish_Timer -= diff; + + if(InVanish) + if(Wait_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_BACKSTAB, true); + DoCast(m_creature->getVictim(), SPELL_KIDNEY_SHOT, true); + m_creature->SetVisibility(VISIBILITY_ON); // ...? Hacklike + InVanish = false; + }else Wait_Timer -= diff; + + if(Gouge_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_GOUGE); + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); + Gouge_Timer = 5500; + }else Gouge_Timer -= diff; + + if(Kick_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_KICK); + Kick_Timer = 7000; + }else Kick_Timer -= diff; + + if(Eviscerate_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_EVISCERATE); + Eviscerate_Timer = 4000; + }else Eviscerate_Timer -= diff; + + if(!InVanish) + DoMeleeAttackIfReady(); + } +}; + +#define SPELL_IMMOLATE 44267 +#define SPELL_SHADOW_BOLT 12471 +#define SPELL_SEED_OF_CORRUPTION 44141 +#define SPELL_CURSE_OF_AGONY 14875 +#define SPELL_FEAR 38595 +#define SPELL_IMP_FIREBALL 44164 +#define SPELL_SUMMON_IMP 44163 + +//#define CREATURE_IMP 44163 +//#define CREATURE_FIZZLE 24656 + +/*struct MANGOS_DLL_DECL mob_fizzleAI : public ScriptedAI +{ + mob_fizzleAI(Creature *c) : ScriptedAI(c) + { + Reset(); + } + + uint64 EllrisGUID; + uint32 Firebal_Timer; + + void Reset() { EllrisGUID = 0; } + + void KilledUnit(Unit* victim); + void JustDied(Unit* killer); + + void Aggro(Unit* who){} + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Chain cast + if (!m_creature->IsNonMeleeSpellCasted(false)) + DoCast(m_creature->getVictim(),SPELL_IMP_FIREBALL); + else DoMeleeAttackIfReady(); + } +};*/ + +struct MANGOS_DLL_DECL boss_ellris_duskhallowAI : public boss_priestess_guestAI +{ + //Warlock + boss_ellris_duskhallowAI(Creature *c) : boss_priestess_guestAI(c) + { + } + + bool HasSummonedImp; + + uint32 Immolate_Timer; + uint32 Shadow_Bolt_Timer; + uint32 Seed_of_Corruption_Timer; + uint32 Curse_of_Agony_Timer; + uint32 Fear_Timer; + + void Reset() + { + //HasSummonedImp = false; + + Immolate_Timer = 6000; + Shadow_Bolt_Timer = 3000; + Seed_of_Corruption_Timer = 2000; + Curse_of_Agony_Timer = 1000; + Fear_Timer = 10000; + + boss_priestess_guestAI::Reset(); + } + + void JustDied(Unit* killer) + { + boss_priestess_guestAI::JustDied(killer); + } + + void UpdateAI(const uint32 diff) + { + if(!HasSummonedImp) + { + //Imp will not despawn unless it's killed, even if owner dies, this is correct way. + DoCast(m_creature,SPELL_SUMMON_IMP); + HasSummonedImp = true; + } + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_priestess_guestAI::UpdateAI(diff); + + if(Immolate_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_IMMOLATE); + Immolate_Timer = 6000; + }else Immolate_Timer -= diff; + + if(Shadow_Bolt_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOW_BOLT); + Shadow_Bolt_Timer = 5000; + }else Shadow_Bolt_Timer -= diff; + + if(Seed_of_Corruption_Timer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_SEED_OF_CORRUPTION); + Seed_of_Corruption_Timer = 10000; + }else Seed_of_Corruption_Timer -= diff; + + if(Curse_of_Agony_Timer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_CURSE_OF_AGONY); + Curse_of_Agony_Timer = 13000; + }else Curse_of_Agony_Timer -= diff; + + if(Fear_Timer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FEAR); + Fear_Timer = 10000; + }else Fear_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +/*void mob_fizzleAI::JustDied(Unit* killer) +{ + if(Creature* Ellris = ((Creature*)Unit::GetUnit(*m_creature, EllrisGUID))) + ((boss_ellris_duskhallowAI*)Ellris->AI())->ImpGUID = 0; +} + +void mob_fizzleAI::KilledUnit(Unit* victim) +{ + if(Creature* Ellris = ((Creature*)Unit::GetUnit(*m_creature, EllrisGUID))) + ((boss_ellris_duskhallowAI*)Ellris->AI())->KilledUnit(victim); +}*/ + +#define SPELL_KNOCKDOWN 11428 +#define SPELL_SNAP_KICK 46182 + +struct MANGOS_DLL_DECL boss_eramas_brightblazeAI : public boss_priestess_guestAI +{ + //Monk + boss_eramas_brightblazeAI(Creature *c) : boss_priestess_guestAI(c) {} + + uint32 Knockdown_Timer; + uint32 Snap_Kick_Timer; + + void Reset() + { + Knockdown_Timer = 6000; + Snap_Kick_Timer = 4500; + + boss_priestess_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_priestess_guestAI::UpdateAI(diff); + + if(Knockdown_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKDOWN); + Knockdown_Timer = 6000; + }else Knockdown_Timer -= diff; + + if(Snap_Kick_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SNAP_KICK); + Snap_Kick_Timer = 4500; + }else Snap_Kick_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +#define SPELL_POLYMORPH 13323 +#define SPELL_ICE_BLOCK 27619 +#define SPELL_BLIZZARD 44178 +#define SPELL_ICE_LANCE 46194 +#define SPELL_CONE_OF_COLD 38384 +#define SPELL_FROSTBOLT 15043 +#define SPELL_BLINK 14514 + +struct MANGOS_DLL_DECL boss_yazzaiAI : public boss_priestess_guestAI +{ + //Mage + boss_yazzaiAI(Creature *c) : boss_priestess_guestAI(c) {} + + bool HasIceBlocked; + + 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; + + 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_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_priestess_guestAI::UpdateAI(diff); + + if(Polymorph_Timer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + DoCast(target, SPELL_POLYMORPH); + m_creature->getThreatManager().modifyThreatPercent(target,-100); + Polymorph_Timer = 20000; + } + }else Polymorph_Timer -= diff; + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 35) && !HasIceBlocked) + { + DoCast(m_creature, SPELL_ICE_BLOCK); + HasIceBlocked = true; + } + + if(Blizzard_Timer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_BLIZZARD); + Blizzard_Timer = 8000; + }else Blizzard_Timer -= diff; + + if(Ice_Lance_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ICE_LANCE); + Ice_Lance_Timer = 12000; + }else Ice_Lance_Timer -= diff; + + if(Cone_of_Cold_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CONE_OF_COLD); + Cone_of_Cold_Timer = 10000; + }else Cone_of_Cold_Timer -= diff; + + if(Frostbolt_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FROSTBOLT); + Frostbolt_Timer = 8000; + }else Frostbolt_Timer -= diff; + + if(Blink_Timer < diff) + { + bool InMeleeRange = false; + std::list& t_list = m_creature->getThreatManager().getThreatList(); + for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + if(Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid())) + //if in melee range + if (target->IsWithinDistInMap(m_creature, 5)) + { + InMeleeRange = true; + break; + } + } + //if anybody is in melee range than escape by blink + if(InMeleeRange) + DoCast(m_creature, SPELL_BLINK); + + Blink_Timer = 8000; + }else Blink_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +#define SPELL_INTERCEPT_STUN 27577 +#define SPELL_DISARM 27581 +#define SPELL_PIERCING_HOWL 23600 +#define SPELL_FRIGHTENING_SHOUT 19134 +#define SPELL_HAMSTRING 27584 +#define SPELL_BATTLE_SHOUT 27578 +#define SPELL_MORTAL_STRIKE 44268 + +struct MANGOS_DLL_DECL boss_warlord_salarisAI : public boss_priestess_guestAI +{ + //Warrior + boss_warlord_salarisAI(Creature *c) : boss_priestess_guestAI(c) {} + + uint32 Intercept_Stun_Timer; + uint32 Disarm_Timer; + uint32 Piercing_Howl_Timer; + uint32 Frightening_Shout_Timer; + uint32 Hamstring_Timer; + uint32 Mortal_Strike_Timer; + + void Reset() + { + Intercept_Stun_Timer = 500; + Disarm_Timer = 6000; + Piercing_Howl_Timer = 10000; + Frightening_Shout_Timer = 18000; + Hamstring_Timer = 4500; + Mortal_Strike_Timer = 8000; + DoCast(m_creature, SPELL_BATTLE_SHOUT); + boss_priestess_guestAI::Reset(); + } + + void Aggro(Unit* who) + { + DoCast(m_creature, SPELL_BATTLE_SHOUT); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_priestess_guestAI::UpdateAI(diff); + + if(Intercept_Stun_Timer < diff) + { + bool InMeleeRange = false; + std::list& t_list = m_creature->getThreatManager().getThreatList(); + for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + if(Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid())) + //if in melee range + if (target->IsWithinDistInMap(m_creature, 5)) + { + InMeleeRange = true; + break; + } + } + //if nobody is in melee range than try to use Intercept + if(!InMeleeRange) + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_INTERCEPT_STUN); + Intercept_Stun_Timer = 10000; + }else Intercept_Stun_Timer -= diff; + + if(Disarm_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DISARM); + Disarm_Timer = 6000; + }else Disarm_Timer -= diff; + + if(Hamstring_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_HAMSTRING); + Hamstring_Timer = 4500; + }else Hamstring_Timer -= diff; + + if(Mortal_Strike_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); + Mortal_Strike_Timer = 4500; + }else Mortal_Strike_Timer -= diff; + + if(Piercing_Howl_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_PIERCING_HOWL); + Piercing_Howl_Timer = 10000; + }else Piercing_Howl_Timer -= diff; + + if(Frightening_Shout_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FRIGHTENING_SHOUT); + Frightening_Shout_Timer = 18000; + }else Frightening_Shout_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +#define SPELL_AIMED_SHOT 44271 +#define SPELL_SHOOT 15620 +#define SPELL_CONCUSSIVE_SHOT 27634 +#define TRIGGER_CONCUSSIVE_SHOT 19410 +#define SPELL_MULTI_SHOT 31942 +#define SPELL_WING_CLIP 44286 +#define SPELL_FREEZING_TRAP 44136 + +#define CREATURE_SLIVER 24552 + +/*struct MANGOS_DLL_DECL mob_sliverAI : public ScriptedAI +{ + mob_sliverAI(Creature *c) : ScriptedAI(c) + { + Reset(); + } + + uint64 GaraxxasGUID; + + void Reset() { GaraxxasGUID = 0; } + + void KilledUnit(Unit* victim); + void JustDied(Unit* killer); + + void Aggro(Unit* who){} + +};*/ + +struct MANGOS_DLL_DECL boss_garaxxasAI : public boss_priestess_guestAI +{ + //Hunter + boss_garaxxasAI(Creature *c) : boss_priestess_guestAI(c) {} + + //uint64 SliverGUID; + bool HasSummonedSliver; + + uint32 Aimed_Shot_Timer; + uint32 Shoot_Timer; + uint32 Concussive_Shot_Timer; + uint32 Multi_Shot_Timer; + uint32 Wing_Clip_Timer; + uint32 Freezing_Trap_Timer; + + void Reset() + { + //SliverGUID = 0; + //HasSummonedSliver = false; + + Aimed_Shot_Timer = 6000; + Shoot_Timer = 2500; + Concussive_Shot_Timer = 8000; + Multi_Shot_Timer = 10000; + Wing_Clip_Timer = 4000; + Freezing_Trap_Timer = 15000; + + boss_priestess_guestAI::Reset(); + } + + void JustDied(Unit* killer) + { + boss_priestess_guestAI::JustDied(killer); + } + + void UpdateAI(const uint32 diff) + { + if(!HasSummonedSliver) + { + Creature* Sliver = m_creature->SummonCreature(CREATURE_SLIVER, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + if(Sliver) + { + //((mob_sliverAI*)Sliver->AI())->GaraxxasGUID = m_creature->GetGUID(); + //SliverGUID = Sliver->GetGUID(); + HasSummonedSliver = true; + } + } + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_priestess_guestAI::UpdateAI(diff); + + if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 5)) + { + if(Wing_Clip_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_WING_CLIP); + Wing_Clip_Timer = 4000; + }else Wing_Clip_Timer -= diff; + + if(Freezing_Trap_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FREEZING_TRAP); + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); + Freezing_Trap_Timer = 30000; + }else Freezing_Trap_Timer -= diff; + + if(!m_creature->getVictim()->hasUnitState(UNIT_STAT_STUNDED | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED | UNIT_STAT_DISTRACTED)) + DoMeleeAttackIfReady(); + }else + { + if(Concussive_Shot_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CONCUSSIVE_SHOT); + Concussive_Shot_Timer = 8000; + }else Concussive_Shot_Timer -= diff; + + if(Multi_Shot_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_MULTI_SHOT); + Multi_Shot_Timer = 10000; + }else Multi_Shot_Timer -= diff; + + if(Aimed_Shot_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_AIMED_SHOT); + Aimed_Shot_Timer = 6000; + }else Aimed_Shot_Timer -= diff; + + if(Shoot_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SHOOT); + Shoot_Timer = 2500; + }else Shoot_Timer -= diff; + } + } +}; + +/*void mob_sliverAI::JustDied(Unit* killer) +{ + if(Creature* Garaxxas = ((Creature*)Unit::GetUnit(*m_creature, GaraxxasGUID))) + ((boss_garaxxasAI*)Garaxxas->AI())->SliverGUID = 0; +} + +void mob_sliverAI::KilledUnit(Unit* victim) +{ + if(Creature* Garaxxas = ((Creature*)Unit::GetUnit(*m_creature, GaraxxasGUID))) + ((boss_garaxxasAI*)Garaxxas->AI())->KilledUnit(victim); +}*/ + +#define SPELL_WINDFURY_TOTEM 27621 +#define SPELL_WAR_STOMP 46026 +#define SPELL_PURGE 27626 +#define SPELL_LESSER_HEALING_WAVE 44256 +#define SPELL_FROST_SHOCK 21401 +#define SPELL_FIRE_NOVA_TOTEM 44257 +#define SPELL_EARTHBIND_TOTEM 15786 + +struct MANGOS_DLL_DECL boss_apokoAI : public boss_priestess_guestAI +{ + //Shaman + boss_apokoAI(Creature *c) : boss_priestess_guestAI(c) {} + + uint32 Totem_Timer; + uint8 Totem_Amount; + uint32 War_Stomp_Timer; + uint32 Purge_Timer; + uint32 Healing_Wave_Timer; + uint32 Frost_Shock_Timer; + + 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_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_priestess_guestAI::UpdateAI(diff); + + if(Totem_Timer < diff) + { + switch(rand()%3) + { + case 0: + DoCast(m_creature, SPELL_WINDFURY_TOTEM); + break; + case 1: + DoCast(m_creature, SPELL_FIRE_NOVA_TOTEM); + break; + case 2: + DoCast(m_creature, SPELL_EARTHBIND_TOTEM); + break; + } + ++Totem_Amount; + Totem_Timer = Totem_Amount*2000; + }else Totem_Timer -= diff; + + if(War_Stomp_Timer < diff) + { + DoCast(m_creature, SPELL_WAR_STOMP); + War_Stomp_Timer = 10000; + }else War_Stomp_Timer -= diff; + + if(Purge_Timer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_PURGE); + Purge_Timer = 15000; + }else Purge_Timer -= diff; + + if(Frost_Shock_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FROST_SHOCK); + Frost_Shock_Timer = 7000; + }else Frost_Shock_Timer -= diff; + + if(Healing_Wave_Timer < diff) + { + // std::vector::iterator itr = Group.begin() + rand()%Group.size(); + // uint64 guid = (*itr)->guid; + // if(guid) + // { + // Unit* pAdd = Unit::GetUnit(*m_creature, (*itr)->guid); + // if(pAdd && pAdd->isAlive()) + // { + DoCast(m_creature, SPELL_LESSER_HEALING_WAVE); + Healing_Wave_Timer = 5000; + // } + // } + }else Healing_Wave_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +#define SPELL_GOBLIN_DRAGON_GUN 44272 +#define SPELL_ROCKET_LAUNCH 44137 +#define SPELL_RECOMBOBULATE 44274 +#define SPELL_HIGH_EXPLOSIVE_SHEEP 44276 +#define SPELL_FEL_IRON_BOMB 46024 +#define SPELL_SHEEP_EXPLOSION 44279 + +#define CREATURE_EXPLOSIVE_SHEEP 24715 + +struct MANGOS_DLL_DECL boss_zelfanAI : public boss_priestess_guestAI +{ + //Engineer + boss_zelfanAI(Creature *c) : boss_priestess_guestAI(c) {} + + uint32 Goblin_Dragon_Gun_Timer; + uint32 Rocket_Launch_Timer; + uint32 Recombobulate_Timer; + uint32 High_Explosive_Sheep_Timer; + uint32 Fel_Iron_Bomb_Timer; + + void Reset() + { + Goblin_Dragon_Gun_Timer = 20000; + Rocket_Launch_Timer = 7000; + Recombobulate_Timer = 4000; + High_Explosive_Sheep_Timer = 10000; + Fel_Iron_Bomb_Timer = 15000; + + boss_priestess_guestAI::Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + boss_priestess_guestAI::UpdateAI(diff); + + if(Goblin_Dragon_Gun_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_GOBLIN_DRAGON_GUN); + Goblin_Dragon_Gun_Timer = 10000; + }else Goblin_Dragon_Gun_Timer -= diff; + + if(Rocket_Launch_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ROCKET_LAUNCH); + Rocket_Launch_Timer = 9000; + }else Rocket_Launch_Timer -= diff; + + if(Fel_Iron_Bomb_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FEL_IRON_BOMB); + Fel_Iron_Bomb_Timer = 15000; + }else Fel_Iron_Bomb_Timer -= diff; + + if(Recombobulate_Timer < diff) + { + for(uint8 i = 0; i < Group.size(); ++i) + if(Unit* pAdd = Unit::GetUnit(*m_creature, Group[i]->guid)) + if(pAdd->IsPolymorphed()) + { + DoCast(pAdd, SPELL_RECOMBOBULATE); + break; + } + }else Recombobulate_Timer -= diff; + + if(High_Explosive_Sheep_Timer < diff) + { + DoCast(m_creature, SPELL_HIGH_EXPLOSIVE_SHEEP); + High_Explosive_Sheep_Timer = 65000; + }else High_Explosive_Sheep_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//struct MANGOS_DLL_DECL mob_high_explosive_sheepAI : public ScriptedAI +//{ +// mob_high_explosive_sheepAI(Creature *c) : ScriptedAI(c) {Reset();} +// +// uint32 Explosion_Timer; +// +// void Reset() +// { +// Explosion_Timer = 60000; +// } +// +// void JustDied(Unit *Killer){} +// +// void Aggro(Unit *who){} +// +// void UpdateAI(const uint32 diff) +// { +// if(Explosion_Timer < diff) +// { +// DoCast(m_creature->getVictim(), SPELL_SHEEP_EXPLOSION); +// }else +// Explosion_Timer -= diff; +// } +//}; + +/*CreatureAI* GetAI_mob_sliver(Creature *_Creature) +{ + return new mob_sliverAI (_Creature); +};*/ + +//CreatureAI* GetAI_mob_high_explosive_sheep(Creature *_Creature) +//{ +// return new mob_high_explosive_sheepAI (_Creature); +//}; + +/*CreatureAI* GetAI_mob_fizzle(Creature *_Creature) +{ + return new mob_fizzleAI (_Creature); +};*/ + +CreatureAI* GetAI_boss_priestess_delrissa(Creature *_Creature) +{ + return new boss_priestess_delrissaAI (_Creature); +} + +CreatureAI* GetAI_boss_kagani_nightstrike(Creature *_Creature) +{ + return new boss_kagani_nightstrikeAI (_Creature); +} + +CreatureAI* GetAI_ellris_duskhallow(Creature *_Creature) +{ + return new boss_ellris_duskhallowAI (_Creature); +} + +CreatureAI* GetAI_eramas_brightblaze(Creature *_Creature) +{ + return new boss_eramas_brightblazeAI (_Creature); +} + +CreatureAI* GetAI_yazzai(Creature *_Creature) +{ + return new boss_yazzaiAI (_Creature); +} + +CreatureAI* GetAI_warlord_salaris(Creature *_Creature) +{ + return new boss_warlord_salarisAI (_Creature); +} + +CreatureAI* GetAI_garaxxas(Creature *_Creature) +{ + return new boss_garaxxasAI (_Creature); +} + +CreatureAI* GetAI_apoko(Creature *_Creature) +{ + return new boss_apokoAI (_Creature); +} + +CreatureAI* GetAI_zelfan(Creature *_Creature) +{ + return new boss_zelfanAI (_Creature); +} + +void AddSC_boss_priestess_delrissa() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_priestess_delrissa"; + newscript->GetAI = GetAI_boss_priestess_delrissa; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_kagani_nightstrike"; + newscript->GetAI = GetAI_boss_kagani_nightstrike; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_ellris_duskhallow"; + newscript->GetAI = GetAI_ellris_duskhallow; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_eramas_brightblaze"; + newscript->GetAI = GetAI_eramas_brightblaze; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_yazzai"; + newscript->GetAI = GetAI_yazzai; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_warlord_salaris"; + newscript->GetAI = GetAI_warlord_salaris; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_garaxxas"; + newscript->GetAI = GetAI_garaxxas; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_apoko"; + newscript->GetAI = GetAI_apoko; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_zelfan"; + newscript->GetAI = GetAI_zelfan; + m_scripts[nrscripts++] = newscript; + + /*newscript = new Script; + newscript->Name="mob_high_explosive_sheep"; + newscript->GetAI = GetAI_mob_high_explosive_sheep; + m_scripts[nrscripts++] = newscript;*/ + + /*newscript = new Script; + newscript->Name="mob_fizzle"; + newscript->GetAI = GetAI_mob_fizzle; + m_scripts[nrscripts++] = newscript;*/ + + /*newscript = new Script; + newscript->Name="mob_sliver"; + newscript->GetAI = GetAI_mob_sliver; + m_scripts[nrscripts++] = newscript;*/ +} diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_selin_fireheart.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_selin_fireheart.cpp index 76d4faed15f..6f1da25f220 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_selin_fireheart.cpp +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_selin_fireheart.cpp @@ -1,385 +1,385 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Selin_Fireheart -SD%Complete: 99 -SDComment: Heroic and Normal Support. Needs further testing. -SDCategory: Magister's Terrace -EndScriptData */ - -#include "precompiled.h" -#include "def_magisters_terrace.h" - -#define SAY_AGGRO "You only waste my time!" -#define SOUND_AGGRO 12378 - -#define SAY_ENERGY "My hunger knows no bounds! " -#define SOUND_ENERGY 12381 - -#define SAY_EMPOWERED "Yes! I am a god!" -#define SOUND_EMPOWERED 12382 - -#define SAY_KILL_1 "Enough distractions!" -#define SOUND_KILL_1 12388 - -#define SAY_KILL_2 "I am invincible!" -#define SOUND_KILL_2 12385 - -#define SAY_DEATH "No! More... I must have more!" -#define SOUND_DEATH 12383 - -//Crystal efect 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 - -struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI -{ - boss_selin_fireheartAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - - Crystals.clear(); - // GUIDs per instance is static, so we only need to load them once. - if(pInstance) - { - uint32 size = pInstance->GetData(DATA_FEL_CRYSTAL_SIZE); - for(uint8 i = 0; i < size; ++i) - { - uint64 guid = pInstance->GetData64(DATA_FEL_CRYSTAL); - outstring_log("Selin: Adding Fel Crystal %u to list", guid); - Crystals.push_back(guid); - } - } - Reset(); - Heroic = c->GetMap()->IsHeroic() ? true : false; - } - - ScriptedInstance* pInstance; - - std::list Crystals; - - uint32 DrainLifeTimer; - uint32 DrainManaTimer; - uint32 FelExplosionTimer; - uint32 DrainCrystalTimer; - uint32 EmpowerTimer; - - bool IsDraining; - bool DrainingCrystal; - bool Heroic; - 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). - - void Reset() - { - if(pInstance) - { - //for(uint8 i = 0; i < CRYSTALS_NUMBER; ++i) - for(std::list::iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) - { - //Unit* pUnit = Unit::GetUnit(*m_creature, FelCrystals[i]); - Unit* pUnit = Unit::GetUnit(*m_creature, *itr); - if(pUnit) - { - if(!pUnit->isAlive()) - ((Creature*)pUnit)->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. - pUnit->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - } - - GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR)); - if(Door) - Door->SetGoState(0); // Close the door. Open it only in JustDied. - - // Set Inst data for encounter - pInstance->SetData(DATA_SELIN_EVENT, NOT_STARTED); - }else error_log(ERROR_INST_DATA); - - DrainLifeTimer = 3000 + rand()%4000; - DrainManaTimer = DrainLifeTimer + 5000; - FelExplosionTimer = 2100; - DrainCrystalTimer = 10000 + rand()%5000; - DrainCrystalTimer = 20000 + rand()%5000; - EmpowerTimer = 10000; - - IsDraining = false; - DrainingCrystal = false; - CrystalGUID = 0; - } - - void SelectNearestCrystal() - { - if(Crystals.empty()) - return; - - float ShortestDistance = 0; - CrystalGUID = 0; - Unit* pCrystal = NULL; - Unit* CrystalChosen = NULL; - //for(uint8 i = 0; i < CRYSTALS_NUMBER; ++i) - for(std::list::iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) - { - pCrystal = NULL; - //pCrystal = Unit::GetUnit(*m_creature, FelCrystals[i]); - pCrystal = Unit::GetUnit(*m_creature, *itr); - if(pCrystal && pCrystal->isAlive()) - { - if(!ShortestDistance || (ShortestDistance > m_creature->GetDistance2d(pCrystal))) - { - ShortestDistance = m_creature->GetDistance2d(pCrystal); - 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) - { - DoYell(SAY_ENERGY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENERGY); - CrystalChosen->CastSpell(CrystalChosen, SPELL_FEL_CRYSTAL_COSMETIC, true); - - float x, y, z; // coords that we move to, close to the crystal. - CrystalChosen->GetClosePoint(x, y, z, m_creature->GetObjectSize(), CONTACT_DISTANCE); - - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - m_creature->GetMotionMaster()->MovePoint(1, x, y, z); - DrainingCrystal = true; - } - } - - void ShatterRemainingCrystals() - { - 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 = ((Creature*)Unit::GetUnit(*m_creature, FelCrystals[i])); - Creature* pCrystal = ((Creature*)Unit::GetUnit(*m_creature, *itr)); - if(pCrystal && pCrystal->isAlive()) - pCrystal->DealDamage(pCrystal, pCrystal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - } - - void Aggro(Unit* who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL_2); - break; - } - } - - void MovementInform(uint32 type, uint32 id) - { - if(type == POINT_MOTION_TYPE && id == 1) - { - Unit* CrystalChosen = Unit::GetUnit(*m_creature, 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 - { - // 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; - } - } - } - - void JustDied(Unit* killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - pInstance->SetData(DATA_SELIN_EVENT, DONE); // Encounter complete! - GameObject* EncounterDoor = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR)); - if(EncounterDoor) - EncounterDoor->SetGoState(1); // Open the door - - ShatterRemainingCrystals(); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(!DrainingCrystal) - { - uint32 maxPowerMana = m_creature->GetMaxPower(POWER_MANA); - if( maxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / maxPowerMana) < 10) ) - { - if( DrainLifeTimer < diff ) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DRAIN_LIFE); - DrainLifeTimer = 10000; - }else DrainLifeTimer -= diff; - - // Heroic only - if( Heroic ) - { - if( DrainManaTimer < diff ) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DRAIN_MANA); - DrainManaTimer = 10000; - }else DrainManaTimer -= diff; - } - } - - if( FelExplosionTimer < diff ) - { - if(!m_creature->IsNonMeleeSpellCasted(false)) - { - DoCast(m_creature, SPELL_FEL_EXPLOSION); - FelExplosionTimer = 2000; - } - }else FelExplosionTimer -= diff; - - // If below 10% mana, start recharging - maxPowerMana = m_creature->GetMaxPower(POWER_MANA); - if( maxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / maxPowerMana) < 10) ) - { - if(DrainCrystalTimer < diff) - { - SelectNearestCrystal(); - if(Heroic) DrainCrystalTimer = 10000 + rand()%5000; - else DrainCrystalTimer = 20000 + rand()%5000; - }else DrainCrystalTimer -= diff; - } - - }else - { - if(IsDraining) - if(EmpowerTimer < diff) - { - IsDraining = false; - DrainingCrystal = false; - DoYell(SAY_EMPOWERED, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_EMPOWERED); - Unit* CrystalChosen = Unit::GetUnit(*m_creature, 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; - - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - }else EmpowerTimer -= diff; - } - - DoMeleeAttackIfReady(); // No need to check if we are draining crystal here, as the spell has a stun. - } -}; - -CreatureAI* GetAI_boss_selin_fireheart(Creature *_Creature) -{ - return new boss_selin_fireheartAI (_Creature); -}; - -struct MANGOS_DLL_DECL mob_fel_crystalAI : public ScriptedAI -{ - mob_fel_crystalAI(Creature *c) : ScriptedAI(c) { Reset(); } - - void Reset() {} - void Aggro(Unit* who) {} - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - void UpdateAI(const uint32 diff) {} - - void JustDied(Unit* killer) - { - if(ScriptedInstance* pInstance = ((ScriptedInstance*)m_creature->GetInstanceData())) - { - Creature* Selin = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_SELIN))); - if(Selin && Selin->isAlive()) - { - if(((boss_selin_fireheartAI*)Selin->AI())->CrystalGUID == m_creature->GetGUID()) - { - // Set this to false if we are the creature that Selin is draining so his AI flows properly - ((boss_selin_fireheartAI*)Selin->AI())->DrainingCrystal = false; - ((boss_selin_fireheartAI*)Selin->AI())->IsDraining = false; - ((boss_selin_fireheartAI*)Selin->AI())->EmpowerTimer = 10000; - if(Selin->getVictim()) - { - Selin->AI()->AttackStart(Selin->getVictim()); - Selin->GetMotionMaster()->MoveChase(Selin->getVictim()); - } - } - } - }else error_log(ERROR_INST_DATA); - } -}; - -CreatureAI* GetAI_mob_fel_crystal(Creature *_Creature) -{ - return new mob_fel_crystalAI (_Creature); -}; - -void AddSC_boss_selin_fireheart() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_selin_fireheart"; - newscript->GetAI = GetAI_boss_selin_fireheart; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_fel_crystal"; - newscript->GetAI = GetAI_mob_fel_crystal; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Selin_Fireheart +SD%Complete: 99 +SDComment: Heroic and Normal Support. Needs further testing. +SDCategory: Magister's Terrace +EndScriptData */ + +#include "precompiled.h" +#include "def_magisters_terrace.h" + +#define SAY_AGGRO "You only waste my time!" +#define SOUND_AGGRO 12378 + +#define SAY_ENERGY "My hunger knows no bounds! " +#define SOUND_ENERGY 12381 + +#define SAY_EMPOWERED "Yes! I am a god!" +#define SOUND_EMPOWERED 12382 + +#define SAY_KILL_1 "Enough distractions!" +#define SOUND_KILL_1 12388 + +#define SAY_KILL_2 "I am invincible!" +#define SOUND_KILL_2 12385 + +#define SAY_DEATH "No! More... I must have more!" +#define SOUND_DEATH 12383 + +//Crystal efect 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 + +struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI +{ + boss_selin_fireheartAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + + Crystals.clear(); + // GUIDs per instance is static, so we only need to load them once. + if(pInstance) + { + uint32 size = pInstance->GetData(DATA_FEL_CRYSTAL_SIZE); + for(uint8 i = 0; i < size; ++i) + { + uint64 guid = pInstance->GetData64(DATA_FEL_CRYSTAL); + outstring_log("Selin: Adding Fel Crystal %u to list", guid); + Crystals.push_back(guid); + } + } + Reset(); + Heroic = c->GetMap()->IsHeroic() ? true : false; + } + + ScriptedInstance* pInstance; + + std::list Crystals; + + uint32 DrainLifeTimer; + uint32 DrainManaTimer; + uint32 FelExplosionTimer; + uint32 DrainCrystalTimer; + uint32 EmpowerTimer; + + bool IsDraining; + bool DrainingCrystal; + bool Heroic; + 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). + + void Reset() + { + if(pInstance) + { + //for(uint8 i = 0; i < CRYSTALS_NUMBER; ++i) + for(std::list::iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) + { + //Unit* pUnit = Unit::GetUnit(*m_creature, FelCrystals[i]); + Unit* pUnit = Unit::GetUnit(*m_creature, *itr); + if(pUnit) + { + if(!pUnit->isAlive()) + ((Creature*)pUnit)->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. + pUnit->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + + GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR)); + if(Door) + Door->SetGoState(0); // Close the door. Open it only in JustDied. + + // Set Inst data for encounter + pInstance->SetData(DATA_SELIN_EVENT, NOT_STARTED); + }else error_log(ERROR_INST_DATA); + + DrainLifeTimer = 3000 + rand()%4000; + DrainManaTimer = DrainLifeTimer + 5000; + FelExplosionTimer = 2100; + DrainCrystalTimer = 10000 + rand()%5000; + DrainCrystalTimer = 20000 + rand()%5000; + EmpowerTimer = 10000; + + IsDraining = false; + DrainingCrystal = false; + CrystalGUID = 0; + } + + void SelectNearestCrystal() + { + if(Crystals.empty()) + return; + + float ShortestDistance = 0; + CrystalGUID = 0; + Unit* pCrystal = NULL; + Unit* CrystalChosen = NULL; + //for(uint8 i = 0; i < CRYSTALS_NUMBER; ++i) + for(std::list::iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) + { + pCrystal = NULL; + //pCrystal = Unit::GetUnit(*m_creature, FelCrystals[i]); + pCrystal = Unit::GetUnit(*m_creature, *itr); + if(pCrystal && pCrystal->isAlive()) + { + if(!ShortestDistance || (ShortestDistance > m_creature->GetDistance2d(pCrystal))) + { + ShortestDistance = m_creature->GetDistance2d(pCrystal); + 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) + { + DoYell(SAY_ENERGY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENERGY); + CrystalChosen->CastSpell(CrystalChosen, SPELL_FEL_CRYSTAL_COSMETIC, true); + + float x, y, z; // coords that we move to, close to the crystal. + CrystalChosen->GetClosePoint(x, y, z, m_creature->GetObjectSize(), CONTACT_DISTANCE); + + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + m_creature->GetMotionMaster()->MovePoint(1, x, y, z); + DrainingCrystal = true; + } + } + + void ShatterRemainingCrystals() + { + 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 = ((Creature*)Unit::GetUnit(*m_creature, FelCrystals[i])); + Creature* pCrystal = ((Creature*)Unit::GetUnit(*m_creature, *itr)); + if(pCrystal && pCrystal->isAlive()) + pCrystal->DealDamage(pCrystal, pCrystal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + void Aggro(Unit* who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL_2); + break; + } + } + + void MovementInform(uint32 type, uint32 id) + { + if(type == POINT_MOTION_TYPE && id == 1) + { + Unit* CrystalChosen = Unit::GetUnit(*m_creature, 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 + { + // 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; + } + } + } + + void JustDied(Unit* killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + pInstance->SetData(DATA_SELIN_EVENT, DONE); // Encounter complete! + GameObject* EncounterDoor = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR)); + if(EncounterDoor) + EncounterDoor->SetGoState(1); // Open the door + + ShatterRemainingCrystals(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(!DrainingCrystal) + { + uint32 maxPowerMana = m_creature->GetMaxPower(POWER_MANA); + if( maxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / maxPowerMana) < 10) ) + { + if( DrainLifeTimer < diff ) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DRAIN_LIFE); + DrainLifeTimer = 10000; + }else DrainLifeTimer -= diff; + + // Heroic only + if( Heroic ) + { + if( DrainManaTimer < diff ) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DRAIN_MANA); + DrainManaTimer = 10000; + }else DrainManaTimer -= diff; + } + } + + if( FelExplosionTimer < diff ) + { + if(!m_creature->IsNonMeleeSpellCasted(false)) + { + DoCast(m_creature, SPELL_FEL_EXPLOSION); + FelExplosionTimer = 2000; + } + }else FelExplosionTimer -= diff; + + // If below 10% mana, start recharging + maxPowerMana = m_creature->GetMaxPower(POWER_MANA); + if( maxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / maxPowerMana) < 10) ) + { + if(DrainCrystalTimer < diff) + { + SelectNearestCrystal(); + if(Heroic) DrainCrystalTimer = 10000 + rand()%5000; + else DrainCrystalTimer = 20000 + rand()%5000; + }else DrainCrystalTimer -= diff; + } + + }else + { + if(IsDraining) + if(EmpowerTimer < diff) + { + IsDraining = false; + DrainingCrystal = false; + DoYell(SAY_EMPOWERED, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_EMPOWERED); + Unit* CrystalChosen = Unit::GetUnit(*m_creature, 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; + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + }else EmpowerTimer -= diff; + } + + DoMeleeAttackIfReady(); // No need to check if we are draining crystal here, as the spell has a stun. + } +}; + +CreatureAI* GetAI_boss_selin_fireheart(Creature *_Creature) +{ + return new boss_selin_fireheartAI (_Creature); +}; + +struct MANGOS_DLL_DECL mob_fel_crystalAI : public ScriptedAI +{ + mob_fel_crystalAI(Creature *c) : ScriptedAI(c) { Reset(); } + + void Reset() {} + void Aggro(Unit* who) {} + void AttackStart(Unit* who) {} + void MoveInLineOfSight(Unit* who) {} + void UpdateAI(const uint32 diff) {} + + void JustDied(Unit* killer) + { + if(ScriptedInstance* pInstance = ((ScriptedInstance*)m_creature->GetInstanceData())) + { + Creature* Selin = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_SELIN))); + if(Selin && Selin->isAlive()) + { + if(((boss_selin_fireheartAI*)Selin->AI())->CrystalGUID == m_creature->GetGUID()) + { + // Set this to false if we are the creature that Selin is draining so his AI flows properly + ((boss_selin_fireheartAI*)Selin->AI())->DrainingCrystal = false; + ((boss_selin_fireheartAI*)Selin->AI())->IsDraining = false; + ((boss_selin_fireheartAI*)Selin->AI())->EmpowerTimer = 10000; + if(Selin->getVictim()) + { + Selin->AI()->AttackStart(Selin->getVictim()); + Selin->GetMotionMaster()->MoveChase(Selin->getVictim()); + } + } + } + }else error_log(ERROR_INST_DATA); + } +}; + +CreatureAI* GetAI_mob_fel_crystal(Creature *_Creature) +{ + return new mob_fel_crystalAI (_Creature); +}; + +void AddSC_boss_selin_fireheart() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_selin_fireheart"; + newscript->GetAI = GetAI_boss_selin_fireheart; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_fel_crystal"; + newscript->GetAI = GetAI_mob_fel_crystal; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_vexallus.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_vexallus.cpp index e815bde5cf2..11bf2668d9d 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_vexallus.cpp +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_vexallus.cpp @@ -1,233 +1,233 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Vexallus -SD%Complete: 90 -SDComment: Heroic and Normal support. Needs further testing. -SDCategory: Magister's Terrace -EndScriptData */ - -#include "precompiled.h" -#include "def_magisters_terrace.h" - -#define SAY_AGGRO "Drain...life..." -#define SOUND_AGGRO 12389 - -#define SAY_ENERGY "Un...con...tainable." -#define SOUND_ENERGY 12392 - -#define SAY_OVERLOAD "Un...leash..." -#define SOUND_OVERLOAD 12390 - -#define SAY_KILL "Con...sume." -#define SOUND_KILL 12393 - -#define SAY_DEATH "What...happen...ed." - -//Pure energy spell info -#define SPELL_ENERGY_BOLT 44342 -#define SPELL_ENERGY_FEEDBACK 44335 - -//Vexallus spell info -#define SPELL_CHAIN_LIGHTNING 44318 -#define SPELL_SUMMON_PURE_ENERGY 44322 //not-working, this script summon this creatures without this spell -#define SPELL_OVERLOAD 44353 -#define SPELL_ARCANE_SHOCK 44319 - -//Creatures -#define CREATURE_PURE_ENERGY 24745 - -struct MANGOS_DLL_DECL boss_vexallusAI : public ScriptedAI -{ - boss_vexallusAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - Heroic = c->GetMap()->IsHeroic() ? true : false; - } - - ScriptedInstance* pInstance; - - uint32 ChainLightningTimer; - uint32 ArcaneShockTimer; - uint32 OverloadTimer; - uint32 SpawnAddInterval; - uint32 AlreadySpawnedAmount; - bool Enraged; - bool Heroic; - - void Reset() - { - ChainLightningTimer = 10000; - ArcaneShockTimer = 8000; - OverloadTimer = 2200; - SpawnAddInterval = 15; - AlreadySpawnedAmount = 0; - - Enraged = false; - - if(pInstance) - pInstance->SetData(DATA_VEXALLUS_EVENT, NOT_STARTED); - } - - void KilledUnit(Unit *victim) - { - DoYell(SAY_KILL, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(victim, SOUND_KILL); - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - if (pInstance) - { - pInstance->SetData(DATA_VEXALLUS_EVENT, DONE); - - GameObject* Door = NULL; - Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_VEXALLUS_DOOR)); - if(Door) - Door->SetGoState(0); - } - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - if (pInstance) - pInstance->SetData(DATA_VEXALLUS_EVENT, IN_PROGRESS); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11) - { - Enraged = true; - } - - if(!Enraged) - { - //used for check, when Vexallus cast adds 85%, 70%, 55%, 40%, 25% - if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < (100-(SpawnAddInterval*(AlreadySpawnedAmount+1)))) - { - DoYell(SAY_ENERGY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENERGY); - Creature* PureEnergyCreature = NULL; - PureEnergyCreature = DoSpawnCreature(CREATURE_PURE_ENERGY, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (PureEnergyCreature && target) - PureEnergyCreature->AI()->AttackStart(target); - - if(Heroic) // *Heroic mode only - he summons two instead of one. - { - PureEnergyCreature = DoSpawnCreature(CREATURE_PURE_ENERGY, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (PureEnergyCreature && target) - PureEnergyCreature->AI()->AttackStart(target); - } - - ++AlreadySpawnedAmount; - }; - - if(ChainLightningTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - DoCast(target, SPELL_CHAIN_LIGHTNING); - ChainLightningTimer = 10000; - }else ChainLightningTimer -= diff; - - if(ArcaneShockTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - DoCast(target, SPELL_ARCANE_SHOCK); - ArcaneShockTimer = 8000; - }else ArcaneShockTimer -= diff; - }else - { - if(OverloadTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - DoCast(target, SPELL_OVERLOAD); - OverloadTimer = 2200; - }else OverloadTimer -= diff; - } - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_vexallus(Creature *_Creature) -{ - return new boss_vexallusAI (_Creature); -}; - -struct MANGOS_DLL_DECL mob_pure_energyAI : public ScriptedAI -{ - mob_pure_energyAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 EnergyBoltTimer; - - void Reset() - { - EnergyBoltTimer = 1700; - } - - void JustDied(Unit* slayer) - { - slayer->CastSpell(slayer, SPELL_ENERGY_FEEDBACK, true, 0, 0, m_creature->GetGUID()); - } - - void Aggro(Unit *who){} - - void UpdateAI(const uint32 diff) - { - if(!m_creature->getVictim() || !m_creature->SelectHostilTarget()) - return; - - if(EnergyBoltTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ENERGY_BOLT); - EnergyBoltTimer = 1700; - }else EnergyBoltTimer -= diff; - } -}; - -CreatureAI* GetAI_mob_pure_energy(Creature *_Creature) -{ - return new mob_pure_energyAI (_Creature); -}; - -void AddSC_boss_vexallus() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_vexallus"; - newscript->GetAI = GetAI_boss_vexallus; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_pure_energy"; - newscript->GetAI = GetAI_mob_pure_energy; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Vexallus +SD%Complete: 90 +SDComment: Heroic and Normal support. Needs further testing. +SDCategory: Magister's Terrace +EndScriptData */ + +#include "precompiled.h" +#include "def_magisters_terrace.h" + +#define SAY_AGGRO "Drain...life..." +#define SOUND_AGGRO 12389 + +#define SAY_ENERGY "Un...con...tainable." +#define SOUND_ENERGY 12392 + +#define SAY_OVERLOAD "Un...leash..." +#define SOUND_OVERLOAD 12390 + +#define SAY_KILL "Con...sume." +#define SOUND_KILL 12393 + +#define SAY_DEATH "What...happen...ed." + +//Pure energy spell info +#define SPELL_ENERGY_BOLT 44342 +#define SPELL_ENERGY_FEEDBACK 44335 + +//Vexallus spell info +#define SPELL_CHAIN_LIGHTNING 44318 +#define SPELL_SUMMON_PURE_ENERGY 44322 //not-working, this script summon this creatures without this spell +#define SPELL_OVERLOAD 44353 +#define SPELL_ARCANE_SHOCK 44319 + +//Creatures +#define CREATURE_PURE_ENERGY 24745 + +struct MANGOS_DLL_DECL boss_vexallusAI : public ScriptedAI +{ + boss_vexallusAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + Heroic = c->GetMap()->IsHeroic() ? true : false; + } + + ScriptedInstance* pInstance; + + uint32 ChainLightningTimer; + uint32 ArcaneShockTimer; + uint32 OverloadTimer; + uint32 SpawnAddInterval; + uint32 AlreadySpawnedAmount; + bool Enraged; + bool Heroic; + + void Reset() + { + ChainLightningTimer = 10000; + ArcaneShockTimer = 8000; + OverloadTimer = 2200; + SpawnAddInterval = 15; + AlreadySpawnedAmount = 0; + + Enraged = false; + + if(pInstance) + pInstance->SetData(DATA_VEXALLUS_EVENT, NOT_STARTED); + } + + void KilledUnit(Unit *victim) + { + DoYell(SAY_KILL, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(victim, SOUND_KILL); + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + if (pInstance) + { + pInstance->SetData(DATA_VEXALLUS_EVENT, DONE); + + GameObject* Door = NULL; + Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_VEXALLUS_DOOR)); + if(Door) + Door->SetGoState(0); + } + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + if (pInstance) + pInstance->SetData(DATA_VEXALLUS_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11) + { + Enraged = true; + } + + if(!Enraged) + { + //used for check, when Vexallus cast adds 85%, 70%, 55%, 40%, 25% + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < (100-(SpawnAddInterval*(AlreadySpawnedAmount+1)))) + { + DoYell(SAY_ENERGY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENERGY); + Creature* PureEnergyCreature = NULL; + PureEnergyCreature = DoSpawnCreature(CREATURE_PURE_ENERGY, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (PureEnergyCreature && target) + PureEnergyCreature->AI()->AttackStart(target); + + if(Heroic) // *Heroic mode only - he summons two instead of one. + { + PureEnergyCreature = DoSpawnCreature(CREATURE_PURE_ENERGY, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (PureEnergyCreature && target) + PureEnergyCreature->AI()->AttackStart(target); + } + + ++AlreadySpawnedAmount; + }; + + if(ChainLightningTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + DoCast(target, SPELL_CHAIN_LIGHTNING); + ChainLightningTimer = 10000; + }else ChainLightningTimer -= diff; + + if(ArcaneShockTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + DoCast(target, SPELL_ARCANE_SHOCK); + ArcaneShockTimer = 8000; + }else ArcaneShockTimer -= diff; + }else + { + if(OverloadTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + DoCast(target, SPELL_OVERLOAD); + OverloadTimer = 2200; + }else OverloadTimer -= diff; + } + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_vexallus(Creature *_Creature) +{ + return new boss_vexallusAI (_Creature); +}; + +struct MANGOS_DLL_DECL mob_pure_energyAI : public ScriptedAI +{ + mob_pure_energyAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 EnergyBoltTimer; + + void Reset() + { + EnergyBoltTimer = 1700; + } + + void JustDied(Unit* slayer) + { + slayer->CastSpell(slayer, SPELL_ENERGY_FEEDBACK, true, 0, 0, m_creature->GetGUID()); + } + + void Aggro(Unit *who){} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->getVictim() || !m_creature->SelectHostilTarget()) + return; + + if(EnergyBoltTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ENERGY_BOLT); + EnergyBoltTimer = 1700; + }else EnergyBoltTimer -= diff; + } +}; + +CreatureAI* GetAI_mob_pure_energy(Creature *_Creature) +{ + return new mob_pure_energyAI (_Creature); +}; + +void AddSC_boss_vexallus() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_vexallus"; + newscript->GetAI = GetAI_boss_vexallus; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_pure_energy"; + newscript->GetAI = GetAI_mob_pure_energy; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/def_magisters_terrace.h b/src/bindings/scripts/scripts/zone/magisters_terrace/def_magisters_terrace.h index d064a50cc13..ed5aa46366a 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/def_magisters_terrace.h +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/def_magisters_terrace.h @@ -1,29 +1,29 @@ -/* Copyright (C) 2006 - 2008 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 - -#define DATA_SELIN 5 -#define DATA_FEL_CRYSTAL 6 -#define DATA_FEL_CRYSTAL_SIZE 7 - -#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 - -#define DATA_KAEL_STATUE_LEFT 13 -#define DATA_KAEL_STATUE_RIGHT 14 - -#define DATA_DELRISSA_DEATH_COUNT 15 - -#define ERROR_INST_DATA "SD2 Error: Instance Data not set properly for Magister's Terrace instance (map 585). Encounters will be buggy." -#endif +/* Copyright (C) 2006 - 2008 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 + +#define DATA_SELIN 5 +#define DATA_FEL_CRYSTAL 6 +#define DATA_FEL_CRYSTAL_SIZE 7 + +#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 + +#define DATA_KAEL_STATUE_LEFT 13 +#define DATA_KAEL_STATUE_RIGHT 14 + +#define DATA_DELRISSA_DEATH_COUNT 15 + +#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/src/bindings/scripts/scripts/zone/magisters_terrace/instance_magisters_terrace.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/instance_magisters_terrace.cpp index 39efb41ebbb..b0d3e90f645 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/instance_magisters_terrace.cpp +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/instance_magisters_terrace.cpp @@ -1,195 +1,195 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Magisters_Terrace -SD%Complete: 100 -SDComment: Designed only for Selin Fireheart -SDCategory: Magister's Terrace -EndScriptData */ - -#include "precompiled.h" -#include "def_magisters_terrace.h" - -#define NUMBER_OF_ENCOUNTERS 4 - -/* -0 - Selin Fireheart -1 - Vexallus -2 - Priestess Delrissa -3 - Kael'thas Sunstrider -*/ - -struct MANGOS_DLL_DECL instance_magisters_terrace : public ScriptedInstance -{ - instance_magisters_terrace(Map* map) : ScriptedInstance(map) - { - Initialize(); - } - - uint32 Encounters[NUMBER_OF_ENCOUNTERS]; - uint32 DelrissaDeathCount; - - std::list FelCrystals; - std::list::iterator CrystalItr; - - uint64 SelinGUID; - uint64 DelrissaGUID; - uint64 VexallusDoorGUID; - uint64 SelinDoorGUID; - uint64 SelinEncounterDoorGUID; - uint64 DelrissaDoorGUID; - uint64 KaelStatue[2]; - - bool InitializedItr; - - void Initialize() - { - for(uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; i++) - Encounters[i] = NOT_STARTED; - - FelCrystals.clear(); - - DelrissaDeathCount = 0; - - SelinGUID = 0; - DelrissaGUID = 0; - VexallusDoorGUID = 0; - SelinDoorGUID = 0; - SelinEncounterDoorGUID = 0; - DelrissaDoorGUID = 0; - KaelStatue[0] = 0; - KaelStatue[1] = 0; - - InitializedItr = false; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; i++) - if(Encounters[i] == IN_PROGRESS) - return true; - return false; - } - - uint32 GetData(uint32 identifier) - { - switch(identifier) - { - case DATA_SELIN_EVENT: return Encounters[0]; - case DATA_VEXALLUS_EVENT: return Encounters[1]; - case DATA_DELRISSA_EVENT: return Encounters[2]; - case DATA_KAELTHAS_EVENT: return Encounters[3]; - case DATA_DELRISSA_DEATH_COUNT: return DelrissaDeathCount; - case DATA_FEL_CRYSTAL_SIZE: return FelCrystals.size(); - } - return 0; - } - - void SetData(uint32 identifier, uint32 data) - { - switch(identifier) - { - case DATA_SELIN_EVENT: Encounters[0] = data; break; - case DATA_VEXALLUS_EVENT: Encounters[1] = data; break; - case DATA_DELRISSA_EVENT: Encounters[2] = data; break; - case DATA_KAELTHAS_EVENT: Encounters[3] = data; break; - - case DATA_DELRISSA_DEATH_COUNT: - if(data) ++DelrissaDeathCount; - else DelrissaDeathCount = 0; - } - } - - void OnCreatureCreate(Creature *creature, uint32 entry) - { - switch(entry) - { - case 24723: - SelinGUID = creature->GetGUID(); - break; - case 24560: - DelrissaGUID = creature->GetGUID(); - break; - case 24722: - FelCrystals.push_back(creature->GetGUID()); - break; - } - } - - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_SELIN: return SelinGUID; - case DATA_DELRISSA: return DelrissaGUID; - case DATA_VEXALLUS_DOOR: return VexallusDoorGUID; - case DATA_SELIN_DOOR: return SelinDoorGUID; - case DATA_SELIN_ENCOUNTER_DOOR: return SelinEncounterDoorGUID; - case DATA_DELRISSA_DOOR: return DelrissaDoorGUID; - case DATA_KAEL_STATUE_LEFT: return KaelStatue[0]; - case DATA_KAEL_STATUE_RIGHT: return KaelStatue[1]; - - case DATA_FEL_CRYSTAL: - { - if(FelCrystals.empty()) - { - error_log("SD2: Magisters Terrace: No Fel Crystals loaded in Inst Data"); - return 0; - } - - if(!InitializedItr) - { - CrystalItr = FelCrystals.begin(); - InitializedItr = true; - } - - uint64 guid = *CrystalItr; - ++CrystalItr; - return guid; - } - } - return 0; - } - - void OnObjectCreate(GameObject* go) - { - switch(go->GetEntry()) - { - case 187896: VexallusDoorGUID = go->GetGUID(); break; - case 187979: SelinDoorGUID = go->GetGUID(); break; - case 188118: SelinEncounterDoorGUID = go->GetGUID(); break; - case 187770: DelrissaDoorGUID = go->GetGUID(); break; - case 188165: KaelStatue[0] = go->GetGUID(); break; - case 188166: KaelStatue[1] = go->GetGUID(); break; - } - } -}; - -InstanceData* GetInstanceData_instance_magisters_terrace(Map* map) -{ - return new instance_magisters_terrace(map); -} - -void AddSC_instance_magisters_terrace() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "instance_magisters_terrace"; - newscript->GetInstanceData = GetInstanceData_instance_magisters_terrace; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Magisters_Terrace +SD%Complete: 100 +SDComment: Designed only for Selin Fireheart +SDCategory: Magister's Terrace +EndScriptData */ + +#include "precompiled.h" +#include "def_magisters_terrace.h" + +#define NUMBER_OF_ENCOUNTERS 4 + +/* +0 - Selin Fireheart +1 - Vexallus +2 - Priestess Delrissa +3 - Kael'thas Sunstrider +*/ + +struct MANGOS_DLL_DECL instance_magisters_terrace : public ScriptedInstance +{ + instance_magisters_terrace(Map* map) : ScriptedInstance(map) + { + Initialize(); + } + + uint32 Encounters[NUMBER_OF_ENCOUNTERS]; + uint32 DelrissaDeathCount; + + std::list FelCrystals; + std::list::iterator CrystalItr; + + uint64 SelinGUID; + uint64 DelrissaGUID; + uint64 VexallusDoorGUID; + uint64 SelinDoorGUID; + uint64 SelinEncounterDoorGUID; + uint64 DelrissaDoorGUID; + uint64 KaelStatue[2]; + + bool InitializedItr; + + void Initialize() + { + for(uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; i++) + Encounters[i] = NOT_STARTED; + + FelCrystals.clear(); + + DelrissaDeathCount = 0; + + SelinGUID = 0; + DelrissaGUID = 0; + VexallusDoorGUID = 0; + SelinDoorGUID = 0; + SelinEncounterDoorGUID = 0; + DelrissaDoorGUID = 0; + KaelStatue[0] = 0; + KaelStatue[1] = 0; + + InitializedItr = false; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; i++) + if(Encounters[i] == IN_PROGRESS) + return true; + return false; + } + + uint32 GetData(uint32 identifier) + { + switch(identifier) + { + case DATA_SELIN_EVENT: return Encounters[0]; + case DATA_VEXALLUS_EVENT: return Encounters[1]; + case DATA_DELRISSA_EVENT: return Encounters[2]; + case DATA_KAELTHAS_EVENT: return Encounters[3]; + case DATA_DELRISSA_DEATH_COUNT: return DelrissaDeathCount; + case DATA_FEL_CRYSTAL_SIZE: return FelCrystals.size(); + } + return 0; + } + + void SetData(uint32 identifier, uint32 data) + { + switch(identifier) + { + case DATA_SELIN_EVENT: Encounters[0] = data; break; + case DATA_VEXALLUS_EVENT: Encounters[1] = data; break; + case DATA_DELRISSA_EVENT: Encounters[2] = data; break; + case DATA_KAELTHAS_EVENT: Encounters[3] = data; break; + + case DATA_DELRISSA_DEATH_COUNT: + if(data) ++DelrissaDeathCount; + else DelrissaDeathCount = 0; + } + } + + void OnCreatureCreate(Creature *creature, uint32 entry) + { + switch(entry) + { + case 24723: + SelinGUID = creature->GetGUID(); + break; + case 24560: + DelrissaGUID = creature->GetGUID(); + break; + case 24722: + FelCrystals.push_back(creature->GetGUID()); + break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_SELIN: return SelinGUID; + case DATA_DELRISSA: return DelrissaGUID; + case DATA_VEXALLUS_DOOR: return VexallusDoorGUID; + case DATA_SELIN_DOOR: return SelinDoorGUID; + case DATA_SELIN_ENCOUNTER_DOOR: return SelinEncounterDoorGUID; + case DATA_DELRISSA_DOOR: return DelrissaDoorGUID; + case DATA_KAEL_STATUE_LEFT: return KaelStatue[0]; + case DATA_KAEL_STATUE_RIGHT: return KaelStatue[1]; + + case DATA_FEL_CRYSTAL: + { + if(FelCrystals.empty()) + { + error_log("SD2: Magisters Terrace: No Fel Crystals loaded in Inst Data"); + return 0; + } + + if(!InitializedItr) + { + CrystalItr = FelCrystals.begin(); + InitializedItr = true; + } + + uint64 guid = *CrystalItr; + ++CrystalItr; + return guid; + } + } + return 0; + } + + void OnObjectCreate(GameObject* go) + { + switch(go->GetEntry()) + { + case 187896: VexallusDoorGUID = go->GetGUID(); break; + case 187979: SelinDoorGUID = go->GetGUID(); break; + case 188118: SelinEncounterDoorGUID = go->GetGUID(); break; + case 187770: DelrissaDoorGUID = go->GetGUID(); break; + case 188165: KaelStatue[0] = go->GetGUID(); break; + case 188166: KaelStatue[1] = go->GetGUID(); break; + } + } +}; + +InstanceData* GetInstanceData_instance_magisters_terrace(Map* map) +{ + return new instance_magisters_terrace(map); +} + +void AddSC_instance_magisters_terrace() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "instance_magisters_terrace"; + newscript->GetInstanceData = GetInstanceData_instance_magisters_terrace; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/maraudon/boss_celebras_the_cursed.cpp b/src/bindings/scripts/scripts/zone/maraudon/boss_celebras_the_cursed.cpp index 6f3b92f5e5b..a9c15a49e50 100644 --- a/src/bindings/scripts/scripts/zone/maraudon/boss_celebras_the_cursed.cpp +++ b/src/bindings/scripts/scripts/zone/maraudon/boss_celebras_the_cursed.cpp @@ -1,97 +1,97 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {Reset();} - - uint32 Wrath_Timer; - uint32 EntanglingRoots_Timer; - uint32 CorruptForces_Timer; - - void Reset() - { - Wrath_Timer = 8000; - EntanglingRoots_Timer = 2000; - CorruptForces_Timer = 30000; - } - - void Aggro(Unit *who) { } - - 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->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Wrath - if (Wrath_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if( target ) - DoCast(target,SPELL_WRATH); - Wrath_Timer = 8000; - }else Wrath_Timer -= diff; - - //EntanglingRoots - if (EntanglingRoots_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ENTANGLINGROOTS); - EntanglingRoots_Timer = 20000; - }else EntanglingRoots_Timer -= diff; - - //CorruptForces - if (CorruptForces_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature,SPELL_CORRUPT_FORCES); - CorruptForces_Timer = 20000; - }else CorruptForces_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_celebras_the_cursed(Creature *_Creature) -{ - return new celebras_the_cursedAI (_Creature); -} - -void AddSC_boss_celebras_the_cursed() -{ - Script *newscript; - newscript = new Script; - newscript->Name="celebras_the_cursed"; - newscript->GetAI = GetAI_celebras_the_cursed; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {Reset();} + + uint32 Wrath_Timer; + uint32 EntanglingRoots_Timer; + uint32 CorruptForces_Timer; + + void Reset() + { + Wrath_Timer = 8000; + EntanglingRoots_Timer = 2000; + CorruptForces_Timer = 30000; + } + + void Aggro(Unit *who) { } + + 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->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Wrath + if (Wrath_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if( target ) + DoCast(target,SPELL_WRATH); + Wrath_Timer = 8000; + }else Wrath_Timer -= diff; + + //EntanglingRoots + if (EntanglingRoots_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ENTANGLINGROOTS); + EntanglingRoots_Timer = 20000; + }else EntanglingRoots_Timer -= diff; + + //CorruptForces + if (CorruptForces_Timer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature,SPELL_CORRUPT_FORCES); + CorruptForces_Timer = 20000; + }else CorruptForces_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_celebras_the_cursed(Creature *_Creature) +{ + return new celebras_the_cursedAI (_Creature); +} + +void AddSC_boss_celebras_the_cursed() +{ + Script *newscript; + newscript = new Script; + newscript->Name="celebras_the_cursed"; + newscript->GetAI = GetAI_celebras_the_cursed; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/maraudon/boss_landslide.cpp b/src/bindings/scripts/scripts/zone/maraudon/boss_landslide.cpp index 466f35dbba7..f9df4b26523 100644 --- a/src/bindings/scripts/scripts/zone/maraudon/boss_landslide.cpp +++ b/src/bindings/scripts/scripts/zone/maraudon/boss_landslide.cpp @@ -1,94 +1,94 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {Reset();} - - uint32 KnockAway_Timer; - uint32 Trample_Timer; - uint32 Landslide_Timer; - - void Reset() - { - KnockAway_Timer = 8000; - Trample_Timer = 2000; - Landslide_Timer = 0; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //KnockAway_Timer - if (KnockAway_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); - KnockAway_Timer = 15000; - }else KnockAway_Timer -= diff; - - //Trample_Timer - if (Trample_Timer < diff) - { - DoCast(m_creature,SPELL_TRAMPLE); - Trample_Timer = 8000; - }else Trample_Timer -= diff; - - //Landslide - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50 ) - { - if (Landslide_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature,SPELL_LANDSLIDE); - Landslide_Timer = 60000; - } else Landslide_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_landslide(Creature *_Creature) -{ - return new boss_landslideAI (_Creature); -} - -void AddSC_boss_landslide() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_landslide"; - newscript->GetAI = GetAI_boss_landslide; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {Reset();} + + uint32 KnockAway_Timer; + uint32 Trample_Timer; + uint32 Landslide_Timer; + + void Reset() + { + KnockAway_Timer = 8000; + Trample_Timer = 2000; + Landslide_Timer = 0; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //KnockAway_Timer + if (KnockAway_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); + KnockAway_Timer = 15000; + }else KnockAway_Timer -= diff; + + //Trample_Timer + if (Trample_Timer < diff) + { + DoCast(m_creature,SPELL_TRAMPLE); + Trample_Timer = 8000; + }else Trample_Timer -= diff; + + //Landslide + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50 ) + { + if (Landslide_Timer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature,SPELL_LANDSLIDE); + Landslide_Timer = 60000; + } else Landslide_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_landslide(Creature *_Creature) +{ + return new boss_landslideAI (_Creature); +} + +void AddSC_boss_landslide() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_landslide"; + newscript->GetAI = GetAI_boss_landslide; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/maraudon/boss_noxxion.cpp b/src/bindings/scripts/scripts/zone/maraudon/boss_noxxion.cpp index b7bd6cc62fb..35a39e04dee 100644 --- a/src/bindings/scripts/scripts/zone/maraudon/boss_noxxion.cpp +++ b/src/bindings/scripts/scripts/zone/maraudon/boss_noxxion.cpp @@ -1,149 +1,149 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Noxxion -SD%Complete: 100 -SDComment: -SDCategory: Maraudon -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_TOXICVOLLEY 21687 -#define SPELL_UPPERCUT 22916 - -struct MANGOS_DLL_DECL boss_noxxionAI : public ScriptedAI -{ - boss_noxxionAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ToxicVolley_Timer; - uint32 Uppercut_Timer; - uint32 Adds_Timer; - uint32 Invisible_Timer; - bool Invisible; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - ToxicVolley_Timer = 7000; - Uppercut_Timer = 16000; - Adds_Timer = 19000; - Invisible_Timer = 15000; //Too much too low? - Invisible = false; - } - - void Aggro(Unit *who) - { - } - - void SummonAdds(Unit* victim) - { - Rand = rand()%8; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%8; - switch (rand()%2) - { - 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) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - 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->SetUInt32Value(UNIT_FIELD_DISPLAYID,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->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //ToxicVolley_Timer - if (ToxicVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_TOXICVOLLEY); - ToxicVolley_Timer = 9000; - }else ToxicVolley_Timer -= diff; - - //Uppercut_Timer - if (Uppercut_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_UPPERCUT); - Uppercut_Timer = 12000; - }else Uppercut_Timer -= diff; - - //Adds_Timer - if (!Invisible && Adds_Timer < 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->SetUInt32Value(UNIT_FIELD_DISPLAYID,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; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_noxxion(Creature *_Creature) -{ - return new boss_noxxionAI (_Creature); -} - -void AddSC_boss_noxxion() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_noxxion"; - newscript->GetAI = GetAI_boss_noxxion; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Noxxion +SD%Complete: 100 +SDComment: +SDCategory: Maraudon +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_TOXICVOLLEY 21687 +#define SPELL_UPPERCUT 22916 + +struct MANGOS_DLL_DECL boss_noxxionAI : public ScriptedAI +{ + boss_noxxionAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ToxicVolley_Timer; + uint32 Uppercut_Timer; + uint32 Adds_Timer; + uint32 Invisible_Timer; + bool Invisible; + int Rand; + int RandX; + int RandY; + Creature* Summoned; + + void Reset() + { + ToxicVolley_Timer = 7000; + Uppercut_Timer = 16000; + Adds_Timer = 19000; + Invisible_Timer = 15000; //Too much too low? + Invisible = false; + } + + void Aggro(Unit *who) + { + } + + void SummonAdds(Unit* victim) + { + Rand = rand()%8; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%8; + switch (rand()%2) + { + 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) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + 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->SetUInt32Value(UNIT_FIELD_DISPLAYID,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->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //ToxicVolley_Timer + if (ToxicVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_TOXICVOLLEY); + ToxicVolley_Timer = 9000; + }else ToxicVolley_Timer -= diff; + + //Uppercut_Timer + if (Uppercut_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_UPPERCUT); + Uppercut_Timer = 12000; + }else Uppercut_Timer -= diff; + + //Adds_Timer + if (!Invisible && Adds_Timer < 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->SetUInt32Value(UNIT_FIELD_DISPLAYID,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; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_noxxion(Creature *_Creature) +{ + return new boss_noxxionAI (_Creature); +} + +void AddSC_boss_noxxion() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_noxxion"; + newscript->GetAI = GetAI_boss_noxxion; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/maraudon/boss_princess_theradras.cpp b/src/bindings/scripts/scripts/zone/maraudon/boss_princess_theradras.cpp index 64215234ee5..8a6c77c8410 100644 --- a/src/bindings/scripts/scripts/zone/maraudon/boss_princess_theradras.cpp +++ b/src/bindings/scripts/scripts/zone/maraudon/boss_princess_theradras.cpp @@ -1,108 +1,108 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void JustDied(Unit* Killer) - { - m_creature->SummonCreature(12238,28.067,61.875,-123.405,4.67,TEMPSUMMON_TIMED_DESPAWN,600000); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Dustfield_Timer - if (Dustfield_Timer < diff) - { - DoCast(m_creature,SPELL_DUSTFIELD); - Dustfield_Timer = 14000; - }else Dustfield_Timer -= diff; - - //Boulder_Timer - if (Boulder_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if( target ) - DoCast(target,SPELL_BOULDER); - Boulder_Timer = 10000; - }else Boulder_Timer -= diff; - - //RepulsiveGaze_Timer - if (RepulsiveGaze_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_REPULSIVEGAZE); - RepulsiveGaze_Timer = 20000; - }else RepulsiveGaze_Timer -= diff; - - //Thrash_Timer - if (Thrash_Timer < diff) - { - DoCast(m_creature,SPELL_THRASH); - Thrash_Timer = 18000; - }else Thrash_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ptheradras(Creature *_Creature) -{ - return new boss_ptheradrasAI (_Creature); -} - -void AddSC_boss_ptheradras() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_princess_theradras"; - newscript->GetAI = GetAI_boss_ptheradras; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void JustDied(Unit* Killer) + { + m_creature->SummonCreature(12238,28.067,61.875,-123.405,4.67,TEMPSUMMON_TIMED_DESPAWN,600000); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Dustfield_Timer + if (Dustfield_Timer < diff) + { + DoCast(m_creature,SPELL_DUSTFIELD); + Dustfield_Timer = 14000; + }else Dustfield_Timer -= diff; + + //Boulder_Timer + if (Boulder_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if( target ) + DoCast(target,SPELL_BOULDER); + Boulder_Timer = 10000; + }else Boulder_Timer -= diff; + + //RepulsiveGaze_Timer + if (RepulsiveGaze_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_REPULSIVEGAZE); + RepulsiveGaze_Timer = 20000; + }else RepulsiveGaze_Timer -= diff; + + //Thrash_Timer + if (Thrash_Timer < diff) + { + DoCast(m_creature,SPELL_THRASH); + Thrash_Timer = 18000; + }else Thrash_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_ptheradras(Creature *_Creature) +{ + return new boss_ptheradrasAI (_Creature); +} + +void AddSC_boss_ptheradras() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_princess_theradras"; + newscript->GetAI = GetAI_boss_ptheradras; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_baron_geddon.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_baron_geddon.cpp index 075ec15da19..f13dc0ece43 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_baron_geddon.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_baron_geddon.cpp @@ -1,105 +1,105 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <2% hp cast Armageddom - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 2 && !m_creature->IsNonMeleeSpellCasted(false)) - { - DoCast(m_creature,SPELL_ARMAGEDDOM); - DoTextEmote("performs one last service for Ragnaros.",NULL); - return; - } - - //Inferno_Timer - if (Inferno_Timer < diff) - { - DoCast(m_creature,SPELL_INFERNO); - Inferno_Timer = 45000; - }else Inferno_Timer -= diff; - - //IgniteMana_Timer - if (IgniteMana_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_IGNITEMANA); - - IgniteMana_Timer = 30000; - }else IgniteMana_Timer -= diff; - - //LivingBomb_Timer - if (LivingBomb_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_LIVINGBOMB); - - LivingBomb_Timer = 35000; - }else LivingBomb_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_baron_geddon(Creature *_Creature) -{ - return new boss_baron_geddonAI (_Creature); -} - -void AddSC_boss_baron_geddon() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_baron_geddon"; - newscript->GetAI = GetAI_boss_baron_geddon; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <2% hp cast Armageddom + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 2 && !m_creature->IsNonMeleeSpellCasted(false)) + { + DoCast(m_creature,SPELL_ARMAGEDDOM); + DoTextEmote("performs one last service for Ragnaros.",NULL); + return; + } + + //Inferno_Timer + if (Inferno_Timer < diff) + { + DoCast(m_creature,SPELL_INFERNO); + Inferno_Timer = 45000; + }else Inferno_Timer -= diff; + + //IgniteMana_Timer + if (IgniteMana_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_IGNITEMANA); + + IgniteMana_Timer = 30000; + }else IgniteMana_Timer -= diff; + + //LivingBomb_Timer + if (LivingBomb_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_LIVINGBOMB); + + LivingBomb_Timer = 35000; + }else LivingBomb_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_baron_geddon(Creature *_Creature) +{ + return new boss_baron_geddonAI (_Creature); +} + +void AddSC_boss_baron_geddon() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_baron_geddon"; + newscript->GetAI = GetAI_boss_baron_geddon; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_garr.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_garr.cpp index 82696672654..cf02f19303d 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_garr.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_garr.cpp @@ -1,168 +1,149 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //AntiMagicPulse_Timer - if (AntiMagicPulse_Timer < diff) - { - DoCast(m_creature,SPELL_ANTIMAGICPULSE); - AntiMagicPulse_Timer = 10000 + rand()%5000; - }else AntiMagicPulse_Timer -= diff; - - //MagmaShackles_Timer - if (MagmaShackles_Timer < diff) - { - DoCast(m_creature,SPELL_MAGMASHACKLES); - MagmaShackles_Timer = 8000 + rand()%4000; - }else MagmaShackles_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_fireswornAI : public ScriptedAI -{ - mob_fireswornAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Immolate_Timer; - - void Reset() - { - Immolate_Timer = 4000; //These times are probably wrong - - //m_creature->RemoveAllAuras(); - //m_creature->DeleteThreatList(); - //m_creature->CombatStop(); - //DoGoHome(); - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Immolate_Timer - if (Immolate_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - DoCast(target,SPELL_IMMOLATE); - - Immolate_Timer = 5000 + rand()%5000; - }else Immolate_Timer -= diff; - - //Cast Erruption and let them die - if (m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.10) - { - DoCast(m_creature->getVictim(),SPELL_ERUPTION); - m_creature->setDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_garr(Creature *_Creature) -{ - return new boss_garrAI (_Creature); -} - -CreatureAI* GetAI_mob_firesworn(Creature *_Creature) -{ - return new mob_fireswornAI (_Creature); -} - -void AddSC_boss_garr() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_garr"; - newscript->GetAI = GetAI_boss_garr; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_firesworn"; - newscript->GetAI = GetAI_mob_firesworn; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //AntiMagicPulse_Timer + if (AntiMagicPulse_Timer < diff) + { + DoCast(m_creature,SPELL_ANTIMAGICPULSE); + AntiMagicPulse_Timer = 10000 + rand()%5000; + }else AntiMagicPulse_Timer -= diff; + + //MagmaShackles_Timer + if (MagmaShackles_Timer < diff) + { + DoCast(m_creature,SPELL_MAGMASHACKLES); + MagmaShackles_Timer = 8000 + rand()%4000; + }else MagmaShackles_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_fireswornAI : public ScriptedAI +{ + mob_fireswornAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Immolate_Timer; + + void Reset() + { + Immolate_Timer = 4000; //These times are probably wrong + + //m_creature->RemoveAllAuras(); + //m_creature->DeleteThreatList(); + //m_creature->CombatStop(); + //DoGoHome(); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Immolate_Timer + if (Immolate_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + DoCast(target,SPELL_IMMOLATE); + + Immolate_Timer = 5000 + rand()%5000; + }else Immolate_Timer -= diff; + + //Cast Erruption and let them die + if (m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.10) + { + DoCast(m_creature->getVictim(),SPELL_ERUPTION); + m_creature->setDeathState(JUST_DIED); + m_creature->RemoveCorpse(); + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_garr(Creature *_Creature) +{ + return new boss_garrAI (_Creature); +} + +CreatureAI* GetAI_mob_firesworn(Creature *_Creature) +{ + return new mob_fireswornAI (_Creature); +} + +void AddSC_boss_garr() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_garr"; + newscript->GetAI = GetAI_boss_garr; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_firesworn"; + newscript->GetAI = GetAI_mob_firesworn; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_gehennas.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_gehennas.cpp index 96c02e77ea1..4f1a6afe71d 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_gehennas.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_gehennas.cpp @@ -1,91 +1,91 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {Reset();} - - uint32 ShadowBolt_Timer; - uint32 RainOfFire_Timer; - uint32 GehennasCurse_Timer; - - void Reset() - { - ShadowBolt_Timer = 6000; - RainOfFire_Timer = 10000; - GehennasCurse_Timer = 12000; - } - - void Aggro(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //ShadowBolt_Timer - if (ShadowBolt_Timer < diff) - { - if( Unit* bTarget = SelectUnit(SELECT_TARGET_RANDOM,1) ) - DoCast(bTarget,SPELL_SHADOWBOLT); - ShadowBolt_Timer = 7000; - }else ShadowBolt_Timer -= diff; - - //RainOfFire_Timer - if (RainOfFire_Timer < diff) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_RAINOFFIRE); - - RainOfFire_Timer = 4000 + rand()%8000; - }else RainOfFire_Timer -= diff; - - //GehennasCurse_Timer - if (GehennasCurse_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_GEHENNASCURSE); - GehennasCurse_Timer = 22000 + rand()%8000; - }else GehennasCurse_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gehennas(Creature *_Creature) -{ - return new boss_gehennasAI (_Creature); -} - -void AddSC_boss_gehennas() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gehennas"; - newscript->GetAI = GetAI_boss_gehennas; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {Reset();} + + uint32 ShadowBolt_Timer; + uint32 RainOfFire_Timer; + uint32 GehennasCurse_Timer; + + void Reset() + { + ShadowBolt_Timer = 6000; + RainOfFire_Timer = 10000; + GehennasCurse_Timer = 12000; + } + + void Aggro(Unit *who) { } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //ShadowBolt_Timer + if (ShadowBolt_Timer < diff) + { + if( Unit* bTarget = SelectUnit(SELECT_TARGET_RANDOM,1) ) + DoCast(bTarget,SPELL_SHADOWBOLT); + ShadowBolt_Timer = 7000; + }else ShadowBolt_Timer -= diff; + + //RainOfFire_Timer + if (RainOfFire_Timer < diff) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_RAINOFFIRE); + + RainOfFire_Timer = 4000 + rand()%8000; + }else RainOfFire_Timer -= diff; + + //GehennasCurse_Timer + if (GehennasCurse_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_GEHENNASCURSE); + GehennasCurse_Timer = 22000 + rand()%8000; + }else GehennasCurse_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_gehennas(Creature *_Creature) +{ + return new boss_gehennasAI (_Creature); +} + +void AddSC_boss_gehennas() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gehennas"; + newscript->GetAI = GetAI_boss_gehennas; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_golemagg.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_golemagg.cpp index 08bb85201ca..008b87d21d1 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_golemagg.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_golemagg.cpp @@ -1,219 +1,201 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Golemagg -SD%Complete: 90 -SDComment: -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" -#include "def_molten_core.h" - -#define SPELL_MAGMASPLASH 13879 -#define SPELL_PYROBLAST 20228 -#define SPELL_EARTHQUAKE 19798 -#define SPELL_ENRAGE 19953 -#define SPELL_BUFF 20553 - -//-- CoreRager Spells -- -#define SPELL_MANGLE 19820 -#define SPELL_AEGIS 20620 //This is self casted whenever we are below 50% - -#define EMOTE_AEGIS "refuses to die while its master is in trouble" - -struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI -{ - boss_golemaggAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 Pyroblast_Timer; - uint32 EarthQuake_Timer; - uint32 Enrage_Timer; - uint32 Buff_Timer; - ScriptedInstance *pInstance; - - void Reset() - { - Pyroblast_Timer = 7000; //These times are probably wrong - EarthQuake_Timer = 3000; - Buff_Timer = 2500; - Enrage_Timer = 0; - - m_creature->CastSpell(m_creature,SPELL_MAGMASPLASH,true); - } - - void Aggro(Unit *who) - { - } - - void JustDied(Unit* Killer) - { - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - pInstance->SetData(DATA_GOLEMAGG_DEATH, 0); - } - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Pyroblast_Timer - if (Pyroblast_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_PYROBLAST); - - Pyroblast_Timer = 7000; - }else Pyroblast_Timer -= diff; - - //Enrage_Timer - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11 ) - { - if (Enrage_Timer < diff) - { - DoCast(m_creature,SPELL_ENRAGE); - Enrage_Timer = 62000; - }else Enrage_Timer -= diff; - } - - //EarthQuake_Timer - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11 ) - { - if (EarthQuake_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_EARTHQUAKE); - EarthQuake_Timer = 3000; - }else EarthQuake_Timer -= diff; - } - - //Casting Buff for Coreragers. Spell is not working right. Players get the buff... - // if(Buff_Timer < diff) - // { - // DoCast(m_creature, SPELL_BUFF); - // Buff_Timer = 2500; - // }else Buff_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_core_ragerAI : public ScriptedAI -{ - mob_core_ragerAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 Mangle_Timer; - uint32 Check_Timer; - ScriptedInstance *pInstance; - - void Reset() - { - Mangle_Timer = 7000; //These times are probably wrong - Check_Timer = 1000; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Mangle_Timer - if (Mangle_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MANGLE); - Mangle_Timer = 10000; - }else Mangle_Timer -= diff; - - //Cast AEGIS - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50 ) - { - DoCast(m_creature,SPELL_AEGIS); - DoTextEmote(EMOTE_AEGIS, NULL); - } - - //Check_Timer - if(Check_Timer < diff) - { - if(pInstance) - { - Unit *pGolemagg = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_GOLEMAGG)); - if(!pGolemagg || !pGolemagg->isAlive()) - { - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true); - } - } - - Check_Timer = 1000; - }else Check_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_golemagg(Creature *_Creature) -{ - return new boss_golemaggAI (_Creature); -} - -CreatureAI* GetAI_mob_core_rager(Creature *_Creature) -{ - return new mob_core_ragerAI (_Creature); -} - -void AddSC_boss_golemagg() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_golemagg"; - newscript->GetAI = GetAI_boss_golemagg; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_core_rager"; - newscript->GetAI = GetAI_mob_core_rager; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Golemagg +SD%Complete: 90 +SDComment: +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "def_molten_core.h" + +#define SPELL_MAGMASPLASH 13879 +#define SPELL_PYROBLAST 20228 +#define SPELL_EARTHQUAKE 19798 +#define SPELL_ENRAGE 19953 +#define SPELL_BUFF 20553 + +//-- CoreRager Spells -- +#define SPELL_MANGLE 19820 +#define SPELL_AEGIS 20620 //This is self casted whenever we are below 50% + +#define EMOTE_AEGIS "refuses to die while its master is in trouble" + +struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI +{ + boss_golemaggAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 Pyroblast_Timer; + uint32 EarthQuake_Timer; + uint32 Enrage_Timer; + uint32 Buff_Timer; + ScriptedInstance *pInstance; + + void Reset() + { + Pyroblast_Timer = 7000; //These times are probably wrong + EarthQuake_Timer = 3000; + Buff_Timer = 2500; + Enrage_Timer = 0; + + m_creature->CastSpell(m_creature,SPELL_MAGMASPLASH,true); + } + + void Aggro(Unit *who) + { + } + + void JustDied(Unit* Killer) + { + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + pInstance->SetData(DATA_GOLEMAGG_DEATH, 0); + } + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Pyroblast_Timer + if (Pyroblast_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_PYROBLAST); + + Pyroblast_Timer = 7000; + }else Pyroblast_Timer -= diff; + + //Enrage_Timer + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11 ) + { + if (Enrage_Timer < diff) + { + DoCast(m_creature,SPELL_ENRAGE); + Enrage_Timer = 62000; + }else Enrage_Timer -= diff; + } + + //EarthQuake_Timer + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11 ) + { + if (EarthQuake_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_EARTHQUAKE); + EarthQuake_Timer = 3000; + }else EarthQuake_Timer -= diff; + } + + //Casting Buff for Coreragers. Spell is not working right. Players get the buff... + // if(Buff_Timer < diff) + // { + // DoCast(m_creature, SPELL_BUFF); + // Buff_Timer = 2500; + // }else Buff_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_core_ragerAI : public ScriptedAI +{ + mob_core_ragerAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 Mangle_Timer; + uint32 Check_Timer; + ScriptedInstance *pInstance; + + void Reset() + { + Mangle_Timer = 7000; //These times are probably wrong + Check_Timer = 1000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Mangle_Timer + if (Mangle_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MANGLE); + Mangle_Timer = 10000; + }else Mangle_Timer -= diff; + + //Cast AEGIS + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50 ) + { + DoCast(m_creature,SPELL_AEGIS); + DoTextEmote(EMOTE_AEGIS, NULL); + } + + //Check_Timer + if(Check_Timer < diff) + { + if(pInstance) + { + Unit *pGolemagg = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_GOLEMAGG)); + if(!pGolemagg || !pGolemagg->isAlive()) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true); + } + } + + Check_Timer = 1000; + }else Check_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_golemagg(Creature *_Creature) +{ + return new boss_golemaggAI (_Creature); +} + +CreatureAI* GetAI_mob_core_rager(Creature *_Creature) +{ + return new mob_core_ragerAI (_Creature); +} + +void AddSC_boss_golemagg() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_golemagg"; + newscript->GetAI = GetAI_boss_golemagg; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_core_rager"; + newscript->GetAI = GetAI_mob_core_rager; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_lucifron.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_lucifron.cpp index c0083fe1a7f..e28f8fa5441 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_lucifron.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_lucifron.cpp @@ -1,90 +1,90 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Impending doom timer - if (ImpendingDoom_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_IMPENDINGDOOM); - ImpendingDoom_Timer = 20000; - }else ImpendingDoom_Timer -= diff; - - //Lucifron's curse timer - if (LucifronCurse_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_LUCIFRONCURSE); - LucifronCurse_Timer = 15000; - }else LucifronCurse_Timer -= diff; - - //Shadowshock - if (ShadowShock_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWSHOCK); - ShadowShock_Timer = 6000; - }else ShadowShock_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_lucifron(Creature *_Creature) -{ - return new boss_lucifronAI (_Creature); -} - -void AddSC_boss_lucifron() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_lucifron"; - newscript->GetAI = GetAI_boss_lucifron; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Impending doom timer + if (ImpendingDoom_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_IMPENDINGDOOM); + ImpendingDoom_Timer = 20000; + }else ImpendingDoom_Timer -= diff; + + //Lucifron's curse timer + if (LucifronCurse_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_LUCIFRONCURSE); + LucifronCurse_Timer = 15000; + }else LucifronCurse_Timer -= diff; + + //Shadowshock + if (ShadowShock_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWSHOCK); + ShadowShock_Timer = 6000; + }else ShadowShock_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_lucifron(Creature *_Creature) +{ + return new boss_lucifronAI (_Creature); +} + +void AddSC_boss_lucifron() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_lucifron"; + newscript->GetAI = GetAI_boss_lucifron; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_magmadar.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_magmadar.cpp index 1d2d9fa1617..e78c6bb1b32 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_magmadar.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_magmadar.cpp @@ -1,97 +1,97 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_FRENZY 19451 -#define SPELL_MAGMASPIT 19449 //This is actually a buff he gives himself -#define SPELL_PANIC 19408 -#define SPELL_LAVABOMB 19411 //This calls a dummy server side effect that isn't implemented yet -#define SPELL_LAVABOMB_ALT 19428 //This is the spell that the lava bomb casts - -struct MANGOS_DLL_DECL boss_magmadarAI : public ScriptedAI -{ - boss_magmadarAI(Creature *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Frenzy_Timer - if (Frenzy_Timer < diff) - { - DoTextEmote("goes into a killing frenzy!",NULL); - DoCast(m_creature,SPELL_FRENZY); - Frenzy_Timer = 15000; - }else Frenzy_Timer -= diff; - - //Panic_Timer - if (Panic_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_PANIC); - Panic_Timer = 35000; - }else Panic_Timer -= diff; - - //Lavabomb_Timer - if (Lavabomb_Timer < diff) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_LAVABOMB_ALT); - - Lavabomb_Timer = 12000; - }else Lavabomb_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_magmadar(Creature *_Creature) -{ - return new boss_magmadarAI (_Creature); -} - -void AddSC_boss_magmadar() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_magmadar"; - newscript->GetAI = GetAI_boss_magmadar; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_FRENZY 19451 +#define SPELL_MAGMASPIT 19449 //This is actually a buff he gives himself +#define SPELL_PANIC 19408 +#define SPELL_LAVABOMB 19411 //This calls a dummy server side effect that isn't implemented yet +#define SPELL_LAVABOMB_ALT 19428 //This is the spell that the lava bomb casts + +struct MANGOS_DLL_DECL boss_magmadarAI : public ScriptedAI +{ + boss_magmadarAI(Creature *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Frenzy_Timer + if (Frenzy_Timer < diff) + { + DoTextEmote("goes into a killing frenzy!",NULL); + DoCast(m_creature,SPELL_FRENZY); + Frenzy_Timer = 15000; + }else Frenzy_Timer -= diff; + + //Panic_Timer + if (Panic_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_PANIC); + Panic_Timer = 35000; + }else Panic_Timer -= diff; + + //Lavabomb_Timer + if (Lavabomb_Timer < diff) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_LAVABOMB_ALT); + + Lavabomb_Timer = 12000; + }else Lavabomb_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_magmadar(Creature *_Creature) +{ + return new boss_magmadarAI (_Creature); +} + +void AddSC_boss_magmadar() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_magmadar"; + newscript->GetAI = GetAI_boss_magmadar; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_majordomo_executus.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_majordomo_executus.cpp index 8c7129eb691..82924040538 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_majordomo_executus.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_majordomo_executus.cpp @@ -1,133 +1,133 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 SPELL_MAGICREFLECTION 20619 -#define SPELL_DAMAGEREFLECTION 21075 -#define SPELL_BLASTWAVE 20229 -#define SPELL_AEGIS 20620 //This is self casted whenever we are below 50% - -#define SAY_AGGRO "Reckless mortals, none may challenge the sons of the living flame!" -#define SOUND_AGGRO 8035 - -#define SAY_SPAWN "The runes of warding have been destroyed! Hunt down the infedels my bretheren." -#define SOUND_SPAWN 8039 - -#define SAY_DEFEAT "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!" -#define SOUND_DEFEAT 8038 - -#define SAY_KILL "Ashes to Ashes!" -#define SOUND_KILL 8037 - -#define SAY_SPECIAL "Burn mortals! Burn for this transgression!" -#define SOUND_SPECIAL 8036 - -#define SAY_SUMMON "Behold Ragnaros, the Firelord! He who was ancient when this world was young! Bow before him, mortals! Bow before your ending!" -#define SOUND_SUMMON 8040 - -#define SAY_ARRIVAL1 "These mortal infidels, my lord! They have invaded your sanctum, and seek to steal your secrets!" -#define SOUND_ARRIVAL1 8041 - -struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI -{ - boss_majordomoAI(Creature *c) : ScriptedAI(c) {Reset();} - - 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 (rand()%5) - return; - - DoYell(SAY_KILL,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Cast Ageis if less than 50% hp - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50) - { - DoCast(m_creature,SPELL_AEGIS); - } - - //MagicReflection_Timer - // if (MagicReflection_Timer < diff) - // { - // DoCast(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) - // { - // DoCast(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) - { - DoCast(m_creature->getVictim(),SPELL_BLASTWAVE); - Blastwave_Timer = 10000; - }else Blastwave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_majordomo(Creature *_Creature) -{ - return new boss_majordomoAI (_Creature); -} - -void AddSC_boss_majordomo() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_majordomo"; - newscript->GetAI = GetAI_boss_majordomo; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 SPELL_MAGICREFLECTION 20619 +#define SPELL_DAMAGEREFLECTION 21075 +#define SPELL_BLASTWAVE 20229 +#define SPELL_AEGIS 20620 //This is self casted whenever we are below 50% + +#define SAY_AGGRO "Reckless mortals, none may challenge the sons of the living flame!" +#define SOUND_AGGRO 8035 + +#define SAY_SPAWN "The runes of warding have been destroyed! Hunt down the infedels my bretheren." +#define SOUND_SPAWN 8039 + +#define SAY_DEFEAT "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!" +#define SOUND_DEFEAT 8038 + +#define SAY_KILL "Ashes to Ashes!" +#define SOUND_KILL 8037 + +#define SAY_SPECIAL "Burn mortals! Burn for this transgression!" +#define SOUND_SPECIAL 8036 + +#define SAY_SUMMON "Behold Ragnaros, the Firelord! He who was ancient when this world was young! Bow before him, mortals! Bow before your ending!" +#define SOUND_SUMMON 8040 + +#define SAY_ARRIVAL1 "These mortal infidels, my lord! They have invaded your sanctum, and seek to steal your secrets!" +#define SOUND_ARRIVAL1 8041 + +struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI +{ + boss_majordomoAI(Creature *c) : ScriptedAI(c) {Reset();} + + 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 (rand()%5) + return; + + DoYell(SAY_KILL,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Cast Ageis if less than 50% hp + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50) + { + DoCast(m_creature,SPELL_AEGIS); + } + + //MagicReflection_Timer + // if (MagicReflection_Timer < diff) + // { + // DoCast(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) + // { + // DoCast(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) + { + DoCast(m_creature->getVictim(),SPELL_BLASTWAVE); + Blastwave_Timer = 10000; + }else Blastwave_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_majordomo(Creature *_Creature) +{ + return new boss_majordomoAI (_Creature); +} + +void AddSC_boss_majordomo() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_majordomo"; + newscript->GetAI = GetAI_boss_majordomo; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_ragnaros.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_ragnaros.cpp index 3a043987cca..03918c238a2 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_ragnaros.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_ragnaros.cpp @@ -1,317 +1,317 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 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 SAY_ARRIVAL_1 "TOO SOON! YOU HAVE AWAKENED ME TOO SOON, EXECUTUS! WHAT IS THE MEANING OF THIS INTRUSION?" -#define SAY_ARRIVAL_3 "FOOL! YOU ALLOWED THESE INSECTS TO RUN RAMPANT THROUGH THE HALLOWED CORE, AND NOW YOU LEAD THEM TO MY VERY LAIR? YOU HAVE FAILED ME, EXECUTUS! JUSTICE SHALL BE MET, INDEED!" -#define SAY_ARRIVAL_5 "NOW FOR YOU, INSECTS. BOLDLY YOU SAUGHT THE POWER OF RAGNAROS NOW YOU SHALL SEE IT FIRST HAND." -#define SAY_REINFORCEMENTS1 "COME FORTH, MY SERVANTS! DEFEND YOUR MASTER!" -#define SAY_REINFORCEMENTS2 "YOU CANNOT DEFEAT THE LIVING FLAME! COME YOU MINIONS OF FIRE! COME FORTH YOU CREATURES OF HATE! YOUR MASTER CALLS!" -#define SAY_HAND "BY FIRE BE PURGED!" -#define SAY_WRATH "TASTE THE FLAMES OF SULFURON!" -#define SAY_KILL "DIE INSECT!" -#define SAY_MAGMABURST "MY PATIENCE IS DWINDILING! COME NATS TO YOUR DEATH!" - -#define SOUND_ARRIVAL_1 8043 -#define SOUND_ARRIVAL_3 8044 -#define SOUND_ARRIVAL_5 8045 -#define SOUND_REINFORCEMENTS1 8049 -#define SOUND_REINFORCEMENTS2 8050 -#define SOUND_HAND 8046 -#define SOUND_WRATH 8047 -#define SOUND_KILL 8051 -#define SOUND_MAGMABURST 8048 - -#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 Scripted_NoMovementAI -{ - boss_ragnarosAI(Creature *c) : Scripted_NoMovementAI(c) {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 (rand()%5) - return; - - DoYell(SAY_KILL, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL); - } - - void Aggro(Unit *who) - { - DoYell(SAY_ARRIVAL_5,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_ARRIVAL_5); - } - - 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); - DoCast(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->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //WrathOfRagnaros_Timer - if (WrathOfRagnaros_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_WRATHOFRAGNAROS); - - if (rand()%2 == 0) - { - DoYell(SAY_WRATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_WRATH); - } - - WrathOfRagnaros_Timer = 30000; - }else WrathOfRagnaros_Timer -= diff; - - //HandOfRagnaros_Timer - if (HandOfRagnaros_Timer < diff) - { - DoCast(m_creature,SPELL_HANDOFRAGNAROS); - - if (rand()%2==0) - { - DoYell(SAY_HAND,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_HAND); - } - - HandOfRagnaros_Timer = 25000; - }else HandOfRagnaros_Timer -= diff; - - //LavaBurst_Timer - if (LavaBurst_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_LAVABURST); - LavaBurst_Timer = 10000; - }else LavaBurst_Timer -= diff; - - //Erruption_Timer - if (LavaBurst_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ERRUPTION); - Erruption_Timer = 20000 + rand()%25000; - }else Erruption_Timer -= diff; - - //ElementalFire_Timer - if (ElementalFire_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ELEMENTALFIRE); - ElementalFire_Timer = 10000 + rand()%4000; - }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 - DoCast(m_creature,23973); - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); - - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - if (!HasSubmergedOnce) - { - DoYell(SAY_REINFORCEMENTS1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_REINFORCEMENTS1); - - // summon 10 elementals - Unit* target = NULL; - for(int i = 0; i < 9;i++) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - Summoned = m_creature->SummonCreature(12143,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,900000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - } - - HasSubmergedOnce = true; - WasBanished = true; - DoCast(m_creature,SPELL_RAGSUBMERGE); - Attack_Timer = 90000; - - }else - { - DoYell(SAY_REINFORCEMENTS2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_REINFORCEMENTS2); - - Unit* target = NULL; - for(int i = 0; i < 9;i++) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - Summoned = m_creature->SummonCreature(12143,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,900000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - } - - WasBanished = true; - DoCast(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) - { - DoCast(m_creature->getVictim(),SPELL_MAGMABURST); - - if (!HasYelledMagmaBurst) - { - //Say our dialog - DoYell(SAY_MAGMABURST,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_MAGMABURST); - HasYelledMagmaBurst = true; - } - - MagmaBurst_Timer = 2500; - }else MagmaBurst_Timer -= diff; - } - } -}; -CreatureAI* GetAI_boss_ragnaros(Creature *_Creature) -{ - return new boss_ragnarosAI (_Creature); -} - -void AddSC_boss_ragnaros() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ragnaros"; - newscript->GetAI = GetAI_boss_ragnaros; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 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 SAY_ARRIVAL_1 "TOO SOON! YOU HAVE AWAKENED ME TOO SOON, EXECUTUS! WHAT IS THE MEANING OF THIS INTRUSION?" +#define SAY_ARRIVAL_3 "FOOL! YOU ALLOWED THESE INSECTS TO RUN RAMPANT THROUGH THE HALLOWED CORE, AND NOW YOU LEAD THEM TO MY VERY LAIR? YOU HAVE FAILED ME, EXECUTUS! JUSTICE SHALL BE MET, INDEED!" +#define SAY_ARRIVAL_5 "NOW FOR YOU, INSECTS. BOLDLY YOU SAUGHT THE POWER OF RAGNAROS NOW YOU SHALL SEE IT FIRST HAND." +#define SAY_REINFORCEMENTS1 "COME FORTH, MY SERVANTS! DEFEND YOUR MASTER!" +#define SAY_REINFORCEMENTS2 "YOU CANNOT DEFEAT THE LIVING FLAME! COME YOU MINIONS OF FIRE! COME FORTH YOU CREATURES OF HATE! YOUR MASTER CALLS!" +#define SAY_HAND "BY FIRE BE PURGED!" +#define SAY_WRATH "TASTE THE FLAMES OF SULFURON!" +#define SAY_KILL "DIE INSECT!" +#define SAY_MAGMABURST "MY PATIENCE IS DWINDILING! COME NATS TO YOUR DEATH!" + +#define SOUND_ARRIVAL_1 8043 +#define SOUND_ARRIVAL_3 8044 +#define SOUND_ARRIVAL_5 8045 +#define SOUND_REINFORCEMENTS1 8049 +#define SOUND_REINFORCEMENTS2 8050 +#define SOUND_HAND 8046 +#define SOUND_WRATH 8047 +#define SOUND_KILL 8051 +#define SOUND_MAGMABURST 8048 + +#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 Scripted_NoMovementAI +{ + boss_ragnarosAI(Creature *c) : Scripted_NoMovementAI(c) {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 (rand()%5) + return; + + DoYell(SAY_KILL, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL); + } + + void Aggro(Unit *who) + { + DoYell(SAY_ARRIVAL_5,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_ARRIVAL_5); + } + + 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); + DoCast(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->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //WrathOfRagnaros_Timer + if (WrathOfRagnaros_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_WRATHOFRAGNAROS); + + if (rand()%2 == 0) + { + DoYell(SAY_WRATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_WRATH); + } + + WrathOfRagnaros_Timer = 30000; + }else WrathOfRagnaros_Timer -= diff; + + //HandOfRagnaros_Timer + if (HandOfRagnaros_Timer < diff) + { + DoCast(m_creature,SPELL_HANDOFRAGNAROS); + + if (rand()%2==0) + { + DoYell(SAY_HAND,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_HAND); + } + + HandOfRagnaros_Timer = 25000; + }else HandOfRagnaros_Timer -= diff; + + //LavaBurst_Timer + if (LavaBurst_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_LAVABURST); + LavaBurst_Timer = 10000; + }else LavaBurst_Timer -= diff; + + //Erruption_Timer + if (LavaBurst_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ERRUPTION); + Erruption_Timer = 20000 + rand()%25000; + }else Erruption_Timer -= diff; + + //ElementalFire_Timer + if (ElementalFire_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ELEMENTALFIRE); + ElementalFire_Timer = 10000 + rand()%4000; + }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 + DoCast(m_creature,23973); + m_creature->setFaction(35); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); + + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + if (!HasSubmergedOnce) + { + DoYell(SAY_REINFORCEMENTS1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_REINFORCEMENTS1); + + // summon 10 elementals + Unit* target = NULL; + for(int i = 0; i < 9;i++) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + Summoned = m_creature->SummonCreature(12143,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,900000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + } + + HasSubmergedOnce = true; + WasBanished = true; + DoCast(m_creature,SPELL_RAGSUBMERGE); + Attack_Timer = 90000; + + }else + { + DoYell(SAY_REINFORCEMENTS2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_REINFORCEMENTS2); + + Unit* target = NULL; + for(int i = 0; i < 9;i++) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + Summoned = m_creature->SummonCreature(12143,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,900000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + } + + WasBanished = true; + DoCast(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) + { + DoCast(m_creature->getVictim(),SPELL_MAGMABURST); + + if (!HasYelledMagmaBurst) + { + //Say our dialog + DoYell(SAY_MAGMABURST,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_MAGMABURST); + HasYelledMagmaBurst = true; + } + + MagmaBurst_Timer = 2500; + }else MagmaBurst_Timer -= diff; + } + } +}; +CreatureAI* GetAI_boss_ragnaros(Creature *_Creature) +{ + return new boss_ragnarosAI (_Creature); +} + +void AddSC_boss_ragnaros() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ragnaros"; + newscript->GetAI = GetAI_boss_ragnaros; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_shazzrah.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_shazzrah.cpp index 5c8746b2567..e3876b79ecc 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_shazzrah.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_shazzrah.cpp @@ -1,121 +1,121 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_ARCANEEXPLOSION 19712 -#define SPELL_SHAZZRAHCURSE 19713 -#define SPELL_DEADENMAGIC 19714 -#define SPELL_COUNTERSPELL 19715 - -struct MANGOS_DLL_DECL boss_shazzrahAI : public ScriptedAI -{ - boss_shazzrahAI(Creature *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //ArcaneExplosion_Timer - if (ArcaneExplosion_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ARCANEEXPLOSION); - ArcaneExplosion_Timer = 5000 + rand()%4000; - }else ArcaneExplosion_Timer -= diff; - - //ShazzrahCurse_Timer - if (ShazzrahCurse_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_SHAZZRAHCURSE); - - ShazzrahCurse_Timer = 25000 + rand()%5000; - }else ShazzrahCurse_Timer -= diff; - - //DeadenMagic_Timer - if (DeadenMagic_Timer < diff) - { - DoCast(m_creature,SPELL_DEADENMAGIC); - DeadenMagic_Timer = 35000; - }else DeadenMagic_Timer -= diff; - - //Countspell_Timer - if (Countspell_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_COUNTERSPELL); - Countspell_Timer = 16000 + rand()%4000; - }else Countspell_Timer -= diff; - - //Blink_Timer - if (Blink_Timer < diff) - { - // Teleporting him to a random gamer and casting Arcane Explosion after that. - // Blink is not working cause of LoS System we need to do this hardcoded. - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0); - m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0,true,0); - DoCast(target,SPELL_ARCANEEXPLOSION); - DoResetThreat(); - - Blink_Timer = 45000; - }else Blink_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_shazzrah(Creature *_Creature) -{ - return new boss_shazzrahAI (_Creature); -} - -void AddSC_boss_shazzrah() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_shazzrah"; - newscript->GetAI = GetAI_boss_shazzrah; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_ARCANEEXPLOSION 19712 +#define SPELL_SHAZZRAHCURSE 19713 +#define SPELL_DEADENMAGIC 19714 +#define SPELL_COUNTERSPELL 19715 + +struct MANGOS_DLL_DECL boss_shazzrahAI : public ScriptedAI +{ + boss_shazzrahAI(Creature *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //ArcaneExplosion_Timer + if (ArcaneExplosion_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ARCANEEXPLOSION); + ArcaneExplosion_Timer = 5000 + rand()%4000; + }else ArcaneExplosion_Timer -= diff; + + //ShazzrahCurse_Timer + if (ShazzrahCurse_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_SHAZZRAHCURSE); + + ShazzrahCurse_Timer = 25000 + rand()%5000; + }else ShazzrahCurse_Timer -= diff; + + //DeadenMagic_Timer + if (DeadenMagic_Timer < diff) + { + DoCast(m_creature,SPELL_DEADENMAGIC); + DeadenMagic_Timer = 35000; + }else DeadenMagic_Timer -= diff; + + //Countspell_Timer + if (Countspell_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_COUNTERSPELL); + Countspell_Timer = 16000 + rand()%4000; + }else Countspell_Timer -= diff; + + //Blink_Timer + if (Blink_Timer < diff) + { + // Teleporting him to a random gamer and casting Arcane Explosion after that. + // Blink is not working cause of LoS System we need to do this hardcoded. + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0); + m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0,true,0); + DoCast(target,SPELL_ARCANEEXPLOSION); + DoResetThreat(); + + Blink_Timer = 45000; + }else Blink_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_shazzrah(Creature *_Creature) +{ + return new boss_shazzrahAI (_Creature); +} + +void AddSC_boss_shazzrah() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_shazzrah"; + newscript->GetAI = GetAI_boss_shazzrah; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/boss_sulfuron_harbinger.cpp b/src/bindings/scripts/scripts/zone/molten_core/boss_sulfuron_harbinger.cpp index fd4affaa570..7b03c2da7a4 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/boss_sulfuron_harbinger.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/boss_sulfuron_harbinger.cpp @@ -1,215 +1,215 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_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 *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 Darkstrike_Timer; - uint32 DemoralizingShout_Timer; - uint32 Inspire_Timer; - uint32 Knockdown_Timer; - uint32 Flamespear_Timer; - ScriptedInstance *pInstance; - - void Reset() - { - Darkstrike_Timer=10000; //These times are probably wrong - DemoralizingShout_Timer = 15000; - Inspire_Timer = 13000; - Knockdown_Timer = 6000; - Flamespear_Timer = 2000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //DemoralizingShout_Timer - if (DemoralizingShout_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DEMORALIZINGSHOUT); - DemoralizingShout_Timer = 15000 + rand()%5000; - }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) - DoCast(target,SPELL_INSPIRE); - - DoCast(m_creature,SPELL_INSPIRE); - - Inspire_Timer = 20000 + rand()%6000; - }else Inspire_Timer -= diff; - - //Knockdown_Timer - if (Knockdown_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKDOWN); - Knockdown_Timer = 12000 + rand()%3000; - }else Knockdown_Timer -= diff; - - //Flamespear_Timer - if (Flamespear_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_FLAMESPEAR); - - Flamespear_Timer = 12000 + rand()%4000; - }else Flamespear_Timer -= diff; - - //DarkStrike_Timer - if (Darkstrike_Timer < diff) - { - DoCast(m_creature, SPELL_DARKSTRIKE); - Darkstrike_Timer = 15000 + rand()%3000; - }else Darkstrike_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_flamewaker_priestAI : public ScriptedAI -{ - mob_flamewaker_priestAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 Heal_Timer; - uint32 ShadowWordPain_Timer; - uint32 Immolate_Timer; - - ScriptedInstance *pInstance; - - void Reset() - { - Heal_Timer = 15000+rand()%15000; - ShadowWordPain_Timer = 2000; - Immolate_Timer = 8000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Casting Heal to Sulfuron or other Guards. - if(Heal_Timer < diff) - { - Unit* pUnit = DoSelectLowestHpFriendly(60.0f, 1); - if (!pUnit) - return; - - DoCast(pUnit, SPELL_HEAL); - - Heal_Timer = 15000+rand()%5000; - }else Heal_Timer -= diff; - - //ShadowWordPain_Timer - if (ShadowWordPain_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_SHADOWWORDPAIN); - - ShadowWordPain_Timer = 18000+rand()%8000; - }else ShadowWordPain_Timer -= diff; - - //Immolate_Timer - if (Immolate_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_IMMOLATE); - - Immolate_Timer = 15000+rand()%10000; - }else Immolate_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_sulfuron(Creature *_Creature) -{ - return new boss_sulfuronAI (_Creature); -} - -CreatureAI* GetAI_mob_flamewaker_priest(Creature *_Creature) -{ - return new mob_flamewaker_priestAI (_Creature); -} - -void AddSC_boss_sulfuron() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_sulfuron"; - newscript->GetAI = GetAI_boss_sulfuron; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_flamewaker_priest"; - newscript->GetAI = GetAI_mob_flamewaker_priest; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_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 *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 Darkstrike_Timer; + uint32 DemoralizingShout_Timer; + uint32 Inspire_Timer; + uint32 Knockdown_Timer; + uint32 Flamespear_Timer; + ScriptedInstance *pInstance; + + void Reset() + { + Darkstrike_Timer=10000; //These times are probably wrong + DemoralizingShout_Timer = 15000; + Inspire_Timer = 13000; + Knockdown_Timer = 6000; + Flamespear_Timer = 2000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //DemoralizingShout_Timer + if (DemoralizingShout_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DEMORALIZINGSHOUT); + DemoralizingShout_Timer = 15000 + rand()%5000; + }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) + DoCast(target,SPELL_INSPIRE); + + DoCast(m_creature,SPELL_INSPIRE); + + Inspire_Timer = 20000 + rand()%6000; + }else Inspire_Timer -= diff; + + //Knockdown_Timer + if (Knockdown_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKDOWN); + Knockdown_Timer = 12000 + rand()%3000; + }else Knockdown_Timer -= diff; + + //Flamespear_Timer + if (Flamespear_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_FLAMESPEAR); + + Flamespear_Timer = 12000 + rand()%4000; + }else Flamespear_Timer -= diff; + + //DarkStrike_Timer + if (Darkstrike_Timer < diff) + { + DoCast(m_creature, SPELL_DARKSTRIKE); + Darkstrike_Timer = 15000 + rand()%3000; + }else Darkstrike_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_flamewaker_priestAI : public ScriptedAI +{ + mob_flamewaker_priestAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 Heal_Timer; + uint32 ShadowWordPain_Timer; + uint32 Immolate_Timer; + + ScriptedInstance *pInstance; + + void Reset() + { + Heal_Timer = 15000+rand()%15000; + ShadowWordPain_Timer = 2000; + Immolate_Timer = 8000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Casting Heal to Sulfuron or other Guards. + if(Heal_Timer < diff) + { + Unit* pUnit = DoSelectLowestHpFriendly(60.0f, 1); + if (!pUnit) + return; + + DoCast(pUnit, SPELL_HEAL); + + Heal_Timer = 15000+rand()%5000; + }else Heal_Timer -= diff; + + //ShadowWordPain_Timer + if (ShadowWordPain_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_SHADOWWORDPAIN); + + ShadowWordPain_Timer = 18000+rand()%8000; + }else ShadowWordPain_Timer -= diff; + + //Immolate_Timer + if (Immolate_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_IMMOLATE); + + Immolate_Timer = 15000+rand()%10000; + }else Immolate_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_sulfuron(Creature *_Creature) +{ + return new boss_sulfuronAI (_Creature); +} + +CreatureAI* GetAI_mob_flamewaker_priest(Creature *_Creature) +{ + return new mob_flamewaker_priestAI (_Creature); +} + +void AddSC_boss_sulfuron() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_sulfuron"; + newscript->GetAI = GetAI_boss_sulfuron; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_flamewaker_priest"; + newscript->GetAI = GetAI_mob_flamewaker_priest; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/def_molten_core.h b/src/bindings/scripts/scripts/zone/molten_core/def_molten_core.h index 584adce0d31..793bedb3ca8 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/def_molten_core.h +++ b/src/bindings/scripts/scripts/zone/molten_core/def_molten_core.h @@ -1,21 +1,21 @@ -/* Copyright (C) 2006 - 2008 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 - -#define DATA_FLAMEWAKERPRIEST 1 -#define DATA_GARRISDEAD 2 -#define DATA_GEDDONISDEAD 3 -#define DATA_GEHENNASISDEAD 4 -#define DATA_GOLEMAGGISDEAD 5 -#define DATA_GOLEMAGG_DEATH 6 -#define DATA_LUCIFRONISDEAD 7 -#define DATA_MAGMADARISDEAD 8 -#define DATA_MAJORDOMOISDEAD 9 -#define DATA_SHAZZRAHISDEAD 10 -#define DATA_SULFURON 11 -#define DATA_SULFURONISDEAD 12 -#define DATA_GOLEMAGG 13 -#endif +/* Copyright (C) 2006 - 2008 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 + +#define DATA_FLAMEWAKERPRIEST 1 +#define DATA_GARRISDEAD 2 +#define DATA_GEDDONISDEAD 3 +#define DATA_GEHENNASISDEAD 4 +#define DATA_GOLEMAGGISDEAD 5 +#define DATA_GOLEMAGG_DEATH 6 +#define DATA_LUCIFRONISDEAD 7 +#define DATA_MAGMADARISDEAD 8 +#define DATA_MAJORDOMOISDEAD 9 +#define DATA_SHAZZRAHISDEAD 10 +#define DATA_SULFURON 11 +#define DATA_SULFURONISDEAD 12 +#define DATA_GOLEMAGG 13 +#endif diff --git a/src/bindings/scripts/scripts/zone/molten_core/instance_molten_core.cpp b/src/bindings/scripts/scripts/zone/molten_core/instance_molten_core.cpp index 60521aa5f9c..53a291affcd 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/instance_molten_core.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/instance_molten_core.cpp @@ -1,260 +1,260 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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 "def_molten_core.h" - -#define ID_LUCIFRON 12118 -#define ID_MAGMADAR 11982 -#define ID_GEHENNAS 12259 -#define ID_GARR 12057 -#define ID_GEDDON 12056 -#define ID_SHAZZRAH 12264 -#define ID_GOLEMAGG 11988 -#define ID_SULFURON 12098 -#define ID_DOMO 12018 -#define ID_RAGNAROS 11502 -#define ID_FLAMEWAKERPRIEST 11662 - -class MANGOS_DLL_SPEC instance_molten_core : public ScriptedInstance -{ - public: - - instance_molten_core(Map *map) : ScriptedInstance(map) {} - - uint64 Lucifron, Magmadar, Gehennas, Garr, Geddon, Shazzrah, Sulfuron, Golemagg, Domo, Ragnaros, FlamewakerPriest; - uint64 RuneGUID[8]; - - //If all Bosses are dead. - bool IsBossDied[9]; - - uint32 CheckTimer; - - //On creation, NOT load. - void Initialize() - { - //Clear all GUIDs - Lucifron = 0; - Magmadar = 0; - Gehennas = 0; - Garr = 0; - Geddon = 0; - Shazzrah = 0; - Sulfuron = 0; - Golemagg = 0; - Domo = 0; - Ragnaros = 0; - FlamewakerPriest = 0; - - RuneGUID[0] = 0; - RuneGUID[1] = 0; - RuneGUID[2] = 0; - RuneGUID[3] = 0; - RuneGUID[4] = 0; - RuneGUID[5] = 0; - RuneGUID[6] = 0; - RuneGUID[7] = 0; - - IsBossDied[0] = false; - IsBossDied[1] = false; - IsBossDied[2] = false; - IsBossDied[3] = false; - IsBossDied[4] = false; - IsBossDied[5] = false; - IsBossDied[6] = false; - - IsBossDied[7] = false; - IsBossDied[8] = false; - - CheckTimer = 10000; - } - //Called every map update - void Update(uint32 diff) - { - - if (CheckTimer < diff) - { - //Check if all bosses are dead and activate Major Domo - - }else CheckTimer -= diff; - - } - - //Used by the map's CanEnter function. - //This is to prevent players from entering during boss encounters. - bool IsEncounterInProgress() const - { - return false; - }; - - //Called when a gameobject is created - void OnObjectCreate(GameObject *obj) - { - //Still searching for the individual rune ids. - //Currently they don't exist within most databases and are hard to find on websites - } - - //called on creature creation - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - //Store specific creatures based on entry id - switch (creature_entry) - { - case ID_LUCIFRON: - Lucifron = creature->GetGUID(); - break; - - case ID_MAGMADAR: - Magmadar = creature->GetGUID(); - break; - - case ID_GEHENNAS: - Gehennas = creature->GetGUID(); - break; - - case ID_GARR: - Garr = creature->GetGUID(); - break; - - case ID_GEDDON: - Geddon = creature->GetGUID(); - break; - - case ID_SHAZZRAH: - Shazzrah = creature->GetGUID(); - break; - - case ID_SULFURON: - Sulfuron = creature->GetGUID(); - break; - - case ID_GOLEMAGG: - Golemagg = creature->GetGUID(); - break; - - case ID_DOMO: - Domo = creature->GetGUID(); - break; - - case ID_RAGNAROS: - Ragnaros = creature->GetGUID(); - break; - - case ID_FLAMEWAKERPRIEST: - FlamewakerPriest = creature->GetGUID(); - break; - - default: - return; - } - } - - uint64 GetData64 (uint32 identifier) - { - switch(identifier) - { - case DATA_SULFURON: - return Sulfuron; - case DATA_GOLEMAGG: - return Sulfuron; - - case DATA_FLAMEWAKERPRIEST: - return FlamewakerPriest; - } - - return 0; - } // end GetData64 - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_LUCIFRONISDEAD: - if(IsBossDied[0]) - return 1; - break; - - case DATA_MAGMADARISDEAD: - if(IsBossDied[1]) - return 1; - break; - - case DATA_GEHENNASISDEAD: - if(IsBossDied[2]) - return 1; - break; - - case DATA_GARRISDEAD: - if(IsBossDied[3]) - return 1; - break; - - case DATA_GEDDONISDEAD: - if(IsBossDied[4]) - return 1; - break; - - case DATA_SHAZZRAHISDEAD: - if(IsBossDied[5]) - return 1; - break; - - case DATA_SULFURONISDEAD: - if(IsBossDied[6]) - return 1; - break; - - case DATA_GOLEMAGGISDEAD: - if(IsBossDied[7]) - return 1; - break; - - case DATA_MAJORDOMOISDEAD: - if(IsBossDied[8]) - return 1; - break; - } - - return 0; - } - - void SetData(uint32 type, uint32 data) - { - if(type == DATA_GOLEMAGG_DEATH) - IsBossDied[7] = true; - } -}; - -InstanceData* GetInstance_instance_molten_core(Map *_Map) -{ - return new instance_molten_core (_Map); -} - -void AddSC_instance_molten_core() -{ - Script *newscript; - newscript = new Script; - newscript->Name="instance_molten_core"; - newscript->GetInstanceData = &GetInstance_instance_molten_core; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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 "def_molten_core.h" + +#define ID_LUCIFRON 12118 +#define ID_MAGMADAR 11982 +#define ID_GEHENNAS 12259 +#define ID_GARR 12057 +#define ID_GEDDON 12056 +#define ID_SHAZZRAH 12264 +#define ID_GOLEMAGG 11988 +#define ID_SULFURON 12098 +#define ID_DOMO 12018 +#define ID_RAGNAROS 11502 +#define ID_FLAMEWAKERPRIEST 11662 + +class MANGOS_DLL_SPEC instance_molten_core : public ScriptedInstance +{ + public: + + instance_molten_core(Map *map) : ScriptedInstance(map) {} + + uint64 Lucifron, Magmadar, Gehennas, Garr, Geddon, Shazzrah, Sulfuron, Golemagg, Domo, Ragnaros, FlamewakerPriest; + uint64 RuneGUID[8]; + + //If all Bosses are dead. + bool IsBossDied[9]; + + uint32 CheckTimer; + + //On creation, NOT load. + void Initialize() + { + //Clear all GUIDs + Lucifron = 0; + Magmadar = 0; + Gehennas = 0; + Garr = 0; + Geddon = 0; + Shazzrah = 0; + Sulfuron = 0; + Golemagg = 0; + Domo = 0; + Ragnaros = 0; + FlamewakerPriest = 0; + + RuneGUID[0] = 0; + RuneGUID[1] = 0; + RuneGUID[2] = 0; + RuneGUID[3] = 0; + RuneGUID[4] = 0; + RuneGUID[5] = 0; + RuneGUID[6] = 0; + RuneGUID[7] = 0; + + IsBossDied[0] = false; + IsBossDied[1] = false; + IsBossDied[2] = false; + IsBossDied[3] = false; + IsBossDied[4] = false; + IsBossDied[5] = false; + IsBossDied[6] = false; + + IsBossDied[7] = false; + IsBossDied[8] = false; + + CheckTimer = 10000; + } + //Called every map update + void Update(uint32 diff) + { + + if (CheckTimer < diff) + { + //Check if all bosses are dead and activate Major Domo + + }else CheckTimer -= diff; + + } + + //Used by the map's CanEnter function. + //This is to prevent players from entering during boss encounters. + bool IsEncounterInProgress() const + { + return false; + }; + + //Called when a gameobject is created + void OnObjectCreate(GameObject *obj) + { + //Still searching for the individual rune ids. + //Currently they don't exist within most databases and are hard to find on websites + } + + //called on creature creation + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + //Store specific creatures based on entry id + switch (creature_entry) + { + case ID_LUCIFRON: + Lucifron = creature->GetGUID(); + break; + + case ID_MAGMADAR: + Magmadar = creature->GetGUID(); + break; + + case ID_GEHENNAS: + Gehennas = creature->GetGUID(); + break; + + case ID_GARR: + Garr = creature->GetGUID(); + break; + + case ID_GEDDON: + Geddon = creature->GetGUID(); + break; + + case ID_SHAZZRAH: + Shazzrah = creature->GetGUID(); + break; + + case ID_SULFURON: + Sulfuron = creature->GetGUID(); + break; + + case ID_GOLEMAGG: + Golemagg = creature->GetGUID(); + break; + + case ID_DOMO: + Domo = creature->GetGUID(); + break; + + case ID_RAGNAROS: + Ragnaros = creature->GetGUID(); + break; + + case ID_FLAMEWAKERPRIEST: + FlamewakerPriest = creature->GetGUID(); + break; + + default: + return; + } + } + + uint64 GetData64 (uint32 identifier) + { + switch(identifier) + { + case DATA_SULFURON: + return Sulfuron; + case DATA_GOLEMAGG: + return Sulfuron; + + case DATA_FLAMEWAKERPRIEST: + return FlamewakerPriest; + } + + return 0; + } // end GetData64 + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_LUCIFRONISDEAD: + if(IsBossDied[0]) + return 1; + break; + + case DATA_MAGMADARISDEAD: + if(IsBossDied[1]) + return 1; + break; + + case DATA_GEHENNASISDEAD: + if(IsBossDied[2]) + return 1; + break; + + case DATA_GARRISDEAD: + if(IsBossDied[3]) + return 1; + break; + + case DATA_GEDDONISDEAD: + if(IsBossDied[4]) + return 1; + break; + + case DATA_SHAZZRAHISDEAD: + if(IsBossDied[5]) + return 1; + break; + + case DATA_SULFURONISDEAD: + if(IsBossDied[6]) + return 1; + break; + + case DATA_GOLEMAGGISDEAD: + if(IsBossDied[7]) + return 1; + break; + + case DATA_MAJORDOMOISDEAD: + if(IsBossDied[8]) + return 1; + break; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + if(type == DATA_GOLEMAGG_DEATH) + IsBossDied[7] = true; + } +}; + +InstanceData* GetInstance_instance_molten_core(Map *_Map) +{ + return new instance_molten_core (_Map); +} + +void AddSC_instance_molten_core() +{ + Script *newscript; + newscript = new Script; + newscript->Name="instance_molten_core"; + newscript->GetInstanceData = &GetInstance_instance_molten_core; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/molten_core/molten_core.cpp b/src/bindings/scripts/scripts/zone/molten_core/molten_core.cpp index c2aab542828..4e406090577 100644 --- a/src/bindings/scripts/scripts/zone/molten_core/molten_core.cpp +++ b/src/bindings/scripts/scripts/zone/molten_core/molten_core.cpp @@ -1,88 +1,88 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Core -SD%Complete: 100 -SDComment: -SDCategory: Molten Core -EndScriptData */ - -/* ContentData -mob_ancient_core_hound -EndContentData */ - -#include "precompiled.h" -#include "../../creature/simple_ai.h" - -#define SPELL_CONE_OF_FIRE 19630 -#define SPELL_BITE 19771 - -//Random Debuff (each hound has only one of these) -#define SPELL_GROUND_STOMP 19364 -#define SPELL_ANCIENT_DREAD 19365 -#define SPELL_CAUTERIZING_FLAMES 19366 -#define SPELL_WITHERING_HEAT 19367 -#define SPELL_ANCIENT_DESPAIR 19369 -#define SPELL_ANCIENT_HYSTERIA 19372 - -CreatureAI* GetAI_mob_ancient_core_hound(Creature *_Creature) -{ - SimpleAI *ai = new SimpleAI(_Creature); - - ai->Spell[0].Enabled = true; - ai->Spell[0].Spell_Id = SPELL_CONE_OF_FIRE; - ai->Spell[0].Cooldown = 7000; - ai->Spell[0].First_Cast = 10000; - ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; - - uint32 RandDebuff; - switch(rand()%6) - { - case 0 : RandDebuff = SPELL_GROUND_STOMP; break; - case 1 : RandDebuff = SPELL_ANCIENT_DREAD; break; - case 2 : RandDebuff = SPELL_CAUTERIZING_FLAMES; break; - case 3 : RandDebuff = SPELL_WITHERING_HEAT; break; - case 4 : RandDebuff = SPELL_ANCIENT_DESPAIR; break; - case 5 : RandDebuff = SPELL_ANCIENT_HYSTERIA; break; - } - - ai->Spell[1].Enabled = true; - ai->Spell[1].Spell_Id = RandDebuff; - ai->Spell[1].Cooldown = 24000; - ai->Spell[1].First_Cast = 15000; - ai->Spell[1].Cast_Target_Type = CAST_HOSTILE_TARGET; - - ai->Spell[2].Enabled = true; - ai->Spell[2].Spell_Id = SPELL_BITE; - ai->Spell[2].Cooldown = 6000; - ai->Spell[2].First_Cast = 4000; - ai->Spell[2].Cast_Target_Type = CAST_HOSTILE_TARGET; - - ai->EnterEvadeMode(); - - return ai; -} - -void AddSC_molten_core() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_ancient_core_hound"; - newscript->GetAI = GetAI_mob_ancient_core_hound; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Core +SD%Complete: 100 +SDComment: +SDCategory: Molten Core +EndScriptData */ + +/* ContentData +mob_ancient_core_hound +EndContentData */ + +#include "precompiled.h" +#include "../../creature/simple_ai.h" + +#define SPELL_CONE_OF_FIRE 19630 +#define SPELL_BITE 19771 + +//Random Debuff (each hound has only one of these) +#define SPELL_GROUND_STOMP 19364 +#define SPELL_ANCIENT_DREAD 19365 +#define SPELL_CAUTERIZING_FLAMES 19366 +#define SPELL_WITHERING_HEAT 19367 +#define SPELL_ANCIENT_DESPAIR 19369 +#define SPELL_ANCIENT_HYSTERIA 19372 + +CreatureAI* GetAI_mob_ancient_core_hound(Creature *_Creature) +{ + SimpleAI *ai = new SimpleAI(_Creature); + + ai->Spell[0].Enabled = true; + ai->Spell[0].Spell_Id = SPELL_CONE_OF_FIRE; + ai->Spell[0].Cooldown = 7000; + ai->Spell[0].First_Cast = 10000; + ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; + + uint32 RandDebuff; + switch(rand()%6) + { + case 0 : RandDebuff = SPELL_GROUND_STOMP; break; + case 1 : RandDebuff = SPELL_ANCIENT_DREAD; break; + case 2 : RandDebuff = SPELL_CAUTERIZING_FLAMES; break; + case 3 : RandDebuff = SPELL_WITHERING_HEAT; break; + case 4 : RandDebuff = SPELL_ANCIENT_DESPAIR; break; + case 5 : RandDebuff = SPELL_ANCIENT_HYSTERIA; break; + } + + ai->Spell[1].Enabled = true; + ai->Spell[1].Spell_Id = RandDebuff; + ai->Spell[1].Cooldown = 24000; + ai->Spell[1].First_Cast = 15000; + ai->Spell[1].Cast_Target_Type = CAST_HOSTILE_TARGET; + + ai->Spell[2].Enabled = true; + ai->Spell[2].Spell_Id = SPELL_BITE; + ai->Spell[2].Cooldown = 6000; + ai->Spell[2].First_Cast = 4000; + ai->Spell[2].Cast_Target_Type = CAST_HOSTILE_TARGET; + + ai->EnterEvadeMode(); + + return ai; +} + +void AddSC_molten_core() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_ancient_core_hound"; + newscript->GetAI = GetAI_mob_ancient_core_hound; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/moonglade/moonglade.cpp b/src/bindings/scripts/scripts/zone/moonglade/moonglade.cpp index d88aadf04ab..34803d14aec 100644 --- a/src/bindings/scripts/scripts/zone/moonglade/moonglade.cpp +++ b/src/bindings/scripts/scripts/zone/moonglade/moonglade.cpp @@ -1,217 +1,217 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Moonglade -SD%Complete: 100 -SDComment: Quest support: 30, 272, 5929, 5930. Special Flight Paths for Druid class. -SDCategory: Moonglade -EndScriptData */ - -/* ContentData -npc_bunthen_plainswind -npc_great_bear_spirit -npc_silva_filnaveth -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_bunthen_plainswind -######*/ - -bool GossipHello_npc_bunthen_plainswind(Player *player, Creature *_Creature) -{ - if(player->getClass() != CLASS_DRUID) - player->SEND_GOSSIP_MENU(4916,_Creature->GetGUID()); - else if(player->GetTeam() != HORDE) - { - if(player->GetQuestStatus(272) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Do you know where I can find Half Pendant of Aquatic Endurance?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - player->SEND_GOSSIP_MENU(4917,_Creature->GetGUID()); - } - else if(player->getClass() == CLASS_DRUID && player->GetTeam() == HORDE) - { - player->ADD_GOSSIP_ITEM( 0, "I'd like to fly to Thunder Bluff.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if(player->GetQuestStatus(30) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Do you know where I can find Half Pendant of Aquatic Endurance?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - - player->SEND_GOSSIP_MENU(4918,_Creature->GetGUID()); - } - return true; -} - -bool GossipSelect_npc_bunthen_plainswind(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(action) - { - case GOSSIP_ACTION_INFO_DEF + 1: - { - player->CLOSE_GOSSIP_MENU(); - if (player->getClass() == CLASS_DRUID && player->GetTeam() == HORDE) - { - std::vector nodes; - - nodes.resize(2); - nodes[0] = 63; // Nighthaven, Moonglade - nodes[1] = 22; // Thunder Bluff, Mulgore - player->ActivateTaxiPathTo(nodes); - } - break; - } - case GOSSIP_ACTION_INFO_DEF + 2: - player->SEND_GOSSIP_MENU(5373,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->SEND_GOSSIP_MENU(5376,_Creature->GetGUID()); - break; - } - return true; -} - -/*###### -## npc_great_bear_spirit -######*/ - -#define GOSSIP_BEAR1 "What do you represent, spirit?" -#define GOSSIP_BEAR2 "I seek to understand the importance of strength of the body." -#define GOSSIP_BEAR3 "I seek to understand the importance of strength of the heart." -#define GOSSIP_BEAR4 "I have heard your words, Great Bear Spirit, and I understand. I now seek your blessings to fully learn the way of the Claw." - -bool GossipHello_npc_great_bear_spirit(Player *player, Creature *_Creature) -{ - //ally or horde quest - if (player->GetQuestStatus(5929) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(5930) == QUEST_STATUS_INCOMPLETE) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_BEAR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(4719, _Creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(4718, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_great_bear_spirit(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_BEAR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(4721, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 1: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_BEAR3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(4733, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_BEAR4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(4734, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->SEND_GOSSIP_MENU(4735, _Creature->GetGUID()); - if (player->GetQuestStatus(5929)==QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(5929); - if (player->GetQuestStatus(5930)==QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(5930); - break; - } - return true; -} - -/*###### -## npc_silva_filnaveth -######*/ - -bool GossipHello_npc_silva_filnaveth(Player *player, Creature *_Creature) -{ - if(player->getClass() != CLASS_DRUID) - player->SEND_GOSSIP_MENU(4913,_Creature->GetGUID()); - else if(player->GetTeam() != ALLIANCE) - { - if(player->GetQuestStatus(30) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Do you know where I can find Half Pendant of Aquatic Agility?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - player->SEND_GOSSIP_MENU(4915,_Creature->GetGUID()); - } - else if(player->getClass() == CLASS_DRUID && player->GetTeam() == ALLIANCE) - { - player->ADD_GOSSIP_ITEM( 0, "I'd like to fly to Rut'theran Village.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if(player->GetQuestStatus(272) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Do you know where I can find Half Pendant of Aquatic Agility?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - - player->SEND_GOSSIP_MENU(4914,_Creature->GetGUID()); - } - return true; -} - -bool GossipSelect_npc_silva_filnaveth(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch(action) - { - case GOSSIP_ACTION_INFO_DEF + 1: - { - player->CLOSE_GOSSIP_MENU(); - if (player->getClass() == CLASS_DRUID && player->GetTeam() == ALLIANCE) - { - std::vector nodes; - - nodes.resize(2); - nodes[0] = 62; // Nighthaven, Moonglade - nodes[1] = 27; // Rut'theran Village, Teldrassil - player->ActivateTaxiPathTo(nodes); - } - break; - } - case GOSSIP_ACTION_INFO_DEF + 2: - player->SEND_GOSSIP_MENU(5374,_Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->SEND_GOSSIP_MENU(5375,_Creature->GetGUID()); - break; - } - return true; -} - -/*###### -## -######*/ - -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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_great_bear_spirit"; - newscript->pGossipHello = &GossipHello_npc_great_bear_spirit; - newscript->pGossipSelect = &GossipSelect_npc_great_bear_spirit; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_silva_filnaveth"; - newscript->pGossipHello = &GossipHello_npc_silva_filnaveth; - newscript->pGossipSelect = &GossipSelect_npc_silva_filnaveth; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Moonglade +SD%Complete: 100 +SDComment: Quest support: 30, 272, 5929, 5930. Special Flight Paths for Druid class. +SDCategory: Moonglade +EndScriptData */ + +/* ContentData +npc_bunthen_plainswind +npc_great_bear_spirit +npc_silva_filnaveth +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_bunthen_plainswind +######*/ + +bool GossipHello_npc_bunthen_plainswind(Player *player, Creature *_Creature) +{ + if(player->getClass() != CLASS_DRUID) + player->SEND_GOSSIP_MENU(4916,_Creature->GetGUID()); + else if(player->GetTeam() != HORDE) + { + if(player->GetQuestStatus(272) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Do you know where I can find Half Pendant of Aquatic Endurance?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + + player->SEND_GOSSIP_MENU(4917,_Creature->GetGUID()); + } + else if(player->getClass() == CLASS_DRUID && player->GetTeam() == HORDE) + { + player->ADD_GOSSIP_ITEM( 0, "I'd like to fly to Thunder Bluff.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + if(player->GetQuestStatus(30) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Do you know where I can find Half Pendant of Aquatic Endurance?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + + player->SEND_GOSSIP_MENU(4918,_Creature->GetGUID()); + } + return true; +} + +bool GossipSelect_npc_bunthen_plainswind(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(action) + { + case GOSSIP_ACTION_INFO_DEF + 1: + { + player->CLOSE_GOSSIP_MENU(); + if (player->getClass() == CLASS_DRUID && player->GetTeam() == HORDE) + { + std::vector nodes; + + nodes.resize(2); + nodes[0] = 63; // Nighthaven, Moonglade + nodes[1] = 22; // Thunder Bluff, Mulgore + player->ActivateTaxiPathTo(nodes); + } + break; + } + case GOSSIP_ACTION_INFO_DEF + 2: + player->SEND_GOSSIP_MENU(5373,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + player->SEND_GOSSIP_MENU(5376,_Creature->GetGUID()); + break; + } + return true; +} + +/*###### +## npc_great_bear_spirit +######*/ + +#define GOSSIP_BEAR1 "What do you represent, spirit?" +#define GOSSIP_BEAR2 "I seek to understand the importance of strength of the body." +#define GOSSIP_BEAR3 "I seek to understand the importance of strength of the heart." +#define GOSSIP_BEAR4 "I have heard your words, Great Bear Spirit, and I understand. I now seek your blessings to fully learn the way of the Claw." + +bool GossipHello_npc_great_bear_spirit(Player *player, Creature *_Creature) +{ + //ally or horde quest + if (player->GetQuestStatus(5929) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(5930) == QUEST_STATUS_INCOMPLETE) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_BEAR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(4719, _Creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(4718, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_great_bear_spirit(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_BEAR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(4721, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 1: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_BEAR3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(4733, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_BEAR4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(4734, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + player->SEND_GOSSIP_MENU(4735, _Creature->GetGUID()); + if (player->GetQuestStatus(5929)==QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(5929); + if (player->GetQuestStatus(5930)==QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(5930); + break; + } + return true; +} + +/*###### +## npc_silva_filnaveth +######*/ + +bool GossipHello_npc_silva_filnaveth(Player *player, Creature *_Creature) +{ + if(player->getClass() != CLASS_DRUID) + player->SEND_GOSSIP_MENU(4913,_Creature->GetGUID()); + else if(player->GetTeam() != ALLIANCE) + { + if(player->GetQuestStatus(30) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Do you know where I can find Half Pendant of Aquatic Agility?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + + player->SEND_GOSSIP_MENU(4915,_Creature->GetGUID()); + } + else if(player->getClass() == CLASS_DRUID && player->GetTeam() == ALLIANCE) + { + player->ADD_GOSSIP_ITEM( 0, "I'd like to fly to Rut'theran Village.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + if(player->GetQuestStatus(272) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Do you know where I can find Half Pendant of Aquatic Agility?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + + player->SEND_GOSSIP_MENU(4914,_Creature->GetGUID()); + } + return true; +} + +bool GossipSelect_npc_silva_filnaveth(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch(action) + { + case GOSSIP_ACTION_INFO_DEF + 1: + { + player->CLOSE_GOSSIP_MENU(); + if (player->getClass() == CLASS_DRUID && player->GetTeam() == ALLIANCE) + { + std::vector nodes; + + nodes.resize(2); + nodes[0] = 62; // Nighthaven, Moonglade + nodes[1] = 27; // Rut'theran Village, Teldrassil + player->ActivateTaxiPathTo(nodes); + } + break; + } + case GOSSIP_ACTION_INFO_DEF + 2: + player->SEND_GOSSIP_MENU(5374,_Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + player->SEND_GOSSIP_MENU(5375,_Creature->GetGUID()); + break; + } + return true; +} + +/*###### +## +######*/ + +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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_great_bear_spirit"; + newscript->pGossipHello = &GossipHello_npc_great_bear_spirit; + newscript->pGossipSelect = &GossipSelect_npc_great_bear_spirit; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_silva_filnaveth"; + newscript->pGossipHello = &GossipHello_npc_silva_filnaveth; + newscript->pGossipSelect = &GossipSelect_npc_silva_filnaveth; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/mulgore/mulgore.cpp b/src/bindings/scripts/scripts/zone/mulgore/mulgore.cpp index 5e10e3500cb..3c7ca5d4b88 100644 --- a/src/bindings/scripts/scripts/zone/mulgore/mulgore.cpp +++ b/src/bindings/scripts/scripts/zone/mulgore/mulgore.cpp @@ -1,64 +1,64 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Mulgore -SD%Complete: 100 -SDComment: Skorn Whitecloud: Just a story if not rewarded for quest -SDCategory: Mulgore -EndScriptData */ - -/* ContentData -npc_skorn_whitecloud -EndContentData */ - -#include "precompiled.h" - -/*###### -# npc_skorn_whitecloud -######*/ - -bool GossipHello_npc_skorn_whitecloud(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (!player->GetQuestRewardStatus(770)) - player->ADD_GOSSIP_ITEM( 0, "Tell me a story, Skorn.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF ); - - player->SEND_GOSSIP_MENU(522,_Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_skorn_whitecloud(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF) - player->SEND_GOSSIP_MENU(523,_Creature->GetGUID()); - - return true; -} - -void AddSC_mulgore() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_skorn_whitecloud"; - newscript->pGossipHello = &GossipHello_npc_skorn_whitecloud; - newscript->pGossipSelect = &GossipSelect_npc_skorn_whitecloud; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Mulgore +SD%Complete: 100 +SDComment: Skorn Whitecloud: Just a story if not rewarded for quest +SDCategory: Mulgore +EndScriptData */ + +/* ContentData +npc_skorn_whitecloud +EndContentData */ + +#include "precompiled.h" + +/*###### +# npc_skorn_whitecloud +######*/ + +bool GossipHello_npc_skorn_whitecloud(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (!player->GetQuestRewardStatus(770)) + player->ADD_GOSSIP_ITEM( 0, "Tell me a story, Skorn.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF ); + + player->SEND_GOSSIP_MENU(522,_Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_skorn_whitecloud(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF) + player->SEND_GOSSIP_MENU(523,_Creature->GetGUID()); + + return true; +} + +void AddSC_mulgore() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_skorn_whitecloud"; + newscript->pGossipHello = &GossipHello_npc_skorn_whitecloud; + newscript->pGossipSelect = &GossipSelect_npc_skorn_whitecloud; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/nagrand/nagrand.cpp b/src/bindings/scripts/scripts/zone/nagrand/nagrand.cpp index 2713d2b2d94..e2baa602b21 100644 --- a/src/bindings/scripts/scripts/zone/nagrand/nagrand.cpp +++ b/src/bindings/scripts/scripts/zone/nagrand/nagrand.cpp @@ -1,568 +1,568 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Nagrand -SD%Complete: 90 -SDComment: Quest support: 9849, 9918, 9874, 9991, 10107, 10108, 10044, 10172, 10646, 10085. TextId's unknown for altruis_the_sufferer and greatmother_geyah (npc_text) -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_creditmarker_visit_with_ancestors -EndContentData */ - -#include "precompiled.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 *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - Spawn = false; - } - - void Aggro(Unit* who) {} - - 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 *_Creature) -{ - return new mob_shattered_rumblerAI (_Creature); -} - -/*###### -## mob_lump -######*/ - -#define SPELL_VISUAL_SLEEP 16093 -#define SPELL_SPEAR_THROW 32248 - -#define LUMP_SAY0 "In Nagrand, food hunt ogre!" -#define LUMP_SAY1 "You taste good with maybe a little salt and pepper." - -#define LUMP_DEFEAT "OK, OK! Lump give up!" - -struct MANGOS_DLL_DECL mob_lumpAI : public ScriptedAI -{ - mob_lumpAI(Creature *c) : ScriptedAI(c) - { - bReset = false; - Reset(); - } - - uint32 Reset_Timer; - uint32 Spear_Throw_Timer; - bool bReset; - - void Reset() - { - Reset_Timer = 60000; - Spear_Throw_Timer = 2000; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - void DamageTaken(Unit *done_by, uint32 & damage) - { - if (done_by->GetTypeId() == TYPEID_PLAYER && (m_creature->GetHealth() - damage)*100 / m_creature->GetMaxHealth() < 30) - { - if (!bReset && ((Player*)done_by)->GetQuestStatus(9918) == QUEST_STATUS_INCOMPLETE) - { - //Take 0 damage - damage = 0; - - ((Player*)done_by)->AttackStop(); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - m_creature->setFaction(1080); //friendly - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_SIT); - m_creature->Say(LUMP_DEFEAT, LANG_UNIVERSAL, 0); - - bReset = true; - } - } - } - - void Aggro(Unit *who) - { - if (m_creature->HasAura(SPELL_VISUAL_SLEEP,0)) - m_creature->RemoveAura(SPELL_VISUAL_SLEEP,0); - - if (!m_creature->IsStandState()) - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE); - - switch(rand()%2) - { - case 0: - DoSay(LUMP_SAY0,LANG_UNIVERSAL,NULL); - break; - case 1: - DoSay(LUMP_SAY1,LANG_UNIVERSAL,NULL); - break; - } - } - - void UpdateAI(const uint32 diff) - { - //check if we waiting for a reset - if (bReset) - { - if (Reset_Timer < diff) - { - EnterEvadeMode(); - bReset = false; - m_creature->setFaction(1711); //hostile - } - else Reset_Timer -= diff; - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Spear_Throw_Timer - if (Spear_Throw_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SPEAR_THROW); - Spear_Throw_Timer = 20000; - }else Spear_Throw_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_lump(Creature *_creature) -{ - return new mob_lumpAI(_creature); -} - -bool GossipHello_mob_lump(Player *player, Creature *_Creature) -{ - if (player->GetQuestStatus(9918) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "I need answers, ogre!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(9352, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_mob_lump(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, "Why are Boulderfist out this far? You know that this is Kurenai territory.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(9353, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(9354, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "This means war, Lump! War I say!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(9355, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->SEND_GOSSIP_MENU(9356, _Creature->GetGUID()); - player->TalkedToCreature(18354, _Creature->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 *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 32); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,7); // lay down - } - - void Aggro(Unit *who) {} - - 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 *_Creature) -{ - return new mob_sunspring_villagerAI (_Creature); -} - -/*###### -## npc_altruis_the_sufferer -######*/ - -bool GossipHello_npc_altruis_the_sufferer(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - //gossip before obtaining Survey the Land - if ( player->GetQuestStatus(9991) == QUEST_STATUS_NONE ) - player->ADD_GOSSIP_ITEM( 0, "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 (player->GetQuestStatus(9991) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Well...?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+20); - - //wowwiki.com/Varedis - if (player->GetQuestStatus(10646) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "[PH] Story about Illidan's Pupil", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+30); - - player->SEND_GOSSIP_MENU(9419, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_altruis_the_sufferer(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+10: - player->ADD_GOSSIP_ITEM( 0, "Legion?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(9420, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - player->ADD_GOSSIP_ITEM( 0, "And now?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(9421, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+12: - player->ADD_GOSSIP_ITEM( 0, "How do you see them now?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); - player->SEND_GOSSIP_MENU(9422, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+13: - player->ADD_GOSSIP_ITEM( 0, "Forge camps?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); - player->SEND_GOSSIP_MENU(9423, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+14: - player->SEND_GOSSIP_MENU(9424, _Creature->GetGUID()); - break; - - case GOSSIP_ACTION_INFO_DEF+20: - player->ADD_GOSSIP_ITEM( 0, "Ok.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); - player->SEND_GOSSIP_MENU(9427, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+21: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(9991); - break; - - case GOSSIP_ACTION_INFO_DEF+30: - player->ADD_GOSSIP_ITEM( 0, "[PH] Story done", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); - player->SEND_GOSSIP_MENU(384, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+31: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(10646); - break; - } - return true; -} - -bool QuestAccept_npc_altruis_the_sufferer(Player *player, Creature *creature, Quest const *quest ) -{ - if ( !player->GetQuestRewardStatus(9991) ) //Survey the Land, q-id 9991 - { - player->CLOSE_GOSSIP_MENU(); - - std::vector nodes; - - nodes.resize(2); - nodes[0] = 113; //from - nodes[1] = 114; //end at - player->ActivateTaxiPathTo(nodes); //TaxiPath 532 - } - 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 *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(10044) == QUEST_STATUS_INCOMPLETE) - { - player->ADD_GOSSIP_ITEM( 0, "Hello, Greatmother. Garrosh told me that you wanted to speak with me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); - } - else if (player->GetQuestStatus(10172) == QUEST_STATUS_INCOMPLETE) - { - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); - } - else - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_greatmother_geyah(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: - player->ADD_GOSSIP_ITEM( 0, "You raised all of the orcs here, Greatmother?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - player->ADD_GOSSIP_ITEM( 0, "Do you believe that?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: - player->ADD_GOSSIP_ITEM( 0, "Left? How can you choose to leave?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: - player->ADD_GOSSIP_ITEM( 0, "What is this duty?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - player->ADD_GOSSIP_ITEM( 0, "Is there anything I can do for you, Greatmother?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: - player->AreaExploredOrEventHappens(10044); - player->CLOSE_GOSSIP_MENU(); - break; - - case GOSSIP_ACTION_INFO_DEF + 10: - player->ADD_GOSSIP_ITEM( 0, "I have done all that I could, Greatmother. I thank you for your kind words.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: - player->ADD_GOSSIP_ITEM( 0, "Greatmother, you are the mother of Durotan?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 14: - player->ADD_GOSSIP_ITEM( 0, "I will return to Azeroth at once, Greatmother.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 15); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 15: - player->AreaExploredOrEventHappens(10172); - player->CLOSE_GOSSIP_MENU(); - break; - } - return true; -} - -/*###### -## npc_lantresor_of_the_blade -######*/ - -bool GossipHello_npc_lantresor_of_the_blade(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(10107) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10108) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "I have killed many of your ogres, Lantresor. I have no fear.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(9361, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lantresor_of_the_blade(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, "Should I know? You look like an orc to me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(9362, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "And the other half?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(9363, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(9364, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "My apologies. I did not mean to offend. I am here on behalf of my people.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(9365, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(9366, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(9367, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM( 0, "What do I need to do?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(9368, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - player->SEND_GOSSIP_MENU(9369, _Creature->GetGUID()); - if (player->GetQuestStatus(10107) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(10107); - if (player->GetQuestStatus(10108) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(10108); - break; - } - return true; -} - -/*###### -## npc_creditmarker_visist_with_ancestors (Quest 10085) -######*/ - -struct MANGOS_DLL_DECL npc_creditmarker_visit_with_ancestorsAI : public ScriptedAI -{ - npc_creditmarker_visit_with_ancestorsAI(Creature* c) : ScriptedAI(c) { Reset(); } - - void Reset() {} - - void Aggro(Unit* who) {} - - void MoveInLineOfSight(Unit *who) - { - if(!who) - return; - - if(who->GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)who)->GetQuestStatus(10085) == QUEST_STATUS_INCOMPLETE) - { - uint32 creditMarkerId = m_creature->GetEntry(); - if((creditMarkerId >= 18840) && (creditMarkerId <= 18843)) - { - // 18840: Sunspring, 18841: Laughing, 18842: Garadar, 18843: Bleeding - if(!((Player*)who)->GetReqKillOrCastCurrentCount(10085, creditMarkerId)) - ((Player*)who)->KilledMonster(creditMarkerId, m_creature->GetGUID()); - } - } - } - } -}; - -CreatureAI* GetAI_npc_creditmarker_visit_with_ancestors(Creature *_Creature) -{ - return new npc_creditmarker_visit_with_ancestorsAI (_Creature); -} - -/*###### -## AddSC -######*/ - -void AddSC_nagrand() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_shattered_rumbler"; - newscript->GetAI = GetAI_mob_shattered_rumbler; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_lump"; - newscript->GetAI = GetAI_mob_lump; - newscript->pGossipHello = &GossipHello_mob_lump; - newscript->pGossipSelect = &GossipSelect_mob_lump; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_sunspring_villager"; - newscript->GetAI = GetAI_mob_sunspring_villager; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_altruis_the_sufferer"; - newscript->pGossipHello = &GossipHello_npc_altruis_the_sufferer; - newscript->pGossipSelect = &GossipSelect_npc_altruis_the_sufferer; - newscript->pQuestAccept = &QuestAccept_npc_altruis_the_sufferer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_greatmother_geyah"; - newscript->pGossipHello = &GossipHello_npc_greatmother_geyah; - newscript->pGossipSelect = &GossipSelect_npc_greatmother_geyah; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_lantresor_of_the_blade"; - newscript->pGossipHello = &GossipHello_npc_lantresor_of_the_blade; - newscript->pGossipSelect = &GossipSelect_npc_lantresor_of_the_blade; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_creditmarker_visit_with_ancestors"; - newscript->GetAI = GetAI_npc_creditmarker_visit_with_ancestors; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Nagrand +SD%Complete: 90 +SDComment: Quest support: 9849, 9918, 9874, 9991, 10107, 10108, 10044, 10172, 10646, 10085. TextId's unknown for altruis_the_sufferer and greatmother_geyah (npc_text) +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_creditmarker_visit_with_ancestors +EndContentData */ + +#include "precompiled.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 *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + Spawn = false; + } + + void Aggro(Unit* who) {} + + 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 *_Creature) +{ + return new mob_shattered_rumblerAI (_Creature); +} + +/*###### +## mob_lump +######*/ + +#define SPELL_VISUAL_SLEEP 16093 +#define SPELL_SPEAR_THROW 32248 + +#define LUMP_SAY0 "In Nagrand, food hunt ogre!" +#define LUMP_SAY1 "You taste good with maybe a little salt and pepper." + +#define LUMP_DEFEAT "OK, OK! Lump give up!" + +struct MANGOS_DLL_DECL mob_lumpAI : public ScriptedAI +{ + mob_lumpAI(Creature *c) : ScriptedAI(c) + { + bReset = false; + Reset(); + } + + uint32 Reset_Timer; + uint32 Spear_Throw_Timer; + bool bReset; + + void Reset() + { + Reset_Timer = 60000; + Spear_Throw_Timer = 2000; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void DamageTaken(Unit *done_by, uint32 & damage) + { + if (done_by->GetTypeId() == TYPEID_PLAYER && (m_creature->GetHealth() - damage)*100 / m_creature->GetMaxHealth() < 30) + { + if (!bReset && ((Player*)done_by)->GetQuestStatus(9918) == QUEST_STATUS_INCOMPLETE) + { + //Take 0 damage + damage = 0; + + ((Player*)done_by)->AttackStop(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + m_creature->setFaction(1080); //friendly + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_SIT); + m_creature->Say(LUMP_DEFEAT, LANG_UNIVERSAL, 0); + + bReset = true; + } + } + } + + void Aggro(Unit *who) + { + if (m_creature->HasAura(SPELL_VISUAL_SLEEP,0)) + m_creature->RemoveAura(SPELL_VISUAL_SLEEP,0); + + if (!m_creature->IsStandState()) + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE); + + switch(rand()%2) + { + case 0: + DoSay(LUMP_SAY0,LANG_UNIVERSAL,NULL); + break; + case 1: + DoSay(LUMP_SAY1,LANG_UNIVERSAL,NULL); + break; + } + } + + void UpdateAI(const uint32 diff) + { + //check if we waiting for a reset + if (bReset) + { + if (Reset_Timer < diff) + { + EnterEvadeMode(); + bReset = false; + m_creature->setFaction(1711); //hostile + } + else Reset_Timer -= diff; + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Spear_Throw_Timer + if (Spear_Throw_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SPEAR_THROW); + Spear_Throw_Timer = 20000; + }else Spear_Throw_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_lump(Creature *_creature) +{ + return new mob_lumpAI(_creature); +} + +bool GossipHello_mob_lump(Player *player, Creature *_Creature) +{ + if (player->GetQuestStatus(9918) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "I need answers, ogre!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(9352, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_mob_lump(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, "Why are Boulderfist out this far? You know that this is Kurenai territory.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(9353, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(9354, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "This means war, Lump! War I say!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(9355, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->SEND_GOSSIP_MENU(9356, _Creature->GetGUID()); + player->TalkedToCreature(18354, _Creature->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 *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 32); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,7); // lay down + } + + void Aggro(Unit *who) {} + + 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 *_Creature) +{ + return new mob_sunspring_villagerAI (_Creature); +} + +/*###### +## npc_altruis_the_sufferer +######*/ + +bool GossipHello_npc_altruis_the_sufferer(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + //gossip before obtaining Survey the Land + if ( player->GetQuestStatus(9991) == QUEST_STATUS_NONE ) + player->ADD_GOSSIP_ITEM( 0, "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 (player->GetQuestStatus(9991) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Well...?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+20); + + //wowwiki.com/Varedis + if (player->GetQuestStatus(10646) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "[PH] Story about Illidan's Pupil", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+30); + + player->SEND_GOSSIP_MENU(9419, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_altruis_the_sufferer(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+10: + player->ADD_GOSSIP_ITEM( 0, "Legion?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(9420, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+11: + player->ADD_GOSSIP_ITEM( 0, "And now?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(9421, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+12: + player->ADD_GOSSIP_ITEM( 0, "How do you see them now?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); + player->SEND_GOSSIP_MENU(9422, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+13: + player->ADD_GOSSIP_ITEM( 0, "Forge camps?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); + player->SEND_GOSSIP_MENU(9423, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+14: + player->SEND_GOSSIP_MENU(9424, _Creature->GetGUID()); + break; + + case GOSSIP_ACTION_INFO_DEF+20: + player->ADD_GOSSIP_ITEM( 0, "Ok.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); + player->SEND_GOSSIP_MENU(9427, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+21: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(9991); + break; + + case GOSSIP_ACTION_INFO_DEF+30: + player->ADD_GOSSIP_ITEM( 0, "[PH] Story done", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); + player->SEND_GOSSIP_MENU(384, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+31: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(10646); + break; + } + return true; +} + +bool QuestAccept_npc_altruis_the_sufferer(Player *player, Creature *creature, Quest const *quest ) +{ + if ( !player->GetQuestRewardStatus(9991) ) //Survey the Land, q-id 9991 + { + player->CLOSE_GOSSIP_MENU(); + + std::vector nodes; + + nodes.resize(2); + nodes[0] = 113; //from + nodes[1] = 114; //end at + player->ActivateTaxiPathTo(nodes); //TaxiPath 532 + } + 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 *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(10044) == QUEST_STATUS_INCOMPLETE) + { + player->ADD_GOSSIP_ITEM( 0, "Hello, Greatmother. Garrosh told me that you wanted to speak with me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + } + else if (player->GetQuestStatus(10172) == QUEST_STATUS_INCOMPLETE) + { + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + } + else + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_greatmother_geyah(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: + player->ADD_GOSSIP_ITEM( 0, "You raised all of the orcs here, Greatmother?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + player->ADD_GOSSIP_ITEM( 0, "Do you believe that?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: + player->ADD_GOSSIP_ITEM( 0, "Left? How can you choose to leave?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: + player->ADD_GOSSIP_ITEM( 0, "What is this duty?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: + player->ADD_GOSSIP_ITEM( 0, "Is there anything I can do for you, Greatmother?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 7: + player->AreaExploredOrEventHappens(10044); + player->CLOSE_GOSSIP_MENU(); + break; + + case GOSSIP_ACTION_INFO_DEF + 10: + player->ADD_GOSSIP_ITEM( 0, "I have done all that I could, Greatmother. I thank you for your kind words.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: + player->ADD_GOSSIP_ITEM( 0, "Greatmother, you are the mother of Durotan?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 13: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 14: + player->ADD_GOSSIP_ITEM( 0, "I will return to Azeroth at once, Greatmother.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 15); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 15: + player->AreaExploredOrEventHappens(10172); + player->CLOSE_GOSSIP_MENU(); + break; + } + return true; +} + +/*###### +## npc_lantresor_of_the_blade +######*/ + +bool GossipHello_npc_lantresor_of_the_blade(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(10107) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10108) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "I have killed many of your ogres, Lantresor. I have no fear.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(9361, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_lantresor_of_the_blade(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, "Should I know? You look like an orc to me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(9362, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "And the other half?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(9363, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(9364, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "My apologies. I did not mean to offend. I am here on behalf of my people.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(9365, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(9366, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(9367, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + player->ADD_GOSSIP_ITEM( 0, "What do I need to do?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + player->SEND_GOSSIP_MENU(9368, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+7: + player->SEND_GOSSIP_MENU(9369, _Creature->GetGUID()); + if (player->GetQuestStatus(10107) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(10107); + if (player->GetQuestStatus(10108) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(10108); + break; + } + return true; +} + +/*###### +## npc_creditmarker_visist_with_ancestors (Quest 10085) +######*/ + +struct MANGOS_DLL_DECL npc_creditmarker_visit_with_ancestorsAI : public ScriptedAI +{ + npc_creditmarker_visit_with_ancestorsAI(Creature* c) : ScriptedAI(c) { Reset(); } + + void Reset() {} + + void Aggro(Unit* who) {} + + void MoveInLineOfSight(Unit *who) + { + if(!who) + return; + + if(who->GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)who)->GetQuestStatus(10085) == QUEST_STATUS_INCOMPLETE) + { + uint32 creditMarkerId = m_creature->GetEntry(); + if((creditMarkerId >= 18840) && (creditMarkerId <= 18843)) + { + // 18840: Sunspring, 18841: Laughing, 18842: Garadar, 18843: Bleeding + if(!((Player*)who)->GetReqKillOrCastCurrentCount(10085, creditMarkerId)) + ((Player*)who)->KilledMonster(creditMarkerId, m_creature->GetGUID()); + } + } + } + } +}; + +CreatureAI* GetAI_npc_creditmarker_visit_with_ancestors(Creature *_Creature) +{ + return new npc_creditmarker_visit_with_ancestorsAI (_Creature); +} + +/*###### +## AddSC +######*/ + +void AddSC_nagrand() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_shattered_rumbler"; + newscript->GetAI = GetAI_mob_shattered_rumbler; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_lump"; + newscript->GetAI = GetAI_mob_lump; + newscript->pGossipHello = &GossipHello_mob_lump; + newscript->pGossipSelect = &GossipSelect_mob_lump; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_sunspring_villager"; + newscript->GetAI = GetAI_mob_sunspring_villager; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_altruis_the_sufferer"; + newscript->pGossipHello = &GossipHello_npc_altruis_the_sufferer; + newscript->pGossipSelect = &GossipSelect_npc_altruis_the_sufferer; + newscript->pQuestAccept = &QuestAccept_npc_altruis_the_sufferer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_greatmother_geyah"; + newscript->pGossipHello = &GossipHello_npc_greatmother_geyah; + newscript->pGossipSelect = &GossipSelect_npc_greatmother_geyah; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_lantresor_of_the_blade"; + newscript->pGossipHello = &GossipHello_npc_lantresor_of_the_blade; + newscript->pGossipSelect = &GossipSelect_npc_lantresor_of_the_blade; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_creditmarker_visit_with_ancestors"; + newscript->GetAI = GetAI_npc_creditmarker_visit_with_ancestors; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp index d2dbd710cc9..be8562f8986 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp @@ -1,215 +1,215 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Anubrekhan -SD%Complete: 100 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO1 "Just a little taste..." -#define SAY_AGGRO2 "There is no way out." -#define SAY_AGGRO3 "Yes, Run! It makes the blood pump faster!" -#define SAY_GREET "Ahh... welcome to my parlor" -#define SAY_TAUNT1 "I hear little hearts beating. Yesss... beating faster now. Soon the beating will stop." -#define SAY_TAUNT2 "Where to go? What to do? So many choices that all end in pain, end in death." -#define SAY_TAUNT3 "Which one shall I eat first? So difficult to choose... the all smell so delicious." -#define SAY_TAUNT4 "Closer now... tasty morsels. I've been too long without food. Without blood to drink." -#define SAY_SLAY "Shh... it will all be over soon." - -#define SOUND_AGGRO1 8785 -#define SOUND_AGGRO2 8786 -#define SOUND_AGGRO3 8787 -#define SOUND_GREET 8788 -#define SOUND_TAUNT1 8790 -#define SOUND_TAUNT2 8791 -#define SOUND_TAUNT3 8792 -#define SOUND_TAUNT4 8793 -#define SOUND_SLAY 8789 - -#define SPELL_IMPALE 28783 //May be wrong spell id. Causes more dmg than I expect -#define SPELL_LOCUSTSWARM 28785 //This is a self buff that triggers the dmg debuff -#define SPELL_SUMMONGUARD 29508 //Summons 1 crypt guard at targeted location - -#define SPELL_SELF_SPAWN_5 29105 //This spawns 5 corpse scarabs ontop of us (most likely the player casts this on death) -#define SPELL_SELF_SPAWN_10 28864 //This is used by the crypt guards when they die - -struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI -{ - boss_anubrekhanAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Impale_Timer; - uint32 LocustSwarm_Timer; - uint32 Summon_Timer; - bool HasTaunted; - - void Reset() - { - Impale_Timer = 15000; //15 seconds - LocustSwarm_Timer = 80000 + (rand()%40000); //Random time between 80 seconds and 2 minutes for initial cast - Summon_Timer = LocustSwarm_Timer + 45000; //45 seconds after initial locust swarm - } - - void KilledUnit(Unit* Victim) - { - //Force the player to spawn corpse scarabs via spell - Victim->CastSpell(Victim, SPELL_SELF_SPAWN_5, true); - - if (rand()%5) - return; - - DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY); - } - - void Aggro(Unit *who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - break; - } - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - //Begin melee attack if we are within range - DoStartAttackAndMovement(who); - - if (!InCombat) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - break; - } - } - } - else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f)) - { - switch(rand()%5) - { - case 0: - DoYell(SAY_TAUNT1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TAUNT1); - break; - case 1: - DoYell(SAY_TAUNT2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TAUNT2); - break; - case 2: - DoYell(SAY_TAUNT3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TAUNT3); - break; - case 3: - DoYell(SAY_TAUNT4, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TAUNT4); - break; - case 4: - DoYell(SAY_GREET, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_GREET); - break; - } - HasTaunted = true; - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Impale_Timer - if (Impale_Timer < diff) - { - //Cast Impale on a random target - //Do NOT cast it when we are afflicted by locust swarm - if (!m_creature->HasAura(SPELL_LOCUSTSWARM,1)) - { - Unit* target = NULL; - - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target)DoCast(target,SPELL_IMPALE); - } - - Impale_Timer = 15000; - }else Impale_Timer -= diff; - - //LocustSwarm_Timer - if (LocustSwarm_Timer < diff) - { - DoCast(m_creature, SPELL_LOCUSTSWARM); - LocustSwarm_Timer = 90000; - }else LocustSwarm_Timer -= diff; - - //Summon_Timer - if (Summon_Timer < diff) - { - DoCast(m_creature, SPELL_SUMMONGUARD); - Summon_Timer = 45000; - }else Summon_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_anubrekhan(Creature *_Creature) -{ - return new boss_anubrekhanAI (_Creature); -} - -void AddSC_boss_anubrekhan() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_anubrekhan"; - newscript->GetAI = GetAI_boss_anubrekhan; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Anubrekhan +SD%Complete: 100 +SDComment: +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO1 "Just a little taste..." +#define SAY_AGGRO2 "There is no way out." +#define SAY_AGGRO3 "Yes, Run! It makes the blood pump faster!" +#define SAY_GREET "Ahh... welcome to my parlor" +#define SAY_TAUNT1 "I hear little hearts beating. Yesss... beating faster now. Soon the beating will stop." +#define SAY_TAUNT2 "Where to go? What to do? So many choices that all end in pain, end in death." +#define SAY_TAUNT3 "Which one shall I eat first? So difficult to choose... the all smell so delicious." +#define SAY_TAUNT4 "Closer now... tasty morsels. I've been too long without food. Without blood to drink." +#define SAY_SLAY "Shh... it will all be over soon." + +#define SOUND_AGGRO1 8785 +#define SOUND_AGGRO2 8786 +#define SOUND_AGGRO3 8787 +#define SOUND_GREET 8788 +#define SOUND_TAUNT1 8790 +#define SOUND_TAUNT2 8791 +#define SOUND_TAUNT3 8792 +#define SOUND_TAUNT4 8793 +#define SOUND_SLAY 8789 + +#define SPELL_IMPALE 28783 //May be wrong spell id. Causes more dmg than I expect +#define SPELL_LOCUSTSWARM 28785 //This is a self buff that triggers the dmg debuff +#define SPELL_SUMMONGUARD 29508 //Summons 1 crypt guard at targeted location + +#define SPELL_SELF_SPAWN_5 29105 //This spawns 5 corpse scarabs ontop of us (most likely the player casts this on death) +#define SPELL_SELF_SPAWN_10 28864 //This is used by the crypt guards when they die + +struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI +{ + boss_anubrekhanAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Impale_Timer; + uint32 LocustSwarm_Timer; + uint32 Summon_Timer; + bool HasTaunted; + + void Reset() + { + Impale_Timer = 15000; //15 seconds + LocustSwarm_Timer = 80000 + (rand()%40000); //Random time between 80 seconds and 2 minutes for initial cast + Summon_Timer = LocustSwarm_Timer + 45000; //45 seconds after initial locust swarm + } + + void KilledUnit(Unit* Victim) + { + //Force the player to spawn corpse scarabs via spell + Victim->CastSpell(Victim, SPELL_SELF_SPAWN_5, true); + + if (rand()%5) + return; + + DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY); + } + + void Aggro(Unit *who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO3); + break; + } + } + + void MoveInLineOfSight(Unit *who) + { + if (!m_creature->getVictim() && 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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + //Begin melee attack if we are within range + DoStartAttackAndMovement(who); + + if (!InCombat) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO3); + break; + } + } + } + else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f)) + { + switch(rand()%5) + { + case 0: + DoYell(SAY_TAUNT1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TAUNT1); + break; + case 1: + DoYell(SAY_TAUNT2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TAUNT2); + break; + case 2: + DoYell(SAY_TAUNT3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TAUNT3); + break; + case 3: + DoYell(SAY_TAUNT4, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TAUNT4); + break; + case 4: + DoYell(SAY_GREET, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_GREET); + break; + } + HasTaunted = true; + } + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Impale_Timer + if (Impale_Timer < diff) + { + //Cast Impale on a random target + //Do NOT cast it when we are afflicted by locust swarm + if (!m_creature->HasAura(SPELL_LOCUSTSWARM,1)) + { + Unit* target = NULL; + + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target)DoCast(target,SPELL_IMPALE); + } + + Impale_Timer = 15000; + }else Impale_Timer -= diff; + + //LocustSwarm_Timer + if (LocustSwarm_Timer < diff) + { + DoCast(m_creature, SPELL_LOCUSTSWARM); + LocustSwarm_Timer = 90000; + }else LocustSwarm_Timer -= diff; + + //Summon_Timer + if (Summon_Timer < diff) + { + DoCast(m_creature, SPELL_SUMMONGUARD); + Summon_Timer = 45000; + }else Summon_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_anubrekhan(Creature *_Creature) +{ + return new boss_anubrekhanAI (_Creature); +} + +void AddSC_boss_anubrekhan() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_anubrekhan"; + newscript->GetAI = GetAI_boss_anubrekhan; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp index 3faf9ad9634..6dd6faa906f 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp @@ -1,202 +1,202 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Faerlina -SD%Complete: 50 -SDComment: Without Mindcontrol boss cannot be defeated -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -#define SAY_GREET "Your old lives, your mortal desires, mean nothing. You are acolytes of the master now, and you will serve the cause without question! The greatest glory is to die in the master's service!" -#define SAY_AGGRO1 "Slay them in the master's name!" -#define SAY_AGGRO2 "You cannot hide from me!" -#define SAY_AGGRO3 "Kneel before me, worm!" -#define SAY_AGGRO4 "Run while you still can!" -#define SAY_SLAY1 "You have failed!" -#define SAY_SLAY2 "Pathetic wretch!" -#define SAY_DEATH "The master... will avenge me!" -#define SAY_RANDOM_AGGRO "???" - -#define SOUND_GREET 8799 -#define SOUND_AGGRO1 8794 -#define SOUND_AGGRO2 8795 -#define SOUND_AGGRO3 8796 -#define SOUND_AGGRO4 8797 -#define SOUND_SLAY1 8800 -#define SOUND_SLAY2 8801 -#define SOUND_DEATH 8798 -#define SOUND_RANDOM_AGGRO 8955 - -#define SPELL_POSIONBOLT_VOLLEY 28796 -#define SPELL_RAINOFFIRE 28794 //Not sure if targeted AoEs work if casted directly upon a player -#define SPELL_ENRAGE 26527 - -struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI -{ - boss_faerlinaAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 PoisonBoltVolley_Timer; - uint32 RainOfFire_Timer; - uint32 Enrage_Timer; - bool HasTaunted; - - void Reset() - { - PoisonBoltVolley_Timer = 8000; - RainOfFire_Timer = 16000; - Enrage_Timer = 60000; - HasTaunted = false; - } - - void Aggro(Unit *who) - { - switch (rand()%4) - { - case 0: - DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO3); - break; - case 3: - DoYell(SAY_AGGRO4,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO4); - break; - } - } - - void MoveInLineOfSight(Unit *who) - { - 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) - { - if(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - //Say our dialog on initial aggro - if (!InCombat) - { - switch (rand()%4) - { - case 0: - DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO3); - break; - case 3: - DoYell(SAY_AGGRO4,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO4); - break; - } - } - } - else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f)) - { - DoYell(SAY_GREET, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_GREET); - HasTaunted = true; - } - } - } - - void KilledUnit(Unit* victim) - { - switch (rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //PoisonBoltVolley_Timer - if (PoisonBoltVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POSIONBOLT_VOLLEY); - PoisonBoltVolley_Timer = 11000; - }else PoisonBoltVolley_Timer -= diff; - - //RainOfFire_Timer - if (RainOfFire_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_RAINOFFIRE); - - RainOfFire_Timer = 16000; - }else RainOfFire_Timer -= diff; - - //Enrage_Timer - if (Enrage_Timer < diff) - { - DoCast(m_creature,SPELL_ENRAGE); - Enrage_Timer = 61000; - }else Enrage_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_faerlina(Creature *_Creature) -{ - return new boss_faerlinaAI (_Creature); -} - -void AddSC_boss_faerlina() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_faerlina"; - newscript->GetAI = GetAI_boss_faerlina; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Faerlina +SD%Complete: 50 +SDComment: Without Mindcontrol boss cannot be defeated +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +#define SAY_GREET "Your old lives, your mortal desires, mean nothing. You are acolytes of the master now, and you will serve the cause without question! The greatest glory is to die in the master's service!" +#define SAY_AGGRO1 "Slay them in the master's name!" +#define SAY_AGGRO2 "You cannot hide from me!" +#define SAY_AGGRO3 "Kneel before me, worm!" +#define SAY_AGGRO4 "Run while you still can!" +#define SAY_SLAY1 "You have failed!" +#define SAY_SLAY2 "Pathetic wretch!" +#define SAY_DEATH "The master... will avenge me!" +#define SAY_RANDOM_AGGRO "???" + +#define SOUND_GREET 8799 +#define SOUND_AGGRO1 8794 +#define SOUND_AGGRO2 8795 +#define SOUND_AGGRO3 8796 +#define SOUND_AGGRO4 8797 +#define SOUND_SLAY1 8800 +#define SOUND_SLAY2 8801 +#define SOUND_DEATH 8798 +#define SOUND_RANDOM_AGGRO 8955 + +#define SPELL_POSIONBOLT_VOLLEY 28796 +#define SPELL_RAINOFFIRE 28794 //Not sure if targeted AoEs work if casted directly upon a player +#define SPELL_ENRAGE 26527 + +struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI +{ + boss_faerlinaAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 PoisonBoltVolley_Timer; + uint32 RainOfFire_Timer; + uint32 Enrage_Timer; + bool HasTaunted; + + void Reset() + { + PoisonBoltVolley_Timer = 8000; + RainOfFire_Timer = 16000; + Enrage_Timer = 60000; + HasTaunted = false; + } + + void Aggro(Unit *who) + { + switch (rand()%4) + { + case 0: + DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO3); + break; + case 3: + DoYell(SAY_AGGRO4,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO4); + break; + } + } + + void MoveInLineOfSight(Unit *who) + { + if (!m_creature->getVictim() && 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)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + DoStartAttackAndMovement(who); + //Say our dialog on initial aggro + if (!InCombat) + { + switch (rand()%4) + { + case 0: + DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO3); + break; + case 3: + DoYell(SAY_AGGRO4,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO4); + break; + } + } + } + else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f)) + { + DoYell(SAY_GREET, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_GREET); + HasTaunted = true; + } + } + } + + void KilledUnit(Unit* victim) + { + switch (rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //PoisonBoltVolley_Timer + if (PoisonBoltVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POSIONBOLT_VOLLEY); + PoisonBoltVolley_Timer = 11000; + }else PoisonBoltVolley_Timer -= diff; + + //RainOfFire_Timer + if (RainOfFire_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_RAINOFFIRE); + + RainOfFire_Timer = 16000; + }else RainOfFire_Timer -= diff; + + //Enrage_Timer + if (Enrage_Timer < diff) + { + DoCast(m_creature,SPELL_ENRAGE); + Enrage_Timer = 61000; + }else Enrage_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_faerlina(Creature *_Creature) +{ + return new boss_faerlinaAI (_Creature); +} + +void AddSC_boss_faerlina() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_faerlina"; + newscript->GetAI = GetAI_boss_faerlina; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_feugen.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_feugen.cpp index fd03b1757f5..facfa2e29fc 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_feugen.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_feugen.cpp @@ -1,33 +1,33 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Feugen -SD%Complete: 0 -SDComment: Merge with Thaddius -SDCategory: Naxxramas -EndScriptData */ - -//Feugen -//8801 aggro Feed you to master! -//8804 slay Feugen make master happy! -//8803 death No... more... Feugen... - -#include "precompiled.h" - -#define SPELL_WARSTOMP 28125 -#define SPELL_MANABURN 28135 -#define SPELL_CHAIN_LIGHTNING 28900 +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Feugen +SD%Complete: 0 +SDComment: Merge with Thaddius +SDCategory: Naxxramas +EndScriptData */ + +//Feugen +//8801 aggro Feed you to master! +//8804 slay Feugen make master happy! +//8803 death No... more... Feugen... + +#include "precompiled.h" + +#define SPELL_WARSTOMP 28125 +#define SPELL_MANABURN 28135 +#define SPELL_CHAIN_LIGHTNING 28900 diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_gluth.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_gluth.cpp index 72b9b6628de..4008d21f635 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_gluth.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_gluth.cpp @@ -1,174 +1,174 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Gluth -SD%Complete: 100 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_MORTALWOUND 25646 -#define SPELL_DECIMATE 28374 -#define SPELL_TERRIFYINGROAR 29685 -#define SPELL_FRENZY 19812 -#define SPELL_ENRAGE 28747 - -#define ADD_1X 3269.590 -#define ADD_1Y -3161.287 -#define ADD_1Z 297.423 - -#define ADD_2X 3277.797 -#define ADD_2Y -3170.352 -#define ADD_2Z 297.423 - -#define ADD_3X 3267.049 -#define ADD_3Y -3172.820 -#define ADD_3Z 297.423 - -#define ADD_4X 3252.157 -#define ADD_4Y -3132.135 -#define ADD_4Z 297.423 - -#define ADD_5X 3259.990 -#define ADD_5Y -3126.590 -#define ADD_5Z 297.423 - -#define ADD_6X 3259.815 -#define ADD_6Y -3137.576 -#define ADD_6Z 297.423 - -#define ADD_7X 3308.030 -#define ADD_7Y -3132.135 -#define ADD_7Z 297.423 - -#define ADD_8X 3303.046 -#define ADD_8Y -3180.682 -#define ADD_8Z 297.423 - -#define ADD_9X 3313.283 -#define ADD_9Y -3180.766 -#define ADD_9Z 297.423 - -struct MANGOS_DLL_DECL boss_gluthAI : public ScriptedAI -{ - boss_gluthAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 MortalWound_Timer; - uint32 Decimate_Timer; - uint32 TerrifyingRoar_Timer; - uint32 Frenzy_Timer; - uint32 Enrage_Timer; - uint32 Summon_Timer; - - void Reset() - { - MortalWound_Timer = 8000; - Decimate_Timer = 100000; - TerrifyingRoar_Timer = 21000; - Frenzy_Timer = 15000; - Enrage_Timer = 304000; - Summon_Timer = 10000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //MortalWound_Timer - if (MortalWound_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTALWOUND); - MortalWound_Timer = 10000; - }else MortalWound_Timer -= diff; - - //Decimate_Timer - if (Decimate_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DECIMATE); - Decimate_Timer = 100000; - }else Decimate_Timer -= diff; - - //TerrifyingRoar_Timer - if (TerrifyingRoar_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_TERRIFYINGROAR); - TerrifyingRoar_Timer = 20000; - }else TerrifyingRoar_Timer -= diff; - - //Frenzy_Timer - if (Frenzy_Timer < diff) - { - DoCast(m_creature,SPELL_FRENZY); - Frenzy_Timer = 10500; - }else Frenzy_Timer -= diff; - - //Enrage_Timer - if (Enrage_Timer < diff) - { - DoCast(m_creature,SPELL_ENRAGE); - Enrage_Timer = 61000; - }else Enrage_Timer -= diff; - - //Summon_Timer - if (Summon_Timer < diff) - { - Unit* target = NULL; - Unit* SummonedZombies = NULL; - - SummonedZombies = m_creature->SummonCreature(16360,ADD_1X,ADD_1Y,ADD_1Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedZombies = m_creature->SummonCreature(16360,ADD_2X,ADD_2Y,ADD_2Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedZombies = m_creature->SummonCreature(16360,ADD_3X,ADD_3Y,ADD_3Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedZombies = m_creature->SummonCreature(16360,ADD_4X,ADD_4Y,ADD_4Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedZombies = m_creature->SummonCreature(16360,ADD_5X,ADD_5Y,ADD_5Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedZombies = m_creature->SummonCreature(16360,ADD_6X,ADD_6Y,ADD_6Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedZombies = m_creature->SummonCreature(16360,ADD_7X,ADD_7Y,ADD_7Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedZombies = m_creature->SummonCreature(16360,ADD_8X,ADD_8Y,ADD_8Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedZombies = m_creature->SummonCreature(16360,ADD_9X,ADD_9Y,ADD_9Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - - if (SummonedZombies) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - SummonedZombies->AddThreat(target,1.0f); - } - - Summon_Timer = 28000; - } else Summon_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gluth(Creature *_Creature) -{ - return new boss_gluthAI (_Creature); -} - -void AddSC_boss_gluth() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gluth"; - newscript->GetAI = GetAI_boss_gluth; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Gluth +SD%Complete: 100 +SDComment: +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_MORTALWOUND 25646 +#define SPELL_DECIMATE 28374 +#define SPELL_TERRIFYINGROAR 29685 +#define SPELL_FRENZY 19812 +#define SPELL_ENRAGE 28747 + +#define ADD_1X 3269.590 +#define ADD_1Y -3161.287 +#define ADD_1Z 297.423 + +#define ADD_2X 3277.797 +#define ADD_2Y -3170.352 +#define ADD_2Z 297.423 + +#define ADD_3X 3267.049 +#define ADD_3Y -3172.820 +#define ADD_3Z 297.423 + +#define ADD_4X 3252.157 +#define ADD_4Y -3132.135 +#define ADD_4Z 297.423 + +#define ADD_5X 3259.990 +#define ADD_5Y -3126.590 +#define ADD_5Z 297.423 + +#define ADD_6X 3259.815 +#define ADD_6Y -3137.576 +#define ADD_6Z 297.423 + +#define ADD_7X 3308.030 +#define ADD_7Y -3132.135 +#define ADD_7Z 297.423 + +#define ADD_8X 3303.046 +#define ADD_8Y -3180.682 +#define ADD_8Z 297.423 + +#define ADD_9X 3313.283 +#define ADD_9Y -3180.766 +#define ADD_9Z 297.423 + +struct MANGOS_DLL_DECL boss_gluthAI : public ScriptedAI +{ + boss_gluthAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 MortalWound_Timer; + uint32 Decimate_Timer; + uint32 TerrifyingRoar_Timer; + uint32 Frenzy_Timer; + uint32 Enrage_Timer; + uint32 Summon_Timer; + + void Reset() + { + MortalWound_Timer = 8000; + Decimate_Timer = 100000; + TerrifyingRoar_Timer = 21000; + Frenzy_Timer = 15000; + Enrage_Timer = 304000; + Summon_Timer = 10000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //MortalWound_Timer + if (MortalWound_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTALWOUND); + MortalWound_Timer = 10000; + }else MortalWound_Timer -= diff; + + //Decimate_Timer + if (Decimate_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DECIMATE); + Decimate_Timer = 100000; + }else Decimate_Timer -= diff; + + //TerrifyingRoar_Timer + if (TerrifyingRoar_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_TERRIFYINGROAR); + TerrifyingRoar_Timer = 20000; + }else TerrifyingRoar_Timer -= diff; + + //Frenzy_Timer + if (Frenzy_Timer < diff) + { + DoCast(m_creature,SPELL_FRENZY); + Frenzy_Timer = 10500; + }else Frenzy_Timer -= diff; + + //Enrage_Timer + if (Enrage_Timer < diff) + { + DoCast(m_creature,SPELL_ENRAGE); + Enrage_Timer = 61000; + }else Enrage_Timer -= diff; + + //Summon_Timer + if (Summon_Timer < diff) + { + Unit* target = NULL; + Unit* SummonedZombies = NULL; + + SummonedZombies = m_creature->SummonCreature(16360,ADD_1X,ADD_1Y,ADD_1Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedZombies = m_creature->SummonCreature(16360,ADD_2X,ADD_2Y,ADD_2Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedZombies = m_creature->SummonCreature(16360,ADD_3X,ADD_3Y,ADD_3Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedZombies = m_creature->SummonCreature(16360,ADD_4X,ADD_4Y,ADD_4Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedZombies = m_creature->SummonCreature(16360,ADD_5X,ADD_5Y,ADD_5Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedZombies = m_creature->SummonCreature(16360,ADD_6X,ADD_6Y,ADD_6Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedZombies = m_creature->SummonCreature(16360,ADD_7X,ADD_7Y,ADD_7Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedZombies = m_creature->SummonCreature(16360,ADD_8X,ADD_8Y,ADD_8Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedZombies = m_creature->SummonCreature(16360,ADD_9X,ADD_9Y,ADD_9Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + + if (SummonedZombies) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + SummonedZombies->AddThreat(target,1.0f); + } + + Summon_Timer = 28000; + } else Summon_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_gluth(Creature *_Creature) +{ + return new boss_gluthAI (_Creature); +} + +void AddSC_boss_gluth() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gluth"; + newscript->GetAI = GetAI_boss_gluth; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp index 3be2727fe16..dcbe8d9b2d3 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp @@ -1,62 +1,62 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Gothik -SD%Complete: 0 -SDComment: Placeholder -SDCategory: Naxxramas -EndScriptData */ - -//Gothik -//8806 spch - Foolishly you have sought your own demise. Brazenly you have disregarded powers beyond your understanding. You have fought hard to invade the realm of the harvester. Now there is only one way out - to walk the lonely path of the damned. -//8808 tlpt - I have waited long enough! Now, you face the harvester of souls! -//8806 slay - Death is the only escape. -//8805 death - I... am... undone! - -#include "precompiled.h" - -//Gothik -#define SPELL_HARVESTSOUL 28679 -#define SPELL_SHADOWBOLT 19729 - -//Unrelenting Trainee -#define SPELL_EAGLECLAW 30285 -#define SPELL_KNOCKDOWN_PASSIVE 6961 - -//Unrelenting Deathknight -#define SPELL_CHARGE 22120 -#define SPELL_SHADOW_MARK 27825 - -//Unrelenting Rider -#define SPELL_UNHOLY_AURA 28340 -#define SPELL_SHADOWBOLT 19729 //Search thru targets and find those who have the SHADOW_MARK to cast this on - -//Spectral Trainee -#define SPELL_ARCANE_EXPLOSION 27989 - -//Spectral Deathknight -#define SPELL_WHIRLWIND 28334 -#define SPELL_SUNDER_ARMOR 25051 //cannot find sunder that reduces armor by 2950 -#define SPELL_CLEAVE 20677 -#define SPELL_MANA_BURN 17631 - -//Spectral Rider -#define SPELL_LIFEDRAIN 24300 -//USES SAME UNHOLY AURA AS UNRELENTING RIDER - -//Spectral Horse -#define SPELL_STOMP 27993 +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Gothik +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Naxxramas +EndScriptData */ + +//Gothik +//8806 spch - Foolishly you have sought your own demise. Brazenly you have disregarded powers beyond your understanding. You have fought hard to invade the realm of the harvester. Now there is only one way out - to walk the lonely path of the damned. +//8808 tlpt - I have waited long enough! Now, you face the harvester of souls! +//8806 slay - Death is the only escape. +//8805 death - I... am... undone! + +#include "precompiled.h" + +//Gothik +#define SPELL_HARVESTSOUL 28679 +#define SPELL_SHADOWBOLT 19729 + +//Unrelenting Trainee +#define SPELL_EAGLECLAW 30285 +#define SPELL_KNOCKDOWN_PASSIVE 6961 + +//Unrelenting Deathknight +#define SPELL_CHARGE 22120 +#define SPELL_SHADOW_MARK 27825 + +//Unrelenting Rider +#define SPELL_UNHOLY_AURA 28340 +#define SPELL_SHADOWBOLT 19729 //Search thru targets and find those who have the SHADOW_MARK to cast this on + +//Spectral Trainee +#define SPELL_ARCANE_EXPLOSION 27989 + +//Spectral Deathknight +#define SPELL_WHIRLWIND 28334 +#define SPELL_SUNDER_ARMOR 25051 //cannot find sunder that reduces armor by 2950 +#define SPELL_CLEAVE 20677 +#define SPELL_MANA_BURN 17631 + +//Spectral Rider +#define SPELL_LIFEDRAIN 24300 +//USES SAME UNHOLY AURA AS UNRELENTING RIDER + +//Spectral Horse +#define SPELL_STOMP 27993 diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_grobbulus.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_grobbulus.cpp index cbe7657ed57..22cc93e89b1 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_grobbulus.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_grobbulus.cpp @@ -1,30 +1,30 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Grobbulus -SD%Complete: 0 -SDComment: Place holder -SDCategory: Naxxramas -EndScriptData */ - -/*Poison Cloud 26590 -Slime Spray 28157 -Fallout slime 28218 -Mutating Injection 28169 -Enrages 26527*/ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Grobbulus +SD%Complete: 0 +SDComment: Place holder +SDCategory: Naxxramas +EndScriptData */ + +/*Poison Cloud 26590 +Slime Spray 28157 +Fallout slime 28218 +Mutating Injection 28169 +Enrages 26527*/ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_heigan.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_heigan.cpp index 147eae49e22..e8a1e78a883 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_heigan.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_heigan.cpp @@ -1,46 +1,46 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Heigan -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Naxxramas -EndScriptData */ - -//Lotheb or Heigan? -//8825 aggro1 - You are mine now! -//8826 aggro2 - I see you! -//8827 aggro3 - You...are next! -//8828 death - -//8829 slay - close your eyes... sleep -//8830 taunt1 - The races of the world will perish. It is only a matter of time. -//8831 taunt2 - I see endless suffering, I see torment, I see rage. I see... everything! -//8832 taunt3 - Soon... the world will tremble! -//8833 taunt4 - The end is upon you. -//8834 taunt5 - Hungry worms will feast on your rotten flesh! - -#include "precompiled.h" - -//Spell used by floor peices to cause damage to players -#define SPELL_ERUPTION 29371 - -//Spells by boss -#define SPELL_WILT 23772 -#define SPELL_FEAVER 29998 - -//Spell by eye stalks -#define SPELL_MIND_FLAY 26143 +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Heigan +SD%Complete: 0 +SDComment: Place Holder +SDCategory: Naxxramas +EndScriptData */ + +//Lotheb or Heigan? +//8825 aggro1 - You are mine now! +//8826 aggro2 - I see you! +//8827 aggro3 - You...are next! +//8828 death - +//8829 slay - close your eyes... sleep +//8830 taunt1 - The races of the world will perish. It is only a matter of time. +//8831 taunt2 - I see endless suffering, I see torment, I see rage. I see... everything! +//8832 taunt3 - Soon... the world will tremble! +//8833 taunt4 - The end is upon you. +//8834 taunt5 - Hungry worms will feast on your rotten flesh! + +#include "precompiled.h" + +//Spell used by floor peices to cause damage to players +#define SPELL_ERUPTION 29371 + +//Spells by boss +#define SPELL_WILT 23772 +#define SPELL_FEAVER 29998 + +//Spell by eye stalks +#define SPELL_MIND_FLAY 26143 diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_highlord_mograine.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_highlord_mograine.cpp index 0641d6d66a3..912d769a202 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_highlord_mograine.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_highlord_mograine.cpp @@ -1,178 +1,178 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Mograine -SD%Complete: 100 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -//All horsemen -#define SPELL_SHIELDWALL 29061 -#define SPELL_BESERK 26662 - -// highlord mograine -#define SPELL_MARK_OF_MOGRAINE 28834 -#define SPELL_RIGHTEOUS_FIRE 28882 // Applied as a 25% chance on melee hit to proc. m_creature->GetVictim() - -#define SAY_TAUNT1 "Enough prattling. Let them come! We shall grind their bones to dust." -#define SAY_TAUNT2 "Conserve your anger! Harness your rage! You will all have outlets for your frustration soon enough." -#define SAY_TAUNT3 "Life is meaningless. It is in death that we are truly tested." -#define SAY_AGGRO1 "You seek death?" -#define SAY_AGGRO2 "None shall pass!" -#define SAY_AGGRO3 "Be still!" -#define SAY_SLAY1 "You will find no peace in death." -#define SAY_SLAY2 "The master's will is done." -#define SAY_SPECIAL "Bow to the might of the Highlord!" -#define SAY_DEATH "I... am... released! Perhaps it's not too late to - noo! I need... more time..." - -#define SOUND_TAUNT1 8842 -#define SOUND_TAUNT2 8843 -#define SOUND_TAUNT3 8844 -#define SOUND_AGGRO1 8835 -#define SOUND_AGGRO2 8836 -#define SOUND_AGGRO3 8837 -#define SOUND_SLAY1 8839 -#define SOUND_SLAY2 8840 -#define SOUND_SPECIAL 8841 -#define SOUND_DEATH 8838 - -#define SPIRIT_OF_MOGRAINE 16775 - -struct MANGOS_DLL_DECL boss_highlord_mograineAI : public ScriptedAI -{ - boss_highlord_mograineAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Mark_Timer; - uint32 RighteousFire_Timer; - bool ShieldWall1; - bool ShieldWall2; - - void Reset() - { - Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. - RighteousFire_Timer = 2000; // applied approx 1 out of 4 attacks - ShieldWall1 = true; - ShieldWall2 = true; - } - - void InitialYell() - { - if(!InCombat) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO3); - break; - } - } - } - - void KilledUnit() - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - InitialYell(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - // Mark of Mograine - if(Mark_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MARK_OF_MOGRAINE); - Mark_Timer = 12000; - }else Mark_Timer -= diff; - - // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds - if(ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) - { - if(ShieldWall1) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall1 = false; - } - } - if(ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) - { - if(ShieldWall2) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall2 = false; - } - } - - // Righteous Fire - if(RighteousFire_Timer < diff) - { - if(rand()%4 == 1) // 1/4 - { - DoCast(m_creature->getVictim(),SPELL_RIGHTEOUS_FIRE); - } - RighteousFire_Timer = 2000; - }else RighteousFire_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_highlord_mograine(Creature *_Creature) -{ - return new boss_highlord_mograineAI (_Creature); -} - -void AddSC_boss_highlord_mograine() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_highlord_mograine"; - newscript->GetAI = GetAI_boss_highlord_mograine; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Mograine +SD%Complete: 100 +SDComment: +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//All horsemen +#define SPELL_SHIELDWALL 29061 +#define SPELL_BESERK 26662 + +// highlord mograine +#define SPELL_MARK_OF_MOGRAINE 28834 +#define SPELL_RIGHTEOUS_FIRE 28882 // Applied as a 25% chance on melee hit to proc. m_creature->GetVictim() + +#define SAY_TAUNT1 "Enough prattling. Let them come! We shall grind their bones to dust." +#define SAY_TAUNT2 "Conserve your anger! Harness your rage! You will all have outlets for your frustration soon enough." +#define SAY_TAUNT3 "Life is meaningless. It is in death that we are truly tested." +#define SAY_AGGRO1 "You seek death?" +#define SAY_AGGRO2 "None shall pass!" +#define SAY_AGGRO3 "Be still!" +#define SAY_SLAY1 "You will find no peace in death." +#define SAY_SLAY2 "The master's will is done." +#define SAY_SPECIAL "Bow to the might of the Highlord!" +#define SAY_DEATH "I... am... released! Perhaps it's not too late to - noo! I need... more time..." + +#define SOUND_TAUNT1 8842 +#define SOUND_TAUNT2 8843 +#define SOUND_TAUNT3 8844 +#define SOUND_AGGRO1 8835 +#define SOUND_AGGRO2 8836 +#define SOUND_AGGRO3 8837 +#define SOUND_SLAY1 8839 +#define SOUND_SLAY2 8840 +#define SOUND_SPECIAL 8841 +#define SOUND_DEATH 8838 + +#define SPIRIT_OF_MOGRAINE 16775 + +struct MANGOS_DLL_DECL boss_highlord_mograineAI : public ScriptedAI +{ + boss_highlord_mograineAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Mark_Timer; + uint32 RighteousFire_Timer; + bool ShieldWall1; + bool ShieldWall2; + + void Reset() + { + Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. + RighteousFire_Timer = 2000; // applied approx 1 out of 4 attacks + ShieldWall1 = true; + ShieldWall2 = true; + } + + void InitialYell() + { + if(!InCombat) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO3); + break; + } + } + } + + void KilledUnit() + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + InitialYell(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + // Mark of Mograine + if(Mark_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MARK_OF_MOGRAINE); + Mark_Timer = 12000; + }else Mark_Timer -= diff; + + // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds + if(ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) + { + if(ShieldWall1) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall1 = false; + } + } + if(ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) + { + if(ShieldWall2) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall2 = false; + } + } + + // Righteous Fire + if(RighteousFire_Timer < diff) + { + if(rand()%4 == 1) // 1/4 + { + DoCast(m_creature->getVictim(),SPELL_RIGHTEOUS_FIRE); + } + RighteousFire_Timer = 2000; + }else RighteousFire_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_highlord_mograine(Creature *_Creature) +{ + return new boss_highlord_mograineAI (_Creature); +} + +void AddSC_boss_highlord_mograine() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_highlord_mograine"; + newscript->GetAI = GetAI_boss_highlord_mograine; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_kelthuzad.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_kelthuzad.cpp index 4f8e2e9470f..27c10592b97 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_kelthuzad.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_kelthuzad.cpp @@ -1,542 +1,542 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_KelThuzud -SD%Complete: 0 -SDComment: VERIFY SCRIPT -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -//***THIS SCRIPTS IS UNDER DEVELOPMENT*** -/* -DATA. -This script has been made with info taken from wowwikki... so there are things wrong... -like spell timers and Says. Also there's another major problem as there is no aggroed list -I cannot make Kel'thuzad to target specific party members, that is needed for spells like -Mana Detonation... so what I'm doing untill now is just to cast everything on my main aggroed -target. Sorry for him. -Another bug is that there are spells that are actually NOT working... I have to implement -them first. -Need DISPELL efect -I also don't know the emotes -*/ - -//Kel'thuzad. Still don't know where to use these... -//Dialog -//8878 dialog01 - Our preparations continue as planned, master. -//8881 lich_naxx_dialog01 - 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. -//8879 dialog02 - I see no complications... Wait... What is this? -//8882 lich_naxx_dialog03 - Your security measures have failed! See to this interruption immediately! -//8880 dialog03 - Yes, master! -//Bigglesworth death -//No!!! A curse upon you, interlopers! The armies of the Lich King will hunt you down. You will not escape your fate... -//slay -//8818 - -//common needed defines -#define NAXXRAMAS_MAP 533 -//Positional defines -#define ADDX_LEFT_FAR 3783.272705 -#define ADDY_LEFT_FAR -5062.697266 -#define ADDZ_LEFT_FAR 143.711203 -#define ADDO_LEFT_FAR 3.617599 - -#define ADDX_LEFT_MIDDLE 3730.291260 -#define ADDY_LEFT_MIDDLE -5027.239258 -#define ADDZ_LEFT_MIDDLE 143.956909 -#define ADDO_LEFT_MIDDLE 4.461900 - -#define ADDX_LEFT_NEAR 3683.868652 -#define ADDY_LEFT_NEAR -5057.281250 -#define ADDZ_LEFT_NEAR 143.183884 -#define ADDO_LEFT_NEAR 5.237086 - -#define ADDX_RIGHT_FAR 3759.355225 -#define ADDY_RIGHT_FAR -5174.128418 -#define ADDZ_RIGHT_FAR 143.802383 -#define ADDO_RIGHT_FAR 2.170104 - -#define ADDX_RIGHT_MIDDLE 370.724365 -#define ADDY_RIGHT_MIDDLE -5185.123047 -#define ADDZ_RIGHT_MIDDLE 143.928024 -#define ADDO_RIGHT_MIDDLE 1.309310 - -#define ADDX_RIGHT_NEAR 3665.121094 -#define ADDY_RIGHT_NEAR -5138.679199 -#define ADDZ_RIGHT_NEAR 143.183212 -#define ADDO_RIGHT_NEAR 0.604023 - -#define WALKX_LEFT_FAR 3754.431396 -#define WALKY_LEFT_FAR -5080.727734 -#define WALKZ_LEFT_FAR 142.036316 -#define WALKO_LEFT_FAR 3.736189 - -#define WALKX_LEFT_MIDDLE 3724.396484 -#define WALKY_LEFT_MIDDLE -5061.330566 -#define WALKZ_LEFT_MIDDLE 142.032700 -#define WALKO_LEFT_MIDDLE 4.564785 - -#define WALKX_LEFT_NEAR 3687.158424 -#define WALKY_LEFT_NEAR -5076.834473 -#define WALKZ_LEFT_NEAR 142.017319 -#define WALKO_LEFT_NEAR 5.237086 - -#define WALKX_RIGHT_FAR 3687.571777 -#define WALKY_RIGHT_FAR -5126.831055 -#define WALKZ_RIGHT_FAR 142.017807 -#define WALKO_RIGHT_FAR 0.604023 - -#define WALKX_RIGHT_MIDDLE 3707.990733 -#define WALKY_RIGHT_MIDDLE -5151.450195 -#define WALKZ_RIGHT_MIDDLE 142.032562 -#define WALKO_RIGHT_MIDDLE 1.376855 - -#define WALKX_RIGHT_NEAR 3739.500000 -#define WALKY_RIGHT_NEAR -5141.883989 -#define WALKZ_RIGHT_NEAR 142.0141130 -#define WALKO_RIGHT_NEAR 2.121412 - -//spells to be casted -#define SPELL_FROST_BOLT 28478 -#define SPELL_FROST_BOLT_NOVA 28479 -#define SPELL_CHAINS_OF_KELTHUZAD 28410 -#define SPELL_MANA_DETONATION 27819 -#define SPELL_SHADOW_FISURE 27810 -#define SPELL_FROST_BLAST 27808 - -//On Aggro -#define SAY_ARRIVAL1 "PRAY FOR MERCY!" -#define SOUND_ARRIVAL1 8809 -#define SAY_ARRIVAL3 "SCREAM YOR DYING BREATH!" -#define SOUND_ARRIVAL3 8810 -#define SAY_ARRIVAL5 "THE END IS UPON YOU!" -#define SOUND_ARRIVAL5 8811 - -//On Summon -#define SAY_REINFORCEMENTS1 "MINIONS, SERVANTS, SOLDIERS OF THE COLD DARK, OBEY THE CALL OF KEL'THUZAD!" -#define SOUND_REINFORCEMENTS1 8819 -#define SAY_REINFORCEMENTS2 "MASTER, I REQUIRE AID!" -#define SOUND_REINFORCEMENTS2 8816 -#define SAY_LICH_NAXX_SUMMON "VERY WELL. WARRIORS OF THE FROZEN WASTES RISE UP!. I COMMAND YOU TO FIGHT, KILL AND DIE AND DIE FOR YOUR MASTER! LET NONE SURVIVE!" -#define SOUND_LICH_NAXX_SUMMON 8824 - -//Random 1/4 taunt said when player enters 300 yards -#define SAY_TAUNT01 "WHO DARES VIOLATE THE SACTITY OF MY DOMAIN? BE WARNED, ALL WHO TRASPASS HERE ARE DOOMED" -#define SOUND_TAUNT01 8820 -#define SAY_TAUNT02 "FOOLS, YOU THINK YOURSELVES TRIUMPHANT? YOU HAVE ONLY TAKEN ONE STEP CLOSER TO THE ABYSS!" -#define SOUND_TAUNT02 8821 -#define SAY_TAUNT03 "I GROW TIRED OF THESE GAMES. PROCEED, AND I WILL BANISH YOUR SOULS TO OBLIVION!" -#define SOUND_TAUNT03 8822 -#define SAY_TAUNT04 "YOU HAVE NO IDEA WHAT HORRORS LIE AHEAD. YOU HAVE SEEN NOTHING! THE FROZEN HEART OF NAXXRAMAS AWAITS YOU!" -#define SOUND_TAUNT04 8823 - -//On kill unit -#define SAY_SLAY "THE DARK VOID AWAITS YOU!" -#define SOUND_SLAY 8817 - -//Specials -#define SAY_FROST "I WILL FREEZE THE BLOOD IN YOUR VEINS!" -#define SOUND_FROST 8815 -#define SAY_CHAIN1 "YOUR SOUL IS BOUND TO ME NOW!" -#define SOUND_CHAIN1 8812 -#define SAY_CHAIN2 "THERE WILL BE NO ESCAPE!" -#define SOUND_CHAIN2 8813 -#define SAY_SPECIAL1 "YOUR PETTY MAGICS ARE NO CHALLENGE TO THE MIGTH OF THE SCOURGE" -#define SOUND_SPECIAL1 9088 -#define SAY_SPECIAL2 "ENOUGH! I GROW TIRED OF THESE DISTRACTIONS!" -#define SOUND_SPECIAL2 9090 -#define SAY_DISPEL "FOOLS, YOU HAVE SPREAD YOUR POWERS TOO THIN. BE FREE, MY MINIONS!" -#define SOUND_DISPEL 9089 - -//On death -#define SAY_DEATH "DO NOT REJOICE... YOUR VICTORY IS A HOLLOW ONE... FOR I SHALL RETURN WITH POWERS BEYOND YOUR IMAGINING!" -#define SOUND_DEATH 8814 - -struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI -{ - boss_kelthuzadAI(Creature* c) : ScriptedAI(c) - { - GuardiansOfIcecrown[0] = 0; - GuardiansOfIcecrown[1] = 0; - GuardiansOfIcecrown[2] = 0; - GuardiansOfIcecrown[3] = 0; - GuardiansOfIcecrown[4] = 0; - GuardiansOfIcecrown_Count = 0; - Reset(); - } - - uint64 GuardiansOfIcecrown[5]; - uint32 GuardiansOfIcecrown_Count; - uint32 GuardiansOfIcecrown_Timer; - uint32 FrostBolt_Timer; - uint32 FrostBoltNova_Timer; - uint32 ChainsOfKelthuzad_Timer; - uint32 ManaDetonation_Timer; - uint32 ShadowFisure_Timer; - uint32 FrostBlast_Timer; - uint32 ChainsOfKelthuzad_Targets; - uint32 Phase1_Timer; - bool Phase2; - bool Phase3; - - void Reset() - { - FrostBolt_Timer = (rand()%60)*1000; //It won't be more than a minute without cast it - FrostBoltNova_Timer = 15000; //Cast every 15 seconds - ChainsOfKelthuzad_Timer = (rand()%30+30)*1000; //Cast no sooner than once every 30 seconds - ManaDetonation_Timer = 20000; //Seems to cast about every 20 seconds - ShadowFisure_Timer = 25000; //25 seconds - FrostBlast_Timer = (rand()%30+30)*1000; //Random time between 30-60 seconds - GuardiansOfIcecrown_Timer = 5000; //5 seconds for summoning each Guardian of Icecrown in phase 3 - - for(int i=0; i<5; i++) - if(GuardiansOfIcecrown[i]) - { - //delete creature - Unit* pUnit = Unit::GetUnit((*m_creature), GuardiansOfIcecrown[i]); - if (pUnit && pUnit->isAlive()) - pUnit->DealDamage(pUnit, pUnit->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - GuardiansOfIcecrown[i] = 0; - } - - Phase1_Timer = 310000; //Phase 1 lasts 5 minutes and 10 seconds - Phase2 = false; - Phase3 = false; - } - - void KilledUnit() - { - if (rand()%5) - return; - - DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - for(int i=0; i<5; i++) - if(GuardiansOfIcecrown[i]) - { - Unit* pUnit = Unit::GetUnit((*m_creature), GuardiansOfIcecrown[i]); - if (!pUnit || !pUnit->isAlive()) - continue; - - pUnit->CombatStop(); - float Walk_Pos_X; - float Walk_Pos_Y; - float Walk_Pos_Z; - switch(rand()%6) - { - case 0: - Walk_Pos_X = ADDX_LEFT_FAR; - Walk_Pos_Y = ADDY_LEFT_FAR; - Walk_Pos_Z = ADDZ_LEFT_FAR; - break; - case 1: - Walk_Pos_X = ADDX_LEFT_MIDDLE; - Walk_Pos_Y = ADDY_LEFT_MIDDLE; - Walk_Pos_Z = ADDZ_LEFT_MIDDLE; - break; - case 2: - Walk_Pos_X = ADDX_LEFT_NEAR; - Walk_Pos_Y = ADDY_LEFT_NEAR; - Walk_Pos_Z = ADDZ_LEFT_NEAR; - break; - case 3: - Walk_Pos_X = ADDX_RIGHT_FAR; - Walk_Pos_Y = ADDY_RIGHT_FAR; - Walk_Pos_Z = ADDZ_RIGHT_FAR; - break; - case 4: - Walk_Pos_X = ADDX_RIGHT_MIDDLE; - Walk_Pos_Y = ADDY_RIGHT_MIDDLE; - Walk_Pos_Z = ADDZ_RIGHT_MIDDLE; - break; - case 5: - Walk_Pos_X = ADDX_RIGHT_NEAR; - Walk_Pos_Y = ADDY_RIGHT_NEAR; - Walk_Pos_Z = ADDZ_RIGHT_NEAR; - break; - } - pUnit->SendMonsterMoveWithSpeed(Walk_Pos_X, Walk_Pos_Y, Walk_Pos_Z,MOVEMENTFLAG_WALK_MODE); - } - } - - void SayInitialAggro() //randomly select 1 of 3 say for aggro - { - switch(rand()%3) - { - case 0: - DoYell(SAY_ARRIVAL1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_ARRIVAL1); - break; - case 1: - DoYell(SAY_ARRIVAL3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_ARRIVAL3); - break; - case 2: - DoYell(SAY_ARRIVAL5,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_ARRIVAL5); - break; - } - } - - void Aggro(Unit* who) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_ARRIVAL1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_ARRIVAL1); - break; - case 1: - DoYell(SAY_ARRIVAL3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_ARRIVAL3); - break; - case 2: - DoYell(SAY_ARRIVAL5,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_ARRIVAL5); - break; - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget()) - return; - - if(m_creature->getVictim() && m_creature->isAlive()) - { - //Check for Frost Bolt - if(FrostBolt_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROST_BOLT); - - if(rand()%2 == 0) - { - DoYell(SAY_FROST,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_FROST); - } - //Cast again on time - FrostBolt_Timer = (rand()%60)*1000; - } - else FrostBolt_Timer -= diff; - - //Check for Frost Bolt Nova - if(FrostBoltNova_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROST_BOLT_NOVA); - - if(rand()%2 == 0) - { - DoYell(SAY_FROST,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_FROST); - } - - FrostBoltNova_Timer = 15000; - } - else FrostBoltNova_Timer -= diff; - - //Check for Chains Of Kelthuzad - if(ChainsOfKelthuzad_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CHAINS_OF_KELTHUZAD); - - if(rand()%2 == 0) - if(rand()%2 == 0) - { - DoYell(SAY_CHAIN1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_CHAIN1); - } - else - { - DoYell(SAY_CHAIN2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_CHAIN2); - } - - //cast again on time - ChainsOfKelthuzad_Timer = (rand()%30+30)*1000; - } - else ChainsOfKelthuzad_Timer -= diff; - - //Check for Mana Detonation - if(ManaDetonation_Timer < diff) - { - //time to cast - //DoCast(m_creature->getVictim(),SPELL_MANA_DETONATION); - - if(rand()%2 == 0) - { - DoYell(SAY_SPECIAL1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SPECIAL1); - } - ManaDetonation_Timer = 20000; - } - else ManaDetonation_Timer -= diff; - - //Check for Shadow Fissure - if(ShadowFisure_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOW_FISURE); - - if(rand()%2 == 0) - { - DoYell(SAY_SPECIAL2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SPECIAL2); - } - - ShadowFisure_Timer = 25000; - } - else ShadowFisure_Timer -= diff; - - //Check for Frost Blast - if(FrostBlast_Timer < diff) - { - //time to cast - //DoCast(m_creature->getVictim(),SPELL_FROST_BLAST); - - if(rand()%2 == 0) - { - DoYell(SAY_FROST,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_FROST); - } - - FrostBlast_Timer = (rand()%30+30)*1000; - } - else FrostBlast_Timer -= diff; - - //start phase 3 when we are 40% health - if(!Phase3 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 40) - { - Phase3 = true; - switch(rand()%2) - { - case 1: - DoYell(SAY_REINFORCEMENTS1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_REINFORCEMENTS1); - break; - case 2: - DoYell(SAY_REINFORCEMENTS2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_REINFORCEMENTS2); - break; - } - //here Lich King should respond to KelThuzad but I don't know which creature to make talk - //so for now just make Kelthuzad says it. - DoPlaySoundToSet(m_creature,SOUND_LICH_NAXX_SUMMON); - } - - if(Phase3 && (GuardiansOfIcecrown_Count < 5)) - if(GuardiansOfIcecrown_Timer < diff) - { - //Summon a Guardian of Icecrown in a random alcove (Creature # 16441) - //uint32 TimeToWalk; - Unit* pUnit = NULL; - float Walk_Pos_X; - float Walk_Pos_Y; - float Walk_Pos_Z; - switch(rand()%6) - { - case 0: - pUnit = m_creature->SummonCreature(16441,ADDX_LEFT_FAR,ADDY_LEFT_FAR,ADDZ_LEFT_FAR,ADDO_LEFT_FAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); - //Setting walk position - Walk_Pos_X = WALKX_LEFT_FAR; - Walk_Pos_Y = WALKY_LEFT_FAR; - Walk_Pos_Z = WALKZ_LEFT_FAR; - break; - case 1: - pUnit = m_creature->SummonCreature(16441,ADDX_LEFT_MIDDLE,ADDY_LEFT_MIDDLE,ADDZ_LEFT_MIDDLE,ADDO_LEFT_MIDDLE,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); - //Start moving guardian towards the center of the room - Walk_Pos_X = WALKX_LEFT_MIDDLE; - Walk_Pos_Y = WALKY_LEFT_MIDDLE; - Walk_Pos_Z = WALKZ_LEFT_MIDDLE; - break; - case 2: - pUnit = m_creature->SummonCreature(16441,ADDX_LEFT_NEAR,ADDY_LEFT_NEAR,ADDZ_LEFT_NEAR,ADDO_LEFT_NEAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); - //Start moving guardian towards the center of the room - Walk_Pos_X = WALKX_LEFT_NEAR; - Walk_Pos_Y = WALKY_LEFT_NEAR; - Walk_Pos_Z = WALKZ_LEFT_NEAR; - break; - case 3: - - pUnit = m_creature->SummonCreature(16441,ADDX_RIGHT_FAR,ADDY_RIGHT_FAR,ADDZ_RIGHT_FAR,ADDO_RIGHT_FAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); - //Start moving guardian towards the center of the room - Walk_Pos_X = WALKX_RIGHT_FAR; - Walk_Pos_Y = WALKY_RIGHT_FAR; - Walk_Pos_Z = WALKZ_RIGHT_FAR; - break; - case 4: - pUnit = m_creature->SummonCreature(16441,ADDX_RIGHT_MIDDLE,ADDY_RIGHT_MIDDLE,ADDZ_RIGHT_MIDDLE,ADDO_RIGHT_MIDDLE,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); - //Start moving guardian towards the center of the room - Walk_Pos_X = WALKX_RIGHT_MIDDLE; - Walk_Pos_Y = WALKY_RIGHT_MIDDLE; - Walk_Pos_Z = WALKZ_RIGHT_MIDDLE; - break; - case 5: - pUnit = m_creature->SummonCreature(16441,ADDX_RIGHT_NEAR,ADDY_RIGHT_NEAR,ADDZ_RIGHT_NEAR,ADDO_RIGHT_NEAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); - //Start moving guardian towards the center of the room - Walk_Pos_X = WALKX_RIGHT_NEAR; - Walk_Pos_Y = WALKY_RIGHT_NEAR; - Walk_Pos_Z = WALKZ_RIGHT_NEAR; - break; - } - - if (pUnit) - { - //if we find no one to figth walk to the center - if(!pUnit->isInCombat()) - pUnit->SendMonsterMoveWithSpeed(Walk_Pos_X,Walk_Pos_Y,Walk_Pos_Z,MOVEMENTFLAG_WALK_MODE); - - //Safe storing of creatures - GuardiansOfIcecrown[GuardiansOfIcecrown_Count] = pUnit->GetGUID(); - - //Update guardian count - GuardiansOfIcecrown_Count++; - - } - //5 seconds until summoning next guardian - GuardiansOfIcecrown_Timer = 5000; - } - else GuardiansOfIcecrown_Timer -= diff; - - DoMeleeAttackIfReady(); - } - } -}; - -CreatureAI* GetAI_boss_kelthuzadAI(Creature *_Creature) -{ - return new boss_kelthuzadAI (_Creature); -} - -void AddSC_boss_kelthuzad() -{ - //This script is disabled until it has been throughly tested - - /* - Script *newscript; - newscript = new Script; - newscript->Name="boss_kelthuzad"; - newscript->GetAI = GetAI_boss_kelthuzadAI; - m_scripts[nrscripts++] = newscript; - */ -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_KelThuzud +SD%Complete: 0 +SDComment: VERIFY SCRIPT +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//***THIS SCRIPTS IS UNDER DEVELOPMENT*** +/* +DATA. +This script has been made with info taken from wowwikki... so there are things wrong... +like spell timers and Says. Also there's another major problem as there is no aggroed list +I cannot make Kel'thuzad to target specific party members, that is needed for spells like +Mana Detonation... so what I'm doing untill now is just to cast everything on my main aggroed +target. Sorry for him. +Another bug is that there are spells that are actually NOT working... I have to implement +them first. +Need DISPELL efect +I also don't know the emotes +*/ + +//Kel'thuzad. Still don't know where to use these... +//Dialog +//8878 dialog01 - Our preparations continue as planned, master. +//8881 lich_naxx_dialog01 - 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. +//8879 dialog02 - I see no complications... Wait... What is this? +//8882 lich_naxx_dialog03 - Your security measures have failed! See to this interruption immediately! +//8880 dialog03 - Yes, master! +//Bigglesworth death +//No!!! A curse upon you, interlopers! The armies of the Lich King will hunt you down. You will not escape your fate... +//slay +//8818 + +//common needed defines +#define NAXXRAMAS_MAP 533 +//Positional defines +#define ADDX_LEFT_FAR 3783.272705 +#define ADDY_LEFT_FAR -5062.697266 +#define ADDZ_LEFT_FAR 143.711203 +#define ADDO_LEFT_FAR 3.617599 + +#define ADDX_LEFT_MIDDLE 3730.291260 +#define ADDY_LEFT_MIDDLE -5027.239258 +#define ADDZ_LEFT_MIDDLE 143.956909 +#define ADDO_LEFT_MIDDLE 4.461900 + +#define ADDX_LEFT_NEAR 3683.868652 +#define ADDY_LEFT_NEAR -5057.281250 +#define ADDZ_LEFT_NEAR 143.183884 +#define ADDO_LEFT_NEAR 5.237086 + +#define ADDX_RIGHT_FAR 3759.355225 +#define ADDY_RIGHT_FAR -5174.128418 +#define ADDZ_RIGHT_FAR 143.802383 +#define ADDO_RIGHT_FAR 2.170104 + +#define ADDX_RIGHT_MIDDLE 370.724365 +#define ADDY_RIGHT_MIDDLE -5185.123047 +#define ADDZ_RIGHT_MIDDLE 143.928024 +#define ADDO_RIGHT_MIDDLE 1.309310 + +#define ADDX_RIGHT_NEAR 3665.121094 +#define ADDY_RIGHT_NEAR -5138.679199 +#define ADDZ_RIGHT_NEAR 143.183212 +#define ADDO_RIGHT_NEAR 0.604023 + +#define WALKX_LEFT_FAR 3754.431396 +#define WALKY_LEFT_FAR -5080.727734 +#define WALKZ_LEFT_FAR 142.036316 +#define WALKO_LEFT_FAR 3.736189 + +#define WALKX_LEFT_MIDDLE 3724.396484 +#define WALKY_LEFT_MIDDLE -5061.330566 +#define WALKZ_LEFT_MIDDLE 142.032700 +#define WALKO_LEFT_MIDDLE 4.564785 + +#define WALKX_LEFT_NEAR 3687.158424 +#define WALKY_LEFT_NEAR -5076.834473 +#define WALKZ_LEFT_NEAR 142.017319 +#define WALKO_LEFT_NEAR 5.237086 + +#define WALKX_RIGHT_FAR 3687.571777 +#define WALKY_RIGHT_FAR -5126.831055 +#define WALKZ_RIGHT_FAR 142.017807 +#define WALKO_RIGHT_FAR 0.604023 + +#define WALKX_RIGHT_MIDDLE 3707.990733 +#define WALKY_RIGHT_MIDDLE -5151.450195 +#define WALKZ_RIGHT_MIDDLE 142.032562 +#define WALKO_RIGHT_MIDDLE 1.376855 + +#define WALKX_RIGHT_NEAR 3739.500000 +#define WALKY_RIGHT_NEAR -5141.883989 +#define WALKZ_RIGHT_NEAR 142.0141130 +#define WALKO_RIGHT_NEAR 2.121412 + +//spells to be casted +#define SPELL_FROST_BOLT 28478 +#define SPELL_FROST_BOLT_NOVA 28479 +#define SPELL_CHAINS_OF_KELTHUZAD 28410 +#define SPELL_MANA_DETONATION 27819 +#define SPELL_SHADOW_FISURE 27810 +#define SPELL_FROST_BLAST 27808 + +//On Aggro +#define SAY_ARRIVAL1 "PRAY FOR MERCY!" +#define SOUND_ARRIVAL1 8809 +#define SAY_ARRIVAL3 "SCREAM YOR DYING BREATH!" +#define SOUND_ARRIVAL3 8810 +#define SAY_ARRIVAL5 "THE END IS UPON YOU!" +#define SOUND_ARRIVAL5 8811 + +//On Summon +#define SAY_REINFORCEMENTS1 "MINIONS, SERVANTS, SOLDIERS OF THE COLD DARK, OBEY THE CALL OF KEL'THUZAD!" +#define SOUND_REINFORCEMENTS1 8819 +#define SAY_REINFORCEMENTS2 "MASTER, I REQUIRE AID!" +#define SOUND_REINFORCEMENTS2 8816 +#define SAY_LICH_NAXX_SUMMON "VERY WELL. WARRIORS OF THE FROZEN WASTES RISE UP!. I COMMAND YOU TO FIGHT, KILL AND DIE AND DIE FOR YOUR MASTER! LET NONE SURVIVE!" +#define SOUND_LICH_NAXX_SUMMON 8824 + +//Random 1/4 taunt said when player enters 300 yards +#define SAY_TAUNT01 "WHO DARES VIOLATE THE SACTITY OF MY DOMAIN? BE WARNED, ALL WHO TRASPASS HERE ARE DOOMED" +#define SOUND_TAUNT01 8820 +#define SAY_TAUNT02 "FOOLS, YOU THINK YOURSELVES TRIUMPHANT? YOU HAVE ONLY TAKEN ONE STEP CLOSER TO THE ABYSS!" +#define SOUND_TAUNT02 8821 +#define SAY_TAUNT03 "I GROW TIRED OF THESE GAMES. PROCEED, AND I WILL BANISH YOUR SOULS TO OBLIVION!" +#define SOUND_TAUNT03 8822 +#define SAY_TAUNT04 "YOU HAVE NO IDEA WHAT HORRORS LIE AHEAD. YOU HAVE SEEN NOTHING! THE FROZEN HEART OF NAXXRAMAS AWAITS YOU!" +#define SOUND_TAUNT04 8823 + +//On kill unit +#define SAY_SLAY "THE DARK VOID AWAITS YOU!" +#define SOUND_SLAY 8817 + +//Specials +#define SAY_FROST "I WILL FREEZE THE BLOOD IN YOUR VEINS!" +#define SOUND_FROST 8815 +#define SAY_CHAIN1 "YOUR SOUL IS BOUND TO ME NOW!" +#define SOUND_CHAIN1 8812 +#define SAY_CHAIN2 "THERE WILL BE NO ESCAPE!" +#define SOUND_CHAIN2 8813 +#define SAY_SPECIAL1 "YOUR PETTY MAGICS ARE NO CHALLENGE TO THE MIGTH OF THE SCOURGE" +#define SOUND_SPECIAL1 9088 +#define SAY_SPECIAL2 "ENOUGH! I GROW TIRED OF THESE DISTRACTIONS!" +#define SOUND_SPECIAL2 9090 +#define SAY_DISPEL "FOOLS, YOU HAVE SPREAD YOUR POWERS TOO THIN. BE FREE, MY MINIONS!" +#define SOUND_DISPEL 9089 + +//On death +#define SAY_DEATH "DO NOT REJOICE... YOUR VICTORY IS A HOLLOW ONE... FOR I SHALL RETURN WITH POWERS BEYOND YOUR IMAGINING!" +#define SOUND_DEATH 8814 + +struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI +{ + boss_kelthuzadAI(Creature* c) : ScriptedAI(c) + { + GuardiansOfIcecrown[0] = 0; + GuardiansOfIcecrown[1] = 0; + GuardiansOfIcecrown[2] = 0; + GuardiansOfIcecrown[3] = 0; + GuardiansOfIcecrown[4] = 0; + GuardiansOfIcecrown_Count = 0; + Reset(); + } + + uint64 GuardiansOfIcecrown[5]; + uint32 GuardiansOfIcecrown_Count; + uint32 GuardiansOfIcecrown_Timer; + uint32 FrostBolt_Timer; + uint32 FrostBoltNova_Timer; + uint32 ChainsOfKelthuzad_Timer; + uint32 ManaDetonation_Timer; + uint32 ShadowFisure_Timer; + uint32 FrostBlast_Timer; + uint32 ChainsOfKelthuzad_Targets; + uint32 Phase1_Timer; + bool Phase2; + bool Phase3; + + void Reset() + { + FrostBolt_Timer = (rand()%60)*1000; //It won't be more than a minute without cast it + FrostBoltNova_Timer = 15000; //Cast every 15 seconds + ChainsOfKelthuzad_Timer = (rand()%30+30)*1000; //Cast no sooner than once every 30 seconds + ManaDetonation_Timer = 20000; //Seems to cast about every 20 seconds + ShadowFisure_Timer = 25000; //25 seconds + FrostBlast_Timer = (rand()%30+30)*1000; //Random time between 30-60 seconds + GuardiansOfIcecrown_Timer = 5000; //5 seconds for summoning each Guardian of Icecrown in phase 3 + + for(int i=0; i<5; i++) + if(GuardiansOfIcecrown[i]) + { + //delete creature + Unit* pUnit = Unit::GetUnit((*m_creature), GuardiansOfIcecrown[i]); + if (pUnit && pUnit->isAlive()) + pUnit->DealDamage(pUnit, pUnit->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + GuardiansOfIcecrown[i] = 0; + } + + Phase1_Timer = 310000; //Phase 1 lasts 5 minutes and 10 seconds + Phase2 = false; + Phase3 = false; + } + + void KilledUnit() + { + if (rand()%5) + return; + + DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + for(int i=0; i<5; i++) + if(GuardiansOfIcecrown[i]) + { + Unit* pUnit = Unit::GetUnit((*m_creature), GuardiansOfIcecrown[i]); + if (!pUnit || !pUnit->isAlive()) + continue; + + pUnit->CombatStop(); + float Walk_Pos_X; + float Walk_Pos_Y; + float Walk_Pos_Z; + switch(rand()%6) + { + case 0: + Walk_Pos_X = ADDX_LEFT_FAR; + Walk_Pos_Y = ADDY_LEFT_FAR; + Walk_Pos_Z = ADDZ_LEFT_FAR; + break; + case 1: + Walk_Pos_X = ADDX_LEFT_MIDDLE; + Walk_Pos_Y = ADDY_LEFT_MIDDLE; + Walk_Pos_Z = ADDZ_LEFT_MIDDLE; + break; + case 2: + Walk_Pos_X = ADDX_LEFT_NEAR; + Walk_Pos_Y = ADDY_LEFT_NEAR; + Walk_Pos_Z = ADDZ_LEFT_NEAR; + break; + case 3: + Walk_Pos_X = ADDX_RIGHT_FAR; + Walk_Pos_Y = ADDY_RIGHT_FAR; + Walk_Pos_Z = ADDZ_RIGHT_FAR; + break; + case 4: + Walk_Pos_X = ADDX_RIGHT_MIDDLE; + Walk_Pos_Y = ADDY_RIGHT_MIDDLE; + Walk_Pos_Z = ADDZ_RIGHT_MIDDLE; + break; + case 5: + Walk_Pos_X = ADDX_RIGHT_NEAR; + Walk_Pos_Y = ADDY_RIGHT_NEAR; + Walk_Pos_Z = ADDZ_RIGHT_NEAR; + break; + } + pUnit->SendMonsterMoveWithSpeed(Walk_Pos_X, Walk_Pos_Y, Walk_Pos_Z,MOVEMENTFLAG_WALK_MODE); + } + } + + void SayInitialAggro() //randomly select 1 of 3 say for aggro + { + switch(rand()%3) + { + case 0: + DoYell(SAY_ARRIVAL1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_ARRIVAL1); + break; + case 1: + DoYell(SAY_ARRIVAL3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_ARRIVAL3); + break; + case 2: + DoYell(SAY_ARRIVAL5,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_ARRIVAL5); + break; + } + } + + void Aggro(Unit* who) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_ARRIVAL1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_ARRIVAL1); + break; + case 1: + DoYell(SAY_ARRIVAL3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_ARRIVAL3); + break; + case 2: + DoYell(SAY_ARRIVAL5,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_ARRIVAL5); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget()) + return; + + if(m_creature->getVictim() && m_creature->isAlive()) + { + //Check for Frost Bolt + if(FrostBolt_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROST_BOLT); + + if(rand()%2 == 0) + { + DoYell(SAY_FROST,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_FROST); + } + //Cast again on time + FrostBolt_Timer = (rand()%60)*1000; + } + else FrostBolt_Timer -= diff; + + //Check for Frost Bolt Nova + if(FrostBoltNova_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROST_BOLT_NOVA); + + if(rand()%2 == 0) + { + DoYell(SAY_FROST,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_FROST); + } + + FrostBoltNova_Timer = 15000; + } + else FrostBoltNova_Timer -= diff; + + //Check for Chains Of Kelthuzad + if(ChainsOfKelthuzad_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CHAINS_OF_KELTHUZAD); + + if(rand()%2 == 0) + if(rand()%2 == 0) + { + DoYell(SAY_CHAIN1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_CHAIN1); + } + else + { + DoYell(SAY_CHAIN2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_CHAIN2); + } + + //cast again on time + ChainsOfKelthuzad_Timer = (rand()%30+30)*1000; + } + else ChainsOfKelthuzad_Timer -= diff; + + //Check for Mana Detonation + if(ManaDetonation_Timer < diff) + { + //time to cast + //DoCast(m_creature->getVictim(),SPELL_MANA_DETONATION); + + if(rand()%2 == 0) + { + DoYell(SAY_SPECIAL1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SPECIAL1); + } + ManaDetonation_Timer = 20000; + } + else ManaDetonation_Timer -= diff; + + //Check for Shadow Fissure + if(ShadowFisure_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOW_FISURE); + + if(rand()%2 == 0) + { + DoYell(SAY_SPECIAL2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SPECIAL2); + } + + ShadowFisure_Timer = 25000; + } + else ShadowFisure_Timer -= diff; + + //Check for Frost Blast + if(FrostBlast_Timer < diff) + { + //time to cast + //DoCast(m_creature->getVictim(),SPELL_FROST_BLAST); + + if(rand()%2 == 0) + { + DoYell(SAY_FROST,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_FROST); + } + + FrostBlast_Timer = (rand()%30+30)*1000; + } + else FrostBlast_Timer -= diff; + + //start phase 3 when we are 40% health + if(!Phase3 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 40) + { + Phase3 = true; + switch(rand()%2) + { + case 1: + DoYell(SAY_REINFORCEMENTS1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_REINFORCEMENTS1); + break; + case 2: + DoYell(SAY_REINFORCEMENTS2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_REINFORCEMENTS2); + break; + } + //here Lich King should respond to KelThuzad but I don't know which creature to make talk + //so for now just make Kelthuzad says it. + DoPlaySoundToSet(m_creature,SOUND_LICH_NAXX_SUMMON); + } + + if(Phase3 && (GuardiansOfIcecrown_Count < 5)) + if(GuardiansOfIcecrown_Timer < diff) + { + //Summon a Guardian of Icecrown in a random alcove (Creature # 16441) + //uint32 TimeToWalk; + Unit* pUnit = NULL; + float Walk_Pos_X; + float Walk_Pos_Y; + float Walk_Pos_Z; + switch(rand()%6) + { + case 0: + pUnit = m_creature->SummonCreature(16441,ADDX_LEFT_FAR,ADDY_LEFT_FAR,ADDZ_LEFT_FAR,ADDO_LEFT_FAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); + //Setting walk position + Walk_Pos_X = WALKX_LEFT_FAR; + Walk_Pos_Y = WALKY_LEFT_FAR; + Walk_Pos_Z = WALKZ_LEFT_FAR; + break; + case 1: + pUnit = m_creature->SummonCreature(16441,ADDX_LEFT_MIDDLE,ADDY_LEFT_MIDDLE,ADDZ_LEFT_MIDDLE,ADDO_LEFT_MIDDLE,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); + //Start moving guardian towards the center of the room + Walk_Pos_X = WALKX_LEFT_MIDDLE; + Walk_Pos_Y = WALKY_LEFT_MIDDLE; + Walk_Pos_Z = WALKZ_LEFT_MIDDLE; + break; + case 2: + pUnit = m_creature->SummonCreature(16441,ADDX_LEFT_NEAR,ADDY_LEFT_NEAR,ADDZ_LEFT_NEAR,ADDO_LEFT_NEAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); + //Start moving guardian towards the center of the room + Walk_Pos_X = WALKX_LEFT_NEAR; + Walk_Pos_Y = WALKY_LEFT_NEAR; + Walk_Pos_Z = WALKZ_LEFT_NEAR; + break; + case 3: + + pUnit = m_creature->SummonCreature(16441,ADDX_RIGHT_FAR,ADDY_RIGHT_FAR,ADDZ_RIGHT_FAR,ADDO_RIGHT_FAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); + //Start moving guardian towards the center of the room + Walk_Pos_X = WALKX_RIGHT_FAR; + Walk_Pos_Y = WALKY_RIGHT_FAR; + Walk_Pos_Z = WALKZ_RIGHT_FAR; + break; + case 4: + pUnit = m_creature->SummonCreature(16441,ADDX_RIGHT_MIDDLE,ADDY_RIGHT_MIDDLE,ADDZ_RIGHT_MIDDLE,ADDO_RIGHT_MIDDLE,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); + //Start moving guardian towards the center of the room + Walk_Pos_X = WALKX_RIGHT_MIDDLE; + Walk_Pos_Y = WALKY_RIGHT_MIDDLE; + Walk_Pos_Z = WALKZ_RIGHT_MIDDLE; + break; + case 5: + pUnit = m_creature->SummonCreature(16441,ADDX_RIGHT_NEAR,ADDY_RIGHT_NEAR,ADDZ_RIGHT_NEAR,ADDO_RIGHT_NEAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); + //Start moving guardian towards the center of the room + Walk_Pos_X = WALKX_RIGHT_NEAR; + Walk_Pos_Y = WALKY_RIGHT_NEAR; + Walk_Pos_Z = WALKZ_RIGHT_NEAR; + break; + } + + if (pUnit) + { + //if we find no one to figth walk to the center + if(!pUnit->isInCombat()) + pUnit->SendMonsterMoveWithSpeed(Walk_Pos_X,Walk_Pos_Y,Walk_Pos_Z,MOVEMENTFLAG_WALK_MODE); + + //Safe storing of creatures + GuardiansOfIcecrown[GuardiansOfIcecrown_Count] = pUnit->GetGUID(); + + //Update guardian count + GuardiansOfIcecrown_Count++; + + } + //5 seconds until summoning next guardian + GuardiansOfIcecrown_Timer = 5000; + } + else GuardiansOfIcecrown_Timer -= diff; + + DoMeleeAttackIfReady(); + } + } +}; + +CreatureAI* GetAI_boss_kelthuzadAI(Creature *_Creature) +{ + return new boss_kelthuzadAI (_Creature); +} + +void AddSC_boss_kelthuzad() +{ + //This script is disabled until it has been throughly tested + + /* + Script *newscript; + newscript = new Script; + newscript->Name="boss_kelthuzad"; + newscript->GetAI = GetAI_boss_kelthuzadAI; + m_scripts[nrscripts++] = newscript; + */ +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_lady_blaumeux.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_lady_blaumeux.cpp index 6946e962aae..932e2e00cdf 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_lady_blaumeux.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_lady_blaumeux.cpp @@ -1,147 +1,147 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Blaumeux -SD%Complete: 100 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -//All horsemen -#define SPELL_SHIELDWALL 29061 -#define SPELL_BESERK 26662 - -// lady blaumeux -#define SPELL_MARK_OF_BLAUMEUX 28833 -#define SPELL_VOIDZONE 28863 - -#define SAY_AGGRO "Defend youself!" -#define SAY_TAUNT1 "Come, Zeliek, do not drive them out. Not before we've had our fun." -#define SAY_TAUNT2 "I do hope they stay alive long enough for me to... introduce myself." -#define SAY_TAUNT3 "The first kill goes to me! Anyone care to wager?" -#define SAY_SPECIAL "Your life is mine!" -#define SAY_SLAY "Who's next?" -#define SAY_DEATH "Tou... che!" - -#define SOUND_AGGRO 8892 -#define SOUND_TAUNT1 8896 -#define SOUND_TAUNT2 8897 -#define SOUND_TAUNT3 8898 -#define SOUND_SPECIAL 8895 -#define SOUND_SLAY 8894 -#define SOUND_DEATH 8893 - -#define SPIRIT_OF_BLAUMEUX 16776 - -struct MANGOS_DLL_DECL boss_lady_blaumeuxAI : public ScriptedAI -{ - boss_lady_blaumeuxAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Mark_Timer; - uint32 VoidZone_Timer; - bool ShieldWall1; - bool ShieldWall2; - - void Reset() - { - Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. - VoidZone_Timer = 12000; // right - ShieldWall1 = true; - ShieldWall2 = true; - } - - void InitialYell() - { - if(!InCombat) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - } - - void KilledUnit() - { - DoYell(SAY_SLAY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void Aggro(Unit *who) - { - InitialYell(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - // Mark of Blaumeux - if(Mark_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MARK_OF_BLAUMEUX); - Mark_Timer = 12000; - }else Mark_Timer -= diff; - - // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds - if(ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) - { - if(ShieldWall1) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall1 = false; - } - } - if(ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) - { - if(ShieldWall2) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall2 = false; - } - } - - // Void Zone - if(VoidZone_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_VOIDZONE); - VoidZone_Timer = 12000; - }else VoidZone_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_lady_blaumeux(Creature *_Creature) -{ - return new boss_lady_blaumeuxAI (_Creature); -} - -void AddSC_boss_lady_blaumeux() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_lady_blaumeux"; - newscript->GetAI = GetAI_boss_lady_blaumeux; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Blaumeux +SD%Complete: 100 +SDComment: +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//All horsemen +#define SPELL_SHIELDWALL 29061 +#define SPELL_BESERK 26662 + +// lady blaumeux +#define SPELL_MARK_OF_BLAUMEUX 28833 +#define SPELL_VOIDZONE 28863 + +#define SAY_AGGRO "Defend youself!" +#define SAY_TAUNT1 "Come, Zeliek, do not drive them out. Not before we've had our fun." +#define SAY_TAUNT2 "I do hope they stay alive long enough for me to... introduce myself." +#define SAY_TAUNT3 "The first kill goes to me! Anyone care to wager?" +#define SAY_SPECIAL "Your life is mine!" +#define SAY_SLAY "Who's next?" +#define SAY_DEATH "Tou... che!" + +#define SOUND_AGGRO 8892 +#define SOUND_TAUNT1 8896 +#define SOUND_TAUNT2 8897 +#define SOUND_TAUNT3 8898 +#define SOUND_SPECIAL 8895 +#define SOUND_SLAY 8894 +#define SOUND_DEATH 8893 + +#define SPIRIT_OF_BLAUMEUX 16776 + +struct MANGOS_DLL_DECL boss_lady_blaumeuxAI : public ScriptedAI +{ + boss_lady_blaumeuxAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Mark_Timer; + uint32 VoidZone_Timer; + bool ShieldWall1; + bool ShieldWall2; + + void Reset() + { + Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. + VoidZone_Timer = 12000; // right + ShieldWall1 = true; + ShieldWall2 = true; + } + + void InitialYell() + { + if(!InCombat) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + } + + void KilledUnit() + { + DoYell(SAY_SLAY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void Aggro(Unit *who) + { + InitialYell(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + // Mark of Blaumeux + if(Mark_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MARK_OF_BLAUMEUX); + Mark_Timer = 12000; + }else Mark_Timer -= diff; + + // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds + if(ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) + { + if(ShieldWall1) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall1 = false; + } + } + if(ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) + { + if(ShieldWall2) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall2 = false; + } + } + + // Void Zone + if(VoidZone_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_VOIDZONE); + VoidZone_Timer = 12000; + }else VoidZone_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_lady_blaumeux(Creature *_Creature) +{ + return new boss_lady_blaumeuxAI (_Creature); +} + +void AddSC_boss_lady_blaumeux() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_lady_blaumeux"; + newscript->GetAI = GetAI_boss_lady_blaumeux; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_loatheb.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_loatheb.cpp index cc4390ceb8e..1c759fdba49 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_loatheb.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_loatheb.cpp @@ -1,216 +1,216 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Loatheb -SD%Complete: 100 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO1 "You are mine now!" -#define SAY_AGGRO2 "I see you!" -#define SAY_AGGRO3 "You...are next!" -#define SAY_SLAY1 "Close your eyes... sleep!" -#define SAY_SLAY2 "The races of the world will perish. It is only a matter of time." -#define SAY_SLAY3 "I see endless suffering, I see torment, I see rage. I see... everything!" -#define SAY_SLAY4 "Soon... the world will tremble!" -#define SAY_SLAY5 "The end is upon you." -#define SAY_SLAY6 "Hungry worms will feast on your rotten flesh!" -#define SAY_DEATH "" - -#define SOUND_AGGRO1 8825 -#define SOUND_AGGRO2 8826 -#define SOUND_AGGRO3 8827 -#define SOUND_SLAY1 8829 -#define SOUND_SLAY2 8830 -#define SOUND_SLAY3 8831 -#define SOUND_SLAY4 8832 -#define SOUND_SLAY5 8833 -#define SOUND_SLAY6 8834 -#define SOUND_DEATH 8828 - -#define SPELL_CORRUPTED_MIND 29198 -#define SPELL_POISON_AURA 29865 -#define SPELL_INEVITABLE_DOOM 29204 -#define SPELL_REMOVE_CURSE 30281 - -#define ADD_1X 2957.040 -#define ADD_1Y -3997.590 -#define ADD_1Z 274.280 - -#define ADD_2X 2909.130 -#define ADD_2Y -4042.970 -#define ADD_2Z 274.280 - -#define ADD_3X 2861.102 -#define ADD_3Y -3997.901 -#define ADD_3Z 274.280 - -struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI -{ - boss_loathebAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 CorruptedMind_Timer; - uint32 PoisonAura_Timer; - uint32 InevitableDoom_Timer; - uint32 InevitableDoom5mins_Timer; - uint32 RemoveCurse_Timer; - uint32 Summon_Timer; - - void Reset() - { - CorruptedMind_Timer = 4000; - PoisonAura_Timer = 2500; - InevitableDoom_Timer = 120000; - InevitableDoom5mins_Timer = 300000; - RemoveCurse_Timer = 30000; - Summon_Timer = 8000; - } - - void Aggro(Unit *who) - { - switch (rand()%3) - { - case 0: - DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO3); - break; - } - } - - void KilledUnit(Unit* victim) - { - switch (rand()%6) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY2); - break; - case 2: - DoYell(SAY_SLAY3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY3); - break; - case 3: - DoYell(SAY_SLAY4,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY4); - break; - case 4: - DoYell(SAY_SLAY5,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY5); - break; - case 5: - DoYell(SAY_SLAY6,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY6); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //CorruptedMind_Timer - if (CorruptedMind_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CORRUPTED_MIND); - CorruptedMind_Timer = 62000; - }else CorruptedMind_Timer -= diff; - - //PoisonAura_Timer - if (PoisonAura_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POISON_AURA); - PoisonAura_Timer = 60000; - }else PoisonAura_Timer -= diff; - - //InevitableDoom_Timer - if (InevitableDoom_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_INEVITABLE_DOOM); - InevitableDoom_Timer = 120000; - }else InevitableDoom_Timer -= diff; - - //InevitableDoom5mins_Timer - if (InevitableDoom5mins_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_INEVITABLE_DOOM); - InevitableDoom5mins_Timer = 15000; - }else InevitableDoom5mins_Timer -= diff; - - //RemoveCurse_Timer - if (RemoveCurse_Timer < diff) - { - DoCast(m_creature,SPELL_REMOVE_CURSE); - RemoveCurse_Timer = 30000; - }else RemoveCurse_Timer -= diff; - - //Summon_Timer - if (Summon_Timer < diff) - { - Unit* target = NULL; - Unit* SummonedSpores = NULL; - - SummonedSpores = m_creature->SummonCreature(16286,ADD_1X,ADD_1Y,ADD_1Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedSpores = m_creature->SummonCreature(16286,ADD_2X,ADD_2Y,ADD_2Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedSpores = m_creature->SummonCreature(16286,ADD_3X,ADD_3Y,ADD_3Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - if (SummonedSpores) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - SummonedSpores->AddThreat(target,1.0f); - } - - Summon_Timer = 28000; - } else Summon_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_loatheb(Creature *_Creature) -{ - return new boss_loathebAI (_Creature); -} - -void AddSC_boss_loatheb() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_loatheb"; - newscript->GetAI = GetAI_boss_loatheb; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Loatheb +SD%Complete: 100 +SDComment: +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO1 "You are mine now!" +#define SAY_AGGRO2 "I see you!" +#define SAY_AGGRO3 "You...are next!" +#define SAY_SLAY1 "Close your eyes... sleep!" +#define SAY_SLAY2 "The races of the world will perish. It is only a matter of time." +#define SAY_SLAY3 "I see endless suffering, I see torment, I see rage. I see... everything!" +#define SAY_SLAY4 "Soon... the world will tremble!" +#define SAY_SLAY5 "The end is upon you." +#define SAY_SLAY6 "Hungry worms will feast on your rotten flesh!" +#define SAY_DEATH "" + +#define SOUND_AGGRO1 8825 +#define SOUND_AGGRO2 8826 +#define SOUND_AGGRO3 8827 +#define SOUND_SLAY1 8829 +#define SOUND_SLAY2 8830 +#define SOUND_SLAY3 8831 +#define SOUND_SLAY4 8832 +#define SOUND_SLAY5 8833 +#define SOUND_SLAY6 8834 +#define SOUND_DEATH 8828 + +#define SPELL_CORRUPTED_MIND 29198 +#define SPELL_POISON_AURA 29865 +#define SPELL_INEVITABLE_DOOM 29204 +#define SPELL_REMOVE_CURSE 30281 + +#define ADD_1X 2957.040 +#define ADD_1Y -3997.590 +#define ADD_1Z 274.280 + +#define ADD_2X 2909.130 +#define ADD_2Y -4042.970 +#define ADD_2Z 274.280 + +#define ADD_3X 2861.102 +#define ADD_3Y -3997.901 +#define ADD_3Z 274.280 + +struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI +{ + boss_loathebAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 CorruptedMind_Timer; + uint32 PoisonAura_Timer; + uint32 InevitableDoom_Timer; + uint32 InevitableDoom5mins_Timer; + uint32 RemoveCurse_Timer; + uint32 Summon_Timer; + + void Reset() + { + CorruptedMind_Timer = 4000; + PoisonAura_Timer = 2500; + InevitableDoom_Timer = 120000; + InevitableDoom5mins_Timer = 300000; + RemoveCurse_Timer = 30000; + Summon_Timer = 8000; + } + + void Aggro(Unit *who) + { + switch (rand()%3) + { + case 0: + DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO3); + break; + } + } + + void KilledUnit(Unit* victim) + { + switch (rand()%6) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY2); + break; + case 2: + DoYell(SAY_SLAY3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY3); + break; + case 3: + DoYell(SAY_SLAY4,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY4); + break; + case 4: + DoYell(SAY_SLAY5,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY5); + break; + case 5: + DoYell(SAY_SLAY6,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY6); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //CorruptedMind_Timer + if (CorruptedMind_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CORRUPTED_MIND); + CorruptedMind_Timer = 62000; + }else CorruptedMind_Timer -= diff; + + //PoisonAura_Timer + if (PoisonAura_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POISON_AURA); + PoisonAura_Timer = 60000; + }else PoisonAura_Timer -= diff; + + //InevitableDoom_Timer + if (InevitableDoom_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_INEVITABLE_DOOM); + InevitableDoom_Timer = 120000; + }else InevitableDoom_Timer -= diff; + + //InevitableDoom5mins_Timer + if (InevitableDoom5mins_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_INEVITABLE_DOOM); + InevitableDoom5mins_Timer = 15000; + }else InevitableDoom5mins_Timer -= diff; + + //RemoveCurse_Timer + if (RemoveCurse_Timer < diff) + { + DoCast(m_creature,SPELL_REMOVE_CURSE); + RemoveCurse_Timer = 30000; + }else RemoveCurse_Timer -= diff; + + //Summon_Timer + if (Summon_Timer < diff) + { + Unit* target = NULL; + Unit* SummonedSpores = NULL; + + SummonedSpores = m_creature->SummonCreature(16286,ADD_1X,ADD_1Y,ADD_1Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedSpores = m_creature->SummonCreature(16286,ADD_2X,ADD_2Y,ADD_2Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedSpores = m_creature->SummonCreature(16286,ADD_3X,ADD_3Y,ADD_3Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + if (SummonedSpores) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + SummonedSpores->AddThreat(target,1.0f); + } + + Summon_Timer = 28000; + } else Summon_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_loatheb(Creature *_Creature) +{ + return new boss_loathebAI (_Creature); +} + +void AddSC_boss_loatheb() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_loatheb"; + newscript->GetAI = GetAI_boss_loatheb; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp index bd10cff23a0..3388ac97f71 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp @@ -1,246 +1,246 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Maexxna -SD%Complete: 80 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_WEBTRAP 28622 //Spell is normally used by the webtrap on the wall NOT by Maexxna -#define SPELL_WEBSPRAY 29484 -#define SPELL_POISONSHOCK 28741 -#define SPELL_NECROTICPOISON 28776 -#define SPELL_ENRAGE 28747 -#define SPELL_SUMMON_SPIDERLING 29434 - -#define LOC_X1 3546.796 -#define LOC_Y1 -3869.082 -#define LOC_Z1 296.450 - -#define LOC_X2 3531.271 -#define LOC_Y2 -3847.424 -#define LOC_Z2 299.450 - -#define LOC_X3 3497.067 -#define LOC_Y3 -3843.384 -#define LOC_Z3 302.384 - -struct MANGOS_DLL_DECL mob_webwrapAI : public ScriptedAI -{ - mob_webwrapAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 victimGUID; - - void Reset() - { - victimGUID = 0; - } - - void SetVictim(Unit* victim) - { - if(victim) - { - victimGUID = victim->GetGUID(); - victim->CastSpell(victim, SPELL_WEBTRAP, true); - } - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if(damage > m_creature->GetHealth()) - { - if(victimGUID) - { - Unit* victim = NULL; - victim = Unit::GetUnit((*m_creature), victimGUID); - victim->RemoveAurasDueToSpell(SPELL_WEBTRAP); - } - } - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - } -}; - -struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI -{ - boss_maexxnaAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 WebTrap_Timer; - uint32 WebSpray_Timer; - uint32 PoisonShock_Timer; - uint32 NecroticPoison_Timer; - uint32 SummonSpiderling_Timer; - bool Enraged; - - void Reset() - { - WebTrap_Timer = 20000; //20 sec init, 40 sec normal - WebSpray_Timer = 40000; //40 seconds - PoisonShock_Timer = 20000; //20 seconds - NecroticPoison_Timer = 30000; //30 seconds - SummonSpiderling_Timer = 30000; //30 sec init, 40 sec normal - Enraged = false; - } - - void Aggro(Unit *who) - { - } - - void DoCastWebWrap() - { - std::list t_list = m_creature->getThreatManager().getThreatList(); - std::vector targets; - - //This spell doesn't work if we only have 1 player on threat list - if(t_list.size() < 2) - return; - - //begin + 1 , so we don't target the one with the highest threat - std::list::iterator itr = t_list.begin(); - std::advance(itr, 1); - for( ; itr!= t_list.end(); ++itr) //store the threat list in a different container - { - Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - //only on alive players - if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) - targets.push_back( target); - } - - while(targets.size() > 3) - //cut down to size if we have more than 3 targets - targets.erase(targets.begin()+rand()%targets.size()); - - int i = 0; - for(std::vector::iterator itr = targets.begin(); itr!= targets.end(); ++itr, ++i) - { - // Teleport the 3 targets to a location on the wall and summon a Web Wrap on them - Unit *target = *itr; - Creature* Wrap = NULL; - if(target) - { - switch(i) - { - case 0: - DoTeleportPlayer(target, LOC_X1, LOC_Y1, LOC_Z1, target->GetOrientation()); - Wrap = m_creature->SummonCreature(16486, LOC_X1, LOC_Y1, LOC_Z1, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); - break; - case 1: - DoTeleportPlayer(target, LOC_X2, LOC_Y2, LOC_Z2, target->GetOrientation()); - Wrap = m_creature->SummonCreature(16486, LOC_X2, LOC_Y2, LOC_Z2, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); - break; - case 2: - DoTeleportPlayer(target, LOC_X3, LOC_Y3, LOC_Z3, target->GetOrientation()); - Wrap = m_creature->SummonCreature(16486, LOC_X3, LOC_Y3, LOC_Z3, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); - break; - } - if(Wrap) - { - Wrap->setFaction(m_creature->getFaction()); - ((mob_webwrapAI*)Wrap->AI())->SetVictim(target); - } - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //WebTrap_Timer - if (WebTrap_Timer < diff) - { - DoCastWebWrap(); - WebTrap_Timer = 40000; - }else WebTrap_Timer -= diff; - - //WebSpray_Timer - if (WebSpray_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_WEBSPRAY); - WebSpray_Timer = 40000; - }else WebSpray_Timer -= diff; - - //PoisonShock_Timer - if (PoisonShock_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_POISONSHOCK); - PoisonShock_Timer = 20000; - }else PoisonShock_Timer -= diff; - - //NecroticPoison_Timer - if (NecroticPoison_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_NECROTICPOISON); - NecroticPoison_Timer = 30000; - }else NecroticPoison_Timer -= diff; - - //SummonSpiderling_Timer - if (SummonSpiderling_Timer < diff) - { - DoCast(m_creature, SPELL_SUMMON_SPIDERLING); - SummonSpiderling_Timer = 40000; - }else SummonSpiderling_Timer -= diff; - - //Enrage if not already enraged and below 30% - if (!Enraged && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) - { - DoCast(m_creature,SPELL_ENRAGE); - Enraged = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_webwrap(Creature* _Creature) -{ - return new mob_webwrapAI (_Creature); -} - -CreatureAI* GetAI_boss_maexxna(Creature *_Creature) -{ - return new boss_maexxnaAI (_Creature); -} - -void AddSC_boss_maexxna() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_maexxna"; - newscript->GetAI = GetAI_boss_maexxna; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_webwrap"; - newscript->GetAI = GetAI_mob_webwrap; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Maexxna +SD%Complete: 80 +SDComment: +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_WEBTRAP 28622 //Spell is normally used by the webtrap on the wall NOT by Maexxna +#define SPELL_WEBSPRAY 29484 +#define SPELL_POISONSHOCK 28741 +#define SPELL_NECROTICPOISON 28776 +#define SPELL_ENRAGE 28747 +#define SPELL_SUMMON_SPIDERLING 29434 + +#define LOC_X1 3546.796 +#define LOC_Y1 -3869.082 +#define LOC_Z1 296.450 + +#define LOC_X2 3531.271 +#define LOC_Y2 -3847.424 +#define LOC_Z2 299.450 + +#define LOC_X3 3497.067 +#define LOC_Y3 -3843.384 +#define LOC_Z3 302.384 + +struct MANGOS_DLL_DECL mob_webwrapAI : public ScriptedAI +{ + mob_webwrapAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 victimGUID; + + void Reset() + { + victimGUID = 0; + } + + void SetVictim(Unit* victim) + { + if(victim) + { + victimGUID = victim->GetGUID(); + victim->CastSpell(victim, SPELL_WEBTRAP, true); + } + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if(damage > m_creature->GetHealth()) + { + if(victimGUID) + { + Unit* victim = NULL; + victim = Unit::GetUnit((*m_creature), victimGUID); + victim->RemoveAurasDueToSpell(SPELL_WEBTRAP); + } + } + } + + void Aggro(Unit *who) + { + } + + void MoveInLineOfSight(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + } +}; + +struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI +{ + boss_maexxnaAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 WebTrap_Timer; + uint32 WebSpray_Timer; + uint32 PoisonShock_Timer; + uint32 NecroticPoison_Timer; + uint32 SummonSpiderling_Timer; + bool Enraged; + + void Reset() + { + WebTrap_Timer = 20000; //20 sec init, 40 sec normal + WebSpray_Timer = 40000; //40 seconds + PoisonShock_Timer = 20000; //20 seconds + NecroticPoison_Timer = 30000; //30 seconds + SummonSpiderling_Timer = 30000; //30 sec init, 40 sec normal + Enraged = false; + } + + void Aggro(Unit *who) + { + } + + void DoCastWebWrap() + { + std::list t_list = m_creature->getThreatManager().getThreatList(); + std::vector targets; + + //This spell doesn't work if we only have 1 player on threat list + if(t_list.size() < 2) + return; + + //begin + 1 , so we don't target the one with the highest threat + std::list::iterator itr = t_list.begin(); + std::advance(itr, 1); + for( ; itr!= t_list.end(); ++itr) //store the threat list in a different container + { + Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + //only on alive players + if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) + targets.push_back( target); + } + + while(targets.size() > 3) + //cut down to size if we have more than 3 targets + targets.erase(targets.begin()+rand()%targets.size()); + + int i = 0; + for(std::vector::iterator itr = targets.begin(); itr!= targets.end(); ++itr, ++i) + { + // Teleport the 3 targets to a location on the wall and summon a Web Wrap on them + Unit *target = *itr; + Creature* Wrap = NULL; + if(target) + { + switch(i) + { + case 0: + DoTeleportPlayer(target, LOC_X1, LOC_Y1, LOC_Z1, target->GetOrientation()); + Wrap = m_creature->SummonCreature(16486, LOC_X1, LOC_Y1, LOC_Z1, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); + break; + case 1: + DoTeleportPlayer(target, LOC_X2, LOC_Y2, LOC_Z2, target->GetOrientation()); + Wrap = m_creature->SummonCreature(16486, LOC_X2, LOC_Y2, LOC_Z2, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); + break; + case 2: + DoTeleportPlayer(target, LOC_X3, LOC_Y3, LOC_Z3, target->GetOrientation()); + Wrap = m_creature->SummonCreature(16486, LOC_X3, LOC_Y3, LOC_Z3, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); + break; + } + if(Wrap) + { + Wrap->setFaction(m_creature->getFaction()); + ((mob_webwrapAI*)Wrap->AI())->SetVictim(target); + } + } + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //WebTrap_Timer + if (WebTrap_Timer < diff) + { + DoCastWebWrap(); + WebTrap_Timer = 40000; + }else WebTrap_Timer -= diff; + + //WebSpray_Timer + if (WebSpray_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_WEBSPRAY); + WebSpray_Timer = 40000; + }else WebSpray_Timer -= diff; + + //PoisonShock_Timer + if (PoisonShock_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_POISONSHOCK); + PoisonShock_Timer = 20000; + }else PoisonShock_Timer -= diff; + + //NecroticPoison_Timer + if (NecroticPoison_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_NECROTICPOISON); + NecroticPoison_Timer = 30000; + }else NecroticPoison_Timer -= diff; + + //SummonSpiderling_Timer + if (SummonSpiderling_Timer < diff) + { + DoCast(m_creature, SPELL_SUMMON_SPIDERLING); + SummonSpiderling_Timer = 40000; + }else SummonSpiderling_Timer -= diff; + + //Enrage if not already enraged and below 30% + if (!Enraged && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) + { + DoCast(m_creature,SPELL_ENRAGE); + Enraged = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_webwrap(Creature* _Creature) +{ + return new mob_webwrapAI (_Creature); +} + +CreatureAI* GetAI_boss_maexxna(Creature *_Creature) +{ + return new boss_maexxnaAI (_Creature); +} + +void AddSC_boss_maexxna() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_maexxna"; + newscript->GetAI = GetAI_boss_maexxna; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_webwrap"; + newscript->GetAI = GetAI_mob_webwrap; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp index 1682344bf91..ada9ab75a91 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp @@ -1,180 +1,180 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Noth -SD%Complete: 40 -SDComment: Missing Balcony stage -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO1 "Glory to the master!" -#define SAY_AGGRO2 "Your life is forfeit!" -#define SAY_AGGRO3 "Die, trespasser!" -#define SAY_SUMMON "Rise, my soldiers! Rise and fight once more!" -#define SAY_SLAY1 "My task is done!" -#define SAY_SLAY2 "Breathe no more!" -#define SAY_DEATH "I will serve the master... in... death!" -#define SOUND_AGGRO1 8845 -#define SOUND_AGGRO2 8846 -#define SOUND_AGGRO3 8847 -#define SOUND_SUMMON 8851 -#define SOUND_SLAY1 8849 -#define SOUND_SLAY2 8850 -#define SOUND_DEATH 8848 - -// Teleport position of Noth on his balcony -#define TELE_X 2631.370 -#define TELE_Y -3529.680 -#define TELE_Z 274.040 -#define TELE_O 6.277 - -#define SPELL_BLINK 29211 -#define SPELL_CRIPPLE 29212 -#define SPELL_CURSEPLAGUEBRINGER 28213 -#define SPELL_WRATHPLAGUEBRINGER 28214 - -// IMPORTANT: BALCONY TELEPORT NOT ADDED YET! WILL BE ADDED SOON! - -struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI -{ - boss_nothAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Blink_Timer; - uint32 Curse_Timer; - uint32 Wrath_Timer; - uint32 Summon_Timer; - - void Reset() - { - Blink_Timer = 25000; - Curse_Timer = 4000; - Wrath_Timer = 9000; - Summon_Timer = 12000; - } - - void Aggro(Unit *who) - { - switch (rand()%3) - { - case 0: - DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO1); - break; - case 1: - DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO2); - break; - case 2: - DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO3); - break; - } - } - - void KilledUnit(Unit* victim) - { - switch (rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Blink_Timer - if (Blink_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CRIPPLE); - DoCast(m_creature,SPELL_BLINK); - - Blink_Timer = 25000; - }else Blink_Timer -= diff; - - //Curse_Timer - if (Curse_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CURSEPLAGUEBRINGER); - Curse_Timer = 28000; - }else Curse_Timer -= diff; - - //Wrath_Timer - if (Wrath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_WRATHPLAGUEBRINGER); - Wrath_Timer = 18000; - }else Wrath_Timer -= diff; - - //Summon_Timer - if (Summon_Timer < diff) - { - DoYell(SAY_SUMMON,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SUMMON); - - Unit* target = NULL; - Unit* SummonedSkeletons = NULL; - - SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); - - if (SummonedSkeletons) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - SummonedSkeletons->AddThreat(target,1.0f); - } - - Summon_Timer = 30500; - } else Summon_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_noth(Creature *_Creature) -{ - return new boss_nothAI (_Creature); -} - -void AddSC_boss_noth() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_noth"; - newscript->GetAI = GetAI_boss_noth; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Noth +SD%Complete: 40 +SDComment: Missing Balcony stage +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO1 "Glory to the master!" +#define SAY_AGGRO2 "Your life is forfeit!" +#define SAY_AGGRO3 "Die, trespasser!" +#define SAY_SUMMON "Rise, my soldiers! Rise and fight once more!" +#define SAY_SLAY1 "My task is done!" +#define SAY_SLAY2 "Breathe no more!" +#define SAY_DEATH "I will serve the master... in... death!" +#define SOUND_AGGRO1 8845 +#define SOUND_AGGRO2 8846 +#define SOUND_AGGRO3 8847 +#define SOUND_SUMMON 8851 +#define SOUND_SLAY1 8849 +#define SOUND_SLAY2 8850 +#define SOUND_DEATH 8848 + +// Teleport position of Noth on his balcony +#define TELE_X 2631.370 +#define TELE_Y -3529.680 +#define TELE_Z 274.040 +#define TELE_O 6.277 + +#define SPELL_BLINK 29211 +#define SPELL_CRIPPLE 29212 +#define SPELL_CURSEPLAGUEBRINGER 28213 +#define SPELL_WRATHPLAGUEBRINGER 28214 + +// IMPORTANT: BALCONY TELEPORT NOT ADDED YET! WILL BE ADDED SOON! + +struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI +{ + boss_nothAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Blink_Timer; + uint32 Curse_Timer; + uint32 Wrath_Timer; + uint32 Summon_Timer; + + void Reset() + { + Blink_Timer = 25000; + Curse_Timer = 4000; + Wrath_Timer = 9000; + Summon_Timer = 12000; + } + + void Aggro(Unit *who) + { + switch (rand()%3) + { + case 0: + DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO1); + break; + case 1: + DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO2); + break; + case 2: + DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO3); + break; + } + } + + void KilledUnit(Unit* victim) + { + switch (rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Blink_Timer + if (Blink_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CRIPPLE); + DoCast(m_creature,SPELL_BLINK); + + Blink_Timer = 25000; + }else Blink_Timer -= diff; + + //Curse_Timer + if (Curse_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CURSEPLAGUEBRINGER); + Curse_Timer = 28000; + }else Curse_Timer -= diff; + + //Wrath_Timer + if (Wrath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_WRATHPLAGUEBRINGER); + Wrath_Timer = 18000; + }else Wrath_Timer -= diff; + + //Summon_Timer + if (Summon_Timer < diff) + { + DoYell(SAY_SUMMON,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SUMMON); + + Unit* target = NULL; + Unit* SummonedSkeletons = NULL; + + SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonedSkeletons = m_creature->SummonCreature(16984,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + + if (SummonedSkeletons) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + SummonedSkeletons->AddThreat(target,1.0f); + } + + Summon_Timer = 30500; + } else Summon_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_noth(Creature *_Creature) +{ + return new boss_nothAI (_Creature); +} + +void AddSC_boss_noth() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_noth"; + newscript->GetAI = GetAI_boss_noth; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_patchwerk.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_patchwerk.cpp index d8a8f73fd69..7fc0461c630 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_patchwerk.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_patchwerk.cpp @@ -1,160 +1,160 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Patchwerk -SD%Complete: 100 -SDComment: Some issues with hateful strike inturrupting the melee swing timer. Probably core issue. -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO1 "Patchwerk want to play!" -#define SAY_AGGRO2 "Kel'Thuzad make Patchwerk his Avatar of War!" -#define SAY_SLAY "No more play?" -#define SAY_DEATH "What happened to... Patch..." - -#define SOUND_AGGRO1 8909 -#define SOUND_AGGRO2 8910 -#define SOUND_SLAY 8912 -#define SOUND_DEATH 8911 - -#define EMOTE_BERSERK "Patchwerk goes into a berserker rage!" -#define EMOTE_ENRAGE "Patchwerk becomes enraged!" - -#define SPELL_HATEFULSTRIKE 28308 -#define SPELL_ENRAGE 29691 -#define SPELL_BERSERK 27680 -#define SPELL_SLIMEBOLT 32309 - -struct MANGOS_DLL_DECL boss_patchwerkAI : public ScriptedAI -{ - boss_patchwerkAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 HatefullStrike_Timer; - uint32 Enrage_Timer; - uint32 Slimebolt_Timer; - bool Enraged; - - void Reset() - { - HatefullStrike_Timer = 1200; //1.2 seconds - Enrage_Timer = 420000; //7 minutes 420,000 - Slimebolt_Timer = 450000; //7.5 minutes 450,000 - Enraged = false; - } - - void KilledUnit(Unit* Victim) - { - if (rand()%5) - return; - - DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - if (rand()%2) - { - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - } - else - { - DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //HatefullStrike_Timer - if (HatefullStrike_Timer < diff) - { - //Cast Hateful strike on the player with the highest - //amount of HP within melee distance - uint32 MostHP = 0; - Unit* pMostHPTarget = NULL; - Unit* pTemp = NULL; - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - - for (i = m_creature->getThreatManager().getThreatList().begin(); i!=m_creature->getThreatManager().getThreatList().end(); ++i) - { - pTemp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); - if (pTemp && pTemp->isAlive() && pTemp->GetHealth() > MostHP && m_creature->GetDistance2d(pTemp) < 5) - { - MostHP = pTemp->GetHealth(); - pMostHPTarget = pTemp; - } - } - - if (pMostHPTarget) - DoCast(pMostHPTarget, SPELL_HATEFULSTRIKE); - - HatefullStrike_Timer = 1200; - }else HatefullStrike_Timer -= diff; - - //Enrage_Timer - if (Enrage_Timer < diff) - { - DoCast(m_creature, SPELL_BERSERK); - DoTextEmote(EMOTE_BERSERK, m_creature->getVictim()); - - Enrage_Timer = 300000; - }else Enrage_Timer -= diff; - - //Slimebolt_Timer - if (Slimebolt_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SLIMEBOLT); - Slimebolt_Timer = 5000; - }else Slimebolt_Timer -= diff; - - //Enrage if not already enraged and below 5% - if (!Enraged && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 5) - { - DoCast(m_creature,SPELL_ENRAGE); - DoTextEmote(EMOTE_ENRAGE,NULL); - Enraged = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_patchwerk(Creature *_Creature) -{ - return new boss_patchwerkAI (_Creature); -} - -void AddSC_boss_patchwerk() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_patchwerk"; - newscript->GetAI = GetAI_boss_patchwerk; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Patchwerk +SD%Complete: 100 +SDComment: Some issues with hateful strike inturrupting the melee swing timer. Probably core issue. +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO1 "Patchwerk want to play!" +#define SAY_AGGRO2 "Kel'Thuzad make Patchwerk his Avatar of War!" +#define SAY_SLAY "No more play?" +#define SAY_DEATH "What happened to... Patch..." + +#define SOUND_AGGRO1 8909 +#define SOUND_AGGRO2 8910 +#define SOUND_SLAY 8912 +#define SOUND_DEATH 8911 + +#define EMOTE_BERSERK "Patchwerk goes into a berserker rage!" +#define EMOTE_ENRAGE "Patchwerk becomes enraged!" + +#define SPELL_HATEFULSTRIKE 28308 +#define SPELL_ENRAGE 29691 +#define SPELL_BERSERK 27680 +#define SPELL_SLIMEBOLT 32309 + +struct MANGOS_DLL_DECL boss_patchwerkAI : public ScriptedAI +{ + boss_patchwerkAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 HatefullStrike_Timer; + uint32 Enrage_Timer; + uint32 Slimebolt_Timer; + bool Enraged; + + void Reset() + { + HatefullStrike_Timer = 1200; //1.2 seconds + Enrage_Timer = 420000; //7 minutes 420,000 + Slimebolt_Timer = 450000; //7.5 minutes 450,000 + Enraged = false; + } + + void KilledUnit(Unit* Victim) + { + if (rand()%5) + return; + + DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + if (rand()%2) + { + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + } + else + { + DoYell(SAY_AGGRO2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //HatefullStrike_Timer + if (HatefullStrike_Timer < diff) + { + //Cast Hateful strike on the player with the highest + //amount of HP within melee distance + uint32 MostHP = 0; + Unit* pMostHPTarget = NULL; + Unit* pTemp = NULL; + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + + for (i = m_creature->getThreatManager().getThreatList().begin(); i!=m_creature->getThreatManager().getThreatList().end(); ++i) + { + pTemp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); + if (pTemp && pTemp->isAlive() && pTemp->GetHealth() > MostHP && m_creature->GetDistance2d(pTemp) < 5) + { + MostHP = pTemp->GetHealth(); + pMostHPTarget = pTemp; + } + } + + if (pMostHPTarget) + DoCast(pMostHPTarget, SPELL_HATEFULSTRIKE); + + HatefullStrike_Timer = 1200; + }else HatefullStrike_Timer -= diff; + + //Enrage_Timer + if (Enrage_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + DoTextEmote(EMOTE_BERSERK, m_creature->getVictim()); + + Enrage_Timer = 300000; + }else Enrage_Timer -= diff; + + //Slimebolt_Timer + if (Slimebolt_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SLIMEBOLT); + Slimebolt_Timer = 5000; + }else Slimebolt_Timer -= diff; + + //Enrage if not already enraged and below 5% + if (!Enraged && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 5) + { + DoCast(m_creature,SPELL_ENRAGE); + DoTextEmote(EMOTE_ENRAGE,NULL); + Enraged = true; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_patchwerk(Creature *_Creature) +{ + return new boss_patchwerkAI (_Creature); +} + +void AddSC_boss_patchwerk() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_patchwerk"; + newscript->GetAI = GetAI_boss_patchwerk; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_razuvious.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_razuvious.cpp index 707ec574076..d193b7224c5 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_razuvious.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_razuvious.cpp @@ -1,167 +1,167 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Razuvious -SD%Complete: 50 -SDComment: Missing adds and event is impossible without Mind Control -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -//Razuvious - NO TEXT sound only -//8852 aggro01 - Hah hah, I'm just getting warmed up! -//8853 aggro02 Stand and fight! -//8854 aggro03 Show me what you've got! -//8861 slay1 - You should've stayed home! -//8863 slay2- -//8858 cmmnd3 - You disappoint me, students! -//8855 cmmnd1 - Do as I taught you! -//8856 cmmnd2 - Show them no mercy! -//8859 cmmnd4 - The time for practice is over! Show me what you've learned! -//8861 Sweep the leg! Do you have a problem with that? -//8860 death - An honorable... death... -//8947 - Aggro Mixed? - ? - -#define SOUND_AGGRO1 8852 -#define SOUND_AGGRO2 8853 -#define SOUND_AGGRO3 8854 -#define SOUND_SLAY1 8861 -#define SOUND_SLAY2 8863 -#define SOUND_COMMND1 8855 -#define SOUND_COMMND2 8856 -#define SOUND_COMMND3 8858 -#define SOUND_COMMND4 8859 -#define SOUND_COMMND5 8861 -#define SOUND_DEATH 8860 -#define SOUND_AGGROMIX 8847 - -#define SPELL_UNBALANCINGSTRIKE 26613 -#define SPELL_DISRUPTINGSHOUT 29107 - -struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI -{ - boss_razuviousAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 UnbalancingStrike_Timer; - uint32 DisruptingShout_Timer; - uint32 CommandSound_Timer; - - void Reset() - { - UnbalancingStrike_Timer = 30000; //30 seconds - DisruptingShout_Timer = 25000; //25 seconds - CommandSound_Timer = 40000; //40 seconds - } - - void KilledUnit(Unit* Victim) - { - if (rand()%3) - return; - - switch (rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - switch (rand()%3) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - case 2: - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - break; - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //UnbalancingStrike_Timer - if (UnbalancingStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_UNBALANCINGSTRIKE); - UnbalancingStrike_Timer = 30000; - }else UnbalancingStrike_Timer -= diff; - - //DisruptingShout_Timer - if (DisruptingShout_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_DISRUPTINGSHOUT); - DisruptingShout_Timer = 25000; - }else DisruptingShout_Timer -= diff; - - //CommandSound_Timer - if (CommandSound_Timer < diff) - { - switch (rand()%5) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_COMMND1); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_COMMND2); - break; - case 2: - DoPlaySoundToSet(m_creature, SOUND_COMMND3); - break; - case 3: - DoPlaySoundToSet(m_creature, SOUND_COMMND4); - break; - case 4: - DoPlaySoundToSet(m_creature, SOUND_COMMND5); - break; - } - - CommandSound_Timer = 40000; - }else CommandSound_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_razuvious(Creature *_Creature) -{ - return new boss_razuviousAI (_Creature); -} - -void AddSC_boss_razuvious() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_razuvious"; - newscript->GetAI = GetAI_boss_razuvious; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Razuvious +SD%Complete: 50 +SDComment: Missing adds and event is impossible without Mind Control +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//Razuvious - NO TEXT sound only +//8852 aggro01 - Hah hah, I'm just getting warmed up! +//8853 aggro02 Stand and fight! +//8854 aggro03 Show me what you've got! +//8861 slay1 - You should've stayed home! +//8863 slay2- +//8858 cmmnd3 - You disappoint me, students! +//8855 cmmnd1 - Do as I taught you! +//8856 cmmnd2 - Show them no mercy! +//8859 cmmnd4 - The time for practice is over! Show me what you've learned! +//8861 Sweep the leg! Do you have a problem with that? +//8860 death - An honorable... death... +//8947 - Aggro Mixed? - ? + +#define SOUND_AGGRO1 8852 +#define SOUND_AGGRO2 8853 +#define SOUND_AGGRO3 8854 +#define SOUND_SLAY1 8861 +#define SOUND_SLAY2 8863 +#define SOUND_COMMND1 8855 +#define SOUND_COMMND2 8856 +#define SOUND_COMMND3 8858 +#define SOUND_COMMND4 8859 +#define SOUND_COMMND5 8861 +#define SOUND_DEATH 8860 +#define SOUND_AGGROMIX 8847 + +#define SPELL_UNBALANCINGSTRIKE 26613 +#define SPELL_DISRUPTINGSHOUT 29107 + +struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI +{ + boss_razuviousAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 UnbalancingStrike_Timer; + uint32 DisruptingShout_Timer; + uint32 CommandSound_Timer; + + void Reset() + { + UnbalancingStrike_Timer = 30000; //30 seconds + DisruptingShout_Timer = 25000; //25 seconds + CommandSound_Timer = 40000; //40 seconds + } + + void KilledUnit(Unit* Victim) + { + if (rand()%3) + return; + + switch (rand()%2) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + switch (rand()%3) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_AGGRO1); + break; + case 1: + DoPlaySoundToSet(m_creature, SOUND_AGGRO2); + break; + case 2: + DoPlaySoundToSet(m_creature, SOUND_AGGRO3); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //UnbalancingStrike_Timer + if (UnbalancingStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_UNBALANCINGSTRIKE); + UnbalancingStrike_Timer = 30000; + }else UnbalancingStrike_Timer -= diff; + + //DisruptingShout_Timer + if (DisruptingShout_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_DISRUPTINGSHOUT); + DisruptingShout_Timer = 25000; + }else DisruptingShout_Timer -= diff; + + //CommandSound_Timer + if (CommandSound_Timer < diff) + { + switch (rand()%5) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_COMMND1); + break; + case 1: + DoPlaySoundToSet(m_creature, SOUND_COMMND2); + break; + case 2: + DoPlaySoundToSet(m_creature, SOUND_COMMND3); + break; + case 3: + DoPlaySoundToSet(m_creature, SOUND_COMMND4); + break; + case 4: + DoPlaySoundToSet(m_creature, SOUND_COMMND5); + break; + } + + CommandSound_Timer = 40000; + }else CommandSound_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_razuvious(Creature *_Creature) +{ + return new boss_razuviousAI (_Creature); +} + +void AddSC_boss_razuvious() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_razuvious"; + newscript->GetAI = GetAI_boss_razuvious; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp index f27375f2835..0dd190bab7c 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp @@ -1,199 +1,199 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Sapphiron -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_ICEBOLT 28522 -#define SPELL_FROST_BREATH 29318 -#define SPELL_FROST_AURA 28531 -#define SPELL_LIFE_DRAIN 28542 -#define SPELL_BLIZZARD 28547 -#define SPELL_BESERK 26662 - -struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI -{ - boss_sapphironAI(Creature* c) : ScriptedAI(c) - { - Reset(); - } - - uint32 Icebolt_Count; - uint32 Icebolt_Timer; - uint32 FrostBreath_Timer; - uint32 FrostAura_Timer; - uint32 LifeDrain_Timer; - uint32 Blizzard_Timer; - uint32 Fly_Timer; - uint32 Fly2_Timer; - uint32 Beserk_Timer; - uint32 phase; - bool landoff; - uint32 land_Timer; - - void Reset() - { - FrostAura_Timer = 2000; - 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); - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget()) - return; - - if(m_creature->getVictim() && m_creature->isAlive()) - { - if(phase == 1) - { - if(FrostAura_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROST_AURA); - FrostAura_Timer = 5000; - }else FrostAura_Timer -= diff; - - if(LifeDrain_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(target,SPELL_LIFE_DRAIN); - LifeDrain_Timer = 24000; - }else LifeDrain_Timer -= diff; - - if(Blizzard_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(target,SPELL_BLIZZARD); - Blizzard_Timer = 20000; - }else Blizzard_Timer -= diff; - - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > 10) - { - if(Fly_Timer < diff) - { - phase = 2; - m_creature->InterruptNonMeleeSpells(false); - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - (*m_creature).GetMotionMaster()->Clear(false); - (*m_creature).GetMotionMaster()->MoveIdle(); - DoCast(m_creature,11010); - m_creature->SetHover(true); - DoCast(m_creature,18430); - Icebolt_Timer = 4000; - Icebolt_Count = 0; - landoff = false; - }else Fly_Timer -= diff; - } - - if (phase == 2) - { - if(Icebolt_Timer < diff && Icebolt_Count < 5) - { - Unit* target = NULL; - - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(target,SPELL_ICEBOLT); - Icebolt_Count ++; - Icebolt_Timer = 4000; - }else Icebolt_Timer -= diff; - - if(Icebolt_Count == 5 && !landoff) - { - if(FrostBreath_Timer < diff ) - { - DoTextEmote("takes a deep breath...",NULL); - DoCast(m_creature->getVictim(),SPELL_FROST_BREATH); - land_Timer = 2000; - landoff = true; - FrostBreath_Timer = 6000; - }else FrostBreath_Timer -= diff; - } - - if(landoff) - { - if(land_Timer < diff) - { - phase = 1; - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); - m_creature->SetHover(false); - (*m_creature).GetMotionMaster()->Clear(false); - (*m_creature).GetMotionMaster()->MoveChase(m_creature->getVictim()); - Fly_Timer = 67000; - }else land_Timer -= diff; - } - - } - - if ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 11) - { - if (Beserk_Timer < diff) - { - DoTextEmote("enrages!",NULL); - DoCast(m_creature,SPELL_BESERK); - Beserk_Timer = 300000; - }else Beserk_Timer -= diff; - } - - if( phase!=2 && m_creature->getVictim() && m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - if( m_creature->isAttackReady() ) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - } - } - } - } -}; - -CreatureAI* GetAI_boss_sapphiron(Creature *_Creature) -{ - return new boss_sapphironAI (_Creature); -} - -void AddSC_boss_sapphiron() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_sapphiron"; - newscript->GetAI = GetAI_boss_sapphiron; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Sapphiron +SD%Complete: 0 +SDComment: Place Holder +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_ICEBOLT 28522 +#define SPELL_FROST_BREATH 29318 +#define SPELL_FROST_AURA 28531 +#define SPELL_LIFE_DRAIN 28542 +#define SPELL_BLIZZARD 28547 +#define SPELL_BESERK 26662 + +struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI +{ + boss_sapphironAI(Creature* c) : ScriptedAI(c) + { + Reset(); + } + + uint32 Icebolt_Count; + uint32 Icebolt_Timer; + uint32 FrostBreath_Timer; + uint32 FrostAura_Timer; + uint32 LifeDrain_Timer; + uint32 Blizzard_Timer; + uint32 Fly_Timer; + uint32 Fly2_Timer; + uint32 Beserk_Timer; + uint32 phase; + bool landoff; + uint32 land_Timer; + + void Reset() + { + FrostAura_Timer = 2000; + 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); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget()) + return; + + if(m_creature->getVictim() && m_creature->isAlive()) + { + if(phase == 1) + { + if(FrostAura_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROST_AURA); + FrostAura_Timer = 5000; + }else FrostAura_Timer -= diff; + + if(LifeDrain_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(target,SPELL_LIFE_DRAIN); + LifeDrain_Timer = 24000; + }else LifeDrain_Timer -= diff; + + if(Blizzard_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(target,SPELL_BLIZZARD); + Blizzard_Timer = 20000; + }else Blizzard_Timer -= diff; + + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > 10) + { + if(Fly_Timer < diff) + { + phase = 2; + m_creature->InterruptNonMeleeSpells(false); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + (*m_creature).GetMotionMaster()->Clear(false); + (*m_creature).GetMotionMaster()->MoveIdle(); + DoCast(m_creature,11010); + m_creature->SetHover(true); + DoCast(m_creature,18430); + Icebolt_Timer = 4000; + Icebolt_Count = 0; + landoff = false; + }else Fly_Timer -= diff; + } + + if (phase == 2) + { + if(Icebolt_Timer < diff && Icebolt_Count < 5) + { + Unit* target = NULL; + + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(target,SPELL_ICEBOLT); + Icebolt_Count ++; + Icebolt_Timer = 4000; + }else Icebolt_Timer -= diff; + + if(Icebolt_Count == 5 && !landoff) + { + if(FrostBreath_Timer < diff ) + { + DoTextEmote("takes a deep breath...",NULL); + DoCast(m_creature->getVictim(),SPELL_FROST_BREATH); + land_Timer = 2000; + landoff = true; + FrostBreath_Timer = 6000; + }else FrostBreath_Timer -= diff; + } + + if(landoff) + { + if(land_Timer < diff) + { + phase = 1; + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + m_creature->SetHover(false); + (*m_creature).GetMotionMaster()->Clear(false); + (*m_creature).GetMotionMaster()->MoveChase(m_creature->getVictim()); + Fly_Timer = 67000; + }else land_Timer -= diff; + } + + } + + if ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 11) + { + if (Beserk_Timer < diff) + { + DoTextEmote("enrages!",NULL); + DoCast(m_creature,SPELL_BESERK); + Beserk_Timer = 300000; + }else Beserk_Timer -= diff; + } + + if( phase!=2 && m_creature->getVictim() && m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + { + if( m_creature->isAttackReady() ) + { + m_creature->AttackerStateUpdate(m_creature->getVictim()); + m_creature->resetAttackTimer(); + } + } + } + } + } +}; + +CreatureAI* GetAI_boss_sapphiron(Creature *_Creature) +{ + return new boss_sapphironAI (_Creature); +} + +void AddSC_boss_sapphiron() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_sapphiron"; + newscript->GetAI = GetAI_boss_sapphiron; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_sir_zeliek.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_sir_zeliek.cpp index 717e84ca984..9bd006b1a85 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_sir_zeliek.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_sir_zeliek.cpp @@ -1,146 +1,146 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Sir_Zeliek -SD%Complete: 100 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -//All horsemen -#define SPELL_SHIELDWALL 29061 -#define SPELL_BESERK 26662 - -// sir zeliek -#define SPELL_MARK_OF_ZELIEK 28835 -#define SPELL_HOLY_WRATH 28883 - -#define SAY_AGGRO "Flee, before it's too late!" -#define SAY_TAUNT1 "Invaders, cease this foolish venture at once! Turn away while you still can!" -#define SAY_TAUNT2 "Perhaps they will come to their senses, and run away as fast as they can!" -#define SAY_TAUNT3 "Do not continue! Turn back while there's still time!" -#define SAY_SPECIAL "I- I have no choice but to obey!" -#define SAY_SLAY "Forgive me!" -#define SAY_DEATH "It is... as it should be." - -#define SOUND_AGGRO 8913 -#define SOUND_TAUNT1 8917 -#define SOUND_TAUNT2 8918 -#define SOUND_TAUNT3 8919 -#define SOUND_SPECIAl 8916 -#define SOUND_SLAY 8915 -#define SOUND_DEATH 8914 - -struct MANGOS_DLL_DECL boss_sir_zeliekAI : public ScriptedAI -{ - boss_sir_zeliekAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Mark_Timer; - uint32 HolyWrath_Timer; - bool ShieldWall1; - bool ShieldWall2; - - void Reset() - { - Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. - HolyWrath_Timer = 12000; // right - ShieldWall1 = true; - ShieldWall2 = true; - } - - void InitialYell() - { - if(!InCombat) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - } - - void KilledUnit() - { - DoYell(SAY_SLAY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - InitialYell(); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - // Mark of Zeliek - if(Mark_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MARK_OF_ZELIEK); - Mark_Timer = 12000; - }else Mark_Timer -= diff; - - // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds - if(ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) - { - if(ShieldWall1) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall1 = false; - } - } - if(ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) - { - if(ShieldWall2) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall2 = false; - } - } - - // Holy Wrath - if(HolyWrath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HOLY_WRATH); - HolyWrath_Timer = 12000; - }else HolyWrath_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_sir_zeliek(Creature *_Creature) -{ - return new boss_sir_zeliekAI (_Creature); -} - -void AddSC_boss_sir_zeliek() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_sir_zeliek"; - newscript->GetAI = GetAI_boss_sir_zeliek; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Sir_Zeliek +SD%Complete: 100 +SDComment: +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//All horsemen +#define SPELL_SHIELDWALL 29061 +#define SPELL_BESERK 26662 + +// sir zeliek +#define SPELL_MARK_OF_ZELIEK 28835 +#define SPELL_HOLY_WRATH 28883 + +#define SAY_AGGRO "Flee, before it's too late!" +#define SAY_TAUNT1 "Invaders, cease this foolish venture at once! Turn away while you still can!" +#define SAY_TAUNT2 "Perhaps they will come to their senses, and run away as fast as they can!" +#define SAY_TAUNT3 "Do not continue! Turn back while there's still time!" +#define SAY_SPECIAL "I- I have no choice but to obey!" +#define SAY_SLAY "Forgive me!" +#define SAY_DEATH "It is... as it should be." + +#define SOUND_AGGRO 8913 +#define SOUND_TAUNT1 8917 +#define SOUND_TAUNT2 8918 +#define SOUND_TAUNT3 8919 +#define SOUND_SPECIAl 8916 +#define SOUND_SLAY 8915 +#define SOUND_DEATH 8914 + +struct MANGOS_DLL_DECL boss_sir_zeliekAI : public ScriptedAI +{ + boss_sir_zeliekAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Mark_Timer; + uint32 HolyWrath_Timer; + bool ShieldWall1; + bool ShieldWall2; + + void Reset() + { + Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. + HolyWrath_Timer = 12000; // right + ShieldWall1 = true; + ShieldWall2 = true; + } + + void InitialYell() + { + if(!InCombat) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + } + + void KilledUnit() + { + DoYell(SAY_SLAY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + InitialYell(); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + // Mark of Zeliek + if(Mark_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MARK_OF_ZELIEK); + Mark_Timer = 12000; + }else Mark_Timer -= diff; + + // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds + if(ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) + { + if(ShieldWall1) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall1 = false; + } + } + if(ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) + { + if(ShieldWall2) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall2 = false; + } + } + + // Holy Wrath + if(HolyWrath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HOLY_WRATH); + HolyWrath_Timer = 12000; + }else HolyWrath_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_sir_zeliek(Creature *_Creature) +{ + return new boss_sir_zeliekAI (_Creature); +} + +void AddSC_boss_sir_zeliek() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_sir_zeliek"; + newscript->GetAI = GetAI_boss_sir_zeliek; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_stalagg.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_stalagg.cpp index 53b46122f24..44ca7aa7a47 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_stalagg.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_stalagg.cpp @@ -1,35 +1,35 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Stalagg -SD%Complete: 0 -SDComment: Merge with Thaddius -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -//Stalagg -//8864 aggro - Stalagg crush you! -//8866 slay - Stalagg Kill! -//8865 death - Master save me... - -#define SPELL_WARSTOMP 28125 -#define SPELL_POWERSURGE 28134 -#define SPELL_CHAIN_LIGHTNING 28900 - -//Not sure how to "force" crushing blows or to knock tank to the opposite platform +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Stalagg +SD%Complete: 0 +SDComment: Merge with Thaddius +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//Stalagg +//8864 aggro - Stalagg crush you! +//8866 slay - Stalagg Kill! +//8865 death - Master save me... + +#define SPELL_WARSTOMP 28125 +#define SPELL_POWERSURGE 28134 +#define SPELL_CHAIN_LIGHTNING 28900 + +//Not sure how to "force" crushing blows or to knock tank to the opposite platform diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp index 0bd59cfa0e2..0ca03f67eb0 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp @@ -1,49 +1,49 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Thaddius -SD%Complete: 0 -SDComment: Merge Feugen & Stalagg with this script -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -//Thaddus -//8873 Lamnt01 - Pleeease! -//8874 Lamnt02 - Stop, make it stop! -//8875 Lamnt03 - Help me! Save me! -//8876 Lamnt04 - Please, nooo! -//8872 greet - You are too late... I... must... OBEY! -//8867 aggro1 - KILL! -//8868 aggro2 - EAT YOUR BONES! -//8869 aggro3 - BREAK YOU! -//8871 elect - Now YOU feel pain! -//8877 slay - You die now! -//8870 die - Thank... you... - -#define SPELL_BALL_LIGHTNING 28299 - -#define SPELL_CHARGE_POSITIVE_DMGBUFF 29659 -#define SPELL_CHARGE_POSITIVE_NEARDMG 28059 - -#define SPELL_CHARGE_NEGATIVE_DMGBUFF 29660 -#define SPELL_CHARGE_NEGATIVE_NEARDMG 28084 - -#define SPELL_CHAIN_LIGHTNING 28900 - -#define SPELL_BESERK 26662 +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Thaddius +SD%Complete: 0 +SDComment: Merge Feugen & Stalagg with this script +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//Thaddus +//8873 Lamnt01 - Pleeease! +//8874 Lamnt02 - Stop, make it stop! +//8875 Lamnt03 - Help me! Save me! +//8876 Lamnt04 - Please, nooo! +//8872 greet - You are too late... I... must... OBEY! +//8867 aggro1 - KILL! +//8868 aggro2 - EAT YOUR BONES! +//8869 aggro3 - BREAK YOU! +//8871 elect - Now YOU feel pain! +//8877 slay - You die now! +//8870 die - Thank... you... + +#define SPELL_BALL_LIGHTNING 28299 + +#define SPELL_CHARGE_POSITIVE_DMGBUFF 29659 +#define SPELL_CHARGE_POSITIVE_NEARDMG 28059 + +#define SPELL_CHARGE_NEGATIVE_DMGBUFF 29660 +#define SPELL_CHARGE_NEGATIVE_NEARDMG 28084 + +#define SPELL_CHAIN_LIGHTNING 28900 + +#define SPELL_BESERK 26662 diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_thane_korthazz.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_thane_korthazz.cpp index af2010fb3d9..beb1b23d8c7 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_thane_korthazz.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_thane_korthazz.cpp @@ -1,147 +1,147 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Thane_Korthazz -SD%Complete: 100 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" - -//All horsemen -#define SPELL_SHIELDWALL 29061 -#define SPELL_BESERK 26662 - -// thane korthazz -#define SPELL_MARK_OF_KORTHAZZ 28832 -#define SPELL_METEOR 26558 // m_creature->getVictim() auto-area spell but with a core problem - -#define SAY_AGGRO "Come out and fight, ye wee ninny!" -#define SAY_TAUNT1 "To arms, ye roustabouts! We've got company!" -#define SAY_TAUNT2 "I heard about enough of yer sniveling. Shut yer fly trap 'afore I shut it for ye!" -#define SAY_TAUNT3 "I'm gonna enjoy killin' these slack-jawed daffodils!" -#define SAY_SLAY "Next time, bring more friends!" -#define SAY_SPECIAl "I like my meat extra crispy!" -#define SAY_DEATH "What a bloody waste this is!" - -#define SOUND_AGGRO 8899 -#define SOUND_TAUNT1 8903 -#define SOUND_TAUNT2 8904 -#define SOUND_TAUNT3 8905 -#define SOUND_SLAY 8901 -#define SOUND_SPECIAL 8902 -#define SOUND_DEATH 8900 - -#define SPIRIT_OF_KORTHAZZ 16778 - -struct MANGOS_DLL_DECL boss_thane_korthazzAI : public ScriptedAI -{ - boss_thane_korthazzAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Mark_Timer; - uint32 Meteor_Timer; - bool ShieldWall1; - bool ShieldWall2; - - void Reset() - { - Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. - Meteor_Timer = 30000; // wrong - ShieldWall1 = true; - ShieldWall2 = true; - } - - void InitialYell() - { - if(!InCombat) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - } - - void KilledUnit() - { - DoYell(SAY_SLAY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - InitialYell(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - // Mark of Korthazz - if(Mark_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MARK_OF_KORTHAZZ); - Mark_Timer = 12000; - }else Mark_Timer -= diff; - - // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds - if(ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) - { - if(ShieldWall1) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall1 = false; - } - } - if(ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) - { - if(ShieldWall2) - { - DoCast(m_creature,SPELL_SHIELDWALL); - ShieldWall2 = false; - } - } - - // Meteor - if(Meteor_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_METEOR); - Meteor_Timer = 20000; // wrong - }else Meteor_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_thane_korthazz(Creature *_Creature) -{ - return new boss_thane_korthazzAI (_Creature); -} - -void AddSC_boss_thane_korthazz() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_thane_korthazz"; - newscript->GetAI = GetAI_boss_thane_korthazz; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Thane_Korthazz +SD%Complete: 100 +SDComment: +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" + +//All horsemen +#define SPELL_SHIELDWALL 29061 +#define SPELL_BESERK 26662 + +// thane korthazz +#define SPELL_MARK_OF_KORTHAZZ 28832 +#define SPELL_METEOR 26558 // m_creature->getVictim() auto-area spell but with a core problem + +#define SAY_AGGRO "Come out and fight, ye wee ninny!" +#define SAY_TAUNT1 "To arms, ye roustabouts! We've got company!" +#define SAY_TAUNT2 "I heard about enough of yer sniveling. Shut yer fly trap 'afore I shut it for ye!" +#define SAY_TAUNT3 "I'm gonna enjoy killin' these slack-jawed daffodils!" +#define SAY_SLAY "Next time, bring more friends!" +#define SAY_SPECIAl "I like my meat extra crispy!" +#define SAY_DEATH "What a bloody waste this is!" + +#define SOUND_AGGRO 8899 +#define SOUND_TAUNT1 8903 +#define SOUND_TAUNT2 8904 +#define SOUND_TAUNT3 8905 +#define SOUND_SLAY 8901 +#define SOUND_SPECIAL 8902 +#define SOUND_DEATH 8900 + +#define SPIRIT_OF_KORTHAZZ 16778 + +struct MANGOS_DLL_DECL boss_thane_korthazzAI : public ScriptedAI +{ + boss_thane_korthazzAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Mark_Timer; + uint32 Meteor_Timer; + bool ShieldWall1; + bool ShieldWall2; + + void Reset() + { + Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. + Meteor_Timer = 30000; // wrong + ShieldWall1 = true; + ShieldWall2 = true; + } + + void InitialYell() + { + if(!InCombat) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + } + + void KilledUnit() + { + DoYell(SAY_SLAY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + InitialYell(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + // Mark of Korthazz + if(Mark_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MARK_OF_KORTHAZZ); + Mark_Timer = 12000; + }else Mark_Timer -= diff; + + // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds + if(ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50) + { + if(ShieldWall1) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall1 = false; + } + } + if(ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) + { + if(ShieldWall2) + { + DoCast(m_creature,SPELL_SHIELDWALL); + ShieldWall2 = false; + } + } + + // Meteor + if(Meteor_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_METEOR); + Meteor_Timer = 20000; // wrong + }else Meteor_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_thane_korthazz(Creature *_Creature) +{ + return new boss_thane_korthazzAI (_Creature); +} + +void AddSC_boss_thane_korthazz() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_thane_korthazz"; + newscript->GetAI = GetAI_boss_thane_korthazz; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp b/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp index 655d1e07a88..c799613d744 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp @@ -1,24 +1,24 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Naxxramas -SD%Complete: 0 -SDComment: Place holder -SDCategory: Naxxramas -EndScriptData */ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Naxxramas +SD%Complete: 0 +SDComment: Place holder +SDCategory: Naxxramas +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp b/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp index 4b41574908f..bb92a16ad25 100644 --- a/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp +++ b/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp @@ -1,423 +1,423 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Netherstorm -SD%Complete: 75 -SDComment: Quest support: 10438, 10652 (special flight paths), 10299,10321,10322,10323,10329,10330,10338,10365(Shutting Down Manaforge) -SDCategory: Netherstorm -EndScriptData */ - -/* ContentData -npc_manaforge_control_console -go_manaforge_control_console -npc_protectorate_nether_drake -npc_veronia -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_manaforge_control_console -######*/ - -#define EMOTE_START "Warning! Emergency shutdown process initiated by $N. Shutdown will complete in two minutes." -#define EMOTE_60 "Emergency shutdown will complete in one minute." -#define EMOTE_30 "Emergency shutdown will complete in thirty seconds." -#define EMOTE_10 "Emergency shutdown will complete in ten seconds." -#define EMOTE_COMPLETE "Emergency shutdown complete." -#define EMOTE_ABORT "Emergency shutdown aborted." - -#define ENTRY_BNAAR_C_CONSOLE 20209 -#define ENTRY_CORUU_C_CONSOLE 20417 -#define ENTRY_DURO_C_CONSOLE 20418 -#define ENTRY_ARA_C_CONSOLE 20440 - -#define ENTRY_SUNFURY_TECH 20218 -#define ENTRY_SUNFURY_PROT 20436 - -#define ENTRY_ARA_TECH 20438 -#define ENTRY_ARA_ENGI 20439 -#define ENTRY_ARA_GORKLONN 20460 - -#define SPELL_DISABLE_VISUAL 35031 -#define SPELL_INTERRUPT_1 35016 //ACID mobs should cast this -#define SPELL_INTERRUPT_2 35176 //ACID mobs should cast this (Manaforge Ara-version) - -struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI -{ - npc_manaforge_control_consoleAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Event_Timer; - uint32 Wave_Timer; - uint32 Phase; - bool Wave; - uint64 someplayer; - uint64 goConsole; - Creature* add; - - void Reset() - { - Event_Timer = 3000; - Wave_Timer = 0; - Phase = 1; - Wave = false; - someplayer = 0; - goConsole = 0; - Creature* add = NULL; - } - - void Aggro(Unit *who) { return; } - - /*void SpellHit(Unit *caster, const SpellEntry *spell) - { - //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 ) - DoSay("Silence! I kill you!",LANG_UNIVERSAL, NULL); - }*/ - - void JustDied(Unit* killer) - { - DoTextEmote(EMOTE_ABORT, NULL); - - if( someplayer ) - { - Unit* p = Unit::GetUnit((*m_creature),someplayer); - if( p && p->GetTypeId() == TYPEID_PLAYER ) - { - switch( m_creature->GetEntry() ) - { - case ENTRY_BNAAR_C_CONSOLE: - ((Player*)p)->FailQuest(10299); - ((Player*)p)->FailQuest(10329); - break; - case ENTRY_CORUU_C_CONSOLE: - ((Player*)p)->FailQuest(10321); - ((Player*)p)->FailQuest(10330); - break; - case ENTRY_DURO_C_CONSOLE: - ((Player*)p)->FailQuest(10322); - ((Player*)p)->FailQuest(10338); - break; - case ENTRY_ARA_C_CONSOLE: - ((Player*)p)->FailQuest(10323); - ((Player*)p)->FailQuest(10365); - break; - } - } - } - - if( goConsole ) - { - if( GameObject* go = GameObject::GetGameObject((*m_creature),goConsole) ) - go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - } - } - - void DoWaveSpawnForCreature(Creature *creature) - { - switch( creature->GetEntry() ) - { - case ENTRY_BNAAR_C_CONSOLE: - if( rand()%2 ) - { - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2933.68,4162.55,164.00,1.60,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2927.36,4212.97,164.00); - } - else - { - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2927.36,4212.97,164.00,4.94,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2933.68,4162.55,164.00); - } - Wave_Timer = 30000; - break; - case ENTRY_CORUU_C_CONSOLE: - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2445.21,2765.26,134.49,3.93,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2424.21,2740.15,133.81); - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2429.86,2731.85,134.53,1.31,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2435.37,2766.04,133.81); - Wave_Timer = 20000; - break; - case ENTRY_DURO_C_CONSOLE: - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2986.80,2205.36,165.37,3.74,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2985.15,2197.32,164.79); - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2952.91,2191.20,165.32,0.22,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2060.01,2185.27,164.67); - Wave_Timer = 15000; - break; - case ENTRY_ARA_C_CONSOLE: - if( rand()%2 ) - { - add = m_creature->SummonCreature(ENTRY_ARA_TECH,4035.11,4038.97,194.27,2.57,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,4003.42,4040.19,193.49); - add = m_creature->SummonCreature(ENTRY_ARA_TECH,4033.66,4036.79,194.28,2.57,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,4003.42,4040.19,193.49); - add = m_creature->SummonCreature(ENTRY_ARA_TECH,4037.13,4037.30,194.23,2.57,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,4003.42,4040.19,193.49); - } - else - { - add = m_creature->SummonCreature(ENTRY_ARA_TECH,3099.59,4049.30,194.22,0.05,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,4028.01,4035.17,193.59); - add = m_creature->SummonCreature(ENTRY_ARA_TECH,3999.72,4046.75,194.22,0.05,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,4028.01,4035.17,193.59); - add = m_creature->SummonCreature(ENTRY_ARA_TECH,3996.81,4048.26,194.22,0.05,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,4028.01,4035.17,193.59); - } - Wave_Timer = 15000; - break; - } - } - void DoFinalSpawnForCreature(Creature *creature) - { - switch( creature->GetEntry() ) - { - case ENTRY_BNAAR_C_CONSOLE: - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2946.52,4201.42,163.47,3.54,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2927.49,4192.81,163.00); - break; - case ENTRY_CORUU_C_CONSOLE: - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2453.88,2737.85,133.27,2.59,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2433.96,2751.53,133.85); - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2441.62,2735.32,134.49,1.97,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2433.96,2751.53,133.85); - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2450.73,2754.50,134.49,3.29,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2433.96,2751.53,133.85); - break; - case ENTRY_DURO_C_CONSOLE: - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2956.18,2202.85,165.32,5.45,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2972.27,2193.22,164.48); - add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2975.30,2211.50,165.32,4.55,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2972.27,2193.22,164.48); - add = m_creature->SummonCreature(ENTRY_SUNFURY_PROT,2965.02,2217.45,164.16,4.96,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,2972.27,2193.22,164.48); - break; - case ENTRY_ARA_C_CONSOLE: - add = m_creature->SummonCreature(ENTRY_ARA_ENGI,3994.51,4020.46,192.18,0.91,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,4008.35,4035.04,192.70); - add = m_creature->SummonCreature(ENTRY_ARA_GORKLONN,4021.56,4059.35,193.59,4.44,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); - if( add ) add->GetMotionMaster()->MovePoint(0,4016.62,4039.89,193.46); - break; - } - } - - void UpdateAI(const uint32 diff) - { - if( Event_Timer < diff ) - { - switch(Phase) - { - case 1: - if( someplayer ) - { - Unit* u = Unit::GetUnit((*m_creature),someplayer); - if( u && u->GetTypeId() == TYPEID_PLAYER ) DoTextEmote(EMOTE_START, u); - } - Event_Timer = 60000; - Wave = true; - ++Phase; - break; - case 2: - DoTextEmote(EMOTE_60, NULL); - Event_Timer = 30000; - ++Phase; - break; - case 3: - DoTextEmote(EMOTE_30, NULL); - Event_Timer = 20000; - DoFinalSpawnForCreature(m_creature); - ++Phase; - break; - case 4: - DoTextEmote(EMOTE_10, NULL); - Event_Timer = 10000; - Wave = false; - ++Phase; - break; - case 5: - DoTextEmote(EMOTE_COMPLETE, NULL); - if( someplayer ) - { - Unit* u = Unit::GetUnit((*m_creature),someplayer); - if( u && u->GetTypeId() == TYPEID_PLAYER ) - ((Player*)u)->KilledMonster(m_creature->GetEntry(),m_creature->GetGUID()); - DoCast(m_creature,SPELL_DISABLE_VISUAL); - } - if( goConsole ) - { - if( GameObject* go = GameObject::GetGameObject((*m_creature),goConsole) ) - go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - } - ++Phase; - break; - default: - break; - } - } else Event_Timer -= diff; - - if( Wave ) - { - if( Wave_Timer < diff ) - { - DoWaveSpawnForCreature(m_creature); - } else Wave_Timer -= diff; - } - } -}; -CreatureAI* GetAI_npc_manaforge_control_console(Creature *_Creature) -{ - return new npc_manaforge_control_consoleAI (_Creature); -} - -/*###### -## go_manaforge_control_console -######*/ - -//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 *player, GameObject* _GO) -{ - if (_GO->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) - { - player->PrepareQuestMenu(_GO->GetGUID()); - player->SendPreparedQuest(_GO->GetGUID()); - } - - Creature* manaforge; - manaforge = NULL; - - switch( _GO->GetAreaId() ) - { - case 3726: //b'naar - if( (player->GetQuestStatus(10299) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10329) == QUEST_STATUS_INCOMPLETE) && - player->HasItemCount(29366,1)) - manaforge = player->SummonCreature(ENTRY_BNAAR_C_CONSOLE,2918.95,4189.98,161.88,0.34,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,125000); - break; - case 3730: //coruu - if( (player->GetQuestStatus(10321) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10330) == QUEST_STATUS_INCOMPLETE) && - player->HasItemCount(29396,1)) - manaforge = player->SummonCreature(ENTRY_CORUU_C_CONSOLE,2426.77,2750.38,133.24,2.14,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,125000); - break; - case 3734: //duro - if( (player->GetQuestStatus(10322) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10338) == QUEST_STATUS_INCOMPLETE) && - player->HasItemCount(29397,1)) - manaforge = player->SummonCreature(ENTRY_DURO_C_CONSOLE,2976.48,2183.29,163.20,1.85,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,125000); - break; - case 3722: //ara - if( (player->GetQuestStatus(10323) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10365) == QUEST_STATUS_INCOMPLETE) && - player->HasItemCount(29411,1)) - manaforge = player->SummonCreature(ENTRY_ARA_C_CONSOLE,4013.71,4028.76,192.10,1.25,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,125000); - break; - } - - if( manaforge ) - { - ((npc_manaforge_control_consoleAI*)manaforge->AI())->someplayer = player->GetGUID(); - ((npc_manaforge_control_consoleAI*)manaforge->AI())->goConsole = _GO->GetGUID(); - _GO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - } - return true; -} - -/*###### -## npc_protectorate_nether_drake -######*/ - -bool GossipHello_npc_protectorate_nether_drake(Player *player, Creature *_Creature) -{ - //On Nethery Wings - if (player->GetQuestStatus(10438) == QUEST_STATUS_INCOMPLETE && player->HasItemCount(29778,1) ) - player->ADD_GOSSIP_ITEM(0, "Fly me to Ultris", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_protectorate_nether_drake(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - - std::vector nodes; - - nodes.resize(2); - nodes[0] = 152; //from drake - nodes[1] = 153; //end at drake - player->ActivateTaxiPathTo(nodes); //TaxiPath 627 (possibly 627+628(152->153->154->155) ) - } - return true; -} - -/*###### -## npc_veronia -######*/ - -bool GossipHello_npc_veronia(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - //Behind Enemy Lines - if (player->GetQuestStatus(10652) && !player->GetQuestRewardStatus(10652)) - player->ADD_GOSSIP_ITEM(0, "Fly me to Manaforge Coruu please", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_veronia(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,34905,true); //TaxiPath 606 - } - return true; -} - -/*###### -## -######*/ - -void AddSC_netherstorm() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="go_manaforge_control_console"; - newscript->pGOHello = &GOHello_go_manaforge_control_console; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_manaforge_control_console"; - newscript->GetAI = GetAI_npc_manaforge_control_console; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_protectorate_nether_drake"; - newscript->pGossipHello = &GossipHello_npc_protectorate_nether_drake; - newscript->pGossipSelect = &GossipSelect_npc_protectorate_nether_drake; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_veronia"; - newscript->pGossipHello = &GossipHello_npc_veronia; - newscript->pGossipSelect = &GossipSelect_npc_veronia; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Netherstorm +SD%Complete: 75 +SDComment: Quest support: 10438, 10652 (special flight paths), 10299,10321,10322,10323,10329,10330,10338,10365(Shutting Down Manaforge) +SDCategory: Netherstorm +EndScriptData */ + +/* ContentData +npc_manaforge_control_console +go_manaforge_control_console +npc_protectorate_nether_drake +npc_veronia +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_manaforge_control_console +######*/ + +#define EMOTE_START "Warning! Emergency shutdown process initiated by $N. Shutdown will complete in two minutes." +#define EMOTE_60 "Emergency shutdown will complete in one minute." +#define EMOTE_30 "Emergency shutdown will complete in thirty seconds." +#define EMOTE_10 "Emergency shutdown will complete in ten seconds." +#define EMOTE_COMPLETE "Emergency shutdown complete." +#define EMOTE_ABORT "Emergency shutdown aborted." + +#define ENTRY_BNAAR_C_CONSOLE 20209 +#define ENTRY_CORUU_C_CONSOLE 20417 +#define ENTRY_DURO_C_CONSOLE 20418 +#define ENTRY_ARA_C_CONSOLE 20440 + +#define ENTRY_SUNFURY_TECH 20218 +#define ENTRY_SUNFURY_PROT 20436 + +#define ENTRY_ARA_TECH 20438 +#define ENTRY_ARA_ENGI 20439 +#define ENTRY_ARA_GORKLONN 20460 + +#define SPELL_DISABLE_VISUAL 35031 +#define SPELL_INTERRUPT_1 35016 //ACID mobs should cast this +#define SPELL_INTERRUPT_2 35176 //ACID mobs should cast this (Manaforge Ara-version) + +struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI +{ + npc_manaforge_control_consoleAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Event_Timer; + uint32 Wave_Timer; + uint32 Phase; + bool Wave; + uint64 someplayer; + uint64 goConsole; + Creature* add; + + void Reset() + { + Event_Timer = 3000; + Wave_Timer = 0; + Phase = 1; + Wave = false; + someplayer = 0; + goConsole = 0; + Creature* add = NULL; + } + + void Aggro(Unit *who) { return; } + + /*void SpellHit(Unit *caster, const SpellEntry *spell) + { + //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 ) + DoSay("Silence! I kill you!",LANG_UNIVERSAL, NULL); + }*/ + + void JustDied(Unit* killer) + { + DoTextEmote(EMOTE_ABORT, NULL); + + if( someplayer ) + { + Unit* p = Unit::GetUnit((*m_creature),someplayer); + if( p && p->GetTypeId() == TYPEID_PLAYER ) + { + switch( m_creature->GetEntry() ) + { + case ENTRY_BNAAR_C_CONSOLE: + ((Player*)p)->FailQuest(10299); + ((Player*)p)->FailQuest(10329); + break; + case ENTRY_CORUU_C_CONSOLE: + ((Player*)p)->FailQuest(10321); + ((Player*)p)->FailQuest(10330); + break; + case ENTRY_DURO_C_CONSOLE: + ((Player*)p)->FailQuest(10322); + ((Player*)p)->FailQuest(10338); + break; + case ENTRY_ARA_C_CONSOLE: + ((Player*)p)->FailQuest(10323); + ((Player*)p)->FailQuest(10365); + break; + } + } + } + + if( goConsole ) + { + if( GameObject* go = GameObject::GetGameObject((*m_creature),goConsole) ) + go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + } + } + + void DoWaveSpawnForCreature(Creature *creature) + { + switch( creature->GetEntry() ) + { + case ENTRY_BNAAR_C_CONSOLE: + if( rand()%2 ) + { + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2933.68,4162.55,164.00,1.60,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2927.36,4212.97,164.00); + } + else + { + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2927.36,4212.97,164.00,4.94,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2933.68,4162.55,164.00); + } + Wave_Timer = 30000; + break; + case ENTRY_CORUU_C_CONSOLE: + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2445.21,2765.26,134.49,3.93,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2424.21,2740.15,133.81); + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2429.86,2731.85,134.53,1.31,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2435.37,2766.04,133.81); + Wave_Timer = 20000; + break; + case ENTRY_DURO_C_CONSOLE: + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2986.80,2205.36,165.37,3.74,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2985.15,2197.32,164.79); + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2952.91,2191.20,165.32,0.22,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2060.01,2185.27,164.67); + Wave_Timer = 15000; + break; + case ENTRY_ARA_C_CONSOLE: + if( rand()%2 ) + { + add = m_creature->SummonCreature(ENTRY_ARA_TECH,4035.11,4038.97,194.27,2.57,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,4003.42,4040.19,193.49); + add = m_creature->SummonCreature(ENTRY_ARA_TECH,4033.66,4036.79,194.28,2.57,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,4003.42,4040.19,193.49); + add = m_creature->SummonCreature(ENTRY_ARA_TECH,4037.13,4037.30,194.23,2.57,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,4003.42,4040.19,193.49); + } + else + { + add = m_creature->SummonCreature(ENTRY_ARA_TECH,3099.59,4049.30,194.22,0.05,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,4028.01,4035.17,193.59); + add = m_creature->SummonCreature(ENTRY_ARA_TECH,3999.72,4046.75,194.22,0.05,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,4028.01,4035.17,193.59); + add = m_creature->SummonCreature(ENTRY_ARA_TECH,3996.81,4048.26,194.22,0.05,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,4028.01,4035.17,193.59); + } + Wave_Timer = 15000; + break; + } + } + void DoFinalSpawnForCreature(Creature *creature) + { + switch( creature->GetEntry() ) + { + case ENTRY_BNAAR_C_CONSOLE: + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2946.52,4201.42,163.47,3.54,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2927.49,4192.81,163.00); + break; + case ENTRY_CORUU_C_CONSOLE: + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2453.88,2737.85,133.27,2.59,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2433.96,2751.53,133.85); + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2441.62,2735.32,134.49,1.97,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2433.96,2751.53,133.85); + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2450.73,2754.50,134.49,3.29,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2433.96,2751.53,133.85); + break; + case ENTRY_DURO_C_CONSOLE: + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2956.18,2202.85,165.32,5.45,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2972.27,2193.22,164.48); + add = m_creature->SummonCreature(ENTRY_SUNFURY_TECH,2975.30,2211.50,165.32,4.55,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2972.27,2193.22,164.48); + add = m_creature->SummonCreature(ENTRY_SUNFURY_PROT,2965.02,2217.45,164.16,4.96,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,2972.27,2193.22,164.48); + break; + case ENTRY_ARA_C_CONSOLE: + add = m_creature->SummonCreature(ENTRY_ARA_ENGI,3994.51,4020.46,192.18,0.91,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,4008.35,4035.04,192.70); + add = m_creature->SummonCreature(ENTRY_ARA_GORKLONN,4021.56,4059.35,193.59,4.44,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if( add ) add->GetMotionMaster()->MovePoint(0,4016.62,4039.89,193.46); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if( Event_Timer < diff ) + { + switch(Phase) + { + case 1: + if( someplayer ) + { + Unit* u = Unit::GetUnit((*m_creature),someplayer); + if( u && u->GetTypeId() == TYPEID_PLAYER ) DoTextEmote(EMOTE_START, u); + } + Event_Timer = 60000; + Wave = true; + ++Phase; + break; + case 2: + DoTextEmote(EMOTE_60, NULL); + Event_Timer = 30000; + ++Phase; + break; + case 3: + DoTextEmote(EMOTE_30, NULL); + Event_Timer = 20000; + DoFinalSpawnForCreature(m_creature); + ++Phase; + break; + case 4: + DoTextEmote(EMOTE_10, NULL); + Event_Timer = 10000; + Wave = false; + ++Phase; + break; + case 5: + DoTextEmote(EMOTE_COMPLETE, NULL); + if( someplayer ) + { + Unit* u = Unit::GetUnit((*m_creature),someplayer); + if( u && u->GetTypeId() == TYPEID_PLAYER ) + ((Player*)u)->KilledMonster(m_creature->GetEntry(),m_creature->GetGUID()); + DoCast(m_creature,SPELL_DISABLE_VISUAL); + } + if( goConsole ) + { + if( GameObject* go = GameObject::GetGameObject((*m_creature),goConsole) ) + go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + } + ++Phase; + break; + default: + break; + } + } else Event_Timer -= diff; + + if( Wave ) + { + if( Wave_Timer < diff ) + { + DoWaveSpawnForCreature(m_creature); + } else Wave_Timer -= diff; + } + } +}; +CreatureAI* GetAI_npc_manaforge_control_console(Creature *_Creature) +{ + return new npc_manaforge_control_consoleAI (_Creature); +} + +/*###### +## go_manaforge_control_console +######*/ + +//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 *player, GameObject* _GO) +{ + if (_GO->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) + { + player->PrepareQuestMenu(_GO->GetGUID()); + player->SendPreparedQuest(_GO->GetGUID()); + } + + Creature* manaforge; + manaforge = NULL; + + switch( _GO->GetAreaId() ) + { + case 3726: //b'naar + if( (player->GetQuestStatus(10299) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10329) == QUEST_STATUS_INCOMPLETE) && + player->HasItemCount(29366,1)) + manaforge = player->SummonCreature(ENTRY_BNAAR_C_CONSOLE,2918.95,4189.98,161.88,0.34,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,125000); + break; + case 3730: //coruu + if( (player->GetQuestStatus(10321) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10330) == QUEST_STATUS_INCOMPLETE) && + player->HasItemCount(29396,1)) + manaforge = player->SummonCreature(ENTRY_CORUU_C_CONSOLE,2426.77,2750.38,133.24,2.14,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,125000); + break; + case 3734: //duro + if( (player->GetQuestStatus(10322) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10338) == QUEST_STATUS_INCOMPLETE) && + player->HasItemCount(29397,1)) + manaforge = player->SummonCreature(ENTRY_DURO_C_CONSOLE,2976.48,2183.29,163.20,1.85,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,125000); + break; + case 3722: //ara + if( (player->GetQuestStatus(10323) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10365) == QUEST_STATUS_INCOMPLETE) && + player->HasItemCount(29411,1)) + manaforge = player->SummonCreature(ENTRY_ARA_C_CONSOLE,4013.71,4028.76,192.10,1.25,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,125000); + break; + } + + if( manaforge ) + { + ((npc_manaforge_control_consoleAI*)manaforge->AI())->someplayer = player->GetGUID(); + ((npc_manaforge_control_consoleAI*)manaforge->AI())->goConsole = _GO->GetGUID(); + _GO->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + } + return true; +} + +/*###### +## npc_protectorate_nether_drake +######*/ + +bool GossipHello_npc_protectorate_nether_drake(Player *player, Creature *_Creature) +{ + //On Nethery Wings + if (player->GetQuestStatus(10438) == QUEST_STATUS_INCOMPLETE && player->HasItemCount(29778,1) ) + player->ADD_GOSSIP_ITEM(0, "Fly me to Ultris", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_protectorate_nether_drake(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + + std::vector nodes; + + nodes.resize(2); + nodes[0] = 152; //from drake + nodes[1] = 153; //end at drake + player->ActivateTaxiPathTo(nodes); //TaxiPath 627 (possibly 627+628(152->153->154->155) ) + } + return true; +} + +/*###### +## npc_veronia +######*/ + +bool GossipHello_npc_veronia(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + //Behind Enemy Lines + if (player->GetQuestStatus(10652) && !player->GetQuestRewardStatus(10652)) + player->ADD_GOSSIP_ITEM(0, "Fly me to Manaforge Coruu please", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_veronia(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,34905,true); //TaxiPath 606 + } + return true; +} + +/*###### +## +######*/ + +void AddSC_netherstorm() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="go_manaforge_control_console"; + newscript->pGOHello = &GOHello_go_manaforge_control_console; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_manaforge_control_console"; + newscript->GetAI = GetAI_npc_manaforge_control_console; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_protectorate_nether_drake"; + newscript->pGossipHello = &GossipHello_npc_protectorate_nether_drake; + newscript->pGossipSelect = &GossipSelect_npc_protectorate_nether_drake; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_veronia"; + newscript->pGossipHello = &GossipHello_npc_veronia; + newscript->pGossipSelect = &GossipSelect_npc_veronia; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/onyxias_lair/boss_onyxia.cpp b/src/bindings/scripts/scripts/zone/onyxias_lair/boss_onyxia.cpp index 87ee5b8b0cc..1c8ff67436f 100644 --- a/src/bindings/scripts/scripts/zone/onyxias_lair/boss_onyxia.cpp +++ b/src/bindings/scripts/scripts/zone/onyxias_lair/boss_onyxia.cpp @@ -1,229 +1,229 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Onyxia -SD%Complete: 50 -SDComment: Phase 2 has many errors. Recommend Rewrite of entire script. -SDCategory: Onyxia's Lair -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_WINGBUFFET 18500 -#define SPELL_FLAMEBREATH 18435 -#define SPELL_CLEAVE 19983 -#define SPELL_TAILSWEEP 15847 -#define SPELL_KNOCK_AWAY 19633 - -#define SPELL_ENGULFINGFLAMES 20019 -#define SPELL_DEEPBREATH 23461 -#define SPELL_FIREBALL 18392 - -#define SPELL_BELLOWINGROAR 18431 -#define SPELL_HEATED_GROUND 22191 - -#define SPELL_SUMMONWHELP 17646 - -#define SAY_AGGRO "How fortuitous. Usually, I must leave my lair to feed." -#define SAY_KILL "Learn your place mortal!" -#define SAY_PHASE_2_TRANS "This meaningless exertion bores me. I'll incinerate you from above!" -#define SAY_PHASE_3_TRANS "It seems you'll need another lesson!" -#define EMOTE_BREATH "takes a deep breath..." - -static float MovementLocations[7][3]= -{ - {-65.8444, -213.809, -60.2985}, - {22.87639, -217.152, -60.0548}, - {-33.5561, -182.682, -60.9457}, - {-31.4963, -250.123, -60.1278}, - {-2.78999, -181.431, -60.8962}, - {-54.9415, -232.242, -60.5555}, - {10.56655, -241.478, -60.9426}, -}; - -static float SpawnLocations[4][3]= -{ - {-30.127, -254.463, -89.440}, - {-30.817, -177.106, -89.258}, - {14.480, -241.560, -85.6300}, - {17.372, -190.840, -85.2810}, -}; - -#define CREATURE_WHELP 11262 - -struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI -{ - boss_onyxiaAI(Creature* c) : ScriptedAI(c) {Reset();} - - uint32 Phase; - - uint32 FlameBreathTimer; - uint32 CleaveTimer; - uint32 TailSweepTimer; - uint32 MovementTimer; - uint32 EngulfingFlamesTimer; - uint32 SummonWhelpsTimer; - uint32 BellowingRoarTimer; - uint32 WingBuffetTimer; - - void Reset() - { - Phase = 1; - - FlameBreathTimer = 20000; - TailSweepTimer = 2000; - CleaveTimer = 15000; - MovementTimer = 5000; - EngulfingFlamesTimer = 15000; - SummonWhelpsTimer = 45000; - BellowingRoarTimer = 30000; - WingBuffetTimer = 17000; - } - - void Aggro(Unit* who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - } - - void KilledUnit(Unit *victim) - { - DoYell(SAY_KILL, LANG_UNIVERSAL, NULL); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 60) && (Phase == 1)) - { - Phase = 2; - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - DoYell(SAY_PHASE_2_TRANS, LANG_UNIVERSAL, NULL); - } - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 40) && (Phase == 2)) - { - Phase = 3; - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); - DoYell(SAY_PHASE_3_TRANS, LANG_UNIVERSAL, NULL); - } - - if(Phase == 1 || Phase == 3) - { - if(FlameBreathTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FLAMEBREATH); - FlameBreathTimer = 15000; - }else FlameBreathTimer -= diff; - - if(TailSweepTimer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(target && !m_creature->HasInArc(M_PI, target)) - DoCast(target, SPELL_TAILSWEEP); - - TailSweepTimer = 10000; - }else TailSweepTimer -= diff; - - if(CleaveTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CLEAVE); - CleaveTimer = 10000; - }else CleaveTimer -= diff; - - if(WingBuffetTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_WINGBUFFET); - WingBuffetTimer = 7000 + ((rand()%8)*1000); - }else WingBuffetTimer -= diff; - - DoMeleeAttackIfReady(); - } - - if(Phase == 2) - { - if(!m_creature->isHover()) - { - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - m_creature->SetHover(true); - } - - if(!m_creature->GetMotionMaster()->empty() && (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)) - m_creature->GetMotionMaster()->Clear(false); - - if(MovementTimer < diff) - { - uint32 random = rand()%8; - if(random < 7) - m_creature->GetMotionMaster()->MovePoint(0, MovementLocations[random][0], MovementLocations[random][1], MovementLocations[random][2]); - else - { - DoTextEmote(EMOTE_BREATH, NULL); - DoCast(m_creature->getVictim(), SPELL_DEEPBREATH); - } - MovementTimer = 25000; - }else MovementTimer -= diff; - - if(EngulfingFlamesTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_ENGULFINGFLAMES); - EngulfingFlamesTimer = 10000; - }else EngulfingFlamesTimer -= diff; - - if(SummonWhelpsTimer < diff) - { - uint32 max = rand()%20; - for(uint8 i = 0; i < max; ++i) - { - uint8 random = rand()%4; - Creature* Whelp = m_creature->SummonCreature(CREATURE_WHELP, SpawnLocations[random][0], SpawnLocations[random][1], SpawnLocations[random][2], 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); - if(Whelp) - Whelp->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM, 0)); - } - SummonWhelpsTimer = 45000; - }else SummonWhelpsTimer -= diff; - } - - if(Phase == 3) - { - if(BellowingRoarTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_BELLOWINGROAR); - BellowingRoarTimer = 30000; - }else BellowingRoarTimer -= diff; - } - } -}; - -CreatureAI* GetAI_boss_onyxiaAI(Creature *_Creature) -{ - return new boss_onyxiaAI (_Creature); -} - -void AddSC_boss_onyxia() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_onyxia"; - newscript->GetAI = GetAI_boss_onyxiaAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Onyxia +SD%Complete: 50 +SDComment: Phase 2 has many errors. Recommend Rewrite of entire script. +SDCategory: Onyxia's Lair +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_WINGBUFFET 18500 +#define SPELL_FLAMEBREATH 18435 +#define SPELL_CLEAVE 19983 +#define SPELL_TAILSWEEP 15847 +#define SPELL_KNOCK_AWAY 19633 + +#define SPELL_ENGULFINGFLAMES 20019 +#define SPELL_DEEPBREATH 23461 +#define SPELL_FIREBALL 18392 + +#define SPELL_BELLOWINGROAR 18431 +#define SPELL_HEATED_GROUND 22191 + +#define SPELL_SUMMONWHELP 17646 + +#define SAY_AGGRO "How fortuitous. Usually, I must leave my lair to feed." +#define SAY_KILL "Learn your place mortal!" +#define SAY_PHASE_2_TRANS "This meaningless exertion bores me. I'll incinerate you from above!" +#define SAY_PHASE_3_TRANS "It seems you'll need another lesson!" +#define EMOTE_BREATH "takes a deep breath..." + +static float MovementLocations[7][3]= +{ + {-65.8444, -213.809, -60.2985}, + {22.87639, -217.152, -60.0548}, + {-33.5561, -182.682, -60.9457}, + {-31.4963, -250.123, -60.1278}, + {-2.78999, -181.431, -60.8962}, + {-54.9415, -232.242, -60.5555}, + {10.56655, -241.478, -60.9426}, +}; + +static float SpawnLocations[4][3]= +{ + {-30.127, -254.463, -89.440}, + {-30.817, -177.106, -89.258}, + {14.480, -241.560, -85.6300}, + {17.372, -190.840, -85.2810}, +}; + +#define CREATURE_WHELP 11262 + +struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI +{ + boss_onyxiaAI(Creature* c) : ScriptedAI(c) {Reset();} + + uint32 Phase; + + uint32 FlameBreathTimer; + uint32 CleaveTimer; + uint32 TailSweepTimer; + uint32 MovementTimer; + uint32 EngulfingFlamesTimer; + uint32 SummonWhelpsTimer; + uint32 BellowingRoarTimer; + uint32 WingBuffetTimer; + + void Reset() + { + Phase = 1; + + FlameBreathTimer = 20000; + TailSweepTimer = 2000; + CleaveTimer = 15000; + MovementTimer = 5000; + EngulfingFlamesTimer = 15000; + SummonWhelpsTimer = 45000; + BellowingRoarTimer = 30000; + WingBuffetTimer = 17000; + } + + void Aggro(Unit* who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + } + + void KilledUnit(Unit *victim) + { + DoYell(SAY_KILL, LANG_UNIVERSAL, NULL); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 60) && (Phase == 1)) + { + Phase = 2; + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + DoYell(SAY_PHASE_2_TRANS, LANG_UNIVERSAL, NULL); + } + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 40) && (Phase == 2)) + { + Phase = 3; + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + DoYell(SAY_PHASE_3_TRANS, LANG_UNIVERSAL, NULL); + } + + if(Phase == 1 || Phase == 3) + { + if(FlameBreathTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FLAMEBREATH); + FlameBreathTimer = 15000; + }else FlameBreathTimer -= diff; + + if(TailSweepTimer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(target && !m_creature->HasInArc(M_PI, target)) + DoCast(target, SPELL_TAILSWEEP); + + TailSweepTimer = 10000; + }else TailSweepTimer -= diff; + + if(CleaveTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + CleaveTimer = 10000; + }else CleaveTimer -= diff; + + if(WingBuffetTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_WINGBUFFET); + WingBuffetTimer = 7000 + ((rand()%8)*1000); + }else WingBuffetTimer -= diff; + + DoMeleeAttackIfReady(); + } + + if(Phase == 2) + { + if(!m_creature->isHover()) + { + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + m_creature->SetHover(true); + } + + if(!m_creature->GetMotionMaster()->empty() && (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)) + m_creature->GetMotionMaster()->Clear(false); + + if(MovementTimer < diff) + { + uint32 random = rand()%8; + if(random < 7) + m_creature->GetMotionMaster()->MovePoint(0, MovementLocations[random][0], MovementLocations[random][1], MovementLocations[random][2]); + else + { + DoTextEmote(EMOTE_BREATH, NULL); + DoCast(m_creature->getVictim(), SPELL_DEEPBREATH); + } + MovementTimer = 25000; + }else MovementTimer -= diff; + + if(EngulfingFlamesTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_ENGULFINGFLAMES); + EngulfingFlamesTimer = 10000; + }else EngulfingFlamesTimer -= diff; + + if(SummonWhelpsTimer < diff) + { + uint32 max = rand()%20; + for(uint8 i = 0; i < max; ++i) + { + uint8 random = rand()%4; + Creature* Whelp = m_creature->SummonCreature(CREATURE_WHELP, SpawnLocations[random][0], SpawnLocations[random][1], SpawnLocations[random][2], 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + if(Whelp) + Whelp->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM, 0)); + } + SummonWhelpsTimer = 45000; + }else SummonWhelpsTimer -= diff; + } + + if(Phase == 3) + { + if(BellowingRoarTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_BELLOWINGROAR); + BellowingRoarTimer = 30000; + }else BellowingRoarTimer -= diff; + } + } +}; + +CreatureAI* GetAI_boss_onyxiaAI(Creature *_Creature) +{ + return new boss_onyxiaAI (_Creature); +} + +void AddSC_boss_onyxia() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_onyxia"; + newscript->GetAI = GetAI_boss_onyxiaAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/orgrimmar/orgrimmar.cpp b/src/bindings/scripts/scripts/zone/orgrimmar/orgrimmar.cpp index 9840f7711dc..c14aceaf121 100644 --- a/src/bindings/scripts/scripts/zone/orgrimmar/orgrimmar.cpp +++ b/src/bindings/scripts/scripts/zone/orgrimmar/orgrimmar.cpp @@ -1,265 +1,265 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Orgrimmar -SD%Complete: 100 -SDComment: Quest support: 2460, 5727, 6566 -SDCategory: Orgrimmar -EndScriptData */ - -/* ContentData -npc_neeru_fireblade npc_text + gossip options text missing -npc_shenthul -npc_thrall_warchief -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_neeru_fireblade -######*/ - -#define QUEST_5727 5727 - -bool GossipHello_npc_neeru_fireblade(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(QUEST_5727) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(0, "You may speak frankly, Neeru...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(4513, _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_neeru_fireblade(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, "[PH] ...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(4513, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(QUEST_5727); - break; - } - return true; -} - -/*###### -## npc_shenthul -######*/ - -#define QUEST_2460 2460 - -struct MANGOS_DLL_DECL npc_shenthulAI : public ScriptedAI -{ - npc_shenthulAI(Creature* c) : ScriptedAI(c) { Reset(); } - - bool CanTalk; - bool CanEmote; - uint32 Salute_Timer; - uint32 Reset_Timer; - uint64 playerGUID; - - void Reset() - { - CanTalk = false; - CanEmote = false; - Salute_Timer = 6000; - Reset_Timer = 0; - playerGUID = 0; - } - - void Aggro(Unit* who) { } - - void UpdateAI(const uint32 diff) - { - if( CanEmote ) - if( Reset_Timer < diff ) - { - if( Unit* temp = Unit::GetUnit((*m_creature),playerGUID) ) - if( temp->GetTypeId() == TYPEID_PLAYER ) - ((Player*)temp)->FailQuest(QUEST_2460); - Reset(); - } else Reset_Timer -= diff; - - if( CanTalk && !CanEmote ) - if( Salute_Timer < diff ) - { - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); - CanEmote = true; - Reset_Timer = 60000; - } else Salute_Timer -= diff; - - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_shenthul(Creature *_Creature) -{ - return new npc_shenthulAI (_Creature); -} - -bool QuestAccept_npc_shenthul(Player* player, Creature* creature, Quest const* quest) -{ - if( quest->GetQuestId() == QUEST_2460 ) - { - ((npc_shenthulAI*)creature->AI())->CanTalk = true; - ((npc_shenthulAI*)creature->AI())->playerGUID = player->GetGUID(); - } - return true; -} - -bool ReciveEmote_npc_shenthul(Player *player, Creature *_Creature, uint32 emote) -{ - if( emote == TEXTEMOTE_SALUTE && player->GetQuestStatus(QUEST_2460) == QUEST_STATUS_INCOMPLETE ) - if( ((npc_shenthulAI*)_Creature->AI())->CanEmote ) - { - player->AreaExploredOrEventHappens(QUEST_2460); - ((npc_shenthulAI*)_Creature->AI())->Reset(); - } - return true; -} - -/*###### -## 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 -{ - npc_thrall_warchiefAI(Creature* c) : ScriptedAI(c) { Reset(); } - - uint32 ChainLightning_Timer; - uint32 Shock_Timer; - - void Reset() - { - ChainLightning_Timer = 2000; - Shock_Timer = 8000; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( ChainLightning_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_CHAIN_LIGHTNING); - ChainLightning_Timer = 9000; - }else ChainLightning_Timer -= diff; - - if( Shock_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_SHOCK); - Shock_Timer = 15000; - }else Shock_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_thrall_warchief(Creature *_Creature) -{ - return new npc_thrall_warchiefAI (_Creature); -} - -bool GossipHello_npc_thrall_warchief(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(QUEST_6566) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(0, "Please share your wisdom with me, Warchief.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_thrall_warchief(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, "What discoveries?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(5733, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(0, "Usurper?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(5734, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(0, "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); - player->SEND_GOSSIP_MENU(5735, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(0, "I... I did not think of it that way, Warchief.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(5736, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM(0, "I live only to serve, Warchief! My life is empty and meaningless without your guidance.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - player->SEND_GOSSIP_MENU(5737, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM(0, "Of course, Warchief!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); - player->SEND_GOSSIP_MENU(5738, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(QUEST_6566); - break; - } - return true; -} - -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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_shenthul"; - newscript->GetAI = GetAI_npc_shenthul; - newscript->pQuestAccept = &QuestAccept_npc_shenthul; - newscript->pReceiveEmote = &ReciveEmote_npc_shenthul; - m_scripts[nrscripts++] = newscript; - - 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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Orgrimmar +SD%Complete: 100 +SDComment: Quest support: 2460, 5727, 6566 +SDCategory: Orgrimmar +EndScriptData */ + +/* ContentData +npc_neeru_fireblade npc_text + gossip options text missing +npc_shenthul +npc_thrall_warchief +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_neeru_fireblade +######*/ + +#define QUEST_5727 5727 + +bool GossipHello_npc_neeru_fireblade(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(QUEST_5727) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(0, "You may speak frankly, Neeru...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(4513, _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_neeru_fireblade(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, "[PH] ...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(4513, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(QUEST_5727); + break; + } + return true; +} + +/*###### +## npc_shenthul +######*/ + +#define QUEST_2460 2460 + +struct MANGOS_DLL_DECL npc_shenthulAI : public ScriptedAI +{ + npc_shenthulAI(Creature* c) : ScriptedAI(c) { Reset(); } + + bool CanTalk; + bool CanEmote; + uint32 Salute_Timer; + uint32 Reset_Timer; + uint64 playerGUID; + + void Reset() + { + CanTalk = false; + CanEmote = false; + Salute_Timer = 6000; + Reset_Timer = 0; + playerGUID = 0; + } + + void Aggro(Unit* who) { } + + void UpdateAI(const uint32 diff) + { + if( CanEmote ) + if( Reset_Timer < diff ) + { + if( Unit* temp = Unit::GetUnit((*m_creature),playerGUID) ) + if( temp->GetTypeId() == TYPEID_PLAYER ) + ((Player*)temp)->FailQuest(QUEST_2460); + Reset(); + } else Reset_Timer -= diff; + + if( CanTalk && !CanEmote ) + if( Salute_Timer < diff ) + { + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + CanEmote = true; + Reset_Timer = 60000; + } else Salute_Timer -= diff; + + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_shenthul(Creature *_Creature) +{ + return new npc_shenthulAI (_Creature); +} + +bool QuestAccept_npc_shenthul(Player* player, Creature* creature, Quest const* quest) +{ + if( quest->GetQuestId() == QUEST_2460 ) + { + ((npc_shenthulAI*)creature->AI())->CanTalk = true; + ((npc_shenthulAI*)creature->AI())->playerGUID = player->GetGUID(); + } + return true; +} + +bool ReciveEmote_npc_shenthul(Player *player, Creature *_Creature, uint32 emote) +{ + if( emote == TEXTEMOTE_SALUTE && player->GetQuestStatus(QUEST_2460) == QUEST_STATUS_INCOMPLETE ) + if( ((npc_shenthulAI*)_Creature->AI())->CanEmote ) + { + player->AreaExploredOrEventHappens(QUEST_2460); + ((npc_shenthulAI*)_Creature->AI())->Reset(); + } + return true; +} + +/*###### +## 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 +{ + npc_thrall_warchiefAI(Creature* c) : ScriptedAI(c) { Reset(); } + + uint32 ChainLightning_Timer; + uint32 Shock_Timer; + + void Reset() + { + ChainLightning_Timer = 2000; + Shock_Timer = 8000; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( ChainLightning_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_CHAIN_LIGHTNING); + ChainLightning_Timer = 9000; + }else ChainLightning_Timer -= diff; + + if( Shock_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_SHOCK); + Shock_Timer = 15000; + }else Shock_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_thrall_warchief(Creature *_Creature) +{ + return new npc_thrall_warchiefAI (_Creature); +} + +bool GossipHello_npc_thrall_warchief(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(QUEST_6566) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM(0, "Please share your wisdom with me, Warchief.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_thrall_warchief(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, "What discoveries?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(5733, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM(0, "Usurper?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(5734, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM(0, "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); + player->SEND_GOSSIP_MENU(5735, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM(0, "I... I did not think of it that way, Warchief.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(5736, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM(0, "I live only to serve, Warchief! My life is empty and meaningless without your guidance.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + player->SEND_GOSSIP_MENU(5737, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + player->ADD_GOSSIP_ITEM(0, "Of course, Warchief!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); + player->SEND_GOSSIP_MENU(5738, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+7: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(QUEST_6566); + break; + } + return true; +} + +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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_shenthul"; + newscript->GetAI = GetAI_npc_shenthul; + newscript->pQuestAccept = &QuestAccept_npc_shenthul; + newscript->pReceiveEmote = &ReciveEmote_npc_shenthul; + m_scripts[nrscripts++] = newscript; + + 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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/razorfen_downs/boss_amnennar_the_coldbringer.cpp b/src/bindings/scripts/scripts/zone/razorfen_downs/boss_amnennar_the_coldbringer.cpp index d25781c0ca6..a7cdf773e63 100644 --- a/src/bindings/scripts/scripts/zone/razorfen_downs/boss_amnennar_the_coldbringer.cpp +++ b/src/bindings/scripts/scripts/zone/razorfen_downs/boss_amnennar_the_coldbringer.cpp @@ -1,140 +1,140 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_0 "You'll never leave this place... alive." -#define SAY_1 "Come, spirits, attend your master." -#define SAY_SLAY "Too...easy!" -#define SOUND_AGGRO 5825 -#define SOUND_SLAY 5826 -#define SOUND_SUMMON 5829 - -#define SPELL_AMNENNARSWRATH 13009 -#define SPELL_FROSTBOLT 10179 - -struct MANGOS_DLL_DECL boss_amnennar_the_coldbringerAI : public ScriptedAI -{ - boss_amnennar_the_coldbringerAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 AmnenarsWrath_Timer; - uint32 FrostBolt_Timer; - bool Spectrals; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - AmnenarsWrath_Timer = 8000; - FrostBolt_Timer = 1000; - Spectrals = false; - } - - void Aggro(Unit *who) - { - DoYell(SAY_0,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void KilledUnit() - { - DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY); - } - - void SummonSpectrals(Unit* victim) - { - Rand = rand()%5; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%5; - switch (rand()%2) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - Summoned = DoSpawnCreature(8585, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - if(Summoned) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //AmnenarsWrath_Timer - if (AmnenarsWrath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_AMNENNARSWRATH); - AmnenarsWrath_Timer = 12000; - } else AmnenarsWrath_Timer -= diff; - - //FrostBolt_Timer - if (FrostBolt_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_FROSTBOLT); - - FrostBolt_Timer = 8000; - } else FrostBolt_Timer -= diff; - - if ( !Spectrals && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50 ) - { - DoYell(SAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON); - - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - SummonSpectrals(target); - SummonSpectrals(target); - SummonSpectrals(target); - Spectrals = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_amnennar_the_coldbringer(Creature *_Creature) -{ - return new boss_amnennar_the_coldbringerAI (_Creature); -} - -void AddSC_boss_amnennar_the_coldbringer() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_amnennar_the_coldbringer"; - newscript->GetAI = GetAI_boss_amnennar_the_coldbringer; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_0 "You'll never leave this place... alive." +#define SAY_1 "Come, spirits, attend your master." +#define SAY_SLAY "Too...easy!" +#define SOUND_AGGRO 5825 +#define SOUND_SLAY 5826 +#define SOUND_SUMMON 5829 + +#define SPELL_AMNENNARSWRATH 13009 +#define SPELL_FROSTBOLT 10179 + +struct MANGOS_DLL_DECL boss_amnennar_the_coldbringerAI : public ScriptedAI +{ + boss_amnennar_the_coldbringerAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 AmnenarsWrath_Timer; + uint32 FrostBolt_Timer; + bool Spectrals; + int Rand; + int RandX; + int RandY; + Creature* Summoned; + + void Reset() + { + AmnenarsWrath_Timer = 8000; + FrostBolt_Timer = 1000; + Spectrals = false; + } + + void Aggro(Unit *who) + { + DoYell(SAY_0,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void KilledUnit() + { + DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY); + } + + void SummonSpectrals(Unit* victim) + { + Rand = rand()%5; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%5; + switch (rand()%2) + { + case 0: RandY = 0 - Rand; break; + case 1: RandY = 0 + Rand; break; + } + Rand = 0; + Summoned = DoSpawnCreature(8585, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); + if(Summoned) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //AmnenarsWrath_Timer + if (AmnenarsWrath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_AMNENNARSWRATH); + AmnenarsWrath_Timer = 12000; + } else AmnenarsWrath_Timer -= diff; + + //FrostBolt_Timer + if (FrostBolt_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_FROSTBOLT); + + FrostBolt_Timer = 8000; + } else FrostBolt_Timer -= diff; + + if ( !Spectrals && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50 ) + { + DoYell(SAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON); + + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + SummonSpectrals(target); + SummonSpectrals(target); + SummonSpectrals(target); + Spectrals = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_amnennar_the_coldbringer(Creature *_Creature) +{ + return new boss_amnennar_the_coldbringerAI (_Creature); +} + +void AddSC_boss_amnennar_the_coldbringer() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_amnennar_the_coldbringer"; + newscript->GetAI = GetAI_boss_amnennar_the_coldbringer; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_ayamiss.cpp b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_ayamiss.cpp index f448351d255..d1e0990c27a 100644 --- a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_ayamiss.cpp +++ b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_ayamiss.cpp @@ -1,107 +1,107 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Ayamiss -SD%Complete: 50 -SDComment: VERIFY SCRIPT -SDCategory: Ruins of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" - -/* -To do: -make him fly from 70-100% -*/ - -#define SPELL_STINGERSPRAY 25749 -#define SPELL_POISONSTINGER 25748 //only used in phase1 -#define SPELL_SUMMONSWARMER 25844 //might be 25708 -// #define SPELL_PARALYZE 23414 doesnt work correct (core) - -struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI -{ - boss_ayamissAI(Creature *c) : ScriptedAI(c) {Reset();} - - Unit *pTarget; - uint32 STINGERSPRAY_Timer; - uint32 POISONSTINGER_Timer; - uint32 SUMMONSWARMER_Timer; - uint32 phase; - - void Reset() - { - pTarget = NULL; - STINGERSPRAY_Timer = 30000; - POISONSTINGER_Timer = 30000; - SUMMONSWARMER_Timer = 60000; - phase=1; - } - - void Aggro(Unit *who) - { - pTarget = who; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //If he is 70% start phase 2 - if (phase==1 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 70 && !m_creature->IsNonMeleeSpellCasted(false)) - { - phase=2; - } - - //STINGERSPRAY_Timer (only in phase2) - if (phase==2 && STINGERSPRAY_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_STINGERSPRAY); - STINGERSPRAY_Timer = 30000; - }else STINGERSPRAY_Timer -= diff; - - //POISONSTINGER_Timer (only in phase1) - if (phase==1 && POISONSTINGER_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POISONSTINGER); - POISONSTINGER_Timer = 30000; - }else POISONSTINGER_Timer -= diff; - - //SUMMONSWARMER_Timer (only in phase1) - if (SUMMONSWARMER_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SUMMONSWARMER); - SUMMONSWARMER_Timer = 60000; - }else SUMMONSWARMER_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ayamiss(Creature *_Creature) -{ - return new boss_ayamissAI (_Creature); -} - -void AddSC_boss_ayamiss() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ayamiss"; - newscript->GetAI = GetAI_boss_ayamiss; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Ayamiss +SD%Complete: 50 +SDComment: VERIFY SCRIPT +SDCategory: Ruins of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" + +/* +To do: +make him fly from 70-100% +*/ + +#define SPELL_STINGERSPRAY 25749 +#define SPELL_POISONSTINGER 25748 //only used in phase1 +#define SPELL_SUMMONSWARMER 25844 //might be 25708 +// #define SPELL_PARALYZE 23414 doesnt work correct (core) + +struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI +{ + boss_ayamissAI(Creature *c) : ScriptedAI(c) {Reset();} + + Unit *pTarget; + uint32 STINGERSPRAY_Timer; + uint32 POISONSTINGER_Timer; + uint32 SUMMONSWARMER_Timer; + uint32 phase; + + void Reset() + { + pTarget = NULL; + STINGERSPRAY_Timer = 30000; + POISONSTINGER_Timer = 30000; + SUMMONSWARMER_Timer = 60000; + phase=1; + } + + void Aggro(Unit *who) + { + pTarget = who; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //If he is 70% start phase 2 + if (phase==1 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 70 && !m_creature->IsNonMeleeSpellCasted(false)) + { + phase=2; + } + + //STINGERSPRAY_Timer (only in phase2) + if (phase==2 && STINGERSPRAY_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_STINGERSPRAY); + STINGERSPRAY_Timer = 30000; + }else STINGERSPRAY_Timer -= diff; + + //POISONSTINGER_Timer (only in phase1) + if (phase==1 && POISONSTINGER_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POISONSTINGER); + POISONSTINGER_Timer = 30000; + }else POISONSTINGER_Timer -= diff; + + //SUMMONSWARMER_Timer (only in phase1) + if (SUMMONSWARMER_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SUMMONSWARMER); + SUMMONSWARMER_Timer = 60000; + }else SUMMONSWARMER_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_ayamiss(Creature *_Creature) +{ + return new boss_ayamissAI (_Creature); +} + +void AddSC_boss_ayamiss() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ayamiss"; + newscript->GetAI = GetAI_boss_ayamiss; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_buru.cpp b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_buru.cpp index 65bec030fe9..e2e16fdbbd3 100644 --- a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_buru.cpp +++ b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_buru.cpp @@ -1,24 +1,24 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Buru -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Ruins of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Buru +SD%Complete: 0 +SDComment: Place Holder +SDCategory: Ruins of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_kurinnaxx.cpp b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_kurinnaxx.cpp index 8b7411dbaa3..65651f436e8 100644 --- a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_kurinnaxx.cpp +++ b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_kurinnaxx.cpp @@ -1,93 +1,93 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Kurinnaxx -SD%Complete: 100 -SDComment: VERIFY SCRIPT AND SQL -SDCategory: Ruins of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_MORTALWOUND 25646 -#define SPELL_SANDTRAP 25656 -#define SPELL_ENRAGE 28798 - -struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI -{ - boss_kurinnaxxAI(Creature *c) : ScriptedAI(c) {Reset();} - - Unit *pTarget; - uint32 MORTALWOUND_Timer; - uint32 SANDTRAP_Timer; - uint32 i; - - void Reset() - { - i=0; - pTarget = NULL; - MORTALWOUND_Timer = 30000; - SANDTRAP_Timer = 30000; - } - - void Aggro(Unit *who) - { - pTarget = who; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <30% cast enrage - if (i==0 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 30 && !m_creature->IsNonMeleeSpellCasted(false)) - { - i=1; - DoCast(m_creature->getVictim(),SPELL_ENRAGE); - } - - //MORTALWOUND_Timer - if (MORTALWOUND_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTALWOUND); - MORTALWOUND_Timer = 30000; - }else MORTALWOUND_Timer -= diff; - - //SANDTRAP_Timer - if (SANDTRAP_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SANDTRAP); - SANDTRAP_Timer = 30000; - }else SANDTRAP_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_kurinnaxx(Creature *_Creature) -{ - return new boss_kurinnaxxAI (_Creature); -} - -void AddSC_boss_kurinnaxx() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_kurinnaxx"; - newscript->GetAI = GetAI_boss_kurinnaxx; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Kurinnaxx +SD%Complete: 100 +SDComment: VERIFY SCRIPT AND SQL +SDCategory: Ruins of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_MORTALWOUND 25646 +#define SPELL_SANDTRAP 25656 +#define SPELL_ENRAGE 28798 + +struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI +{ + boss_kurinnaxxAI(Creature *c) : ScriptedAI(c) {Reset();} + + Unit *pTarget; + uint32 MORTALWOUND_Timer; + uint32 SANDTRAP_Timer; + uint32 i; + + void Reset() + { + i=0; + pTarget = NULL; + MORTALWOUND_Timer = 30000; + SANDTRAP_Timer = 30000; + } + + void Aggro(Unit *who) + { + pTarget = who; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <30% cast enrage + if (i==0 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 30 && !m_creature->IsNonMeleeSpellCasted(false)) + { + i=1; + DoCast(m_creature->getVictim(),SPELL_ENRAGE); + } + + //MORTALWOUND_Timer + if (MORTALWOUND_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTALWOUND); + MORTALWOUND_Timer = 30000; + }else MORTALWOUND_Timer -= diff; + + //SANDTRAP_Timer + if (SANDTRAP_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SANDTRAP); + SANDTRAP_Timer = 30000; + }else SANDTRAP_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_kurinnaxx(Creature *_Creature) +{ + return new boss_kurinnaxxAI (_Creature); +} + +void AddSC_boss_kurinnaxx() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_kurinnaxx"; + newscript->GetAI = GetAI_boss_kurinnaxx; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_moam.cpp b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_moam.cpp index 42d30bb4eca..56b6ae18137 100644 --- a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_moam.cpp +++ b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_moam.cpp @@ -1,117 +1,117 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Moam -SD%Complete: 100 -SDComment: VERIFY SCRIPT AND SQL -SDCategory: Ruins of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_TRAMPLE 15550 -#define SPELL_DRAINMANA 27256 -#define SPELL_ARCANEERUPTION 25672 -#define SPELL_SUMMONMANA 25681 -#define SPELL_GRDRSLEEP 24360 //Greater Dreamless Sleep - -#define SAY_MANA "moam bristles with energy!" - -struct MANGOS_DLL_DECL boss_moamAI : public ScriptedAI -{ - boss_moamAI(Creature *c) : ScriptedAI(c) {Reset();} - - Unit *pTarget; - uint32 TRAMPLE_Timer; - uint32 DRAINMANA_Timer; - uint32 SUMMONMANA_Timer; - uint32 i; - uint32 j; - - void Reset() - { - i=0; - j=0; - pTarget = NULL; - TRAMPLE_Timer = 30000; - DRAINMANA_Timer = 30000; - } - - void Aggro(Unit *who) - { - pTarget = who; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are 100%MANA cast Arcane Erruption - //if (j==1 && m_creature->GetMana()*100 / m_creature->GetMaxMana() == 100 && !m_creature->IsNonMeleeSpellCasted(false)) - { - DoCast(m_creature->getVictim(),SPELL_ARCANEERUPTION); - DoYell(SAY_MANA,LANG_UNIVERSAL,NULL); - } - - //If we are <50%HP cast MANA FIEND (Summon Mana) and Sleep - //if (i==0 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) - { - i=1; - DoCast(m_creature->getVictim(),SPELL_SUMMONMANA); - DoCast(m_creature->getVictim(),SPELL_GRDRSLEEP); - } - - //SUMMONMANA_Timer - if (i==1 && SUMMONMANA_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SUMMONMANA); - SUMMONMANA_Timer = 90000; - }else SUMMONMANA_Timer -= diff; - - //TRAMPLE_Timer - if (TRAMPLE_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_TRAMPLE); - j=1; - - TRAMPLE_Timer = 30000; - }else TRAMPLE_Timer -= diff; - - //DRAINMANA_Timer - if (DRAINMANA_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DRAINMANA); - DRAINMANA_Timer = 30000; - }else DRAINMANA_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_moam(Creature *_Creature) -{ - return new boss_moamAI (_Creature); -} - -void AddSC_boss_moam() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_moam"; - newscript->GetAI = GetAI_boss_moam; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Moam +SD%Complete: 100 +SDComment: VERIFY SCRIPT AND SQL +SDCategory: Ruins of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_TRAMPLE 15550 +#define SPELL_DRAINMANA 27256 +#define SPELL_ARCANEERUPTION 25672 +#define SPELL_SUMMONMANA 25681 +#define SPELL_GRDRSLEEP 24360 //Greater Dreamless Sleep + +#define SAY_MANA "moam bristles with energy!" + +struct MANGOS_DLL_DECL boss_moamAI : public ScriptedAI +{ + boss_moamAI(Creature *c) : ScriptedAI(c) {Reset();} + + Unit *pTarget; + uint32 TRAMPLE_Timer; + uint32 DRAINMANA_Timer; + uint32 SUMMONMANA_Timer; + uint32 i; + uint32 j; + + void Reset() + { + i=0; + j=0; + pTarget = NULL; + TRAMPLE_Timer = 30000; + DRAINMANA_Timer = 30000; + } + + void Aggro(Unit *who) + { + pTarget = who; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are 100%MANA cast Arcane Erruption + //if (j==1 && m_creature->GetMana()*100 / m_creature->GetMaxMana() == 100 && !m_creature->IsNonMeleeSpellCasted(false)) + { + DoCast(m_creature->getVictim(),SPELL_ARCANEERUPTION); + DoYell(SAY_MANA,LANG_UNIVERSAL,NULL); + } + + //If we are <50%HP cast MANA FIEND (Summon Mana) and Sleep + //if (i==0 && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) + { + i=1; + DoCast(m_creature->getVictim(),SPELL_SUMMONMANA); + DoCast(m_creature->getVictim(),SPELL_GRDRSLEEP); + } + + //SUMMONMANA_Timer + if (i==1 && SUMMONMANA_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SUMMONMANA); + SUMMONMANA_Timer = 90000; + }else SUMMONMANA_Timer -= diff; + + //TRAMPLE_Timer + if (TRAMPLE_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_TRAMPLE); + j=1; + + TRAMPLE_Timer = 30000; + }else TRAMPLE_Timer -= diff; + + //DRAINMANA_Timer + if (DRAINMANA_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DRAINMANA); + DRAINMANA_Timer = 30000; + }else DRAINMANA_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_moam(Creature *_Creature) +{ + return new boss_moamAI (_Creature); +} + +void AddSC_boss_moam() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_moam"; + newscript->GetAI = GetAI_boss_moam; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_ossirian.cpp b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_ossirian.cpp index a2a04673925..fadf80992a4 100644 --- a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_ossirian.cpp +++ b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_ossirian.cpp @@ -1,36 +1,36 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Ossirian -SD%Complete: 0 -SDComment: Place holder -SDCategory: Ruins of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" - -//Ossirian -//8593 I am rejuvinated! -//8594 I have... failed -//8595 My powers are renewed! -//8596 My powers return! -//8597 Protect the city at all costs! -//8598 Sands of the desert rise and block out the sun! -//8599 The walls have been breached! -//8600 To your posts. Defend the city. -//8601 Tresspassers will be terminated. -//8602 You are terminated. +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Ossirian +SD%Complete: 0 +SDComment: Place holder +SDCategory: Ruins of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" + +//Ossirian +//8593 I am rejuvinated! +//8594 I have... failed +//8595 My powers are renewed! +//8596 My powers return! +//8597 Protect the city at all costs! +//8598 Sands of the desert rise and block out the sun! +//8599 The walls have been breached! +//8600 To your posts. Defend the city. +//8601 Tresspassers will be terminated. +//8602 You are terminated. diff --git a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_rajaxx.cpp b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_rajaxx.cpp index 3daff71f58a..574449784e5 100644 --- a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_rajaxx.cpp +++ b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/boss_rajaxx.cpp @@ -1,42 +1,42 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Rajaxx -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Ruins of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" - -//Rajaxx -//8603 Attack and make them pay dearly! -//8604 Breath your last! -//8605 Crush them! Drive them out! -//8606 Do not hesitate! Destroy them! -//8613 Warriors! Captians! Continue the fight... -//8614 You are not worth my time $N! -//8612 The time of our retribution is at hand! Let darkness reign in the hearts of our enemies! -//8610 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! -//8608 Fear is for the enemy! Fear and death! -//8611 Staghelm will whimper and beg for his life, just as his whelp of a son did! One thousand years of injustice will end this day! -//8607 Fandral! Your time has come! Go and hide in the Emerald Dream and pray we never find you! -//8609 Impudent fool! I will kill you myself! - -//Andorov - no sound -//"Remember, Rajaxx, when I said I'd kill you last? I lied..." -//"They come now. Try not to get yourself killed, young blood." +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Rajaxx +SD%Complete: 0 +SDComment: Place Holder +SDCategory: Ruins of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" + +//Rajaxx +//8603 Attack and make them pay dearly! +//8604 Breath your last! +//8605 Crush them! Drive them out! +//8606 Do not hesitate! Destroy them! +//8613 Warriors! Captians! Continue the fight... +//8614 You are not worth my time $N! +//8612 The time of our retribution is at hand! Let darkness reign in the hearts of our enemies! +//8610 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! +//8608 Fear is for the enemy! Fear and death! +//8611 Staghelm will whimper and beg for his life, just as his whelp of a son did! One thousand years of injustice will end this day! +//8607 Fandral! Your time has come! Go and hide in the Emerald Dream and pray we never find you! +//8609 Impudent fool! I will kill you myself! + +//Andorov - no sound +//"Remember, Rajaxx, when I said I'd kill you last? I lied..." +//"They come now. Try not to get yourself killed, young blood." diff --git a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp index a2bddd52efe..a4e0ebf17d4 100644 --- a/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp +++ b/src/bindings/scripts/scripts/zone/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp @@ -1,24 +1,24 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Ruins_of_Ahnqiraj -SD%Complete: 0 -SDComment: Place holder -SDCategory: Ruins of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Ruins_of_Ahnqiraj +SD%Complete: 0 +SDComment: Place holder +SDCategory: Ruins of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_arcanist_doan.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_arcanist_doan.cpp index 3a6a3526269..ebd9895d0aa 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_arcanist_doan.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_arcanist_doan.cpp @@ -1,171 +1,171 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Arcanist_Doan -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_POLYMORPH 12826 -#define SPELL_AOESILENCE 8988 -#define SPELL_ARCANEEXPLOSION3 8438 -#define SPELL_ARCANEEXPLOSION4 8439 -#define SPELL_FIREAOE 9435 -#define SPELL_BLINK 1953 -#define SPELL_FIREBALL 21162 -#define SPELL_MANASHIELD4 10191 -#define SPELL_ARCANEBUBBLE 9438 - -#define SAY_AGGRO "You will not defile these mysteries!" -#define SAY_SPECIALAE "Burn in righteous fire!" - -#define SOUND_AGGRO 5842 -#define SOUND_SPECIALAE 5843 - -struct MANGOS_DLL_DECL boss_arcanist_doanAI : public ScriptedAI -{ - boss_arcanist_doanAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FullAOE_Timer; - uint32 Polymorph_Timer; - uint32 Yell_Timer; - uint32 ArcaneBubble_Timer; - uint32 AoESilence_Timer; - uint32 ArcaneExplosion3_Timer; - uint32 ArcaneExplosion4_Timer; - uint32 Blink_Timer; - uint32 Fireball_Timer; - uint32 ManaShield4_Timer; - - void Reset() - { - FullAOE_Timer = 5000; - Polymorph_Timer = 1; - Yell_Timer = 2000; - ArcaneBubble_Timer = 3000; - AoESilence_Timer = 20000; - ArcaneExplosion3_Timer = 10000; - ArcaneExplosion4_Timer = 10000; - Blink_Timer = 40000; - Fireball_Timer = 6000; - ManaShield4_Timer = 70000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <50% hp cast Arcane Bubble and start casting SPECIAL FIRE AOE - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) - { - if (Polymorph_Timer < diff) - { - Unit* target = NULL; - - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target)DoCast(target,SPELL_POLYMORPH); - Polymorph_Timer = 40000; - }else Polymorph_Timer -= diff; - - if (Yell_Timer < diff) - { - DoYell(SAY_SPECIALAE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SPECIALAE); - Yell_Timer = 40000; - }else Yell_Timer -= diff; - - if (ArcaneBubble_Timer < diff) - { - DoCast(m_creature,SPELL_ARCANEBUBBLE); - ArcaneBubble_Timer = 40000; - }else ArcaneBubble_Timer -= diff; - - if (FullAOE_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIREAOE); - FullAOE_Timer = 40000; - }else FullAOE_Timer -= diff; - } - - //AoESilence_Timer - if (AoESilence_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_AOESILENCE); - AoESilence_Timer = 30000; - }else AoESilence_Timer -= diff; - - //ArcaneExplosion3_Timer - if (ArcaneExplosion3_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ARCANEEXPLOSION3); - ArcaneExplosion3_Timer = 8000; - }else ArcaneExplosion3_Timer -= diff; - - //ArcaneExplosion4_Timer - if (ArcaneExplosion4_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ARCANEEXPLOSION4); - ArcaneExplosion4_Timer = 10000; - }else ArcaneExplosion4_Timer -= diff; - - //Blink_Timer - if (Blink_Timer < diff) - { - DoCast(m_creature,SPELL_BLINK); - Blink_Timer = 30000; - }else Blink_Timer -= diff; - - //Fireball_Timer - if (Fireball_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIREBALL); - Fireball_Timer = 12000; - }else Fireball_Timer -= diff; - - //ManaShiled4_Timer - if (ManaShield4_Timer < diff) - { - DoCast(m_creature,SPELL_MANASHIELD4); - ManaShield4_Timer = 70000; - }else ManaShield4_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_arcanist_doan(Creature *_Creature) -{ - return new boss_arcanist_doanAI (_Creature); -} - -void AddSC_boss_arcanist_doan() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_arcanist_doan"; - newscript->GetAI = GetAI_boss_arcanist_doan; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Arcanist_Doan +SD%Complete: 100 +SDComment: +SDCategory: Scarlet Monastery +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_POLYMORPH 12826 +#define SPELL_AOESILENCE 8988 +#define SPELL_ARCANEEXPLOSION3 8438 +#define SPELL_ARCANEEXPLOSION4 8439 +#define SPELL_FIREAOE 9435 +#define SPELL_BLINK 1953 +#define SPELL_FIREBALL 21162 +#define SPELL_MANASHIELD4 10191 +#define SPELL_ARCANEBUBBLE 9438 + +#define SAY_AGGRO "You will not defile these mysteries!" +#define SAY_SPECIALAE "Burn in righteous fire!" + +#define SOUND_AGGRO 5842 +#define SOUND_SPECIALAE 5843 + +struct MANGOS_DLL_DECL boss_arcanist_doanAI : public ScriptedAI +{ + boss_arcanist_doanAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FullAOE_Timer; + uint32 Polymorph_Timer; + uint32 Yell_Timer; + uint32 ArcaneBubble_Timer; + uint32 AoESilence_Timer; + uint32 ArcaneExplosion3_Timer; + uint32 ArcaneExplosion4_Timer; + uint32 Blink_Timer; + uint32 Fireball_Timer; + uint32 ManaShield4_Timer; + + void Reset() + { + FullAOE_Timer = 5000; + Polymorph_Timer = 1; + Yell_Timer = 2000; + ArcaneBubble_Timer = 3000; + AoESilence_Timer = 20000; + ArcaneExplosion3_Timer = 10000; + ArcaneExplosion4_Timer = 10000; + Blink_Timer = 40000; + Fireball_Timer = 6000; + ManaShield4_Timer = 70000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <50% hp cast Arcane Bubble and start casting SPECIAL FIRE AOE + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) + { + if (Polymorph_Timer < diff) + { + Unit* target = NULL; + + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target)DoCast(target,SPELL_POLYMORPH); + Polymorph_Timer = 40000; + }else Polymorph_Timer -= diff; + + if (Yell_Timer < diff) + { + DoYell(SAY_SPECIALAE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SPECIALAE); + Yell_Timer = 40000; + }else Yell_Timer -= diff; + + if (ArcaneBubble_Timer < diff) + { + DoCast(m_creature,SPELL_ARCANEBUBBLE); + ArcaneBubble_Timer = 40000; + }else ArcaneBubble_Timer -= diff; + + if (FullAOE_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIREAOE); + FullAOE_Timer = 40000; + }else FullAOE_Timer -= diff; + } + + //AoESilence_Timer + if (AoESilence_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_AOESILENCE); + AoESilence_Timer = 30000; + }else AoESilence_Timer -= diff; + + //ArcaneExplosion3_Timer + if (ArcaneExplosion3_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ARCANEEXPLOSION3); + ArcaneExplosion3_Timer = 8000; + }else ArcaneExplosion3_Timer -= diff; + + //ArcaneExplosion4_Timer + if (ArcaneExplosion4_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ARCANEEXPLOSION4); + ArcaneExplosion4_Timer = 10000; + }else ArcaneExplosion4_Timer -= diff; + + //Blink_Timer + if (Blink_Timer < diff) + { + DoCast(m_creature,SPELL_BLINK); + Blink_Timer = 30000; + }else Blink_Timer -= diff; + + //Fireball_Timer + if (Fireball_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIREBALL); + Fireball_Timer = 12000; + }else Fireball_Timer -= diff; + + //ManaShiled4_Timer + if (ManaShield4_Timer < diff) + { + DoCast(m_creature,SPELL_MANASHIELD4); + ManaShield4_Timer = 70000; + }else ManaShield4_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_arcanist_doan(Creature *_Creature) +{ + return new boss_arcanist_doanAI (_Creature); +} + +void AddSC_boss_arcanist_doan() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_arcanist_doan"; + newscript->GetAI = GetAI_boss_arcanist_doan; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_azshir_the_sleepless.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_azshir_the_sleepless.cpp index d975cb3d192..0db96caaf5c 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_azshir_the_sleepless.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_azshir_the_sleepless.cpp @@ -1,97 +1,97 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {Reset();} - - uint32 SoulSiphon_Timer; - uint32 CallOftheGrave_Timer; - uint32 Terrify_Timer; - - void Reset() - { - SoulSiphon_Timer = 1; - CallOftheGrave_Timer = 30000; - Terrify_Timer = 20000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <50% hp cast Soul Siphon rank 1 - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) - { - //SoulSiphon_Timer - if (SoulSiphon_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SOULSIPHON); - return; - - SoulSiphon_Timer = 20000; - }else SoulSiphon_Timer -= diff; - } - - //CallOfTheGrave_Timer - if (CallOftheGrave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CALLOFTHEGRAVE); - CallOftheGrave_Timer = 30000; - }else CallOftheGrave_Timer -= diff; - - //Terrify_Timer - if (Terrify_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_TERRIFY); - Terrify_Timer = 20000; - }else Terrify_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_azshir_the_sleepless(Creature *_Creature) -{ - return new boss_azshir_the_sleeplessAI (_Creature); -} - -void AddSC_boss_azshir_the_sleepless() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_azshir_the_sleepless"; - newscript->GetAI = GetAI_boss_azshir_the_sleepless; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {Reset();} + + uint32 SoulSiphon_Timer; + uint32 CallOftheGrave_Timer; + uint32 Terrify_Timer; + + void Reset() + { + SoulSiphon_Timer = 1; + CallOftheGrave_Timer = 30000; + Terrify_Timer = 20000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <50% hp cast Soul Siphon rank 1 + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) + { + //SoulSiphon_Timer + if (SoulSiphon_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SOULSIPHON); + return; + + SoulSiphon_Timer = 20000; + }else SoulSiphon_Timer -= diff; + } + + //CallOfTheGrave_Timer + if (CallOftheGrave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CALLOFTHEGRAVE); + CallOftheGrave_Timer = 30000; + }else CallOftheGrave_Timer -= diff; + + //Terrify_Timer + if (Terrify_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_TERRIFY); + Terrify_Timer = 20000; + }else Terrify_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_azshir_the_sleepless(Creature *_Creature) +{ + return new boss_azshir_the_sleeplessAI (_Creature); +} + +void AddSC_boss_azshir_the_sleepless() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_azshir_the_sleepless"; + newscript->GetAI = GetAI_boss_azshir_the_sleepless; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_bloodmage_thalnos.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_bloodmage_thalnos.cpp index a130df0fa56..8d0bd53da57 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_bloodmage_thalnos.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_bloodmage_thalnos.cpp @@ -1,136 +1,136 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_FROSTNOVA2 865 -#define SPELL_FLAMESHOCK3 8053 -#define SPELL_SHADOWBOLT5 1106 -#define SPELL_FLAMESPIKE 8814 -#define SPELL_FIRENOVA 16079 - -#define SAY_AGGRO "We hunger for vengeance." -#define SAY_HEALTH "No rest... for the angry dead!" -#define SAY_DEATH "More... More souls!" - -#define SOUND_AGGRO 5844 -#define SOUND_HEALTH 5846 -#define SOUND_DEATH 5845 - -struct MANGOS_DLL_DECL boss_bloodmage_thalnosAI : public ScriptedAI -{ - boss_bloodmage_thalnosAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FrostNova2_Timer; - uint32 FlameShock3_Timer; - uint32 ShadowBolt5_Timer; - uint32 FlameSpike_Timer; - uint32 FireNova_Timer; - uint32 Yell_Timer; - - void Reset() - { - Yell_Timer = 1; - FrostNova2_Timer = 10000; - FlameShock3_Timer = 15000; - ShadowBolt5_Timer = 20000; - FlameSpike_Timer = 20000; - FireNova_Timer = 10000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <35% hp - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 35) - { - Yell_Timer -= diff; - - if (Yell_Timer < diff) - { - DoYell(SAY_HEALTH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_HEALTH); - Yell_Timer = 900000; - } - } - - //FrostNova2_Timer - if (FrostNova2_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROSTNOVA2); - FrostNova2_Timer = 10000; - }else FrostNova2_Timer -= diff; - - //FlameShock3_Timer - if (FlameShock3_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FLAMESHOCK3); - FlameShock3_Timer = 15000; - }else FlameShock3_Timer -= diff; - - //ShadowBolt5_Timer - if (ShadowBolt5_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWBOLT5); - ShadowBolt5_Timer = 20000; - }else ShadowBolt5_Timer -= diff; - - //FlameSpike_Timer - if (FlameSpike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FLAMESPIKE); - FlameSpike_Timer = 30000; - }else FlameSpike_Timer -= diff; - - //FireNova_Timer - if (FireNova_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIRENOVA); - FireNova_Timer = 20000; - }else FireNova_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_bloodmage_thalnos(Creature *_Creature) -{ - return new boss_bloodmage_thalnosAI (_Creature); -} - -void AddSC_boss_bloodmage_thalnos() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_bloodmage_thalnos"; - newscript->GetAI = GetAI_boss_bloodmage_thalnos; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_FROSTNOVA2 865 +#define SPELL_FLAMESHOCK3 8053 +#define SPELL_SHADOWBOLT5 1106 +#define SPELL_FLAMESPIKE 8814 +#define SPELL_FIRENOVA 16079 + +#define SAY_AGGRO "We hunger for vengeance." +#define SAY_HEALTH "No rest... for the angry dead!" +#define SAY_DEATH "More... More souls!" + +#define SOUND_AGGRO 5844 +#define SOUND_HEALTH 5846 +#define SOUND_DEATH 5845 + +struct MANGOS_DLL_DECL boss_bloodmage_thalnosAI : public ScriptedAI +{ + boss_bloodmage_thalnosAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FrostNova2_Timer; + uint32 FlameShock3_Timer; + uint32 ShadowBolt5_Timer; + uint32 FlameSpike_Timer; + uint32 FireNova_Timer; + uint32 Yell_Timer; + + void Reset() + { + Yell_Timer = 1; + FrostNova2_Timer = 10000; + FlameShock3_Timer = 15000; + ShadowBolt5_Timer = 20000; + FlameSpike_Timer = 20000; + FireNova_Timer = 10000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <35% hp + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 35) + { + Yell_Timer -= diff; + + if (Yell_Timer < diff) + { + DoYell(SAY_HEALTH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_HEALTH); + Yell_Timer = 900000; + } + } + + //FrostNova2_Timer + if (FrostNova2_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROSTNOVA2); + FrostNova2_Timer = 10000; + }else FrostNova2_Timer -= diff; + + //FlameShock3_Timer + if (FlameShock3_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FLAMESHOCK3); + FlameShock3_Timer = 15000; + }else FlameShock3_Timer -= diff; + + //ShadowBolt5_Timer + if (ShadowBolt5_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWBOLT5); + ShadowBolt5_Timer = 20000; + }else ShadowBolt5_Timer -= diff; + + //FlameSpike_Timer + if (FlameSpike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FLAMESPIKE); + FlameSpike_Timer = 30000; + }else FlameSpike_Timer -= diff; + + //FireNova_Timer + if (FireNova_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIRENOVA); + FireNova_Timer = 20000; + }else FireNova_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_bloodmage_thalnos(Creature *_Creature) +{ + return new boss_bloodmage_thalnosAI (_Creature); +} + +void AddSC_boss_bloodmage_thalnos() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_bloodmage_thalnos"; + newscript->GetAI = GetAI_boss_bloodmage_thalnos; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_herod.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_herod.cpp index ea4cdc52e03..7a39603184a 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_herod.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_herod.cpp @@ -1,197 +1,197 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Herod -SD%Complete: 90 -SDComment: Missing adds spawn at death -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_RUSHINGCHARGE 32021 -#define SPELL_RUSHINGCHARGE1 6268 - -#define SPELL_CLEAVE 11608 -#define SPELL_WHIRLWIND 8989 -#define SPELL_SUNDERARMOR 16145 -#define SPELL_REND 21949 -#define SPELL_THUNDERCLAP 15588 -#define SPELL_SLAM 11430 -#define SPELL_BERSERKERSTANCE 2458 -#define SPELL_ENRAGE 28747 -#define SPELL_FIREBALL11 10151 -#define SPELL_CONEOFCOLD5 10161 - -#define SAY_AGGRO "Ah, I have been waiting for a real challenge!" -#define SAY_WHIRLWIND "Blades of Light!" -#define SAY_ENRAGE "Light, give me strength!" -#define SAY_DEATH "Hah, is that all?" - -#define SOUND_AGGRO 5830 -#define SOUND_WHIRLWIND 5832 -#define SOUND_ENRAGE 5833 -#define SOUND_DEATH 5831 - -struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI -{ - boss_herodAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Yell_Timer; - uint32 Enrage_Timer; - uint32 Cleave_Timer; - uint32 Whirlwind_Timer; - uint32 SunderArmor_Timer; - uint32 Rend_Timer; - uint32 ThunderClap_Timer; - uint32 Slam_Timer; - uint32 Fireball11_Timer; - uint32 ConeOfCold5_Timer; - - void Reset() - { - Yell_Timer = 58000; - Whirlwind_Timer = 60000; - Enrage_Timer = 0; - Cleave_Timer = 15000; - SunderArmor_Timer = 40000; - Rend_Timer = 25000; - ThunderClap_Timer = 25000; - Slam_Timer = 20000; - Fireball11_Timer = 30000; - ConeOfCold5_Timer = 40000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - - //Activate Berserker Stance - DoCast(m_creature,SPELL_BERSERKERSTANCE); - - //Switch between 2 different charge methods - switch (rand()%2) - { - case 0: - DoCast(m_creature,SPELL_RUSHINGCHARGE); - break; - case 1: - DoCast(m_creature,SPELL_RUSHINGCHARGE1); - break; - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <10% hp goes Enraged - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 10 && !m_creature->IsNonMeleeSpellCasted(false) && Enrage_Timer < diff) - { - DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_ENRAGE); - - DoCast(m_creature,SPELL_ENRAGE); - - //Shouldn't cast this agian - Enrage_Timer = diff; - } - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 15000; - }else Cleave_Timer -= diff; - - //Yelling and Whirlwind casting - if (Yell_Timer < diff) - { - //Say Whirlwind monologe - DoYell(SAY_WHIRLWIND,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_WHIRLWIND); - - Yell_Timer = 30000; - }else Yell_Timer -= diff; - - if (Whirlwind_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_WHIRLWIND); - Whirlwind_Timer = 30000; - }else Whirlwind_Timer -= diff; - - //SunderArmor_Timer - if (SunderArmor_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SUNDERARMOR); - SunderArmor_Timer = 40000; - }else SunderArmor_Timer -= diff; - - //Rend_Timer - if (Rend_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_REND); - Rend_Timer = 25000; - }else Rend_Timer -= diff; - - //ThunderClap_Timer - if (ThunderClap_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); - ThunderClap_Timer = 20000; - }else ThunderClap_Timer -= diff; - - //Slam_Timer - if (Slam_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SLAM); - Slam_Timer = 20000; - }else Slam_Timer -= diff; - - //Fireball11_Timer - if (Fireball11_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FIREBALL11); - Fireball11_Timer = 30000; - }else Fireball11_Timer -= diff; - - //ConeOfCold5_Timer - if (ConeOfCold5_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CONEOFCOLD5); - ConeOfCold5_Timer = 40000; - }else ConeOfCold5_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_herod(Creature *_Creature) -{ - return new boss_herodAI (_Creature); -} - -void AddSC_boss_herod() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_herod"; - newscript->GetAI = GetAI_boss_herod; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Herod +SD%Complete: 90 +SDComment: Missing adds spawn at death +SDCategory: Scarlet Monastery +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_RUSHINGCHARGE 32021 +#define SPELL_RUSHINGCHARGE1 6268 + +#define SPELL_CLEAVE 11608 +#define SPELL_WHIRLWIND 8989 +#define SPELL_SUNDERARMOR 16145 +#define SPELL_REND 21949 +#define SPELL_THUNDERCLAP 15588 +#define SPELL_SLAM 11430 +#define SPELL_BERSERKERSTANCE 2458 +#define SPELL_ENRAGE 28747 +#define SPELL_FIREBALL11 10151 +#define SPELL_CONEOFCOLD5 10161 + +#define SAY_AGGRO "Ah, I have been waiting for a real challenge!" +#define SAY_WHIRLWIND "Blades of Light!" +#define SAY_ENRAGE "Light, give me strength!" +#define SAY_DEATH "Hah, is that all?" + +#define SOUND_AGGRO 5830 +#define SOUND_WHIRLWIND 5832 +#define SOUND_ENRAGE 5833 +#define SOUND_DEATH 5831 + +struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI +{ + boss_herodAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Yell_Timer; + uint32 Enrage_Timer; + uint32 Cleave_Timer; + uint32 Whirlwind_Timer; + uint32 SunderArmor_Timer; + uint32 Rend_Timer; + uint32 ThunderClap_Timer; + uint32 Slam_Timer; + uint32 Fireball11_Timer; + uint32 ConeOfCold5_Timer; + + void Reset() + { + Yell_Timer = 58000; + Whirlwind_Timer = 60000; + Enrage_Timer = 0; + Cleave_Timer = 15000; + SunderArmor_Timer = 40000; + Rend_Timer = 25000; + ThunderClap_Timer = 25000; + Slam_Timer = 20000; + Fireball11_Timer = 30000; + ConeOfCold5_Timer = 40000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + + //Activate Berserker Stance + DoCast(m_creature,SPELL_BERSERKERSTANCE); + + //Switch between 2 different charge methods + switch (rand()%2) + { + case 0: + DoCast(m_creature,SPELL_RUSHINGCHARGE); + break; + case 1: + DoCast(m_creature,SPELL_RUSHINGCHARGE1); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <10% hp goes Enraged + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 10 && !m_creature->IsNonMeleeSpellCasted(false) && Enrage_Timer < diff) + { + DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_ENRAGE); + + DoCast(m_creature,SPELL_ENRAGE); + + //Shouldn't cast this agian + Enrage_Timer = diff; + } + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 15000; + }else Cleave_Timer -= diff; + + //Yelling and Whirlwind casting + if (Yell_Timer < diff) + { + //Say Whirlwind monologe + DoYell(SAY_WHIRLWIND,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_WHIRLWIND); + + Yell_Timer = 30000; + }else Yell_Timer -= diff; + + if (Whirlwind_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_WHIRLWIND); + Whirlwind_Timer = 30000; + }else Whirlwind_Timer -= diff; + + //SunderArmor_Timer + if (SunderArmor_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SUNDERARMOR); + SunderArmor_Timer = 40000; + }else SunderArmor_Timer -= diff; + + //Rend_Timer + if (Rend_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_REND); + Rend_Timer = 25000; + }else Rend_Timer -= diff; + + //ThunderClap_Timer + if (ThunderClap_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); + ThunderClap_Timer = 20000; + }else ThunderClap_Timer -= diff; + + //Slam_Timer + if (Slam_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SLAM); + Slam_Timer = 20000; + }else Slam_Timer -= diff; + + //Fireball11_Timer + if (Fireball11_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FIREBALL11); + Fireball11_Timer = 30000; + }else Fireball11_Timer -= diff; + + //ConeOfCold5_Timer + if (ConeOfCold5_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CONEOFCOLD5); + ConeOfCold5_Timer = 40000; + }else ConeOfCold5_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_herod(Creature *_Creature) +{ + return new boss_herodAI (_Creature); +} + +void AddSC_boss_herod() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_herod"; + newscript->GetAI = GetAI_boss_herod; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp index 2817b50eb4c..1edb1a6210f 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp @@ -1,132 +1,132 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Faribanks -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SLEEP2 1090 -#define SPELL_CURSEOFBLOOD 16098 -#define SPELL_SMITE 6060 -#define SPELL_SHADOWWORDPAIN 2767 -#define SPELL_FLASHHEAL4 9474 -#define SPELL_RENEW6 6078 -#define SPELL_DEVOURINGPLAGUE3 19277 -#define SPELL_MINDBLAST5 8105 - -struct MANGOS_DLL_DECL boss_high_inquisitor_fairbanksAI : public ScriptedAI -{ - boss_high_inquisitor_fairbanksAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Healing_Timer; - uint32 Sleep2_Timer; - uint32 Smite_Timer; - uint32 ShadowWordPain_Timer; - uint32 CurseOfBlood_Timer; - uint32 DevouringPlague3_Timer; - uint32 MindBlast5_Timer; - - void Reset() - { - Healing_Timer = 300; - Sleep2_Timer = 45000; - Smite_Timer = 30000; - ShadowWordPain_Timer = 30000; - CurseOfBlood_Timer = 45000; - DevouringPlague3_Timer = 60000; - MindBlast5_Timer = 20000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <45% hp cast Renew rank 6 or Flash heal rank 4 - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 45 && !m_creature->IsNonMeleeSpellCasted(false) && Healing_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_RENEW6 || SPELL_FLASHHEAL4); - Healing_Timer = 30000; - }else Healing_Timer -= diff; - - //Sleep2_Timer - if (Sleep2_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SLEEP2); - Sleep2_Timer = 45000; - }else Sleep2_Timer -= diff; - - //Smite_Timer - if (Smite_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SMITE); - Smite_Timer = 20000; - }else Smite_Timer -= diff; - - //ShadowWordPain_Timer - if (ShadowWordPain_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); - ShadowWordPain_Timer = 30000; - }else ShadowWordPain_Timer -= diff; - - //CurseOfBlood_Timer - if (CurseOfBlood_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CURSEOFBLOOD); - CurseOfBlood_Timer = 25000; - }else CurseOfBlood_Timer -= diff; - - //DevouringPlague3_Timer - if (DevouringPlague3_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DEVOURINGPLAGUE3); - DevouringPlague3_Timer = 35000; - }else DevouringPlague3_Timer -= diff; - - //MindBlast5_Timer - if (MindBlast5_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST5); - MindBlast5_Timer = 30000; - }else MindBlast5_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_high_inquisitor_fairbanks(Creature *_Creature) -{ - return new boss_high_inquisitor_fairbanksAI (_Creature); -} - -void AddSC_boss_high_inquisitor_fairbanks() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_high_inquisitor_fairbanks"; - newscript->GetAI = GetAI_boss_high_inquisitor_fairbanks; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Faribanks +SD%Complete: 100 +SDComment: +SDCategory: Scarlet Monastery +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SLEEP2 1090 +#define SPELL_CURSEOFBLOOD 16098 +#define SPELL_SMITE 6060 +#define SPELL_SHADOWWORDPAIN 2767 +#define SPELL_FLASHHEAL4 9474 +#define SPELL_RENEW6 6078 +#define SPELL_DEVOURINGPLAGUE3 19277 +#define SPELL_MINDBLAST5 8105 + +struct MANGOS_DLL_DECL boss_high_inquisitor_fairbanksAI : public ScriptedAI +{ + boss_high_inquisitor_fairbanksAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Healing_Timer; + uint32 Sleep2_Timer; + uint32 Smite_Timer; + uint32 ShadowWordPain_Timer; + uint32 CurseOfBlood_Timer; + uint32 DevouringPlague3_Timer; + uint32 MindBlast5_Timer; + + void Reset() + { + Healing_Timer = 300; + Sleep2_Timer = 45000; + Smite_Timer = 30000; + ShadowWordPain_Timer = 30000; + CurseOfBlood_Timer = 45000; + DevouringPlague3_Timer = 60000; + MindBlast5_Timer = 20000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <45% hp cast Renew rank 6 or Flash heal rank 4 + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 45 && !m_creature->IsNonMeleeSpellCasted(false) && Healing_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_RENEW6 || SPELL_FLASHHEAL4); + Healing_Timer = 30000; + }else Healing_Timer -= diff; + + //Sleep2_Timer + if (Sleep2_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SLEEP2); + Sleep2_Timer = 45000; + }else Sleep2_Timer -= diff; + + //Smite_Timer + if (Smite_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SMITE); + Smite_Timer = 20000; + }else Smite_Timer -= diff; + + //ShadowWordPain_Timer + if (ShadowWordPain_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); + ShadowWordPain_Timer = 30000; + }else ShadowWordPain_Timer -= diff; + + //CurseOfBlood_Timer + if (CurseOfBlood_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CURSEOFBLOOD); + CurseOfBlood_Timer = 25000; + }else CurseOfBlood_Timer -= diff; + + //DevouringPlague3_Timer + if (DevouringPlague3_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DEVOURINGPLAGUE3); + DevouringPlague3_Timer = 35000; + }else DevouringPlague3_Timer -= diff; + + //MindBlast5_Timer + if (MindBlast5_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MINDBLAST5); + MindBlast5_Timer = 30000; + }else MindBlast5_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_high_inquisitor_fairbanks(Creature *_Creature) +{ + return new boss_high_inquisitor_fairbanksAI (_Creature); +} + +void AddSC_boss_high_inquisitor_fairbanks() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_high_inquisitor_fairbanks"; + newscript->GetAI = GetAI_boss_high_inquisitor_fairbanks; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_whitemane.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_whitemane.cpp index 3a7c03a03b4..1da3ef99b86 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_whitemane.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_whitemane.cpp @@ -1,177 +1,177 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_Inquistor_Whitmane -SD%Complete: 50 -SDComment: Missing connection with commander mograine -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_DEEPSLEEP 9256 -#define SPELL_SCARLETRESURRECTION 9232 - -#define SPELL_CRUSADERSTRIKE 17281 -#define SPELL_HAMMEROFJUSTICE 13005 -#define SPELL_HOLYSMITE6 9481 -#define SPELL_HOLYFIRE5 15265 -#define SPELL_MINDBLAST6 8106 - -#define SPELL_POWERWORDSHIELD 6065 - -#define SPELL_RENEW 6078 -#define SPELL_FLASHHEAL6 10916 - -#define SAY_AGGRO "There is no escape for you. The Crusade shall destroy all who carry the Scourge's taint." -#define SAY_SPAWN "What, Mograine has fallen? You shall pay for this treachery! " -#define SAY_RES "Arise, my champion!" -#define SAY_DEATH "The Light has spoken!" - -//#define SOUND_AGGRO -#define SOUND_RES 5840 -#define SOUND_SPAWN 5838 -#define SOUND_DEATH 5839 - -struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI -{ - boss_high_inquisitor_whitemaneAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Healing_Timer; - uint32 Renew_Timer; - uint32 PowerWordShield_Timer; - uint32 CrusaderStrike_Timer; - uint32 HammerOfJustice_Timer; - uint32 HolySmite6_Timer; - uint32 HolyFire5_Timer; - uint32 MindBlast6_Timer; - - void Reset() - { - Healing_Timer = 0; - Renew_Timer= 0; - PowerWordShield_Timer = 2000; - CrusaderStrike_Timer = 12000; - HammerOfJustice_Timer = 18000; - HolySmite6_Timer = 10000; - HolyFire5_Timer = 20000; - MindBlast6_Timer = 6000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - /* - //This is going to be a routine to make the resurrection event... - if (m_creature->isAlive && m_creature->isAlive) - { - m_creature->Relocate(1163.113370,1398.856812,32.527786,3.171014); - - DoYell(SAY_SPAWN,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SPAWN); - DoCast(m_creature->getVictim(),SPELL_DEEPSLEEP); - DoCast(m-creature->GetGUID(51117),SPELL_SCARLETRESURRECTION) - } - */ - - //If we are <75% hp cast healing spells at self and Mograine - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 75 ) - { - if (Healing_Timer < diff) - { - DoCast(m_creature,SPELL_FLASHHEAL6); - return; - - //22-32 seconds until we should cast this agian - Healing_Timer = 22000 + rand()%10000; - }else Healing_Timer -= diff; - } - - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 30) - { - if (Renew_Timer < diff) - { - DoCast(m_creature,SPELL_RENEW); - Renew_Timer = 30000; - }else Renew_Timer -= diff; - } - - //PowerWordShield_Timer - if (PowerWordShield_Timer < diff) - { - DoCast(m_creature,SPELL_POWERWORDSHIELD); - PowerWordShield_Timer = 25000; - }else PowerWordShield_Timer -= diff; - - //CrusaderStrike_Timer - if (CrusaderStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE); - CrusaderStrike_Timer = 15000; - }else CrusaderStrike_Timer -= diff; - - //HammerOfJustice_Timer - if (HammerOfJustice_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE); - HammerOfJustice_Timer = 12000; - }else HammerOfJustice_Timer -= diff; - - //HolySmite6_Timer - if (HolySmite6_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HOLYSMITE6); - HolySmite6_Timer = 10000; - }else HolySmite6_Timer -= diff; - - //HolyFire5_Timer - if (HolyFire5_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HOLYFIRE5); - HolyFire5_Timer = 15000; - }else HolyFire5_Timer -= diff; - - //MindBlast6_Timer - if (MindBlast6_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST6); - MindBlast6_Timer = 8000; - }else MindBlast6_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_high_inquisitor_whitemane(Creature *_Creature) -{ - return new boss_high_inquisitor_whitemaneAI (_Creature); -} - -void AddSC_boss_high_inquisitor_whitemane() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_high_inquisitor_whitemane"; - newscript->GetAI = GetAI_boss_high_inquisitor_whitemane; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_Inquistor_Whitmane +SD%Complete: 50 +SDComment: Missing connection with commander mograine +SDCategory: Scarlet Monastery +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_DEEPSLEEP 9256 +#define SPELL_SCARLETRESURRECTION 9232 + +#define SPELL_CRUSADERSTRIKE 17281 +#define SPELL_HAMMEROFJUSTICE 13005 +#define SPELL_HOLYSMITE6 9481 +#define SPELL_HOLYFIRE5 15265 +#define SPELL_MINDBLAST6 8106 + +#define SPELL_POWERWORDSHIELD 6065 + +#define SPELL_RENEW 6078 +#define SPELL_FLASHHEAL6 10916 + +#define SAY_AGGRO "There is no escape for you. The Crusade shall destroy all who carry the Scourge's taint." +#define SAY_SPAWN "What, Mograine has fallen? You shall pay for this treachery! " +#define SAY_RES "Arise, my champion!" +#define SAY_DEATH "The Light has spoken!" + +//#define SOUND_AGGRO +#define SOUND_RES 5840 +#define SOUND_SPAWN 5838 +#define SOUND_DEATH 5839 + +struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI +{ + boss_high_inquisitor_whitemaneAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Healing_Timer; + uint32 Renew_Timer; + uint32 PowerWordShield_Timer; + uint32 CrusaderStrike_Timer; + uint32 HammerOfJustice_Timer; + uint32 HolySmite6_Timer; + uint32 HolyFire5_Timer; + uint32 MindBlast6_Timer; + + void Reset() + { + Healing_Timer = 0; + Renew_Timer= 0; + PowerWordShield_Timer = 2000; + CrusaderStrike_Timer = 12000; + HammerOfJustice_Timer = 18000; + HolySmite6_Timer = 10000; + HolyFire5_Timer = 20000; + MindBlast6_Timer = 6000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + /* + //This is going to be a routine to make the resurrection event... + if (m_creature->isAlive && m_creature->isAlive) + { + m_creature->Relocate(1163.113370,1398.856812,32.527786,3.171014); + + DoYell(SAY_SPAWN,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SPAWN); + DoCast(m_creature->getVictim(),SPELL_DEEPSLEEP); + DoCast(m-creature->GetGUID(51117),SPELL_SCARLETRESURRECTION) + } + */ + + //If we are <75% hp cast healing spells at self and Mograine + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 75 ) + { + if (Healing_Timer < diff) + { + DoCast(m_creature,SPELL_FLASHHEAL6); + return; + + //22-32 seconds until we should cast this agian + Healing_Timer = 22000 + rand()%10000; + }else Healing_Timer -= diff; + } + + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 30) + { + if (Renew_Timer < diff) + { + DoCast(m_creature,SPELL_RENEW); + Renew_Timer = 30000; + }else Renew_Timer -= diff; + } + + //PowerWordShield_Timer + if (PowerWordShield_Timer < diff) + { + DoCast(m_creature,SPELL_POWERWORDSHIELD); + PowerWordShield_Timer = 25000; + }else PowerWordShield_Timer -= diff; + + //CrusaderStrike_Timer + if (CrusaderStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE); + CrusaderStrike_Timer = 15000; + }else CrusaderStrike_Timer -= diff; + + //HammerOfJustice_Timer + if (HammerOfJustice_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE); + HammerOfJustice_Timer = 12000; + }else HammerOfJustice_Timer -= diff; + + //HolySmite6_Timer + if (HolySmite6_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HOLYSMITE6); + HolySmite6_Timer = 10000; + }else HolySmite6_Timer -= diff; + + //HolyFire5_Timer + if (HolyFire5_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HOLYFIRE5); + HolyFire5_Timer = 15000; + }else HolyFire5_Timer -= diff; + + //MindBlast6_Timer + if (MindBlast6_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MINDBLAST6); + MindBlast6_Timer = 8000; + }else MindBlast6_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_high_inquisitor_whitemane(Creature *_Creature) +{ + return new boss_high_inquisitor_whitemaneAI (_Creature); +} + +void AddSC_boss_high_inquisitor_whitemane() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_high_inquisitor_whitemane"; + newscript->GetAI = GetAI_boss_high_inquisitor_whitemane; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_houndmaster_loksey.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_houndmaster_loksey.cpp index 342424eed2f..de0fc7537d9 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_houndmaster_loksey.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_houndmaster_loksey.cpp @@ -1,78 +1,78 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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: -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SUMMONSCARLETHOUND 17164 -#define SPELL_ENRAGE 28747 - -#define SAY_AGGRO "Release the hounds!" -#define SOUND_AGGRO 5841 - -struct MANGOS_DLL_DECL boss_houndmaster_lokseyAI : public ScriptedAI -{ - boss_houndmaster_lokseyAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Enrage_Timer; - - void Reset() - { - Enrage_Timer = 6000000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - - DoCast(m_creature,SPELL_SUMMONSCARLETHOUND); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <10% hp cast healing spells at self and Mograine - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 10 && !m_creature->IsNonMeleeSpellCasted(false) && Enrage_Timer < diff) - { - DoCast(m_creature,SPELL_ENRAGE); - Enrage_Timer = 900000; - }else Enrage_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_houndmaster_loksey(Creature *_Creature) -{ - return new boss_houndmaster_lokseyAI (_Creature); -} - -void AddSC_boss_houndmaster_loksey() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_houndmaster_loksey"; - newscript->GetAI = GetAI_boss_houndmaster_loksey; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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: +SDCategory: Scarlet Monastery +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SUMMONSCARLETHOUND 17164 +#define SPELL_ENRAGE 28747 + +#define SAY_AGGRO "Release the hounds!" +#define SOUND_AGGRO 5841 + +struct MANGOS_DLL_DECL boss_houndmaster_lokseyAI : public ScriptedAI +{ + boss_houndmaster_lokseyAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Enrage_Timer; + + void Reset() + { + Enrage_Timer = 6000000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + + DoCast(m_creature,SPELL_SUMMONSCARLETHOUND); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <10% hp cast healing spells at self and Mograine + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 10 && !m_creature->IsNonMeleeSpellCasted(false) && Enrage_Timer < diff) + { + DoCast(m_creature,SPELL_ENRAGE); + Enrage_Timer = 900000; + }else Enrage_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_houndmaster_loksey(Creature *_Creature) +{ + return new boss_houndmaster_lokseyAI (_Creature); +} + +void AddSC_boss_houndmaster_loksey() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_houndmaster_loksey"; + newscript->GetAI = GetAI_boss_houndmaster_loksey; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_interrogator_vishas.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_interrogator_vishas.cpp index c21eef4b458..4bfe70c94a9 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_interrogator_vishas.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_interrogator_vishas.cpp @@ -1,113 +1,113 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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" - -#define SPELL_POWERWORDSHIELD 6065 - -#define SAY_AGGRO "Tell me... tell me everything!" -#define SAY_HEALTH1 "Naughty secrets" -#define SAY_HEALTH2 "I'll rip the secrets from your flesh!" -#define SAY_DEATH "Purged by pain!" - -#define SOUND_AGGRO 5847 -#define SOUND_HEALTH1 5849 -#define SOUND_HEALTH2 5850 -#define SOUND_DEATH 5848 - -struct MANGOS_DLL_DECL boss_interrogator_vishasAI : public ScriptedAI -{ - boss_interrogator_vishasAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Yell_Timer; - uint32 PowerWordShield_Timer; - - void Reset() - { - Yell_Timer = 6000000; - PowerWordShield_Timer = 60000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are low on hp Do sayings - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 60 && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Yell_Timer - if (Yell_Timer < diff) - { - DoYell(SAY_HEALTH1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_HEALTH1); - return; - - //60 seconds until we should cast this agian - Yell_Timer = 60000; - }else Yell_Timer -= diff; - } - - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 30 && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Yell_Timer - if (Yell_Timer < diff) - { - DoYell(SAY_HEALTH2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_HEALTH2); - return; - - //60 seconds until we should cast this agian - Yell_Timer = 6000000; - }else Yell_Timer -= diff; - } - - //PowerWordShield_Timer - if (PowerWordShield_Timer < diff) - { - DoCast(m_creature,SPELL_POWERWORDSHIELD); - PowerWordShield_Timer = 60000; - }else PowerWordShield_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_interrogator_vishas(Creature *_Creature) -{ - return new boss_interrogator_vishasAI (_Creature); -} - -void AddSC_boss_interrogator_vishas() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_interrogator_vishas"; - newscript->GetAI = GetAI_boss_interrogator_vishas; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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" + +#define SPELL_POWERWORDSHIELD 6065 + +#define SAY_AGGRO "Tell me... tell me everything!" +#define SAY_HEALTH1 "Naughty secrets" +#define SAY_HEALTH2 "I'll rip the secrets from your flesh!" +#define SAY_DEATH "Purged by pain!" + +#define SOUND_AGGRO 5847 +#define SOUND_HEALTH1 5849 +#define SOUND_HEALTH2 5850 +#define SOUND_DEATH 5848 + +struct MANGOS_DLL_DECL boss_interrogator_vishasAI : public ScriptedAI +{ + boss_interrogator_vishasAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Yell_Timer; + uint32 PowerWordShield_Timer; + + void Reset() + { + Yell_Timer = 6000000; + PowerWordShield_Timer = 60000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are low on hp Do sayings + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 60 && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Yell_Timer + if (Yell_Timer < diff) + { + DoYell(SAY_HEALTH1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_HEALTH1); + return; + + //60 seconds until we should cast this agian + Yell_Timer = 60000; + }else Yell_Timer -= diff; + } + + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 30 && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Yell_Timer + if (Yell_Timer < diff) + { + DoYell(SAY_HEALTH2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_HEALTH2); + return; + + //60 seconds until we should cast this agian + Yell_Timer = 6000000; + }else Yell_Timer -= diff; + } + + //PowerWordShield_Timer + if (PowerWordShield_Timer < diff) + { + DoCast(m_creature,SPELL_POWERWORDSHIELD); + PowerWordShield_Timer = 60000; + }else PowerWordShield_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_interrogator_vishas(Creature *_Creature) +{ + return new boss_interrogator_vishasAI (_Creature); +} + +void AddSC_boss_interrogator_vishas() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_interrogator_vishas"; + newscript->GetAI = GetAI_boss_interrogator_vishas; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_scarlet_commander_mograine.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_scarlet_commander_mograine.cpp index 6bdcda14913..2b5692b123b 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_scarlet_commander_mograine.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_scarlet_commander_mograine.cpp @@ -1,160 +1,160 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Scarlet_Commander_Mograine -SD%Complete: 100 -SDComment: Missing revive -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_DIVINESHIELD2 1020 -#define SPELL_CRUSADERSTRIKE5 35395 -#define SPELL_HAMMEROFJUSTICE3 5589 -#define SPELL_HOLYLIGHT6 3472 -#define SPELL_CONSECRATION3 20922 -#define SPELL_BLESSINGOFWISDOM 1044 -#define SPELL_RETRIBUTIONAURA3 10299 -#define SPELL_BLESSINGOFPROTECTION3 10278 -#define SPELL_FLASHHEAL6 10916 - -#define SAY_AGGRO "Infidels! They must be purified!" -#define SAY_RES "At your side, milady!" -#define SAY_DEATH "Unworthy!" - -#define SOUND_AGGRO 5835 -#define SOUND_RES 5837 -#define SOUND_DEATH 5836 - -struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI -{ - boss_scarlet_commander_mograineAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Heal_Timer; - uint32 DivineShield2_Timer; - uint32 CrusaderStrike5_Timer; - uint32 HammerOfJustice3_Timer; - uint32 Consecration3_Timer; - uint32 BlessingOfWisdom_Timer; - uint32 BlessingOfProtection3_Timer; - - void Reset() - { - Heal_Timer = 80000; - DivineShield2_Timer = 60000; - CrusaderStrike5_Timer = 20000; - HammerOfJustice3_Timer = 80000; - Consecration3_Timer = 30000; - BlessingOfWisdom_Timer = 45000; - BlessingOfProtection3_Timer = 45000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - DoCast(m_creature,SPELL_RETRIBUTIONAURA3); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <50% hp cast Arcane Bubble and start casting SPECIAL Arcane Explosion - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) - { - //heal_Timer - if (Heal_Timer < diff) - { - //Switch between 2 different charge methods - switch (rand()%2) - { - case 0: - DoCast(m_creature,SPELL_HOLYLIGHT6); - break; - case 1: - DoCast(m_creature,SPELL_FLASHHEAL6); - break; - } - return; - - //60 seconds until we should cast this agian - Heal_Timer = 60000; - }else Heal_Timer -= diff; - } - - //DivineShield2_Timer - if (DivineShield2_Timer < diff) - { - DoCast(m_creature,SPELL_DIVINESHIELD2); - DivineShield2_Timer = 60000; - }else DivineShield2_Timer -= diff; - - //CrusaderStrike5_Timer - if (CrusaderStrike5_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE5); - CrusaderStrike5_Timer = 20000; - }else CrusaderStrike5_Timer -= diff; - - //HammerOfJustice3_Timer - if (HammerOfJustice3_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE3); - HammerOfJustice3_Timer = 30000; - }else HammerOfJustice3_Timer -= diff; - - //Consecration3_Timer - if (Consecration3_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CONSECRATION3); - Consecration3_Timer = 20000; - }else Consecration3_Timer -= diff; - - //BlessingOfWisdom_Timer - if (BlessingOfWisdom_Timer < diff) - { - DoCast(m_creature,SPELL_BLESSINGOFWISDOM); - BlessingOfWisdom_Timer = 45000; - }else BlessingOfWisdom_Timer -= diff; - - //BlessingOfProtection3_Timer - if (BlessingOfProtection3_Timer < diff) - { - DoCast(m_creature,SPELL_BLESSINGOFPROTECTION3); - BlessingOfProtection3_Timer = 50000; - }else BlessingOfProtection3_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_scarlet_commander_mograine(Creature *_Creature) -{ - return new boss_scarlet_commander_mograineAI (_Creature); -} - -void AddSC_boss_scarlet_commander_mograine() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_scarlet_commander_mograine"; - newscript->GetAI = GetAI_boss_scarlet_commander_mograine; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Scarlet_Commander_Mograine +SD%Complete: 100 +SDComment: Missing revive +SDCategory: Scarlet Monastery +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_DIVINESHIELD2 1020 +#define SPELL_CRUSADERSTRIKE5 35395 +#define SPELL_HAMMEROFJUSTICE3 5589 +#define SPELL_HOLYLIGHT6 3472 +#define SPELL_CONSECRATION3 20922 +#define SPELL_BLESSINGOFWISDOM 1044 +#define SPELL_RETRIBUTIONAURA3 10299 +#define SPELL_BLESSINGOFPROTECTION3 10278 +#define SPELL_FLASHHEAL6 10916 + +#define SAY_AGGRO "Infidels! They must be purified!" +#define SAY_RES "At your side, milady!" +#define SAY_DEATH "Unworthy!" + +#define SOUND_AGGRO 5835 +#define SOUND_RES 5837 +#define SOUND_DEATH 5836 + +struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI +{ + boss_scarlet_commander_mograineAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Heal_Timer; + uint32 DivineShield2_Timer; + uint32 CrusaderStrike5_Timer; + uint32 HammerOfJustice3_Timer; + uint32 Consecration3_Timer; + uint32 BlessingOfWisdom_Timer; + uint32 BlessingOfProtection3_Timer; + + void Reset() + { + Heal_Timer = 80000; + DivineShield2_Timer = 60000; + CrusaderStrike5_Timer = 20000; + HammerOfJustice3_Timer = 80000; + Consecration3_Timer = 30000; + BlessingOfWisdom_Timer = 45000; + BlessingOfProtection3_Timer = 45000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + DoCast(m_creature,SPELL_RETRIBUTIONAURA3); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <50% hp cast Arcane Bubble and start casting SPECIAL Arcane Explosion + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) + { + //heal_Timer + if (Heal_Timer < diff) + { + //Switch between 2 different charge methods + switch (rand()%2) + { + case 0: + DoCast(m_creature,SPELL_HOLYLIGHT6); + break; + case 1: + DoCast(m_creature,SPELL_FLASHHEAL6); + break; + } + return; + + //60 seconds until we should cast this agian + Heal_Timer = 60000; + }else Heal_Timer -= diff; + } + + //DivineShield2_Timer + if (DivineShield2_Timer < diff) + { + DoCast(m_creature,SPELL_DIVINESHIELD2); + DivineShield2_Timer = 60000; + }else DivineShield2_Timer -= diff; + + //CrusaderStrike5_Timer + if (CrusaderStrike5_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE5); + CrusaderStrike5_Timer = 20000; + }else CrusaderStrike5_Timer -= diff; + + //HammerOfJustice3_Timer + if (HammerOfJustice3_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE3); + HammerOfJustice3_Timer = 30000; + }else HammerOfJustice3_Timer -= diff; + + //Consecration3_Timer + if (Consecration3_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CONSECRATION3); + Consecration3_Timer = 20000; + }else Consecration3_Timer -= diff; + + //BlessingOfWisdom_Timer + if (BlessingOfWisdom_Timer < diff) + { + DoCast(m_creature,SPELL_BLESSINGOFWISDOM); + BlessingOfWisdom_Timer = 45000; + }else BlessingOfWisdom_Timer -= diff; + + //BlessingOfProtection3_Timer + if (BlessingOfProtection3_Timer < diff) + { + DoCast(m_creature,SPELL_BLESSINGOFPROTECTION3); + BlessingOfProtection3_Timer = 50000; + }else BlessingOfProtection3_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_scarlet_commander_mograine(Creature *_Creature) +{ + return new boss_scarlet_commander_mograineAI (_Creature); +} + +void AddSC_boss_scarlet_commander_mograine() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_scarlet_commander_mograine"; + newscript->GetAI = GetAI_boss_scarlet_commander_mograine; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_scorn.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_scorn.cpp index abfda1462ca..2ce8db28680 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_scorn.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_scorn.cpp @@ -1,100 +1,100 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //LichSlap_Timer - if (LichSlap_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_LICHSLAP); - LichSlap_Timer = 45000; - }else LichSlap_Timer -= diff; - - //FrostboltVolley_Timer - if (FrostboltVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROSTBOLTVOLLEY); - FrostboltVolley_Timer = 20000; - }else FrostboltVolley_Timer -= diff; - - //MindFlay_Timer - if (MindFlay_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MINDFLAY); - MindFlay_Timer = 20000; - }else MindFlay_Timer -= diff; - - //FrostNova_Timer - if (FrostNova_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROSTNOVA); - FrostNova_Timer = 15000; - }else FrostNova_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_scorn(Creature *_Creature) -{ - return new boss_scornAI (_Creature); -} - -void AddSC_boss_scorn() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_scorn"; - newscript->GetAI = GetAI_boss_scorn; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //LichSlap_Timer + if (LichSlap_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_LICHSLAP); + LichSlap_Timer = 45000; + }else LichSlap_Timer -= diff; + + //FrostboltVolley_Timer + if (FrostboltVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROSTBOLTVOLLEY); + FrostboltVolley_Timer = 20000; + }else FrostboltVolley_Timer -= diff; + + //MindFlay_Timer + if (MindFlay_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MINDFLAY); + MindFlay_Timer = 20000; + }else MindFlay_Timer -= diff; + + //FrostNova_Timer + if (FrostNova_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROSTNOVA); + FrostNova_Timer = 15000; + }else FrostNova_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_scorn(Creature *_Creature) +{ + return new boss_scornAI (_Creature); +} + +void AddSC_boss_scorn() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_scorn"; + newscript->GetAI = GetAI_boss_scorn; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_darkmaster_gandling.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_darkmaster_gandling.cpp index bb4c17f3425..a3e8527db2b 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_darkmaster_gandling.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_darkmaster_gandling.cpp @@ -1,192 +1,192 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Darkmaster_Gandling -SD%Complete: 99 -SDComment: Doors missing in instance script. -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.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 - -struct MANGOS_DLL_DECL boss_darkmaster_gandlingAI : public ScriptedAI -{ - boss_darkmaster_gandlingAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ArcaneMissiles_Timer; - uint32 ShadowShield_Timer; - uint32 Curse_Timer; - uint32 Teleport_Timer; - Creature *Summoned; - - void Reset() - { - ArcaneMissiles_Timer = 4500; - ShadowShield_Timer = 12000; - Curse_Timer = 2000; - Teleport_Timer = 16000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //ArcaneMissiles_Timer - if (ArcaneMissiles_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ARCANEMISSILES); - ArcaneMissiles_Timer = 8000; - }else ArcaneMissiles_Timer -= diff; - - //ShadowShield_Timer - if (ShadowShield_Timer < diff) - { - DoCast(m_creature,SPELL_SHADOWSHIELD); - ShadowShield_Timer = 14000 + rand()%14000; - }else ShadowShield_Timer -= diff; - - //Curse_Timer - if (Curse_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CURSE); - Curse_Timer = 15000 + rand()%12000; - }else Curse_Timer -= diff; - - //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->GetHealth()*100 / m_creature->GetMaxHealth() > 3 ) - { - if(Teleport_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target && target->GetTypeId() == TYPEID_PLAYER) - { - if(m_creature->getThreatManager().getThreat(target)) - m_creature->getThreatManager().modifyThreatPercent(target, -100); - - switch(rand()%6) - { - case 0: - DoTeleportPlayer(target, 250.0696,0.3921,84.8408,3.149); - Summoned = m_creature->SummonCreature(16119,254.2325,0.3417,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,257.7133,4.0226,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,258.6702,-2.60656,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - break; - case 1: - DoTeleportPlayer(target, 181.4220,-91.9481,84.8410,1.608); - Summoned = m_creature->SummonCreature(16119,184.0519,-73.5649,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,179.5951,-73.7045,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,180.6452,-78.2143,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,283.2274,-78.1518,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - break; - case 2: - DoTeleportPlayer(target, 95.1547,-1.8173,85.2289,0.043); - Summoned = m_creature->SummonCreature(16119,100.9404,-1.8016,85.2289,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,101.3729,0.4882,85.2289,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,101.4596,-4.4740,85.2289,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - break; - case 3: - DoTeleportPlayer(target, 250.0696,0.3921,72.6722,3.149); - Summoned = m_creature->SummonCreature(16119,240.34481,0.7368,72.6722,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,240.3633,-2.9520,72.6722,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,240.6702,3.34949,72.6722,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - break; - case 4: - DoTeleportPlayer(target, 181.4220,-91.9481,70.7734,1.608); - Summoned = m_creature->SummonCreature(16119,184.0519,-73.5649,70.7734,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,179.5951,-73.7045,70.7734,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,180.6452,-78.2143,70.7734,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,283.2274,-78.1518,70.7734,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - break; - case 5: - DoTeleportPlayer(target, 106.1541,-1.8994,75.3663,0.043); - Summoned = m_creature->SummonCreature(16119,115.3945,-1.5555,75.3663,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,257.7133,1.8066,75.3663,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(16119,258.6702,-5.1001,75.3663,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - break; - } - } - Teleport_Timer = 20000 + rand()%15000; - }else Teleport_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_darkmaster_gandling(Creature *_Creature) -{ - return new boss_darkmaster_gandlingAI (_Creature); -} - -void AddSC_boss_darkmaster_gandling() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_darkmaster_gandling"; - newscript->GetAI = GetAI_boss_darkmaster_gandling; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Darkmaster_Gandling +SD%Complete: 99 +SDComment: Doors missing in instance script. +SDCategory: Scholomance +EndScriptData */ + +#include "precompiled.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 + +struct MANGOS_DLL_DECL boss_darkmaster_gandlingAI : public ScriptedAI +{ + boss_darkmaster_gandlingAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ArcaneMissiles_Timer; + uint32 ShadowShield_Timer; + uint32 Curse_Timer; + uint32 Teleport_Timer; + Creature *Summoned; + + void Reset() + { + ArcaneMissiles_Timer = 4500; + ShadowShield_Timer = 12000; + Curse_Timer = 2000; + Teleport_Timer = 16000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //ArcaneMissiles_Timer + if (ArcaneMissiles_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ARCANEMISSILES); + ArcaneMissiles_Timer = 8000; + }else ArcaneMissiles_Timer -= diff; + + //ShadowShield_Timer + if (ShadowShield_Timer < diff) + { + DoCast(m_creature,SPELL_SHADOWSHIELD); + ShadowShield_Timer = 14000 + rand()%14000; + }else ShadowShield_Timer -= diff; + + //Curse_Timer + if (Curse_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CURSE); + Curse_Timer = 15000 + rand()%12000; + }else Curse_Timer -= diff; + + //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->GetHealth()*100 / m_creature->GetMaxHealth() > 3 ) + { + if(Teleport_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target && target->GetTypeId() == TYPEID_PLAYER) + { + if(m_creature->getThreatManager().getThreat(target)) + m_creature->getThreatManager().modifyThreatPercent(target, -100); + + switch(rand()%6) + { + case 0: + DoTeleportPlayer(target, 250.0696,0.3921,84.8408,3.149); + Summoned = m_creature->SummonCreature(16119,254.2325,0.3417,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,257.7133,4.0226,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,258.6702,-2.60656,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + break; + case 1: + DoTeleportPlayer(target, 181.4220,-91.9481,84.8410,1.608); + Summoned = m_creature->SummonCreature(16119,184.0519,-73.5649,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,179.5951,-73.7045,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,180.6452,-78.2143,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,283.2274,-78.1518,84.8407,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + break; + case 2: + DoTeleportPlayer(target, 95.1547,-1.8173,85.2289,0.043); + Summoned = m_creature->SummonCreature(16119,100.9404,-1.8016,85.2289,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,101.3729,0.4882,85.2289,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,101.4596,-4.4740,85.2289,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + break; + case 3: + DoTeleportPlayer(target, 250.0696,0.3921,72.6722,3.149); + Summoned = m_creature->SummonCreature(16119,240.34481,0.7368,72.6722,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,240.3633,-2.9520,72.6722,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,240.6702,3.34949,72.6722,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + break; + case 4: + DoTeleportPlayer(target, 181.4220,-91.9481,70.7734,1.608); + Summoned = m_creature->SummonCreature(16119,184.0519,-73.5649,70.7734,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,179.5951,-73.7045,70.7734,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,180.6452,-78.2143,70.7734,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,283.2274,-78.1518,70.7734,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + break; + case 5: + DoTeleportPlayer(target, 106.1541,-1.8994,75.3663,0.043); + Summoned = m_creature->SummonCreature(16119,115.3945,-1.5555,75.3663,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,257.7133,1.8066,75.3663,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(16119,258.6702,-5.1001,75.3663,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + break; + } + } + Teleport_Timer = 20000 + rand()%15000; + }else Teleport_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_darkmaster_gandling(Creature *_Creature) +{ + return new boss_darkmaster_gandlingAI (_Creature); +} + +void AddSC_boss_darkmaster_gandling() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_darkmaster_gandling"; + newscript->GetAI = GetAI_boss_darkmaster_gandling; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_death_knight_darkreaver.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_death_knight_darkreaver.cpp index 344ab9840d9..46fdc01e76c 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_death_knight_darkreaver.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_death_knight_darkreaver.cpp @@ -1,59 +1,59 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 - } - } - - void Aggro(Unit *who) - { - } -}; -CreatureAI* GetAI_boss_death_knight_darkreaver(Creature *_Creature) -{ - return new boss_death_knight_darkreaverAI (_Creature); -} - -void AddSC_boss_death_knight_darkreaver() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_death_knight_darkreaver"; - newscript->GetAI = GetAI_boss_death_knight_darkreaver; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 + } + } + + void Aggro(Unit *who) + { + } +}; +CreatureAI* GetAI_boss_death_knight_darkreaver(Creature *_Creature) +{ + return new boss_death_knight_darkreaverAI (_Creature); +} + +void AddSC_boss_death_knight_darkreaver() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_death_knight_darkreaver"; + newscript->GetAI = GetAI_boss_death_knight_darkreaver; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_doctor_theolen_krastinov.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_doctor_theolen_krastinov.cpp index 4dd663fbc5f..8fc33e2cef7 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_doctor_theolen_krastinov.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_doctor_theolen_krastinov.cpp @@ -1,108 +1,108 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_scholomance.h" - -#define SPELL_REND 18106 -#define SPELL_CLEAVE 15584 -#define SPELL_FRENZY 28371 - -struct MANGOS_DLL_DECL boss_theolenkrastinovAI : public ScriptedAI -{ - boss_theolenkrastinovAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Rend_Timer; - uint32 Cleave_Timer; - uint32 Frenzy_Timer; - - void Reset() - { - Rend_Timer = 8000; - Cleave_Timer = 9000; - Frenzy_Timer =0; - } - - void JustDied(Unit *killer) - { - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - { - pInstance->SetData(DATA_DOCTORTHEOLENKRASTINOV_DEATH, 0); - - if(pInstance->GetData(DATA_CANSPAWNGANDLING)) - m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Rend_Timer - if (Rend_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_REND); - Rend_Timer = 10000; - }else Rend_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 10000; - }else Cleave_Timer -= diff; - - //Frenzy_Timer - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 26 ) - { - if (Frenzy_Timer < diff) - { - DoCast(m_creature,SPELL_FRENZY); - DoTextEmote("goes into a killing frenzy!",NULL); - - Frenzy_Timer = 8000; - }else Frenzy_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_theolenkrastinov(Creature *_Creature) -{ - return new boss_theolenkrastinovAI (_Creature); -} - -void AddSC_boss_theolenkrastinov() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_doctor_theolen_krastinov"; - newscript->GetAI = GetAI_boss_theolenkrastinov; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_scholomance.h" + +#define SPELL_REND 18106 +#define SPELL_CLEAVE 15584 +#define SPELL_FRENZY 28371 + +struct MANGOS_DLL_DECL boss_theolenkrastinovAI : public ScriptedAI +{ + boss_theolenkrastinovAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Rend_Timer; + uint32 Cleave_Timer; + uint32 Frenzy_Timer; + + void Reset() + { + Rend_Timer = 8000; + Cleave_Timer = 9000; + Frenzy_Timer =0; + } + + void JustDied(Unit *killer) + { + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + { + pInstance->SetData(DATA_DOCTORTHEOLENKRASTINOV_DEATH, 0); + + if(pInstance->GetData(DATA_CANSPAWNGANDLING)) + m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Rend_Timer + if (Rend_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_REND); + Rend_Timer = 10000; + }else Rend_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 10000; + }else Cleave_Timer -= diff; + + //Frenzy_Timer + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 26 ) + { + if (Frenzy_Timer < diff) + { + DoCast(m_creature,SPELL_FRENZY); + DoTextEmote("goes into a killing frenzy!",NULL); + + Frenzy_Timer = 8000; + }else Frenzy_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_theolenkrastinov(Creature *_Creature) +{ + return new boss_theolenkrastinovAI (_Creature); +} + +void AddSC_boss_theolenkrastinov() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_doctor_theolen_krastinov"; + newscript->GetAI = GetAI_boss_theolenkrastinov; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_illucia_barov.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_illucia_barov.cpp index 1a45b7e2697..f4d797a8887 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_illucia_barov.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_illucia_barov.cpp @@ -1,116 +1,116 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_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 *c) : ScriptedAI(c) {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) - { - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - { - pInstance->SetData(DATA_LADYILLUCIABAROV_DEATH, 0); - - if(pInstance->GetData(DATA_CANSPAWNGANDLING)) - m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //CurseOfAgony_Timer - if (CurseOfAgony_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CURSEOFAGONY); - CurseOfAgony_Timer = 30000; - }else CurseOfAgony_Timer -= diff; - - //ShadowShock_Timer - if (ShadowShock_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_SHADOWSHOCK); - - ShadowShock_Timer = 12000; - }else ShadowShock_Timer -= diff; - - //Silence_Timer - if (Silence_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SILENCE); - Silence_Timer = 14000; - }else Silence_Timer -= diff; - - //Fear_Timer - if (Fear_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FEAR); - Fear_Timer = 30000; - }else Fear_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_illuciabarov(Creature *_Creature) -{ - return new boss_illuciabarovAI (_Creature); -} - -void AddSC_boss_illuciabarov() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_illucia_barov"; - newscript->GetAI = GetAI_boss_illuciabarov; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_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 *c) : ScriptedAI(c) {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) + { + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + { + pInstance->SetData(DATA_LADYILLUCIABAROV_DEATH, 0); + + if(pInstance->GetData(DATA_CANSPAWNGANDLING)) + m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //CurseOfAgony_Timer + if (CurseOfAgony_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CURSEOFAGONY); + CurseOfAgony_Timer = 30000; + }else CurseOfAgony_Timer -= diff; + + //ShadowShock_Timer + if (ShadowShock_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_SHADOWSHOCK); + + ShadowShock_Timer = 12000; + }else ShadowShock_Timer -= diff; + + //Silence_Timer + if (Silence_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SILENCE); + Silence_Timer = 14000; + }else Silence_Timer -= diff; + + //Fear_Timer + if (Fear_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FEAR); + Fear_Timer = 30000; + }else Fear_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_illuciabarov(Creature *_Creature) +{ + return new boss_illuciabarovAI (_Creature); +} + +void AddSC_boss_illuciabarov() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_illucia_barov"; + newscript->GetAI = GetAI_boss_illuciabarov; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_instructor_malicia.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_instructor_malicia.cpp index 9d2dbc174d5..78a40f46448 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_instructor_malicia.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_instructor_malicia.cpp @@ -1,152 +1,152 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_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 *c) : ScriptedAI(c) {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) - { - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - { - pInstance->SetData(DATA_INSTRUCTORMALICIA_DEATH, 0); - - if(pInstance->GetData(DATA_CANSPAWNGANDLING)) - m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //CallOfGraves_Timer - if (CallOfGraves_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CALLOFGRAVES); - CallOfGraves_Timer = 65000; - }else CallOfGraves_Timer -= diff; - - //Corruption_Timer - if (Corruption_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_CORRUPTION); - - Corruption_Timer = 24000; - }else Corruption_Timer -= diff; - - //Renew_Timer - if (Renew_Timer < diff) - { - DoCast(m_creature, SPELL_RENEW); - Renew_Timer = 10000; - }else Renew_Timer -= diff; - - //FlashHeal_Timer - if (FlashHeal_Timer < diff) - { - DoCast(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) - { - DoCast(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 *_Creature) -{ - return new boss_instructormaliciaAI (_Creature); -} - -void AddSC_boss_instructormalicia() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_instructor_malicia"; - newscript->GetAI = GetAI_boss_instructormalicia; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_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 *c) : ScriptedAI(c) {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) + { + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + { + pInstance->SetData(DATA_INSTRUCTORMALICIA_DEATH, 0); + + if(pInstance->GetData(DATA_CANSPAWNGANDLING)) + m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //CallOfGraves_Timer + if (CallOfGraves_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CALLOFGRAVES); + CallOfGraves_Timer = 65000; + }else CallOfGraves_Timer -= diff; + + //Corruption_Timer + if (Corruption_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_CORRUPTION); + + Corruption_Timer = 24000; + }else Corruption_Timer -= diff; + + //Renew_Timer + if (Renew_Timer < diff) + { + DoCast(m_creature, SPELL_RENEW); + Renew_Timer = 10000; + }else Renew_Timer -= diff; + + //FlashHeal_Timer + if (FlashHeal_Timer < diff) + { + DoCast(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) + { + DoCast(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 *_Creature) +{ + return new boss_instructormaliciaAI (_Creature); +} + +void AddSC_boss_instructormalicia() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_instructor_malicia"; + newscript->GetAI = GetAI_boss_instructormalicia; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_jandice_barov.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_jandice_barov.cpp index 05eaba72a3f..69f35357937 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_jandice_barov.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_jandice_barov.cpp @@ -1,226 +1,208 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_jandicebarov -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_CURSEOFBLOOD 24673 -//#define SPELL_ILLUSION 17773 - -//Spells of Illusion of Jandice Barov -#define SPELL_CLEAVE 15584 - -struct MANGOS_DLL_DECL boss_jandicebarovAI : public ScriptedAI -{ - boss_jandicebarovAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 CurseOfBlood_Timer; - uint32 Illusion_Timer; - //uint32 Illusioncounter; - uint32 Invisible_Timer; - bool Invisible; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - CurseOfBlood_Timer = 15000; - Illusion_Timer = 30000; - Invisible_Timer = 3000; //Too much too low? - Invisible = false; - } - - void Aggro(Unit *who) - { - } - - void SummonIllusions(Unit* victim) - { - Rand = rand()%10; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%10; - switch (rand()%2) - { - 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) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - if (Invisible && Invisible_Timer < diff) - { - //Become visible again - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //Jandice Model - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,11073); - Invisible = false; - } else if (Invisible) - { - Invisible_Timer -= diff; - //Do nothing while invisible - return; - } - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //CurseOfBlood_Timer - if (CurseOfBlood_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CURSEOFBLOOD); - CurseOfBlood_Timer = 30000; - }else CurseOfBlood_Timer -= diff; - - //Illusion_Timer - if (!Invisible && Illusion_Timer < diff) - { - //Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // Invisible Model - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,11686); - - //Summon 10 Illusions attacking random gamers - Unit* target = NULL; - for(int i = 0; i < 10;i++) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - SummonIllusions(target); - } - Invisible = true; - Invisible_Timer = 3000; - - Illusion_Timer = 25000; - }else Illusion_Timer -= diff; - - // //Illusion_Timer - // if (Illusion_Timer < diff) - // { - // //Cast - // DoCast(m_creature->getVictim(),SPELL_ILLUSION); - // - // //3 Illusion will be summoned - // if (Illusioncounter < 3) - // { - // Illusion_Timer = 500; - // Illusioncounter++; - // } - // else { - // 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 *c) : ScriptedAI(c) {Reset();} - - uint32 Cleave_Timer; - - void Reset() - { - Cleave_Timer = 4000; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 5000 + rand()%3000; - }else Cleave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_jandicebarov(Creature *_Creature) -{ - return new boss_jandicebarovAI (_Creature); -} - -CreatureAI* GetAI_mob_illusionofjandicebarov(Creature *_Creature) -{ - return new mob_illusionofjandicebarovAI (_Creature); -} - -void AddSC_boss_jandicebarov() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_jandice_barov"; - newscript->GetAI = GetAI_boss_jandicebarov; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_illusionofjandicebarov"; - newscript->GetAI = GetAI_mob_illusionofjandicebarov; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_jandicebarov +SD%Complete: 100 +SDComment: +SDCategory: Scholomance +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_CURSEOFBLOOD 24673 +//#define SPELL_ILLUSION 17773 + +//Spells of Illusion of Jandice Barov +#define SPELL_CLEAVE 15584 + +struct MANGOS_DLL_DECL boss_jandicebarovAI : public ScriptedAI +{ + boss_jandicebarovAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 CurseOfBlood_Timer; + uint32 Illusion_Timer; + //uint32 Illusioncounter; + uint32 Invisible_Timer; + bool Invisible; + int Rand; + int RandX; + int RandY; + Creature* Summoned; + + void Reset() + { + CurseOfBlood_Timer = 15000; + Illusion_Timer = 30000; + Invisible_Timer = 3000; //Too much too low? + Invisible = false; + } + + void Aggro(Unit *who) + { + } + + void SummonIllusions(Unit* victim) + { + Rand = rand()%10; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%10; + switch (rand()%2) + { + 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) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + if (Invisible && Invisible_Timer < diff) + { + //Become visible again + m_creature->setFaction(14); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //Jandice Model + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,11073); + Invisible = false; + } else if (Invisible) + { + Invisible_Timer -= diff; + //Do nothing while invisible + return; + } + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //CurseOfBlood_Timer + if (CurseOfBlood_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CURSEOFBLOOD); + CurseOfBlood_Timer = 30000; + }else CurseOfBlood_Timer -= diff; + + //Illusion_Timer + if (!Invisible && Illusion_Timer < diff) + { + //Inturrupt any spell casting + m_creature->InterruptNonMeleeSpells(false); + m_creature->setFaction(35); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // Invisible Model + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,11686); + + //Summon 10 Illusions attacking random gamers + Unit* target = NULL; + for(int i = 0; i < 10;i++) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + SummonIllusions(target); + } + Invisible = true; + Invisible_Timer = 3000; + + Illusion_Timer = 25000; + }else Illusion_Timer -= diff; + + // //Illusion_Timer + // if (Illusion_Timer < diff) + // { + // //Cast + // DoCast(m_creature->getVictim(),SPELL_ILLUSION); + // + // //3 Illusion will be summoned + // if (Illusioncounter < 3) + // { + // Illusion_Timer = 500; + // Illusioncounter++; + // } + // else { + // 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 *c) : ScriptedAI(c) {Reset();} + + uint32 Cleave_Timer; + + void Reset() + { + Cleave_Timer = 4000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 5000 + rand()%3000; + }else Cleave_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_jandicebarov(Creature *_Creature) +{ + return new boss_jandicebarovAI (_Creature); +} + +CreatureAI* GetAI_mob_illusionofjandicebarov(Creature *_Creature) +{ + return new mob_illusionofjandicebarovAI (_Creature); +} + +void AddSC_boss_jandicebarov() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_jandice_barov"; + newscript->GetAI = GetAI_boss_jandicebarov; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_illusionofjandicebarov"; + newscript->GetAI = GetAI_mob_illusionofjandicebarov; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_kormok.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_kormok.cpp index c9fb3c3a260..e0a837ef82a 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_kormok.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_kormok.cpp @@ -1,155 +1,155 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void SummonMinion(Unit* victim) - { - Rand1 = rand()%8; - switch (rand()%2) - { - case 0: Rand1X = 0 - Rand1; break; - case 1: Rand1X = 0 + Rand1; break; - } - Rand1 = 0; - Rand1 = rand()%8; - switch (rand()%2) - { - 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); - ((CreatureAI*)SummonedMinions->AI())->AttackStart(victim); - } - - void SummonMages(Unit* victim) - { - Rand2 = rand()%10; - switch (rand()%2) - { - case 0: Rand2X = 0 - Rand2; break; - case 1: Rand2X = 0 + Rand2; break; - } - Rand2 = 0; - Rand2 = rand()%10; - switch (rand()%2) - { - 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); - ((CreatureAI*)SummonedMages->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //ShadowVolley_Timer - if (ShadowVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); - ShadowVolley_Timer = 15000; - }else ShadowVolley_Timer -= diff; - - //BoneShield_Timer - if (BoneShield_Timer < diff) - { - DoCast(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->GetHealth()*100 / m_creature->GetMaxHealth() < 26 ) - { - //Cast - SummonMages(m_creature->getVictim()); - SummonMages(m_creature->getVictim()); - Mages = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_kormok(Creature *_Creature) -{ - return new boss_kormokAI (_Creature); -} - -void AddSC_boss_kormok() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_kormok"; - newscript->GetAI = GetAI_boss_kormok; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void SummonMinion(Unit* victim) + { + Rand1 = rand()%8; + switch (rand()%2) + { + case 0: Rand1X = 0 - Rand1; break; + case 1: Rand1X = 0 + Rand1; break; + } + Rand1 = 0; + Rand1 = rand()%8; + switch (rand()%2) + { + 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); + ((CreatureAI*)SummonedMinions->AI())->AttackStart(victim); + } + + void SummonMages(Unit* victim) + { + Rand2 = rand()%10; + switch (rand()%2) + { + case 0: Rand2X = 0 - Rand2; break; + case 1: Rand2X = 0 + Rand2; break; + } + Rand2 = 0; + Rand2 = rand()%10; + switch (rand()%2) + { + 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); + ((CreatureAI*)SummonedMages->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //ShadowVolley_Timer + if (ShadowVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); + ShadowVolley_Timer = 15000; + }else ShadowVolley_Timer -= diff; + + //BoneShield_Timer + if (BoneShield_Timer < diff) + { + DoCast(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->GetHealth()*100 / m_creature->GetMaxHealth() < 26 ) + { + //Cast + SummonMages(m_creature->getVictim()); + SummonMages(m_creature->getVictim()); + Mages = true; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_kormok(Creature *_Creature) +{ + return new boss_kormokAI (_Creature); +} + +void AddSC_boss_kormok() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_kormok"; + newscript->GetAI = GetAI_boss_kormok; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_lord_alexei_barov.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_lord_alexei_barov.cpp index 65601ff3ee3..a7a6d29b3d7 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_lord_alexei_barov.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_lord_alexei_barov.cpp @@ -1,98 +1,98 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_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 *c) : ScriptedAI(c) {Reset();} - - uint32 Immolate_Timer; - uint32 VeilofShadow_Timer; - - void Reset() - { - Immolate_Timer = 7000; - VeilofShadow_Timer = 15000; - - m_creature->LoadCreaturesAddon(); - } - - void JustDied(Unit *killer) - { - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - { - pInstance->SetData(DATA_LORDALEXEIBAROV_DEATH, 0); - - if(pInstance->GetData(DATA_CANSPAWNGANDLING)) - m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Immolate_Timer - if (Immolate_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_IMMOLATE); - - Immolate_Timer = 12000; - }else Immolate_Timer -= diff; - - //VeilofShadow_Timer - if (VeilofShadow_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_VEILOFSHADOW); - VeilofShadow_Timer = 20000; - }else VeilofShadow_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_lordalexeibarov(Creature *_Creature) -{ - return new boss_lordalexeibarovAI (_Creature); -} - -void AddSC_boss_lordalexeibarov() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_lord_alexei_barov"; - newscript->GetAI = GetAI_boss_lordalexeibarov; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_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 *c) : ScriptedAI(c) {Reset();} + + uint32 Immolate_Timer; + uint32 VeilofShadow_Timer; + + void Reset() + { + Immolate_Timer = 7000; + VeilofShadow_Timer = 15000; + + m_creature->LoadCreaturesAddon(); + } + + void JustDied(Unit *killer) + { + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + { + pInstance->SetData(DATA_LORDALEXEIBAROV_DEATH, 0); + + if(pInstance->GetData(DATA_CANSPAWNGANDLING)) + m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Immolate_Timer + if (Immolate_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_IMMOLATE); + + Immolate_Timer = 12000; + }else Immolate_Timer -= diff; + + //VeilofShadow_Timer + if (VeilofShadow_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_VEILOFSHADOW); + VeilofShadow_Timer = 20000; + }else VeilofShadow_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_lordalexeibarov(Creature *_Creature) +{ + return new boss_lordalexeibarovAI (_Creature); +} + +void AddSC_boss_lordalexeibarov() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_lord_alexei_barov"; + newscript->GetAI = GetAI_boss_lordalexeibarov; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_lorekeeper_polkelt.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_lorekeeper_polkelt.cpp index c1d6929ddfa..019cbb2b9a0 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_lorekeeper_polkelt.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_lorekeeper_polkelt.cpp @@ -1,113 +1,113 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_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 *c) : ScriptedAI(c) {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) - { - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - { - pInstance->SetData(DATA_LOREKEEPERPOLKELT_DEATH, 0); - - if(pInstance->GetData(DATA_CANSPAWNGANDLING)) - m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //VolatileInfection_Timer - if (VolatileInfection_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_VOLATILEINFECTION); - VolatileInfection_Timer = 32000; - }else VolatileInfection_Timer -= diff; - - //Darkplague_Timer - if (Darkplague_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DARKPLAGUE); - Darkplague_Timer = 8000; - }else Darkplague_Timer -= diff; - - //CorrosiveAcid_Timer - if (CorrosiveAcid_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CORROSIVEACID); - CorrosiveAcid_Timer = 25000; - }else CorrosiveAcid_Timer -= diff; - - //NoxiousCatalyst_Timer - if (NoxiousCatalyst_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_NOXIOUSCATALYST); - NoxiousCatalyst_Timer = 38000; - }else NoxiousCatalyst_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_lorekeeperpolkelt(Creature *_Creature) -{ - return new boss_lorekeeperpolkeltAI (_Creature); -} - -void AddSC_boss_lorekeeperpolkelt() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_lorekeeper_polkelt"; - newscript->GetAI = GetAI_boss_lorekeeperpolkelt; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_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 *c) : ScriptedAI(c) {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) + { + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + { + pInstance->SetData(DATA_LOREKEEPERPOLKELT_DEATH, 0); + + if(pInstance->GetData(DATA_CANSPAWNGANDLING)) + m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //VolatileInfection_Timer + if (VolatileInfection_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_VOLATILEINFECTION); + VolatileInfection_Timer = 32000; + }else VolatileInfection_Timer -= diff; + + //Darkplague_Timer + if (Darkplague_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DARKPLAGUE); + Darkplague_Timer = 8000; + }else Darkplague_Timer -= diff; + + //CorrosiveAcid_Timer + if (CorrosiveAcid_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CORROSIVEACID); + CorrosiveAcid_Timer = 25000; + }else CorrosiveAcid_Timer -= diff; + + //NoxiousCatalyst_Timer + if (NoxiousCatalyst_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_NOXIOUSCATALYST); + NoxiousCatalyst_Timer = 38000; + }else NoxiousCatalyst_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_lorekeeperpolkelt(Creature *_Creature) +{ + return new boss_lorekeeperpolkeltAI (_Creature); +} + +void AddSC_boss_lorekeeperpolkelt() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_lorekeeper_polkelt"; + newscript->GetAI = GetAI_boss_lorekeeperpolkelt; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_ras_frostwhisper.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_ras_frostwhisper.cpp index f8d9e6a66b8..1ee23c92e76 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_ras_frostwhisper.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_ras_frostwhisper.cpp @@ -1,125 +1,125 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //IceArmor_Timer - if (IceArmor_Timer < diff) - { - DoCast(m_creature, SPELL_ICEARMOR); - IceArmor_Timer = 180000; - }else IceArmor_Timer -= diff; - - //Frostbolt_Timer - if (Frostbolt_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_FROSTBOLT); - - Frostbolt_Timer = 8000; - }else Frostbolt_Timer -= diff; - - //Freeze_Timer - if (Freeze_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FREEZE); - Freeze_Timer = 24000; - }else Freeze_Timer -= diff; - - //Fear_Timer - if (Fear_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FEAR); - Fear_Timer = 30000; - }else Fear_Timer -= diff; - - //ChillNova_Timer - if (ChillNova_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CHILLNOVA); - ChillNova_Timer = 14000; - }else ChillNova_Timer -= diff; - - //FrostVolley_Timer - if (FrostVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROSTVOLLEY); - FrostVolley_Timer = 15000; - }else FrostVolley_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_rasfrost(Creature *_Creature) -{ - return new boss_rasfrostAI (_Creature); -} - -void AddSC_boss_rasfrost() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_boss_ras_frostwhisper"; - newscript->GetAI = GetAI_boss_rasfrost; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //IceArmor_Timer + if (IceArmor_Timer < diff) + { + DoCast(m_creature, SPELL_ICEARMOR); + IceArmor_Timer = 180000; + }else IceArmor_Timer -= diff; + + //Frostbolt_Timer + if (Frostbolt_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_FROSTBOLT); + + Frostbolt_Timer = 8000; + }else Frostbolt_Timer -= diff; + + //Freeze_Timer + if (Freeze_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FREEZE); + Freeze_Timer = 24000; + }else Freeze_Timer -= diff; + + //Fear_Timer + if (Fear_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FEAR); + Fear_Timer = 30000; + }else Fear_Timer -= diff; + + //ChillNova_Timer + if (ChillNova_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CHILLNOVA); + ChillNova_Timer = 14000; + }else ChillNova_Timer -= diff; + + //FrostVolley_Timer + if (FrostVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROSTVOLLEY); + FrostVolley_Timer = 15000; + }else FrostVolley_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_rasfrost(Creature *_Creature) +{ + return new boss_rasfrostAI (_Creature); +} + +void AddSC_boss_rasfrost() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_boss_ras_frostwhisper"; + newscript->GetAI = GetAI_boss_rasfrost; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_the_ravenian.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_the_ravenian.cpp index ae833b8cc1c..b1afb78a56e 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_the_ravenian.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_the_ravenian.cpp @@ -1,118 +1,118 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_scholomance.h" - -#define SPELL_TRAMPLE 15550 -#define SPELL_CLEAVE 20691 -#define SPELL_SUNDERINCLEAVE 25174 -#define SPELL_KNOCKAWAY 10101 - -#define SAY_AGGRO1 "Mine! Mine! Mine! Gizlock is the ruler of this domain! You shall never reveal my presence!" - -struct MANGOS_DLL_DECL boss_theravenianAI : public ScriptedAI -{ - boss_theravenianAI(Creature *c) : ScriptedAI(c) {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) - { - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - { - pInstance->SetData(DATA_THERAVENIAN_DEATH, 0); - - if(pInstance->GetData(DATA_CANSPAWNGANDLING)) - m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Trample_Timer - if (Trample_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_TRAMPLE); - Trample_Timer = 10000; - }else Trample_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - //SunderingCleave_Timer - if (SunderingCleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SUNDERINCLEAVE); - SunderingCleave_Timer = 20000; - }else SunderingCleave_Timer -= diff; - - //KnockAway_Timer - if (KnockAway_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); - KnockAway_Timer = 12000; - }else KnockAway_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_theravenian(Creature *_Creature) -{ - return new boss_theravenianAI (_Creature); -} - -void AddSC_boss_theravenian() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_the_ravenian"; - newscript->GetAI = GetAI_boss_theravenian; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_scholomance.h" + +#define SPELL_TRAMPLE 15550 +#define SPELL_CLEAVE 20691 +#define SPELL_SUNDERINCLEAVE 25174 +#define SPELL_KNOCKAWAY 10101 + +#define SAY_AGGRO1 "Mine! Mine! Mine! Gizlock is the ruler of this domain! You shall never reveal my presence!" + +struct MANGOS_DLL_DECL boss_theravenianAI : public ScriptedAI +{ + boss_theravenianAI(Creature *c) : ScriptedAI(c) {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) + { + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + { + pInstance->SetData(DATA_THERAVENIAN_DEATH, 0); + + if(pInstance->GetData(DATA_CANSPAWNGANDLING)) + m_creature->SummonCreature(1853, 180.73, -9.43856, 75.507, 1.61399, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO1, LANG_UNIVERSAL, NULL); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Trample_Timer + if (Trample_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_TRAMPLE); + Trample_Timer = 10000; + }else Trample_Timer -= diff; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 7000; + }else Cleave_Timer -= diff; + + //SunderingCleave_Timer + if (SunderingCleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SUNDERINCLEAVE); + SunderingCleave_Timer = 20000; + }else SunderingCleave_Timer -= diff; + + //KnockAway_Timer + if (KnockAway_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); + KnockAway_Timer = 12000; + }else KnockAway_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_theravenian(Creature *_Creature) +{ + return new boss_theravenianAI (_Creature); +} + +void AddSC_boss_theravenian() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_the_ravenian"; + newscript->GetAI = GetAI_boss_theravenian; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/boss_vectus.cpp b/src/bindings/scripts/scripts/zone/scholomance/boss_vectus.cpp index d6808efaf8a..91c57763d09 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/boss_vectus.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/boss_vectus.cpp @@ -1,95 +1,95 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FIRESHIELD 19626 -#define SPELL_BLASTWAVE 13021 -#define SPELL_FRENZY 28371 - -struct MANGOS_DLL_DECL boss_vectusAI : public ScriptedAI -{ - boss_vectusAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FireShield_Timer; - uint32 BlastWave_Timer; - uint32 Frenzy_Timer; - - void Reset() - { - FireShield_Timer = 2000; - BlastWave_Timer = 14000; - Frenzy_Timer = 0; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //FireShield_Timer - if (FireShield_Timer < diff) - { - DoCast(m_creature, SPELL_FIRESHIELD); - FireShield_Timer = 90000; - }else FireShield_Timer -= diff; - - //BlastWave_Timer - if (BlastWave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_BLASTWAVE); - BlastWave_Timer = 12000; - }else BlastWave_Timer -= diff; - - //Frenzy_Timer - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 25 ) - { - if (Frenzy_Timer < diff) - { - DoCast(m_creature,SPELL_FRENZY); - DoTextEmote("goes into a killing frenzy!",NULL); - - Frenzy_Timer = 24000; - }else Frenzy_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_vectus(Creature *_Creature) -{ - return new boss_vectusAI (_Creature); -} - -void AddSC_boss_vectus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_vectus"; - newscript->GetAI = GetAI_boss_vectus; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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: 100 +SDComment: +SDCategory: Scholomance +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_FIRESHIELD 19626 +#define SPELL_BLASTWAVE 13021 +#define SPELL_FRENZY 28371 + +struct MANGOS_DLL_DECL boss_vectusAI : public ScriptedAI +{ + boss_vectusAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FireShield_Timer; + uint32 BlastWave_Timer; + uint32 Frenzy_Timer; + + void Reset() + { + FireShield_Timer = 2000; + BlastWave_Timer = 14000; + Frenzy_Timer = 0; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //FireShield_Timer + if (FireShield_Timer < diff) + { + DoCast(m_creature, SPELL_FIRESHIELD); + FireShield_Timer = 90000; + }else FireShield_Timer -= diff; + + //BlastWave_Timer + if (BlastWave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_BLASTWAVE); + BlastWave_Timer = 12000; + }else BlastWave_Timer -= diff; + + //Frenzy_Timer + if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 25 ) + { + if (Frenzy_Timer < diff) + { + DoCast(m_creature,SPELL_FRENZY); + DoTextEmote("goes into a killing frenzy!",NULL); + + Frenzy_Timer = 24000; + }else Frenzy_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_vectus(Creature *_Creature) +{ + return new boss_vectusAI (_Creature); +} + +void AddSC_boss_vectus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_vectus"; + newscript->GetAI = GetAI_boss_vectus; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/scholomance/def_scholomance.h b/src/bindings/scripts/scripts/zone/scholomance/def_scholomance.h index a4023315e01..cbeab113b85 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/def_scholomance.h +++ b/src/bindings/scripts/scripts/zone/scholomance/def_scholomance.h @@ -1,15 +1,15 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_SCHOLOMANCE_H -#define DEF_SCHOLOMANCE_H - -#define DATA_CANSPAWNGANDLING 1 -#define DATA_DOCTORTHEOLENKRASTINOV_DEATH 2 -#define DATA_INSTRUCTORMALICIA_DEATH 3 -#define DATA_LADYILLUCIABAROV_DEATH 4 -#define DATA_LORDALEXEIBAROV_DEATH 5 -#define DATA_LOREKEEPERPOLKELT_DEATH 6 -#define DATA_THERAVENIAN_DEATH 7 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_SCHOLOMANCE_H +#define DEF_SCHOLOMANCE_H + +#define DATA_CANSPAWNGANDLING 1 +#define DATA_DOCTORTHEOLENKRASTINOV_DEATH 2 +#define DATA_INSTRUCTORMALICIA_DEATH 3 +#define DATA_LADYILLUCIABAROV_DEATH 4 +#define DATA_LORDALEXEIBAROV_DEATH 5 +#define DATA_LOREKEEPERPOLKELT_DEATH 6 +#define DATA_THERAVENIAN_DEATH 7 +#endif diff --git a/src/bindings/scripts/scripts/zone/scholomance/instance_scholomance.cpp b/src/bindings/scripts/scripts/zone/scholomance/instance_scholomance.cpp index 7084635493c..c8e6f17f8c0 100644 --- a/src/bindings/scripts/scripts/zone/scholomance/instance_scholomance.cpp +++ b/src/bindings/scripts/scripts/zone/scholomance/instance_scholomance.cpp @@ -1,102 +1,102 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Scholomance -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" -#include "def_scholomance.h" - -struct MANGOS_DLL_DECL instance_scholomance : public ScriptedInstance -{ - instance_scholomance(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - //Lord Alexei Barov, Doctor Theolen Krastinov, The Ravenian, Lorekeeper Polkelt, Instructor Malicia and the Lady Illucia Barov. - bool IsBossDied[6]; - - void Initialize() - { - IsBossDied[0] = false; - IsBossDied[1] = false; - IsBossDied[2] = false; - IsBossDied[3] = false; - IsBossDied[4] = false; - IsBossDied[5] = false; - } - - bool IsEncounterInProgress() const - { - //not active in scholomance - return false; - } - - uint32 GetData(uint32 type) - { - if(type == DATA_CANSPAWNGANDLING) - if(IsBossDied[0] && IsBossDied[1] && IsBossDied[2] && IsBossDied[3] && IsBossDied[4] && IsBossDied[5]) - return 1; - - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_LORDALEXEIBAROV_DEATH: - IsBossDied[0] = true; - break; - - case DATA_DOCTORTHEOLENKRASTINOV_DEATH: - IsBossDied[1] = true; - break; - - case DATA_THERAVENIAN_DEATH: - IsBossDied[2] = true; - break; - - case DATA_LOREKEEPERPOLKELT_DEATH: - IsBossDied[3] = true; - break; - - case DATA_INSTRUCTORMALICIA_DEATH: - IsBossDied[4] = true; - break; - - case DATA_LADYILLUCIABAROV_DEATH: - IsBossDied[5] = true; - break; - } - } -}; - -InstanceData* GetInstanceData_instance_scholomance(Map* map) -{ - return new instance_scholomance(map); -} - -void AddSC_instance_scholomance() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_scholomance"; - newscript->GetInstanceData = GetInstanceData_instance_scholomance; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Scholomance +SD%Complete: 100 +SDComment: +SDCategory: Scholomance +EndScriptData */ + +#include "precompiled.h" +#include "def_scholomance.h" + +struct MANGOS_DLL_DECL instance_scholomance : public ScriptedInstance +{ + instance_scholomance(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + //Lord Alexei Barov, Doctor Theolen Krastinov, The Ravenian, Lorekeeper Polkelt, Instructor Malicia and the Lady Illucia Barov. + bool IsBossDied[6]; + + void Initialize() + { + IsBossDied[0] = false; + IsBossDied[1] = false; + IsBossDied[2] = false; + IsBossDied[3] = false; + IsBossDied[4] = false; + IsBossDied[5] = false; + } + + bool IsEncounterInProgress() const + { + //not active in scholomance + return false; + } + + uint32 GetData(uint32 type) + { + if(type == DATA_CANSPAWNGANDLING) + if(IsBossDied[0] && IsBossDied[1] && IsBossDied[2] && IsBossDied[3] && IsBossDied[4] && IsBossDied[5]) + return 1; + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_LORDALEXEIBAROV_DEATH: + IsBossDied[0] = true; + break; + + case DATA_DOCTORTHEOLENKRASTINOV_DEATH: + IsBossDied[1] = true; + break; + + case DATA_THERAVENIAN_DEATH: + IsBossDied[2] = true; + break; + + case DATA_LOREKEEPERPOLKELT_DEATH: + IsBossDied[3] = true; + break; + + case DATA_INSTRUCTORMALICIA_DEATH: + IsBossDied[4] = true; + break; + + case DATA_LADYILLUCIABAROV_DEATH: + IsBossDied[5] = true; + break; + } + } +}; + +InstanceData* GetInstanceData_instance_scholomance(Map* map) +{ + return new instance_scholomance(map); +} + +void AddSC_instance_scholomance() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_scholomance"; + newscript->GetInstanceData = GetInstanceData_instance_scholomance; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/searing_gorge/searing_gorge.cpp b/src/bindings/scripts/scripts/zone/searing_gorge/searing_gorge.cpp index 6834cd8a078..4d2264f8fd7 100644 --- a/src/bindings/scripts/scripts/zone/searing_gorge/searing_gorge.cpp +++ b/src/bindings/scripts/scripts/zone/searing_gorge/searing_gorge.cpp @@ -1,159 +1,159 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Searing_Gorge -SD%Complete: 80 -SDComment: Quest support: 3377, 3441 (More accurate info on Kalaran needed). Lothos Riftwaker teleport to Molten Core. -SDCategory: Searing Gorge -EndScriptData */ - -/* ContentData -npc_kalaran_windblade -npc_lothos_riftwaker -npc_zamael_lunthistle -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_kalaran_windblade -######*/ - -bool GossipHello_npc_kalaran_windblade(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(3441) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Tell me what drives this vengance?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_kalaran_windblade(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, "Continue please", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(1954, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "Let me confer with my colleagues", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(1955, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(3441); - break; - } - return true; -} - -/*###### -## npc_lothos_riftwaker -######*/ - -bool GossipHello_npc_lothos_riftwaker(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestRewardStatus(7487) || player->GetQuestRewardStatus(7848)) - player->ADD_GOSSIP_ITEM(0, "Teleport me to the Molten Core", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lothos_riftwaker(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->CLOSE_GOSSIP_MENU(); - player->TeleportTo(409, 1096, -467, -104.6, 3.64); - } - - return true; -} - -/*###### -## npc_zamael_lunthistle -######*/ - -bool GossipHello_npc_zamael_lunthistle(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(3377) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Tell me your story", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(1920, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_zamael_lunthistle(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, "Please continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(1921, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "Goodbye", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(1922, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(3377); - break; - } - return true; -} - -/*###### -## -######*/ - -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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_lothos_riftwaker"; - newscript->pGossipHello = &GossipHello_npc_lothos_riftwaker; - newscript->pGossipSelect = &GossipSelect_npc_lothos_riftwaker; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_zamael_lunthistle"; - newscript->pGossipHello = &GossipHello_npc_zamael_lunthistle; - newscript->pGossipSelect = &GossipSelect_npc_zamael_lunthistle; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Searing_Gorge +SD%Complete: 80 +SDComment: Quest support: 3377, 3441 (More accurate info on Kalaran needed). Lothos Riftwaker teleport to Molten Core. +SDCategory: Searing Gorge +EndScriptData */ + +/* ContentData +npc_kalaran_windblade +npc_lothos_riftwaker +npc_zamael_lunthistle +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_kalaran_windblade +######*/ + +bool GossipHello_npc_kalaran_windblade(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(3441) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Tell me what drives this vengance?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_kalaran_windblade(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, "Continue please", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(1954, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "Let me confer with my colleagues", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(1955, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(3441); + break; + } + return true; +} + +/*###### +## npc_lothos_riftwaker +######*/ + +bool GossipHello_npc_lothos_riftwaker(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestRewardStatus(7487) || player->GetQuestRewardStatus(7848)) + player->ADD_GOSSIP_ITEM(0, "Teleport me to the Molten Core", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_lothos_riftwaker(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(409, 1096, -467, -104.6, 3.64); + } + + return true; +} + +/*###### +## npc_zamael_lunthistle +######*/ + +bool GossipHello_npc_zamael_lunthistle(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(3377) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Tell me your story", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(1920, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_zamael_lunthistle(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, "Please continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(1921, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "Goodbye", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(1922, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(3377); + break; + } + return true; +} + +/*###### +## +######*/ + +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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_lothos_riftwaker"; + newscript->pGossipHello = &GossipHello_npc_lothos_riftwaker; + newscript->pGossipSelect = &GossipSelect_npc_lothos_riftwaker; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_zamael_lunthistle"; + newscript->pGossipHello = &GossipHello_npc_zamael_lunthistle; + newscript->pGossipSelect = &GossipSelect_npc_zamael_lunthistle; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/shadowfang_keep/def_shadowfang_keep.h b/src/bindings/scripts/scripts/zone/shadowfang_keep/def_shadowfang_keep.h index 7ece07f0231..b49e7623257 100644 --- a/src/bindings/scripts/scripts/zone/shadowfang_keep/def_shadowfang_keep.h +++ b/src/bindings/scripts/scripts/zone/shadowfang_keep/def_shadowfang_keep.h @@ -1,12 +1,12 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_SHADOWFANG_H -#define DEF_SHADOWFANG_H - -#define TYPE_FREE_NPC 1 -#define TYPE_RETHILGORE 2 -#define TYPE_FENRUS 3 -#define TYPE_NANDOS 4 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_SHADOWFANG_H +#define DEF_SHADOWFANG_H + +#define TYPE_FREE_NPC 1 +#define TYPE_RETHILGORE 2 +#define TYPE_FENRUS 3 +#define TYPE_NANDOS 4 +#endif diff --git a/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp b/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp index 5e4ce0b3267..8051d3dd57f 100644 --- a/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp +++ b/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp @@ -1,152 +1,152 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Shadowfang_Keep -SD%Complete: 75 -SDComment: TODO: check what other parts would require additional code (ex: make sure door are in open state if boss dead) -SDCategory: Shadowfang Keep -EndScriptData */ - -#include "precompiled.h" -#include "def_shadowfang_keep.h" - -#define ENCOUNTERS 4 - -//#define ENTRY_BOSS_RETHILGORE 3914 -//#define ENTRY_BOSS_FENRUS 4274 -//#define ENTRY_BOSS_NANDOS 3927 - -#define ENTRY_COURTYARD_DOOR 18895 //door to open when talking to NPC's -#define ENTRY_SORCERER_DOOR 18972 //door to open when Fenrus the Devourer -#define ENTRY_ARUGAL_DOOR 18971 //door to open when Wolf Master Nandos - -struct MANGOS_DLL_DECL instance_shadowfang_keep : public ScriptedInstance -{ - instance_shadowfang_keep(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint32 Encounter[ENCOUNTERS]; - - /*uint64 RethilgoreGUID; - uint64 FenrusGUID; - uint64 NandosGUID;*/ - - GameObject *DoorCourtyard; - GameObject *DoorSorcerer; - GameObject *DoorArugal; - - void Initialize() - { - /*RethilgoreGUID = 0; - FenrusGUID = 0; - NandosGUID = 0;*/ - - DoorCourtyard = NULL; - DoorSorcerer = NULL; - DoorArugal = NULL; - } - - void OnObjectCreate(GameObject *go) - { - switch(go->GetEntry()) - { - case ENTRY_COURTYARD_DOOR: DoorCourtyard = go; break; - case ENTRY_SORCERER_DOOR: DoorSorcerer = go; break; - case ENTRY_ARUGAL_DOOR: DoorArugal = go; break; - } - } - - /*void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case ENTRY_BOSS_RETHILGORE: - RethilgoreGUID = creature->GetGUID(); - break; - case ENTRY_BOSS_FENRUS: - FenrusGUID = creature->GetGUID(); - break; - case ENTRY_BOSS_NANDOS: - NandosGUID = creature->GetGUID(); - break; - } - }*/ - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case TYPE_FREE_NPC: - if(data == DONE) - { - if(DoorCourtyard) - DoorCourtyard->UseDoorOrButton(); - } - Encounter[0] = data; - break; - case TYPE_RETHILGORE: - Encounter[1] = data; - break; - case TYPE_FENRUS: - if(data == DONE) - { - if(DoorSorcerer) - DoorSorcerer->UseDoorOrButton(); - } - Encounter[2] = data; - break; - case TYPE_NANDOS: - if(data == DONE) - { - if(DoorArugal) - DoorArugal->UseDoorOrButton(); - } - Encounter[3] = data; - break; - } - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case TYPE_FREE_NPC: - return Encounter[0]; - case TYPE_RETHILGORE: - return Encounter[1]; - case TYPE_FENRUS: - return Encounter[2]; - case TYPE_NANDOS: - return Encounter[3]; - } - return 0; - } - -}; - -InstanceData* GetInstanceData_instance_shadowfang_keep(Map* map) -{ - return new instance_shadowfang_keep(map); -} - -void AddSC_instance_shadowfang_keep() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_shadowfang_keep"; - newscript->GetInstanceData = GetInstanceData_instance_shadowfang_keep; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Shadowfang_Keep +SD%Complete: 75 +SDComment: TODO: check what other parts would require additional code (ex: make sure door are in open state if boss dead) +SDCategory: Shadowfang Keep +EndScriptData */ + +#include "precompiled.h" +#include "def_shadowfang_keep.h" + +#define ENCOUNTERS 4 + +//#define ENTRY_BOSS_RETHILGORE 3914 +//#define ENTRY_BOSS_FENRUS 4274 +//#define ENTRY_BOSS_NANDOS 3927 + +#define ENTRY_COURTYARD_DOOR 18895 //door to open when talking to NPC's +#define ENTRY_SORCERER_DOOR 18972 //door to open when Fenrus the Devourer +#define ENTRY_ARUGAL_DOOR 18971 //door to open when Wolf Master Nandos + +struct MANGOS_DLL_DECL instance_shadowfang_keep : public ScriptedInstance +{ + instance_shadowfang_keep(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 Encounter[ENCOUNTERS]; + + /*uint64 RethilgoreGUID; + uint64 FenrusGUID; + uint64 NandosGUID;*/ + + GameObject *DoorCourtyard; + GameObject *DoorSorcerer; + GameObject *DoorArugal; + + void Initialize() + { + /*RethilgoreGUID = 0; + FenrusGUID = 0; + NandosGUID = 0;*/ + + DoorCourtyard = NULL; + DoorSorcerer = NULL; + DoorArugal = NULL; + } + + void OnObjectCreate(GameObject *go) + { + switch(go->GetEntry()) + { + case ENTRY_COURTYARD_DOOR: DoorCourtyard = go; break; + case ENTRY_SORCERER_DOOR: DoorSorcerer = go; break; + case ENTRY_ARUGAL_DOOR: DoorArugal = go; break; + } + } + + /*void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case ENTRY_BOSS_RETHILGORE: + RethilgoreGUID = creature->GetGUID(); + break; + case ENTRY_BOSS_FENRUS: + FenrusGUID = creature->GetGUID(); + break; + case ENTRY_BOSS_NANDOS: + NandosGUID = creature->GetGUID(); + break; + } + }*/ + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case TYPE_FREE_NPC: + if(data == DONE) + { + if(DoorCourtyard) + DoorCourtyard->UseDoorOrButton(); + } + Encounter[0] = data; + break; + case TYPE_RETHILGORE: + Encounter[1] = data; + break; + case TYPE_FENRUS: + if(data == DONE) + { + if(DoorSorcerer) + DoorSorcerer->UseDoorOrButton(); + } + Encounter[2] = data; + break; + case TYPE_NANDOS: + if(data == DONE) + { + if(DoorArugal) + DoorArugal->UseDoorOrButton(); + } + Encounter[3] = data; + break; + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case TYPE_FREE_NPC: + return Encounter[0]; + case TYPE_RETHILGORE: + return Encounter[1]; + case TYPE_FENRUS: + return Encounter[2]; + case TYPE_NANDOS: + return Encounter[3]; + } + return 0; + } + +}; + +InstanceData* GetInstanceData_instance_shadowfang_keep(Map* map) +{ + return new instance_shadowfang_keep(map); +} + +void AddSC_instance_shadowfang_keep() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_shadowfang_keep"; + newscript->GetInstanceData = GetInstanceData_instance_shadowfang_keep; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/shadowfang_keep/shadowfang_keep.cpp b/src/bindings/scripts/scripts/zone/shadowfang_keep/shadowfang_keep.cpp index 172a0907a79..587986c6556 100644 --- a/src/bindings/scripts/scripts/zone/shadowfang_keep/shadowfang_keep.cpp +++ b/src/bindings/scripts/scripts/zone/shadowfang_keep/shadowfang_keep.cpp @@ -1,117 +1,117 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Shadowfang_Keep -SD%Complete: 75 -SDComment: npc_shadowfang_prisoner using escortAI for movement to door. Might need additional code in case being attacked. Add proper texts/say(). -SDCategory: Shadowfang Keep -EndScriptData */ - -/* ContentData -npc_shadowfang_prisoner -EndContentData */ - -#include "precompiled.h" -#include "../../npc/npc_escortAI.h" -#include "def_shadowfang_keep.h" - -/*###### -## npc_shadowfang_prisoner -######*/ - -struct MANGOS_DLL_DECL npc_shadowfang_prisonerAI : public npc_escortAI -{ - npc_shadowfang_prisonerAI(Creature *c) : npc_escortAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - void WaypointReached(uint32 i) - { - if( pInstance && i == 6) - { - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - m_creature->Say("Thanks for freeing me, I'll open this door for you, then I will get out of here.", LANG_UNIVERSAL, 0); - pInstance->SetData(TYPE_FREE_NPC, DONE); - } - } - - void Reset() {} - void Aggro(Unit* who) {} -}; - -CreatureAI* GetAI_npc_shadowfang_prisoner(Creature *_Creature) -{ - npc_shadowfang_prisonerAI* prisonerAI = new npc_shadowfang_prisonerAI(_Creature); - - uint32 eCreature = _Creature->GetEntry(); - - if( eCreature==3849) //adamant - prisonerAI->AddWaypoint(0, -254.47, 2117.48, 81.17); - if( eCreature==3850) //ashcrombe - prisonerAI->AddWaypoint(0, -252.35, 2126.71, 81.17); - - prisonerAI->AddWaypoint(1, -253.63, 2131.27, 81.28); - prisonerAI->AddWaypoint(2, -249.66, 2142.45, 87.01); - prisonerAI->AddWaypoint(3, -248.08, 2143.68, 87.01); - prisonerAI->AddWaypoint(4, -238.87, 2139.93, 87.01); - prisonerAI->AddWaypoint(5, -235.47, 2149.18, 90.59); - prisonerAI->AddWaypoint(6, -239.89, 2156.06, 90.62, 20000); - - return (CreatureAI*)prisonerAI; -} - -bool GossipHello_npc_shadowfang_prisoner(Player *player, Creature *_Creature) -{ - ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); - - if( pInstance && !pInstance->GetData(TYPE_FREE_NPC) && pInstance->GetData(TYPE_RETHILGORE) == DONE ) - player->ADD_GOSSIP_ITEM( 0, "Thanks, I'll follow you to the door.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_shadowfang_prisoner(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - ((npc_escortAI*)(_Creature->AI()))->Start(false, false, false, player->GetGUID()); - } - return true; -} - -/*###### -## AddSC -######*/ - -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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Shadowfang_Keep +SD%Complete: 75 +SDComment: npc_shadowfang_prisoner using escortAI for movement to door. Might need additional code in case being attacked. Add proper texts/say(). +SDCategory: Shadowfang Keep +EndScriptData */ + +/* ContentData +npc_shadowfang_prisoner +EndContentData */ + +#include "precompiled.h" +#include "../../npc/npc_escortAI.h" +#include "def_shadowfang_keep.h" + +/*###### +## npc_shadowfang_prisoner +######*/ + +struct MANGOS_DLL_DECL npc_shadowfang_prisonerAI : public npc_escortAI +{ + npc_shadowfang_prisonerAI(Creature *c) : npc_escortAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + void WaypointReached(uint32 i) + { + if( pInstance && i == 6) + { + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + m_creature->Say("Thanks for freeing me, I'll open this door for you, then I will get out of here.", LANG_UNIVERSAL, 0); + pInstance->SetData(TYPE_FREE_NPC, DONE); + } + } + + void Reset() {} + void Aggro(Unit* who) {} +}; + +CreatureAI* GetAI_npc_shadowfang_prisoner(Creature *_Creature) +{ + npc_shadowfang_prisonerAI* prisonerAI = new npc_shadowfang_prisonerAI(_Creature); + + uint32 eCreature = _Creature->GetEntry(); + + if( eCreature==3849) //adamant + prisonerAI->AddWaypoint(0, -254.47, 2117.48, 81.17); + if( eCreature==3850) //ashcrombe + prisonerAI->AddWaypoint(0, -252.35, 2126.71, 81.17); + + prisonerAI->AddWaypoint(1, -253.63, 2131.27, 81.28); + prisonerAI->AddWaypoint(2, -249.66, 2142.45, 87.01); + prisonerAI->AddWaypoint(3, -248.08, 2143.68, 87.01); + prisonerAI->AddWaypoint(4, -238.87, 2139.93, 87.01); + prisonerAI->AddWaypoint(5, -235.47, 2149.18, 90.59); + prisonerAI->AddWaypoint(6, -239.89, 2156.06, 90.62, 20000); + + return (CreatureAI*)prisonerAI; +} + +bool GossipHello_npc_shadowfang_prisoner(Player *player, Creature *_Creature) +{ + ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData()); + + if( pInstance && !pInstance->GetData(TYPE_FREE_NPC) && pInstance->GetData(TYPE_RETHILGORE) == DONE ) + player->ADD_GOSSIP_ITEM( 0, "Thanks, I'll follow you to the door.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_shadowfang_prisoner(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + ((npc_escortAI*)(_Creature->AI()))->Start(false, false, false, player->GetGUID()); + } + return true; +} + +/*###### +## AddSC +######*/ + +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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp b/src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp index 1960d9f9cc1..fdfac7f9ece 100644 --- a/src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp +++ b/src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp @@ -1,211 +1,211 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Doomwalker -SD%Complete: 100 -SDComment: -SDCategory: Shadowmoon Valley -EndScriptData */ - -#include "precompiled.h" - -//-------------------------------------- -//Spells -#define SPELL_SUNDER_ARMOR 30901 - -#define SPELL_CHAIN_LIGHTNING 33665 - -#define SPELL_OVERRUN 32636 -#define SAY_OVERRUN_1 "Trajectory locked." -#define SOUND_OVERRUN_1 11347 -#define SAY_OVERRUN_2 "Engage maximum speed." -#define SOUND_OVERRUN_2 11348 - -#define SPELL_ENRAGE 34624 - -#define SPELL_MARK_DEATH 37128 - -#define SPELL_EARTHQUAKE 32686 -#define SAY_EARTHQUAKE_1 "Tectonic disruption commencing." -#define SOUND_EARTHQUAKE_1 11345 -#define SAY_EARTHQUAKE_2 "Magnitude set. Release." -#define SOUND_EARTHQUAKE_2 11346 - -#define SAY_AGGRO "Do not proceed. You will be eliminated!" -#define SOUND_AGGRO 11344 - -#define SAY_SLAY_1 "Threat level zero." -#define SOUND_SLAY_1 11349 -#define SAY_SLAY_2 "Directive accomplished." -#define SOUND_SLAY_2 11350 -#define SAY_SLAY_3 "Target exterminated." -#define SOUND_SLAY_3 11351 - -#define SAY_DEATH "System failure in five... four..." -#define SOUND_DEATH 11352 - -struct MANGOS_DLL_DECL boss_doomwalkerAI : public ScriptedAI -{ - boss_doomwalkerAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Chain_Timer; - uint32 Enrage_Timer; - uint32 Overrun_Timer; - uint32 Quake_Timer; - uint32 Armor_Timer; - - bool InEnrage; - - void Reset() - { - Enrage_Timer = 0; - Armor_Timer = 10000; - Chain_Timer = 20000; - Quake_Timer = 60000; - Overrun_Timer = 120000; - - InEnrage = false; - } - - void KilledUnit(Unit* Victim) - { - if(rand()%5) - return; - - switch(rand()%3) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY_2); - break; - case 2: - DoYell(SAY_SLAY_3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY_3); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - //when hp <= 20% gain enrage - if (((m_creature->GetHealth()*100)/ m_creature->GetMaxHealth()) <= 20) - { - if(Enrage_Timer < diff) - { - DoCast(m_creature,SPELL_ENRAGE); - Enrage_Timer = 6000; - InEnrage = true; - }else Enrage_Timer -= diff; - } - - //Spell Overrun - if (Overrun_Timer < diff) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_OVERRUN_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_OVERRUN_1); - break; - case 1: - DoYell(SAY_OVERRUN_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_OVERRUN_2); - break; - } - DoCast(m_creature->getVictim(),SPELL_OVERRUN); - Overrun_Timer = (30 + rand()% 40) * 1000; //30-70sec cooldown - - }else Overrun_Timer -= diff; - - //Spell Earthquake - if (Quake_Timer < diff) - { - if (rand()%2) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_EARTHQUAKE_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_EARTHQUAKE_1); - break; - case 1: - DoYell(SAY_EARTHQUAKE_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_EARTHQUAKE_2); - break; - } - if(InEnrage) - { - m_creature->RemoveAura(SPELL_ENRAGE, 0);//remove enrage before casting earthquake because enrage + earthquake = 16000dmg over 8sec and all dead - } - DoCast(m_creature,SPELL_EARTHQUAKE); - Quake_Timer = (70 + rand()% 30) * 1000; //70-100sec cooldown - }else Quake_Timer -= diff; - - //Spell Chain Lightning - if (Chain_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CHAIN_LIGHTNING); - Chain_Timer = (50 + rand()% 50) * 1000; //50-100sec cooldown - }else Chain_Timer -= diff; - - //Spell Sunder Armor - if (Armor_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SUNDER_ARMOR); - Armor_Timer = (15 + rand()% 7) * 1000; //15-23sec cooldown about 70 proc to stack - }else Armor_Timer -= diff; - - DoMeleeAttackIfReady(); - } - } -}; - -CreatureAI* GetAI_boss_doomwalker(Creature *_Creature) -{ - return new boss_doomwalkerAI (_Creature); -} - -void AddSC_boss_doomwalker() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_doomwalker"; - newscript->GetAI = GetAI_boss_doomwalker; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Doomwalker +SD%Complete: 100 +SDComment: +SDCategory: Shadowmoon Valley +EndScriptData */ + +#include "precompiled.h" + +//-------------------------------------- +//Spells +#define SPELL_SUNDER_ARMOR 30901 + +#define SPELL_CHAIN_LIGHTNING 33665 + +#define SPELL_OVERRUN 32636 +#define SAY_OVERRUN_1 "Trajectory locked." +#define SOUND_OVERRUN_1 11347 +#define SAY_OVERRUN_2 "Engage maximum speed." +#define SOUND_OVERRUN_2 11348 + +#define SPELL_ENRAGE 34624 + +#define SPELL_MARK_DEATH 37128 + +#define SPELL_EARTHQUAKE 32686 +#define SAY_EARTHQUAKE_1 "Tectonic disruption commencing." +#define SOUND_EARTHQUAKE_1 11345 +#define SAY_EARTHQUAKE_2 "Magnitude set. Release." +#define SOUND_EARTHQUAKE_2 11346 + +#define SAY_AGGRO "Do not proceed. You will be eliminated!" +#define SOUND_AGGRO 11344 + +#define SAY_SLAY_1 "Threat level zero." +#define SOUND_SLAY_1 11349 +#define SAY_SLAY_2 "Directive accomplished." +#define SOUND_SLAY_2 11350 +#define SAY_SLAY_3 "Target exterminated." +#define SOUND_SLAY_3 11351 + +#define SAY_DEATH "System failure in five... four..." +#define SOUND_DEATH 11352 + +struct MANGOS_DLL_DECL boss_doomwalkerAI : public ScriptedAI +{ + boss_doomwalkerAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Chain_Timer; + uint32 Enrage_Timer; + uint32 Overrun_Timer; + uint32 Quake_Timer; + uint32 Armor_Timer; + + bool InEnrage; + + void Reset() + { + Enrage_Timer = 0; + Armor_Timer = 10000; + Chain_Timer = 20000; + Quake_Timer = 60000; + Overrun_Timer = 120000; + + InEnrage = false; + } + + void KilledUnit(Unit* Victim) + { + if(rand()%5) + return; + + switch(rand()%3) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY_2); + break; + case 2: + DoYell(SAY_SLAY_3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY_3); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + { + //when hp <= 20% gain enrage + if (((m_creature->GetHealth()*100)/ m_creature->GetMaxHealth()) <= 20) + { + if(Enrage_Timer < diff) + { + DoCast(m_creature,SPELL_ENRAGE); + Enrage_Timer = 6000; + InEnrage = true; + }else Enrage_Timer -= diff; + } + + //Spell Overrun + if (Overrun_Timer < diff) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_OVERRUN_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_OVERRUN_1); + break; + case 1: + DoYell(SAY_OVERRUN_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_OVERRUN_2); + break; + } + DoCast(m_creature->getVictim(),SPELL_OVERRUN); + Overrun_Timer = (30 + rand()% 40) * 1000; //30-70sec cooldown + + }else Overrun_Timer -= diff; + + //Spell Earthquake + if (Quake_Timer < diff) + { + if (rand()%2) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_EARTHQUAKE_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_EARTHQUAKE_1); + break; + case 1: + DoYell(SAY_EARTHQUAKE_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_EARTHQUAKE_2); + break; + } + if(InEnrage) + { + m_creature->RemoveAura(SPELL_ENRAGE, 0);//remove enrage before casting earthquake because enrage + earthquake = 16000dmg over 8sec and all dead + } + DoCast(m_creature,SPELL_EARTHQUAKE); + Quake_Timer = (70 + rand()% 30) * 1000; //70-100sec cooldown + }else Quake_Timer -= diff; + + //Spell Chain Lightning + if (Chain_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CHAIN_LIGHTNING); + Chain_Timer = (50 + rand()% 50) * 1000; //50-100sec cooldown + }else Chain_Timer -= diff; + + //Spell Sunder Armor + if (Armor_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SUNDER_ARMOR); + Armor_Timer = (15 + rand()% 7) * 1000; //15-23sec cooldown about 70 proc to stack + }else Armor_Timer -= diff; + + DoMeleeAttackIfReady(); + } + } +}; + +CreatureAI* GetAI_boss_doomwalker(Creature *_Creature) +{ + return new boss_doomwalkerAI (_Creature); +} + +void AddSC_boss_doomwalker() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_doomwalker"; + newscript->GetAI = GetAI_boss_doomwalker; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp b/src/bindings/scripts/scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp index d75d50c666b..c2d5f6dfecc 100644 --- a/src/bindings/scripts/scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp +++ b/src/bindings/scripts/scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp @@ -1,748 +1,748 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Shadowmoon_Valley -SD%Complete: 100 -SDComment: Quest support: 10519, 10583, 10601, 10814, 10804, 10854, 11082. Vendor Drake Dealer Hurlunk. Teleporter TO Invasion Point: Cataclysm -SDCategory: Shadowmoon Valley -EndScriptData */ - -/* ContentData -mob_mature_netherwing_drake -mob_enslaved_netherwing_drake -npc_drake_dealer_hurlunk -npc_invis_legion_teleporter -npcs_flanis_swiftwing_and_kagrosh -npc_murkblood_overseer -npc_neltharaku -npc_karynaku -npc_oronok_tornheart -EndContentData */ - -#include "precompiled.h" - -/*##### -# mob_mature_netherwing_drake -#####*/ - -#define SPELL_PLACE_CARCASS 38439 -#define SPELL_JUST_EATEN 38502 -#define SPELL_NETHER_BREATH 38467 - -#define SAY_JUST_EATEN "Thank you, mortal." - -struct MANGOS_DLL_DECL mob_mature_netherwing_drakeAI : public ScriptedAI -{ - mob_mature_netherwing_drakeAI(Creature* c) : ScriptedAI(c) - { - Reset(); - PlayerGUID = 0; - } - - uint64 PlayerGUID; - - bool IsEating; - bool Evade; - - uint32 ResetTimer; - uint32 CastTimer; - uint32 EatTimer; - - void Reset() - { - IsEating = false; - Evade = false; - - ResetTimer = 120000; - EatTimer = 5000; - CastTimer = 5000; - } - - void Aggro(Unit* who) { } - - void MoveInLineOfSight(Unit* who) - { - if(m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void SpellHit(Unit* caster, const SpellEntry* spell) - { - if(!caster) - return; - - if(caster->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_PLACE_CARCASS && !m_creature->HasAura(SPELL_JUST_EATEN, 0) && !PlayerGUID) - { - float PlayerX, PlayerY, PlayerZ; - caster->GetClosePoint(PlayerX, PlayerY, PlayerZ, m_creature->GetObjectSize()); - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - m_creature->GetMotionMaster()->MovePoint(1, PlayerX, PlayerY, PlayerZ); - PlayerGUID = caster->GetGUID(); - } - } - - void MovementInform(uint32 type, uint32 id) - { - if(type != POINT_MOTION_TYPE) - return; - - if(id == 1) - { - IsEating = true; - EatTimer = 5000; - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACKUNARMED); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - } - } - - void UpdateAI(const uint32 diff) - { - if(IsEating) - if(EatTimer < diff) - { - IsEating = false; - DoCast(m_creature, SPELL_JUST_EATEN); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - DoSay(SAY_JUST_EATEN, LANG_DRACONIC, NULL); - if(PlayerGUID) - { - Player* plr = ((Player*)Unit::GetUnit((*m_creature), PlayerGUID)); - if(plr && plr->GetQuestStatus(10804) == QUEST_STATUS_INCOMPLETE) - { - plr->KilledMonster(22131, m_creature->GetGUID()); - Evade = true; - PlayerGUID = 0; - } - } - }else EatTimer -= diff; - - if(Evade) - if(ResetTimer < diff) - EnterEvadeMode(); - else ResetTimer -= diff; - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(CastTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_NETHER_BREATH); - CastTimer = 5000; - }else CastTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_mature_netherwing_drake(Creature *_creature) -{ - return new mob_mature_netherwing_drakeAI(_creature); -} - -/*### -# mob_enslaved_netherwing_drake -####*/ - -#define FACTION_DEFAULT 62 -#define FACTION_FRIENDLY 1840 // Not sure if this is correct, it was taken off of Mordenai. - -#define SPELL_HIT_FORCE_OF_NELTHARAKU 38762 -#define SPELL_FORCE_OF_NELTHARAKU 38775 - -#define CREATURE_DRAGONMAW_SUBJUGATOR 21718 -#define CREATURE_ESCAPE_DUMMY 22317 - -struct MANGOS_DLL_DECL mob_enslaved_netherwing_drakeAI : public ScriptedAI -{ - mob_enslaved_netherwing_drakeAI(Creature* c) : ScriptedAI(c) - { - Reset(); - PlayerGUID = 0; - Tapped = false; - } - - uint64 PlayerGUID; - uint32 FlyTimer; - bool Tapped; - - void Reset() - { - if(!Tapped) - m_creature->setFaction(FACTION_DEFAULT); - - FlyTimer = 10000; - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - m_creature->SetVisibility(VISIBILITY_ON); - } - - void Aggro(Unit* who) { } - - Creature* SelectCreatureInGrid(uint32 entry, float range) - { - Creature* pCreature = NULL; - - // Time for some omg mind blowing code to search for creature - CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*m_creature, entry, true, range); - MaNGOS::CreatureLastSearcher searcher(pCreature, creature_check); - - TypeContainerVisitor, GridTypeMapContainer> creature_searcher(searcher); - - CellLock cell_lock(cell, pair); - cell_lock->Visit(cell_lock, creature_searcher,*(m_creature->GetMap())); - - return pCreature; - } - - void SpellHit(Unit* caster, const SpellEntry* spell) - { - if(!caster) - return; - - if(caster->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_HIT_FORCE_OF_NELTHARAKU && !Tapped) - { - Tapped = true; - PlayerGUID = caster->GetGUID(); - - m_creature->setFaction(FACTION_FRIENDLY); - DoCast(caster, SPELL_FORCE_OF_NELTHARAKU, true); - - Creature* Dragonmaw = SelectCreatureInGrid(CREATURE_DRAGONMAW_SUBJUGATOR, 50); - - if(Dragonmaw) - { - m_creature->AddThreat(Dragonmaw, 100000.0f); - AttackStart(Dragonmaw); - } - - HostilReference* ref = m_creature->getThreatManager().getOnlineContainer().getReferenceByTarget(caster); - if(ref) - ref->removeReference(); - } - } - - void MovementInform(uint32 type, uint32 id) - { - if(type != POINT_MOTION_TYPE) - return; - - if(id == 1) - { - if(PlayerGUID) - { - Unit* plr = Unit::GetUnit((*m_creature), PlayerGUID); - if(plr) - DoCast(plr, SPELL_FORCE_OF_NELTHARAKU, true); - - PlayerGUID = 0; - } - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_creature->RemoveCorpse(); - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - { - if(Tapped) - if(FlyTimer < diff) - { - Tapped = false; - if(PlayerGUID) - { - Player* plr = ((Player*)Unit::GetUnit((*m_creature), PlayerGUID)); - if(plr && plr->GetQuestStatus(10854) == QUEST_STATUS_INCOMPLETE) - { - plr->KilledMonster(22316, m_creature->GetGUID()); - /* - float x,y,z; - m_creature->GetPosition(x,y,z); - - float dx,dy,dz; - m_creature->GetRandomPoint(x, y, z, 20, dx, dy, dz); - dz += 20; // so it's in the air, not ground*/ - - float dx, dy, dz; - - Creature* EscapeDummy = SelectCreatureInGrid(CREATURE_ESCAPE_DUMMY, 30); - if(EscapeDummy) - EscapeDummy->GetPosition(dx, dy, dz); - else - { - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20, dx, dy, dz); - dz += 25; - } - - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - m_creature->GetMotionMaster()->MovePoint(1, dx, dy, dz); - } - } - }else FlyTimer -= diff; - return; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_enslaved_netherwing_drake(Creature* _Creature) -{ - return new mob_enslaved_netherwing_drakeAI(_Creature); -} - -/*##### -# mob_dragonmaw_peon -#####*/ - -struct MANGOS_DLL_DECL mob_dragonmaw_peonAI : public ScriptedAI -{ - mob_dragonmaw_peonAI(Creature* c) : ScriptedAI(c) - { - Reset(); - } - - uint64 PlayerGUID; - bool Tapped; - uint32 PoisonTimer; - - void Reset() - { - PlayerGUID = 0; - Tapped = false; - PoisonTimer = 0; - } - - void Aggro(Unit* who) { } - - void SpellHit(Unit* caster, const SpellEntry* spell) - { - if(!caster) - return; - - if(caster->GetTypeId() == TYPEID_PLAYER && spell->Id == 40468 && !Tapped) - { - PlayerGUID = caster->GetGUID(); - - Tapped = true; - float x, y, z; - caster->GetClosePoint(x, y, z, m_creature->GetObjectSize()); - - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - m_creature->GetMotionMaster()->MovePoint(1, x, y, z); - } - } - - void MovementInform(uint32 type, uint32 id) - { - if(type != POINT_MOTION_TYPE) - return; - - if(id) - { - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_EAT); - PoisonTimer = 15000; - } - } - - void UpdateAI(const uint32 diff) - { - if(PoisonTimer) - if(PoisonTimer <= diff) - { - if(PlayerGUID) - { - Player* plr = ((Player*)Unit::GetUnit((*m_creature), PlayerGUID)); - if(plr && plr->GetQuestStatus(11020) == QUEST_STATUS_INCOMPLETE) - plr->KilledMonster(23209, m_creature->GetGUID()); - } - PoisonTimer = 0; - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - }else PoisonTimer -= diff; - } -}; - -/*###### -## npc_drake_dealer_hurlunk -######*/ - -bool GossipHello_npc_drake_dealer_hurlunk(Player *player, Creature *_Creature) -{ - if (_Creature->isVendor() && player->GetReputationRank(1015) == REP_EXALTED) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_drake_dealer_hurlunk(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_TRADE) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - - return true; -} - -/*###### -## npc_invis_legion_teleporter -######*/ - -#define SPELL_TELE_A_TO 37387 -#define SPELL_TELE_H_TO 37389 - -struct MANGOS_DLL_DECL npc_invis_legion_teleporterAI : public ScriptedAI -{ - npc_invis_legion_teleporterAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 PlayerGuid; - uint32 TeleTimer; - - void Reset() - { - PlayerGuid=0; - TeleTimer = 5000; - } - - void Aggro(Unit* who) - { - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || who->GetTypeId() != TYPEID_PLAYER) - return; - - if(who->GetTypeId() == TYPEID_PLAYER && m_creature->GetDistance(who)<4) - { - if (who->isAlive() || !who->isInCombat()) - PlayerGuid = who->GetGUID(); - } - } - - void UpdateAI(const uint32 diff) - { - if(TeleTimer < diff) - { - if(PlayerGuid) - { - Player* player = ((Player*)Unit::GetUnit((*m_creature), PlayerGuid)); - - if(m_creature->GetDistance(player)<3) - { - if(player->GetTeam()== ALLIANCE && player->GetQuestRewardStatus(10589)) - player->CastSpell(player,SPELL_TELE_A_TO,false); - if(player->GetTeam()== HORDE && player->GetQuestRewardStatus(10604)) - player->CastSpell(player,SPELL_TELE_H_TO,false); - } - PlayerGuid=0; - } - TeleTimer = 5000; - }else TeleTimer -= diff; - } -}; -CreatureAI* GetAI_npc_invis_legion_teleporter(Creature *_Creature) -{ - return new npc_invis_legion_teleporterAI (_Creature); -} - -/*###### -## npc_flanis_swiftwing_and_kagrosh -######*/ - -bool GossipHello_npcs_flanis_swiftwing_and_kagrosh(Player *player, Creature *_Creature) -{ - if (player->GetQuestStatus(10583) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(30658,1,true)) - player->ADD_GOSSIP_ITEM( 0, "Take Flanis's Pack", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - if (player->GetQuestStatus(10601) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(30659,1,true)) - player->ADD_GOSSIP_ITEM( 0, "Take Kagrosh's Pack", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npcs_flanis_swiftwing_and_kagrosh(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 30658, 1, false); - if( msg == EQUIP_ERR_OK ) - { - player->StoreNewItem( dest, 30658, 1, true); - player->PlayerTalkClass->ClearMenus(); - } - } - if (action == GOSSIP_ACTION_INFO_DEF+2) - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 30659, 1, false); - if( msg == EQUIP_ERR_OK ) - { - player->StoreNewItem( dest, 30659, 1, true); - player->PlayerTalkClass->ClearMenus(); - } - } - return true; -} - -/*###### -## npc_murkblood_overseer -######*/ - -#define QUEST_11082 11082 - -bool GossipHello_npc_murkblood_overseer(Player *player, Creature *_Creature) -{ - if (player->GetQuestStatus(QUEST_11082) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "I am here for you, overseer.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_murkblood_overseer(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, "How dare you question an overseer of the Dragonmaw!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - //correct id not known - player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(0, "Who speaks of me? What are you talking about, broken?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - //correct id not known - player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(0, "Continue please.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - //correct id not known - player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(0, "Who are these bidders?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - //correct id not known - player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM(0, "Well... yes.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - //correct id not known - player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - //correct id not known - player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); - _Creature->CastSpell(player,41121,false); - player->AreaExploredOrEventHappens(QUEST_11082); - break; - } - return true; -} - -/*###### -## npc_neltharaku -######*/ - -bool GossipHello_npc_neltharaku(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(10814) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "I am listening, dragon", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(10613, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_neltharaku(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "But you are dragons! How could orcs do this to you?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(10614, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "Your mate?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(10615, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "I have battled many beasts, dragon. I will help you.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(10616, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(10814); - break; - } - return true; -} - -/*###### -## 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 *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - if (_Creature->isVendor()) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - if (player->GetQuestStatus(10519) == QUEST_STATUS_INCOMPLETE) - { - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(10312, _Creature->GetGUID()); - }else - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_oronok_tornheart(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_TRADE: - player->SEND_VENDORLIST( _Creature->GetGUID() ); - break; - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(10313, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(10314, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(10315, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(10316, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(10317, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - player->SEND_GOSSIP_MENU(10318, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(10519); - break; - } - return true; -} - -/*#### -# npc_karynaku -####*/ - -bool QuestAccept_npc_karynaku(Player* player, Creature* creature, Quest const* quest) -{ - if(quest->GetQuestId() == 10870) // Ally of the Netherwing - { - std::vector nodes; - - nodes.resize(2); - nodes[0] = 161; // From Karynaku - nodes[1] = 162; // To Mordenai - error_log("SD2: Player %s started quest 10870 which has disabled taxi node, need to be fixed in core", player->GetName()); - //player->ActivateTaxiPathTo(nodes, 20811); - } - - return true; -} - -void AddSC_shadowmoon_valley() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "mob_mature_netherwing_drake"; - newscript->GetAI = GetAI_mob_mature_netherwing_drake; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "mob_enslaved_netherwing_drake"; - newscript->GetAI = GetAI_mob_enslaved_netherwing_drake; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_drake_dealer_hurlunk"; - newscript->pGossipHello = &GossipHello_npc_drake_dealer_hurlunk; - newscript->pGossipSelect = &GossipSelect_npc_drake_dealer_hurlunk; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_invis_legion_teleporter"; - newscript->GetAI = GetAI_npc_invis_legion_teleporter; - m_scripts[nrscripts++] = newscript; - - 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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_murkblood_overseer"; - newscript->pGossipHello = &GossipHello_npc_murkblood_overseer; - newscript->pGossipSelect = &GossipSelect_npc_murkblood_overseer; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_neltharaku"; - newscript->pGossipHello = &GossipHello_npc_neltharaku; - newscript->pGossipSelect = &GossipSelect_npc_neltharaku; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "npc_karynaku"; - newscript->pQuestAccept = &QuestAccept_npc_karynaku; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_oronok_tornheart"; - newscript->pGossipHello = &GossipHello_npc_oronok_tornheart; - newscript->pGossipSelect = &GossipSelect_npc_oronok_tornheart; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Shadowmoon_Valley +SD%Complete: 100 +SDComment: Quest support: 10519, 10583, 10601, 10814, 10804, 10854, 11082. Vendor Drake Dealer Hurlunk. Teleporter TO Invasion Point: Cataclysm +SDCategory: Shadowmoon Valley +EndScriptData */ + +/* ContentData +mob_mature_netherwing_drake +mob_enslaved_netherwing_drake +npc_drake_dealer_hurlunk +npc_invis_legion_teleporter +npcs_flanis_swiftwing_and_kagrosh +npc_murkblood_overseer +npc_neltharaku +npc_karynaku +npc_oronok_tornheart +EndContentData */ + +#include "precompiled.h" + +/*##### +# mob_mature_netherwing_drake +#####*/ + +#define SPELL_PLACE_CARCASS 38439 +#define SPELL_JUST_EATEN 38502 +#define SPELL_NETHER_BREATH 38467 + +#define SAY_JUST_EATEN "Thank you, mortal." + +struct MANGOS_DLL_DECL mob_mature_netherwing_drakeAI : public ScriptedAI +{ + mob_mature_netherwing_drakeAI(Creature* c) : ScriptedAI(c) + { + Reset(); + PlayerGUID = 0; + } + + uint64 PlayerGUID; + + bool IsEating; + bool Evade; + + uint32 ResetTimer; + uint32 CastTimer; + uint32 EatTimer; + + void Reset() + { + IsEating = false; + Evade = false; + + ResetTimer = 120000; + EatTimer = 5000; + CastTimer = 5000; + } + + void Aggro(Unit* who) { } + + void MoveInLineOfSight(Unit* who) + { + if(m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void SpellHit(Unit* caster, const SpellEntry* spell) + { + if(!caster) + return; + + if(caster->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_PLACE_CARCASS && !m_creature->HasAura(SPELL_JUST_EATEN, 0) && !PlayerGUID) + { + float PlayerX, PlayerY, PlayerZ; + caster->GetClosePoint(PlayerX, PlayerY, PlayerZ, m_creature->GetObjectSize()); + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + m_creature->GetMotionMaster()->MovePoint(1, PlayerX, PlayerY, PlayerZ); + PlayerGUID = caster->GetGUID(); + } + } + + void MovementInform(uint32 type, uint32 id) + { + if(type != POINT_MOTION_TYPE) + return; + + if(id == 1) + { + IsEating = true; + EatTimer = 5000; + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACKUNARMED); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + } + } + + void UpdateAI(const uint32 diff) + { + if(IsEating) + if(EatTimer < diff) + { + IsEating = false; + DoCast(m_creature, SPELL_JUST_EATEN); + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + DoSay(SAY_JUST_EATEN, LANG_DRACONIC, NULL); + if(PlayerGUID) + { + Player* plr = ((Player*)Unit::GetUnit((*m_creature), PlayerGUID)); + if(plr && plr->GetQuestStatus(10804) == QUEST_STATUS_INCOMPLETE) + { + plr->KilledMonster(22131, m_creature->GetGUID()); + Evade = true; + PlayerGUID = 0; + } + } + }else EatTimer -= diff; + + if(Evade) + if(ResetTimer < diff) + EnterEvadeMode(); + else ResetTimer -= diff; + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(CastTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_NETHER_BREATH); + CastTimer = 5000; + }else CastTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_mature_netherwing_drake(Creature *_creature) +{ + return new mob_mature_netherwing_drakeAI(_creature); +} + +/*### +# mob_enslaved_netherwing_drake +####*/ + +#define FACTION_DEFAULT 62 +#define FACTION_FRIENDLY 1840 // Not sure if this is correct, it was taken off of Mordenai. + +#define SPELL_HIT_FORCE_OF_NELTHARAKU 38762 +#define SPELL_FORCE_OF_NELTHARAKU 38775 + +#define CREATURE_DRAGONMAW_SUBJUGATOR 21718 +#define CREATURE_ESCAPE_DUMMY 22317 + +struct MANGOS_DLL_DECL mob_enslaved_netherwing_drakeAI : public ScriptedAI +{ + mob_enslaved_netherwing_drakeAI(Creature* c) : ScriptedAI(c) + { + Reset(); + PlayerGUID = 0; + Tapped = false; + } + + uint64 PlayerGUID; + uint32 FlyTimer; + bool Tapped; + + void Reset() + { + if(!Tapped) + m_creature->setFaction(FACTION_DEFAULT); + + FlyTimer = 10000; + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + m_creature->SetVisibility(VISIBILITY_ON); + } + + void Aggro(Unit* who) { } + + Creature* SelectCreatureInGrid(uint32 entry, float range) + { + Creature* pCreature = NULL; + + // Time for some omg mind blowing code to search for creature + CellPair pair(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*m_creature, entry, true, range); + MaNGOS::CreatureLastSearcher searcher(pCreature, creature_check); + + TypeContainerVisitor, GridTypeMapContainer> creature_searcher(searcher); + + CellLock cell_lock(cell, pair); + cell_lock->Visit(cell_lock, creature_searcher,*(m_creature->GetMap())); + + return pCreature; + } + + void SpellHit(Unit* caster, const SpellEntry* spell) + { + if(!caster) + return; + + if(caster->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_HIT_FORCE_OF_NELTHARAKU && !Tapped) + { + Tapped = true; + PlayerGUID = caster->GetGUID(); + + m_creature->setFaction(FACTION_FRIENDLY); + DoCast(caster, SPELL_FORCE_OF_NELTHARAKU, true); + + Creature* Dragonmaw = SelectCreatureInGrid(CREATURE_DRAGONMAW_SUBJUGATOR, 50); + + if(Dragonmaw) + { + m_creature->AddThreat(Dragonmaw, 100000.0f); + AttackStart(Dragonmaw); + } + + HostilReference* ref = m_creature->getThreatManager().getOnlineContainer().getReferenceByTarget(caster); + if(ref) + ref->removeReference(); + } + } + + void MovementInform(uint32 type, uint32 id) + { + if(type != POINT_MOTION_TYPE) + return; + + if(id == 1) + { + if(PlayerGUID) + { + Unit* plr = Unit::GetUnit((*m_creature), PlayerGUID); + if(plr) + DoCast(plr, SPELL_FORCE_OF_NELTHARAKU, true); + + PlayerGUID = 0; + } + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_creature->RemoveCorpse(); + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + { + if(Tapped) + if(FlyTimer < diff) + { + Tapped = false; + if(PlayerGUID) + { + Player* plr = ((Player*)Unit::GetUnit((*m_creature), PlayerGUID)); + if(plr && plr->GetQuestStatus(10854) == QUEST_STATUS_INCOMPLETE) + { + plr->KilledMonster(22316, m_creature->GetGUID()); + /* + float x,y,z; + m_creature->GetPosition(x,y,z); + + float dx,dy,dz; + m_creature->GetRandomPoint(x, y, z, 20, dx, dy, dz); + dz += 20; // so it's in the air, not ground*/ + + float dx, dy, dz; + + Creature* EscapeDummy = SelectCreatureInGrid(CREATURE_ESCAPE_DUMMY, 30); + if(EscapeDummy) + EscapeDummy->GetPosition(dx, dy, dz); + else + { + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20, dx, dy, dz); + dz += 25; + } + + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + m_creature->GetMotionMaster()->MovePoint(1, dx, dy, dz); + } + } + }else FlyTimer -= diff; + return; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_enslaved_netherwing_drake(Creature* _Creature) +{ + return new mob_enslaved_netherwing_drakeAI(_Creature); +} + +/*##### +# mob_dragonmaw_peon +#####*/ + +struct MANGOS_DLL_DECL mob_dragonmaw_peonAI : public ScriptedAI +{ + mob_dragonmaw_peonAI(Creature* c) : ScriptedAI(c) + { + Reset(); + } + + uint64 PlayerGUID; + bool Tapped; + uint32 PoisonTimer; + + void Reset() + { + PlayerGUID = 0; + Tapped = false; + PoisonTimer = 0; + } + + void Aggro(Unit* who) { } + + void SpellHit(Unit* caster, const SpellEntry* spell) + { + if(!caster) + return; + + if(caster->GetTypeId() == TYPEID_PLAYER && spell->Id == 40468 && !Tapped) + { + PlayerGUID = caster->GetGUID(); + + Tapped = true; + float x, y, z; + caster->GetClosePoint(x, y, z, m_creature->GetObjectSize()); + + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + m_creature->GetMotionMaster()->MovePoint(1, x, y, z); + } + } + + void MovementInform(uint32 type, uint32 id) + { + if(type != POINT_MOTION_TYPE) + return; + + if(id) + { + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_EAT); + PoisonTimer = 15000; + } + } + + void UpdateAI(const uint32 diff) + { + if(PoisonTimer) + if(PoisonTimer <= diff) + { + if(PlayerGUID) + { + Player* plr = ((Player*)Unit::GetUnit((*m_creature), PlayerGUID)); + if(plr && plr->GetQuestStatus(11020) == QUEST_STATUS_INCOMPLETE) + plr->KilledMonster(23209, m_creature->GetGUID()); + } + PoisonTimer = 0; + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + }else PoisonTimer -= diff; + } +}; + +/*###### +## npc_drake_dealer_hurlunk +######*/ + +bool GossipHello_npc_drake_dealer_hurlunk(Player *player, Creature *_Creature) +{ + if (_Creature->isVendor() && player->GetReputationRank(1015) == REP_EXALTED) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_drake_dealer_hurlunk(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_TRADE) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + + return true; +} + +/*###### +## npc_invis_legion_teleporter +######*/ + +#define SPELL_TELE_A_TO 37387 +#define SPELL_TELE_H_TO 37389 + +struct MANGOS_DLL_DECL npc_invis_legion_teleporterAI : public ScriptedAI +{ + npc_invis_legion_teleporterAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 PlayerGuid; + uint32 TeleTimer; + + void Reset() + { + PlayerGuid=0; + TeleTimer = 5000; + } + + void Aggro(Unit* who) + { + } + + void MoveInLineOfSight(Unit *who) + { + if (!who || who->GetTypeId() != TYPEID_PLAYER) + return; + + if(who->GetTypeId() == TYPEID_PLAYER && m_creature->GetDistance(who)<4) + { + if (who->isAlive() || !who->isInCombat()) + PlayerGuid = who->GetGUID(); + } + } + + void UpdateAI(const uint32 diff) + { + if(TeleTimer < diff) + { + if(PlayerGuid) + { + Player* player = ((Player*)Unit::GetUnit((*m_creature), PlayerGuid)); + + if(m_creature->GetDistance(player)<3) + { + if(player->GetTeam()== ALLIANCE && player->GetQuestRewardStatus(10589)) + player->CastSpell(player,SPELL_TELE_A_TO,false); + if(player->GetTeam()== HORDE && player->GetQuestRewardStatus(10604)) + player->CastSpell(player,SPELL_TELE_H_TO,false); + } + PlayerGuid=0; + } + TeleTimer = 5000; + }else TeleTimer -= diff; + } +}; +CreatureAI* GetAI_npc_invis_legion_teleporter(Creature *_Creature) +{ + return new npc_invis_legion_teleporterAI (_Creature); +} + +/*###### +## npc_flanis_swiftwing_and_kagrosh +######*/ + +bool GossipHello_npcs_flanis_swiftwing_and_kagrosh(Player *player, Creature *_Creature) +{ + if (player->GetQuestStatus(10583) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(30658,1,true)) + player->ADD_GOSSIP_ITEM( 0, "Take Flanis's Pack", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + if (player->GetQuestStatus(10601) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(30659,1,true)) + player->ADD_GOSSIP_ITEM( 0, "Take Kagrosh's Pack", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npcs_flanis_swiftwing_and_kagrosh(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 30658, 1, false); + if( msg == EQUIP_ERR_OK ) + { + player->StoreNewItem( dest, 30658, 1, true); + player->PlayerTalkClass->ClearMenus(); + } + } + if (action == GOSSIP_ACTION_INFO_DEF+2) + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 30659, 1, false); + if( msg == EQUIP_ERR_OK ) + { + player->StoreNewItem( dest, 30659, 1, true); + player->PlayerTalkClass->ClearMenus(); + } + } + return true; +} + +/*###### +## npc_murkblood_overseer +######*/ + +#define QUEST_11082 11082 + +bool GossipHello_npc_murkblood_overseer(Player *player, Creature *_Creature) +{ + if (player->GetQuestStatus(QUEST_11082) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "I am here for you, overseer.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_murkblood_overseer(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, "How dare you question an overseer of the Dragonmaw!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + //correct id not known + player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM(0, "Who speaks of me? What are you talking about, broken?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + //correct id not known + player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM(0, "Continue please.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + //correct id not known + player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM(0, "Who are these bidders?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + //correct id not known + player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM(0, "Well... yes.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + //correct id not known + player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + //correct id not known + player->SEND_GOSSIP_MENU(10940, _Creature->GetGUID()); + _Creature->CastSpell(player,41121,false); + player->AreaExploredOrEventHappens(QUEST_11082); + break; + } + return true; +} + +/*###### +## npc_neltharaku +######*/ + +bool GossipHello_npc_neltharaku(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(10814) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "I am listening, dragon", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(10613, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_neltharaku(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "But you are dragons! How could orcs do this to you?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(10614, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "Your mate?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(10615, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "I have battled many beasts, dragon. I will help you.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(10616, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(10814); + break; + } + return true; +} + +/*###### +## 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 *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + if (_Creature->isVendor()) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + + if (player->GetQuestStatus(10519) == QUEST_STATUS_INCOMPLETE) + { + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + player->SEND_GOSSIP_MENU(10312, _Creature->GetGUID()); + }else + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_oronok_tornheart(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_TRADE: + player->SEND_VENDORLIST( _Creature->GetGUID() ); + break; + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(10313, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(10314, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(10315, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(10316, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(10317, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ORONOK7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + player->SEND_GOSSIP_MENU(10318, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(10519); + break; + } + return true; +} + +/*#### +# npc_karynaku +####*/ + +bool QuestAccept_npc_karynaku(Player* player, Creature* creature, Quest const* quest) +{ + if(quest->GetQuestId() == 10870) // Ally of the Netherwing + { + std::vector nodes; + + nodes.resize(2); + nodes[0] = 161; // From Karynaku + nodes[1] = 162; // To Mordenai + error_log("SD2: Player %s started quest 10870 which has disabled taxi node, need to be fixed in core", player->GetName()); + //player->ActivateTaxiPathTo(nodes, 20811); + } + + return true; +} + +void AddSC_shadowmoon_valley() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "mob_mature_netherwing_drake"; + newscript->GetAI = GetAI_mob_mature_netherwing_drake; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "mob_enslaved_netherwing_drake"; + newscript->GetAI = GetAI_mob_enslaved_netherwing_drake; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_drake_dealer_hurlunk"; + newscript->pGossipHello = &GossipHello_npc_drake_dealer_hurlunk; + newscript->pGossipSelect = &GossipSelect_npc_drake_dealer_hurlunk; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_invis_legion_teleporter"; + newscript->GetAI = GetAI_npc_invis_legion_teleporter; + m_scripts[nrscripts++] = newscript; + + 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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_murkblood_overseer"; + newscript->pGossipHello = &GossipHello_npc_murkblood_overseer; + newscript->pGossipSelect = &GossipSelect_npc_murkblood_overseer; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_neltharaku"; + newscript->pGossipHello = &GossipHello_npc_neltharaku; + newscript->pGossipSelect = &GossipSelect_npc_neltharaku; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "npc_karynaku"; + newscript->pQuestAccept = &QuestAccept_npc_karynaku; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_oronok_tornheart"; + newscript->pGossipHello = &GossipHello_npc_oronok_tornheart; + newscript->pGossipSelect = &GossipSelect_npc_oronok_tornheart; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/shattrath/shattrath_city.cpp b/src/bindings/scripts/scripts/zone/shattrath/shattrath_city.cpp index 8ad5a6e6321..c731edf08fe 100644 --- a/src/bindings/scripts/scripts/zone/shattrath/shattrath_city.cpp +++ b/src/bindings/scripts/scripts/zone/shattrath/shattrath_city.cpp @@ -1,268 +1,268 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Shattrath_City -SD%Complete: 100 -SDComment: Quest support: 10004, 10009. Flask vendors, Teleport to Caverns of Time -SDCategory: Shattrath City -EndScriptData */ - -/* ContentData -npc_raliq_the_drunk -npc_salsalabim -npc_shattrathflaskvendors -npc_zephyr -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_raliq_the_drunk -######*/ - -#define GOSSIP_RALIQ "You owe Sim'salabim money. Hand them over or die!" - -#define FACTION_HOSTILE_RD 45 -#define FACTION_FRIENDLY_RD 35 - -#define SPELL_UPPERCUT 10966 - -struct MANGOS_DLL_DECL npc_raliq_the_drunkAI : public ScriptedAI -{ - npc_raliq_the_drunkAI(Creature* c) : ScriptedAI(c) { Reset(); } - - uint32 Uppercut_Timer; - - void Reset() - { - Uppercut_Timer = 5000; - m_creature->setFaction(FACTION_FRIENDLY_RD); - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( Uppercut_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_UPPERCUT); - Uppercut_Timer = 15000; - }else Uppercut_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_raliq_the_drunk(Creature *_Creature) -{ - return new npc_raliq_the_drunkAI (_Creature); -} - -bool GossipHello_npc_raliq_the_drunk(Player *player, Creature *_Creature ) -{ - if( player->GetQuestStatus(10009) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM(1, GOSSIP_RALIQ, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(9440, _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_raliq_the_drunk(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_INFO_DEF+1 ) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->setFaction(FACTION_HOSTILE_RD); - ((npc_raliq_the_drunkAI*)_Creature->AI())->AttackStart(player); - } - 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* c) : ScriptedAI(c) { Reset(); } - - uint32 MagneticPull_Timer; - - void Reset() - { - MagneticPull_Timer = 15000; - m_creature->setFaction(FACTION_FRIENDLY_SA); - } - - void Aggro(Unit *who) {} - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if( done_by->GetTypeId() == TYPEID_PLAYER ) - if( (m_creature->GetHealth()-damage)*100 / m_creature->GetMaxHealth() < 20 ) - { - ((Player*)done_by)->GroupEventHappens(QUEST_10004,m_creature); - damage = 0; - EnterEvadeMode(); - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( MagneticPull_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_MAGNETIC_PULL); - MagneticPull_Timer = 15000; - }else MagneticPull_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_salsalabim(Creature *_Creature) -{ - return new npc_salsalabimAI (_Creature); -} - -bool GossipHello_npc_salsalabim(Player *player, Creature *_Creature) -{ - if( player->GetQuestStatus(QUEST_10004) == QUEST_STATUS_INCOMPLETE ) - { - _Creature->setFaction(FACTION_HOSTILE_SA); - ((npc_salsalabimAI*)_Creature->AI())->AttackStart(player); - } - else - { - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - } - return true; -} - -/* -################################################## -Shattrath City Flask Vendors provides flasks to people exalted with 3 factions: -Haldor the Compulsive -Arcanist Xorith -Both sell special flasks for use in Outlands 25man raids only, -purchasable for one Mark of Illidari each -Purchase requires exalted reputation with Scryers/Aldor, Cenarion Expedition and The Sha'tar -################################################## -*/ - -bool GossipHello_npc_shattrathflaskvendors(Player *player, Creature *_Creature) -{ - if(_Creature->GetEntry() == 23484) - { - // Aldor vendor - if( _Creature->isVendor() && (player->GetReputationRank(932) == REP_EXALTED) && (player->GetReputationRank(935) == REP_EXALTED) && (player->GetReputationRank(942) == REP_EXALTED) ) - { - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU(11085, _Creature->GetGUID()); - } - else - { - player->SEND_GOSSIP_MENU(11083, _Creature->GetGUID()); - } - } - - if(_Creature->GetEntry() == 23483) - { - // Scryers vendor - if( _Creature->isVendor() && (player->GetReputationRank(934) == REP_EXALTED) && (player->GetReputationRank(935) == REP_EXALTED) && (player->GetReputationRank(942) == REP_EXALTED) ) - { - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU(11085, _Creature->GetGUID()); - } - else - { - player->SEND_GOSSIP_MENU(11084, _Creature->GetGUID()); - } - } - - return true; -} - -bool GossipSelect_npc_shattrathflaskvendors(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if( action == GOSSIP_ACTION_TRADE ) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - - return true; -} - -/*###### -# npc_zephyr -######*/ - -bool GossipHello_npc_zephyr(Player *player, Creature *_Creature) -{ - if( player->GetReputationRank(989) >= REP_REVERED ) - player->ADD_GOSSIP_ITEM(0, "Take me to the Caverns of Time.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_zephyr(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if( action == GOSSIP_ACTION_INFO_DEF+1 ) - player->CastSpell(player,37778,false); - - return true; -} - -void AddSC_shattrath_city() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_raliq_the_drunk"; - newscript->pGossipHello = &GossipHello_npc_raliq_the_drunk; - newscript->pGossipSelect = &GossipSelect_npc_raliq_the_drunk; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_salsalabim"; - newscript->GetAI = GetAI_npc_salsalabim; - newscript->pGossipHello = &GossipHello_npc_salsalabim; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_shattrathflaskvendors"; - newscript->pGossipHello = &GossipHello_npc_shattrathflaskvendors; - newscript->pGossipSelect = &GossipSelect_npc_shattrathflaskvendors; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_zephyr"; - newscript->pGossipHello = &GossipHello_npc_zephyr; - newscript->pGossipSelect = &GossipSelect_npc_zephyr; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Shattrath_City +SD%Complete: 100 +SDComment: Quest support: 10004, 10009. Flask vendors, Teleport to Caverns of Time +SDCategory: Shattrath City +EndScriptData */ + +/* ContentData +npc_raliq_the_drunk +npc_salsalabim +npc_shattrathflaskvendors +npc_zephyr +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_raliq_the_drunk +######*/ + +#define GOSSIP_RALIQ "You owe Sim'salabim money. Hand them over or die!" + +#define FACTION_HOSTILE_RD 45 +#define FACTION_FRIENDLY_RD 35 + +#define SPELL_UPPERCUT 10966 + +struct MANGOS_DLL_DECL npc_raliq_the_drunkAI : public ScriptedAI +{ + npc_raliq_the_drunkAI(Creature* c) : ScriptedAI(c) { Reset(); } + + uint32 Uppercut_Timer; + + void Reset() + { + Uppercut_Timer = 5000; + m_creature->setFaction(FACTION_FRIENDLY_RD); + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( Uppercut_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_UPPERCUT); + Uppercut_Timer = 15000; + }else Uppercut_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_raliq_the_drunk(Creature *_Creature) +{ + return new npc_raliq_the_drunkAI (_Creature); +} + +bool GossipHello_npc_raliq_the_drunk(Player *player, Creature *_Creature ) +{ + if( player->GetQuestStatus(10009) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM(1, GOSSIP_RALIQ, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(9440, _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_raliq_the_drunk(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->setFaction(FACTION_HOSTILE_RD); + ((npc_raliq_the_drunkAI*)_Creature->AI())->AttackStart(player); + } + 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* c) : ScriptedAI(c) { Reset(); } + + uint32 MagneticPull_Timer; + + void Reset() + { + MagneticPull_Timer = 15000; + m_creature->setFaction(FACTION_FRIENDLY_SA); + } + + void Aggro(Unit *who) {} + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if( done_by->GetTypeId() == TYPEID_PLAYER ) + if( (m_creature->GetHealth()-damage)*100 / m_creature->GetMaxHealth() < 20 ) + { + ((Player*)done_by)->GroupEventHappens(QUEST_10004,m_creature); + damage = 0; + EnterEvadeMode(); + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( MagneticPull_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_MAGNETIC_PULL); + MagneticPull_Timer = 15000; + }else MagneticPull_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_salsalabim(Creature *_Creature) +{ + return new npc_salsalabimAI (_Creature); +} + +bool GossipHello_npc_salsalabim(Player *player, Creature *_Creature) +{ + if( player->GetQuestStatus(QUEST_10004) == QUEST_STATUS_INCOMPLETE ) + { + _Creature->setFaction(FACTION_HOSTILE_SA); + ((npc_salsalabimAI*)_Creature->AI())->AttackStart(player); + } + else + { + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + } + return true; +} + +/* +################################################## +Shattrath City Flask Vendors provides flasks to people exalted with 3 factions: +Haldor the Compulsive +Arcanist Xorith +Both sell special flasks for use in Outlands 25man raids only, +purchasable for one Mark of Illidari each +Purchase requires exalted reputation with Scryers/Aldor, Cenarion Expedition and The Sha'tar +################################################## +*/ + +bool GossipHello_npc_shattrathflaskvendors(Player *player, Creature *_Creature) +{ + if(_Creature->GetEntry() == 23484) + { + // Aldor vendor + if( _Creature->isVendor() && (player->GetReputationRank(932) == REP_EXALTED) && (player->GetReputationRank(935) == REP_EXALTED) && (player->GetReputationRank(942) == REP_EXALTED) ) + { + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + player->SEND_GOSSIP_MENU(11085, _Creature->GetGUID()); + } + else + { + player->SEND_GOSSIP_MENU(11083, _Creature->GetGUID()); + } + } + + if(_Creature->GetEntry() == 23483) + { + // Scryers vendor + if( _Creature->isVendor() && (player->GetReputationRank(934) == REP_EXALTED) && (player->GetReputationRank(935) == REP_EXALTED) && (player->GetReputationRank(942) == REP_EXALTED) ) + { + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + player->SEND_GOSSIP_MENU(11085, _Creature->GetGUID()); + } + else + { + player->SEND_GOSSIP_MENU(11084, _Creature->GetGUID()); + } + } + + return true; +} + +bool GossipSelect_npc_shattrathflaskvendors(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if( action == GOSSIP_ACTION_TRADE ) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + + return true; +} + +/*###### +# npc_zephyr +######*/ + +bool GossipHello_npc_zephyr(Player *player, Creature *_Creature) +{ + if( player->GetReputationRank(989) >= REP_REVERED ) + player->ADD_GOSSIP_ITEM(0, "Take me to the Caverns of Time.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_zephyr(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + player->CastSpell(player,37778,false); + + return true; +} + +void AddSC_shattrath_city() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_raliq_the_drunk"; + newscript->pGossipHello = &GossipHello_npc_raliq_the_drunk; + newscript->pGossipSelect = &GossipSelect_npc_raliq_the_drunk; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_salsalabim"; + newscript->GetAI = GetAI_npc_salsalabim; + newscript->pGossipHello = &GossipHello_npc_salsalabim; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_shattrathflaskvendors"; + newscript->pGossipHello = &GossipHello_npc_shattrathflaskvendors; + newscript->pGossipSelect = &GossipSelect_npc_shattrathflaskvendors; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_zephyr"; + newscript->pGossipHello = &GossipHello_npc_zephyr; + newscript->pGossipSelect = &GossipSelect_npc_zephyr; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/silithus/silithus.cpp b/src/bindings/scripts/scripts/zone/silithus/silithus.cpp index 8b7681d0557..fec0619509d 100644 --- a/src/bindings/scripts/scripts/zone/silithus/silithus.cpp +++ b/src/bindings/scripts/scripts/zone/silithus/silithus.cpp @@ -1,149 +1,149 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Silithus -SD%Complete: 100 -SDComment: Quest support: 8304. -SDCategory: Silithus -EndScriptData */ - -/* ContentData -npcs_rutgar_and_frankal -EndContentData */ - -#include "precompiled.h" - -/*### -## npcs_rutgar_and_frankal -###*/ - -//gossip item text best guess -#define GOSSIP_ITEM1 "I seek information about Natalia" - -#define GOSSIP_ITEM2 "That sounds dangerous!" -#define GOSSIP_ITEM3 "What did you do?" -#define GOSSIP_ITEM4 "Who?" -#define GOSSIP_ITEM5 "Women do that. What did she demand?" -#define GOSSIP_ITEM6 "What do you mean?" -#define GOSSIP_ITEM7 "What happened next?" - -#define GOSSIP_ITEM11 "Yes, please continue" -#define GOSSIP_ITEM12 "What language?" -#define GOSSIP_ITEM13 "The Priestess attacked you?!" -#define GOSSIP_ITEM14 "I should ask the monkey about this" -#define GOSSIP_ITEM15 "Then what..." - -//trigger creatures to kill -#define TRIGGER_RUTGAR 15222 -#define TRIGGER_FRANKAL 15221 - -bool GossipHello_npcs_rutgar_and_frankal(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(8304) == QUEST_STATUS_INCOMPLETE && - _Creature->GetEntry() == 15170 && - !player->GetReqKillOrCastCurrentCount(8304, TRIGGER_RUTGAR )) - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - if (player->GetQuestStatus(8304) == QUEST_STATUS_INCOMPLETE && - _Creature->GetEntry() == 15171 && - player->GetReqKillOrCastCurrentCount(8304, TRIGGER_RUTGAR )) - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); - - player->SEND_GOSSIP_MENU(7754, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npcs_rutgar_and_frankal(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(7755, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 1: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(7756, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(7757, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(7758, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(7759, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(7760, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - player->SEND_GOSSIP_MENU(7761, _Creature->GetGUID()); - //'kill' our trigger to update quest status - player->KilledMonster( TRIGGER_RUTGAR, _Creature->GetGUID() ); - break; - - case GOSSIP_ACTION_INFO_DEF + 9: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM11, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(7762, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM12, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(7763, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM13, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - player->SEND_GOSSIP_MENU(7764, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM14, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); - player->SEND_GOSSIP_MENU(7765, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM15, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); - player->SEND_GOSSIP_MENU(7766, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 14: - player->SEND_GOSSIP_MENU(7767, _Creature->GetGUID()); - //'kill' our trigger to update quest status - player->KilledMonster( TRIGGER_FRANKAL, _Creature->GetGUID() ); - break; - } - return true; -} - -/*### -## -####*/ - -void AddSC_silithus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="npcs_rutgar_and_frankal"; - newscript->pGossipHello = &GossipHello_npcs_rutgar_and_frankal; - newscript->pGossipSelect = &GossipSelect_npcs_rutgar_and_frankal; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Silithus +SD%Complete: 100 +SDComment: Quest support: 8304. +SDCategory: Silithus +EndScriptData */ + +/* ContentData +npcs_rutgar_and_frankal +EndContentData */ + +#include "precompiled.h" + +/*### +## npcs_rutgar_and_frankal +###*/ + +//gossip item text best guess +#define GOSSIP_ITEM1 "I seek information about Natalia" + +#define GOSSIP_ITEM2 "That sounds dangerous!" +#define GOSSIP_ITEM3 "What did you do?" +#define GOSSIP_ITEM4 "Who?" +#define GOSSIP_ITEM5 "Women do that. What did she demand?" +#define GOSSIP_ITEM6 "What do you mean?" +#define GOSSIP_ITEM7 "What happened next?" + +#define GOSSIP_ITEM11 "Yes, please continue" +#define GOSSIP_ITEM12 "What language?" +#define GOSSIP_ITEM13 "The Priestess attacked you?!" +#define GOSSIP_ITEM14 "I should ask the monkey about this" +#define GOSSIP_ITEM15 "Then what..." + +//trigger creatures to kill +#define TRIGGER_RUTGAR 15222 +#define TRIGGER_FRANKAL 15221 + +bool GossipHello_npcs_rutgar_and_frankal(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(8304) == QUEST_STATUS_INCOMPLETE && + _Creature->GetEntry() == 15170 && + !player->GetReqKillOrCastCurrentCount(8304, TRIGGER_RUTGAR )) + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + if (player->GetQuestStatus(8304) == QUEST_STATUS_INCOMPLETE && + _Creature->GetEntry() == 15171 && + player->GetReqKillOrCastCurrentCount(8304, TRIGGER_RUTGAR )) + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); + + player->SEND_GOSSIP_MENU(7754, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npcs_rutgar_and_frankal(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(7755, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 1: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(7756, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(7757, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(7758, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 4: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(7759, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 5: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->SEND_GOSSIP_MENU(7760, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 6: + player->SEND_GOSSIP_MENU(7761, _Creature->GetGUID()); + //'kill' our trigger to update quest status + player->KilledMonster( TRIGGER_RUTGAR, _Creature->GetGUID() ); + break; + + case GOSSIP_ACTION_INFO_DEF + 9: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM11, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(7762, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 10: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM12, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + player->SEND_GOSSIP_MENU(7763, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 11: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM13, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); + player->SEND_GOSSIP_MENU(7764, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 12: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM14, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); + player->SEND_GOSSIP_MENU(7765, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 13: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM15, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); + player->SEND_GOSSIP_MENU(7766, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 14: + player->SEND_GOSSIP_MENU(7767, _Creature->GetGUID()); + //'kill' our trigger to update quest status + player->KilledMonster( TRIGGER_FRANKAL, _Creature->GetGUID() ); + break; + } + return true; +} + +/*### +## +####*/ + +void AddSC_silithus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="npcs_rutgar_and_frankal"; + newscript->pGossipHello = &GossipHello_npcs_rutgar_and_frankal; + newscript->pGossipSelect = &GossipSelect_npcs_rutgar_and_frankal; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/silvermoon/silvermoon_city.cpp b/src/bindings/scripts/scripts/zone/silvermoon/silvermoon_city.cpp index 1a237eefde0..11fcbbcfc5d 100644 --- a/src/bindings/scripts/scripts/zone/silvermoon/silvermoon_city.cpp +++ b/src/bindings/scripts/scripts/zone/silvermoon/silvermoon_city.cpp @@ -1,103 +1,103 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Silvermoon_City -SD%Complete: 100 -SDComment: Quest support: 9685 -SDCategory: Silvermoon City -EndScriptData */ - -/* ContentData -npc_blood_knight_stillblade -EndContentData */ - -#include "precompiled.h" - -/*####### -# npc_blood_knight_stillblade -#######*/ - -#define SAY_HEAL "Thank you, dear Paladin, you just saved my life." - -#define QUEST_REDEEMING_THE_DEAD 9685 -#define SPELL_SHIMMERING_VESSEL 31225 -#define SPELL_REVIVE_SELF 32343 - -struct MANGOS_DLL_DECL npc_blood_knight_stillbladeAI : public ScriptedAI -{ - npc_blood_knight_stillbladeAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 lifeTimer; - bool spellHit; - - void Reset() - { - lifeTimer = 120000; - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 32); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,7); // lay down - spellHit = false; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - return; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->GetUInt32Value(UNIT_FIELD_BYTES_1)) - { - if(lifeTimer < diff) - m_creature->AI()->EnterEvadeMode(); - else - lifeTimer -= diff; - } - } - - 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))) - { - ((Player*)Hitter)->AreaExploredOrEventHappens(QUEST_REDEEMING_THE_DEAD); - DoCast(m_creature,SPELL_REVIVE_SELF); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - //m_creature->RemoveAllAuras(); - DoSay(SAY_HEAL,LANG_COMMON,NULL); - spellHit = true; - } - } -}; - -CreatureAI* GetAI_npc_blood_knight_stillblade(Creature *_Creature) -{ - return new npc_blood_knight_stillbladeAI (_Creature); -} - -void AddSC_silvermoon_city() -{ - Script *newscript; - newscript = new Script; - newscript->Name="npc_blood_knight_stillblade"; - newscript->GetAI = GetAI_npc_blood_knight_stillblade; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Silvermoon_City +SD%Complete: 100 +SDComment: Quest support: 9685 +SDCategory: Silvermoon City +EndScriptData */ + +/* ContentData +npc_blood_knight_stillblade +EndContentData */ + +#include "precompiled.h" + +/*####### +# npc_blood_knight_stillblade +#######*/ + +#define SAY_HEAL "Thank you, dear Paladin, you just saved my life." + +#define QUEST_REDEEMING_THE_DEAD 9685 +#define SPELL_SHIMMERING_VESSEL 31225 +#define SPELL_REVIVE_SELF 32343 + +struct MANGOS_DLL_DECL npc_blood_knight_stillbladeAI : public ScriptedAI +{ + npc_blood_knight_stillbladeAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 lifeTimer; + bool spellHit; + + void Reset() + { + lifeTimer = 120000; + m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 32); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,7); // lay down + spellHit = false; + } + + void Aggro(Unit *who) + { + } + + void MoveInLineOfSight(Unit *who) + { + return; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->GetUInt32Value(UNIT_FIELD_BYTES_1)) + { + if(lifeTimer < diff) + m_creature->AI()->EnterEvadeMode(); + else + lifeTimer -= diff; + } + } + + 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))) + { + ((Player*)Hitter)->AreaExploredOrEventHappens(QUEST_REDEEMING_THE_DEAD); + DoCast(m_creature,SPELL_REVIVE_SELF); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); + m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); + //m_creature->RemoveAllAuras(); + DoSay(SAY_HEAL,LANG_COMMON,NULL); + spellHit = true; + } + } +}; + +CreatureAI* GetAI_npc_blood_knight_stillblade(Creature *_Creature) +{ + return new npc_blood_knight_stillbladeAI (_Creature); +} + +void AddSC_silvermoon_city() +{ + Script *newscript; + newscript = new Script; + newscript->Name="npc_blood_knight_stillblade"; + newscript->GetAI = GetAI_npc_blood_knight_stillblade; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/silverpine_forest/silverpine_forest.cpp b/src/bindings/scripts/scripts/zone/silverpine_forest/silverpine_forest.cpp index 87c346d58b4..9652afcdcee 100644 --- a/src/bindings/scripts/scripts/zone/silverpine_forest/silverpine_forest.cpp +++ b/src/bindings/scripts/scripts/zone/silverpine_forest/silverpine_forest.cpp @@ -1,100 +1,100 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Silverpine_Forest -SD%Complete: 100 -SDComment: Quest support: 1886 -SDCategory: Silverpine Forest -EndScriptData */ - -/* ContentData -npc_astor_hadren -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_astor_hadren -######*/ - -struct MANGOS_DLL_DECL npc_astor_hadrenAI : public ScriptedAI -{ - npc_astor_hadrenAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - m_creature->setFaction(68); - } - - void Aggro(Unit* who) - { - } - - 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 *player, Creature *_Creature) -{ - if (player->GetQuestStatus(1886) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "You're Astor Hadren, right?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - player->SEND_GOSSIP_MENU(623, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_astor_hadren(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF + 1: - player->ADD_GOSSIP_ITEM( 0, "You've got something I need, Astor. And I'll be taking it now.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(624, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - player->CLOSE_GOSSIP_MENU(); - _Creature->setFaction(21); - if(player) - ((npc_astor_hadrenAI*)_Creature->AI())->AttackStart(player); - break; - } - return true; -} - -/*###### -## AddSC -######*/ - -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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Silverpine_Forest +SD%Complete: 100 +SDComment: Quest support: 1886 +SDCategory: Silverpine Forest +EndScriptData */ + +/* ContentData +npc_astor_hadren +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_astor_hadren +######*/ + +struct MANGOS_DLL_DECL npc_astor_hadrenAI : public ScriptedAI +{ + npc_astor_hadrenAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + m_creature->setFaction(68); + } + + void Aggro(Unit* who) + { + } + + 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 *player, Creature *_Creature) +{ + if (player->GetQuestStatus(1886) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "You're Astor Hadren, right?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + player->SEND_GOSSIP_MENU(623, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_astor_hadren(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF + 1: + player->ADD_GOSSIP_ITEM( 0, "You've got something I need, Astor. And I'll be taking it now.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(624, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + player->CLOSE_GOSSIP_MENU(); + _Creature->setFaction(21); + if(player) + ((npc_astor_hadrenAI*)_Creature->AI())->AttackStart(player); + break; + } + return true; +} + +/*###### +## AddSC +######*/ + +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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stonetalon_mountains/stonetalon_mountains.cpp b/src/bindings/scripts/scripts/zone/stonetalon_mountains/stonetalon_mountains.cpp index 652af2fe802..8ec72e61a92 100644 --- a/src/bindings/scripts/scripts/zone/stonetalon_mountains/stonetalon_mountains.cpp +++ b/src/bindings/scripts/scripts/zone/stonetalon_mountains/stonetalon_mountains.cpp @@ -1,80 +1,80 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Stonetalon_Mountains -SD%Complete: 95 -SDComment: Quest support: 6627 (Braug Dimspirits questions/'answers' might have more to it, need more info) -SDCategory: Stonetalon Mountains -EndScriptData */ - -#include "precompiled.h" - -/*###### -## npc_braug_dimspirit -######*/ - -bool GossipHello_npc_braug_dimspirit(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(6627) == QUEST_STATUS_INCOMPLETE) - { - player->ADD_GOSSIP_ITEM( 0, "Ysera", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM( 0, "Neltharion", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->ADD_GOSSIP_ITEM( 0, "Nozdormu", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM( 0, "Alexstrasza", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM( 0, "Malygos", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(5820, _Creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(5819, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_braug_dimspirit(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player,6766,false); - - } - if (action == GOSSIP_ACTION_INFO_DEF+2) - { - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(6627); - } - return true; -} - -/*###### -## AddSC -######*/ - -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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Stonetalon_Mountains +SD%Complete: 95 +SDComment: Quest support: 6627 (Braug Dimspirits questions/'answers' might have more to it, need more info) +SDCategory: Stonetalon Mountains +EndScriptData */ + +#include "precompiled.h" + +/*###### +## npc_braug_dimspirit +######*/ + +bool GossipHello_npc_braug_dimspirit(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(6627) == QUEST_STATUS_INCOMPLETE) + { + player->ADD_GOSSIP_ITEM( 0, "Ysera", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM( 0, "Neltharion", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->ADD_GOSSIP_ITEM( 0, "Nozdormu", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM( 0, "Alexstrasza", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM( 0, "Malygos", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(5820, _Creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(5819, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_braug_dimspirit(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player,6766,false); + + } + if (action == GOSSIP_ACTION_INFO_DEF+2) + { + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(6627); + } + return true; +} + +/*###### +## AddSC +######*/ + +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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stormwind/stormwind_city.cpp b/src/bindings/scripts/scripts/zone/stormwind/stormwind_city.cpp index 0821a424cc4..a0546651de9 100644 --- a/src/bindings/scripts/scripts/zone/stormwind/stormwind_city.cpp +++ b/src/bindings/scripts/scripts/zone/stormwind/stormwind_city.cpp @@ -1,272 +1,272 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Stormwind_City -SD%Complete: 100 -SDComment: Quest support: 1640, 1447, 4185, 11223 (DB support required for spell 42711). Receive emote General Marcus -SDCategory: Stormwind City -EndScriptData */ - -/* ContentData -npc_archmage_malin -npc_bartleby -npc_dashel_stonefist -npc_general_marcus_jonathan -npc_lady_katrana_prestor -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 *player, Creature *_Creature) -{ - if(_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if(player->GetQuestStatus(11223) == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(11223)) - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_MALIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_archmage_malin(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if(action = GOSSIP_ACTION_INFO_DEF) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player, 42711, true); - } - - return true; -} - -/*###### -## npc_bartleby -######*/ - -struct MANGOS_DLL_DECL npc_bartlebyAI : public ScriptedAI -{ - npc_bartlebyAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint64 PlayerGUID; - - void Reset() - { - m_creature->setFaction(11); - m_creature->setEmoteState(7); - - PlayerGUID = 0; - } - - void JustDied(Unit *who) - { - m_creature->setFaction(11); - } - - void DamageTaken(Unit *done_by, uint32 & damage) - { - if(damage > m_creature->GetHealth() || ((m_creature->GetHealth() - damage)*100 / m_creature->GetMaxHealth() < 15)) - { - //Take 0 damage - damage = 0; - - if (done_by->GetTypeId() == TYPEID_PLAYER && done_by->GetGUID() == PlayerGUID) - { - ((Player*)done_by)->AttackStop(); - ((Player*)done_by)->AreaExploredOrEventHappens(1640); - } - m_creature->CombatStop(); - EnterEvadeMode(); - } - } - - void Aggro(Unit *who) {} -}; - -bool QuestAccept_npc_bartleby(Player *player, Creature *_Creature, Quest const *_Quest) -{ - if(_Quest->GetQuestId() == 1640) - { - _Creature->setFaction(168); - ((npc_bartlebyAI*)_Creature->AI())->PlayerGUID = player->GetGUID(); - ((npc_bartlebyAI*)_Creature->AI())->AttackStart(player); - } - return true; -} - -CreatureAI* GetAI_npc_bartleby(Creature *_creature) -{ - return new npc_bartlebyAI(_creature); -} - -/*###### -## npc_dashel_stonefist -######*/ - -struct MANGOS_DLL_DECL npc_dashel_stonefistAI : public ScriptedAI -{ - npc_dashel_stonefistAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - m_creature->setFaction(11); - m_creature->setEmoteState(7); - } - - void DamageTaken(Unit *done_by, uint32 & damage) - { - if((damage > m_creature->GetHealth()) || (m_creature->GetHealth() - damage)*100 / m_creature->GetMaxHealth() < 15) - { - //Take 0 damage - damage = 0; - - if (done_by->GetTypeId() == TYPEID_PLAYER) - { - ((Player*)done_by)->AttackStop(); - ((Player*)done_by)->AreaExploredOrEventHappens(1447); - } - //m_creature->CombatStop(); - EnterEvadeMode(); - } - AttackedBy(done_by); - } - - void Aggro(Unit *who) {} -}; - -bool QuestAccept_npc_dashel_stonefist(Player *player, Creature *_Creature, Quest const *_Quest) -{ - if(_Quest->GetQuestId() == 1447) - { - _Creature->setFaction(168); - ((npc_dashel_stonefistAI*)_Creature->AI())->AttackStart(player); - } - return true; -} - -CreatureAI* GetAI_npc_dashel_stonefist(Creature *_creature) -{ - return new npc_dashel_stonefistAI(_creature); -} - -/*###### -## npc_general_marcus_jonathan -######*/ - -bool ReceiveEmote_npc_general_marcus_jonathan(Player *player, Creature *_Creature, uint32 emote) -{ - if(player->GetTeam() == ALLIANCE) - { - if (emote == TEXTEMOTE_SALUTE) - { - _Creature->SetOrientation(_Creature->GetAngle(player)); - _Creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); - } - if (emote == TEXTEMOTE_WAVE) - { - _Creature->MonsterSay("Greetings citizen",LANG_COMMON,0); - } - } - return true; -} - -/*###### -## npc_lady_katrana_prestor -######*/ - -#define GOSSIP_ITEM_KAT_1 "Pardon the intrusion, Lady Prestor, but Highlord Bolvar suggested that I seek your advice." -#define GOSSIP_ITEM_KAT_2 "My apologies, Lady Prestor." -#define GOSSIP_ITEM_KAT_3 "Begging your pardon, Lady Prestor. That was not my intent." -#define GOSSIP_ITEM_KAT_4 "Thank you for your time, Lady Prestor." - -bool GossipHello_npc_lady_katrana_prestor(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(4185) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KAT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(2693, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lady_katrana_prestor(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KAT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(2694, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KAT_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(2695, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KAT_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(2696, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(4185); - break; - } - 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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "npc_bartleby"; - newscript->GetAI = GetAI_npc_bartleby; - newscript->pQuestAccept = &QuestAccept_npc_bartleby; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "npc_dashel_stonefist"; - newscript->GetAI = GetAI_npc_dashel_stonefist; - newscript->pQuestAccept = &QuestAccept_npc_dashel_stonefist; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name = "npc_general_marcus_jonathan"; - newscript->pReceiveEmote = &ReceiveEmote_npc_general_marcus_jonathan; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_lady_katrana_prestor"; - newscript->pGossipHello = &GossipHello_npc_lady_katrana_prestor; - newscript->pGossipSelect = &GossipSelect_npc_lady_katrana_prestor; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Stormwind_City +SD%Complete: 100 +SDComment: Quest support: 1640, 1447, 4185, 11223 (DB support required for spell 42711). Receive emote General Marcus +SDCategory: Stormwind City +EndScriptData */ + +/* ContentData +npc_archmage_malin +npc_bartleby +npc_dashel_stonefist +npc_general_marcus_jonathan +npc_lady_katrana_prestor +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 *player, Creature *_Creature) +{ + if(_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if(player->GetQuestStatus(11223) == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(11223)) + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_MALIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_archmage_malin(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if(action = GOSSIP_ACTION_INFO_DEF) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player, 42711, true); + } + + return true; +} + +/*###### +## npc_bartleby +######*/ + +struct MANGOS_DLL_DECL npc_bartlebyAI : public ScriptedAI +{ + npc_bartlebyAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint64 PlayerGUID; + + void Reset() + { + m_creature->setFaction(11); + m_creature->setEmoteState(7); + + PlayerGUID = 0; + } + + void JustDied(Unit *who) + { + m_creature->setFaction(11); + } + + void DamageTaken(Unit *done_by, uint32 & damage) + { + if(damage > m_creature->GetHealth() || ((m_creature->GetHealth() - damage)*100 / m_creature->GetMaxHealth() < 15)) + { + //Take 0 damage + damage = 0; + + if (done_by->GetTypeId() == TYPEID_PLAYER && done_by->GetGUID() == PlayerGUID) + { + ((Player*)done_by)->AttackStop(); + ((Player*)done_by)->AreaExploredOrEventHappens(1640); + } + m_creature->CombatStop(); + EnterEvadeMode(); + } + } + + void Aggro(Unit *who) {} +}; + +bool QuestAccept_npc_bartleby(Player *player, Creature *_Creature, Quest const *_Quest) +{ + if(_Quest->GetQuestId() == 1640) + { + _Creature->setFaction(168); + ((npc_bartlebyAI*)_Creature->AI())->PlayerGUID = player->GetGUID(); + ((npc_bartlebyAI*)_Creature->AI())->AttackStart(player); + } + return true; +} + +CreatureAI* GetAI_npc_bartleby(Creature *_creature) +{ + return new npc_bartlebyAI(_creature); +} + +/*###### +## npc_dashel_stonefist +######*/ + +struct MANGOS_DLL_DECL npc_dashel_stonefistAI : public ScriptedAI +{ + npc_dashel_stonefistAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + m_creature->setFaction(11); + m_creature->setEmoteState(7); + } + + void DamageTaken(Unit *done_by, uint32 & damage) + { + if((damage > m_creature->GetHealth()) || (m_creature->GetHealth() - damage)*100 / m_creature->GetMaxHealth() < 15) + { + //Take 0 damage + damage = 0; + + if (done_by->GetTypeId() == TYPEID_PLAYER) + { + ((Player*)done_by)->AttackStop(); + ((Player*)done_by)->AreaExploredOrEventHappens(1447); + } + //m_creature->CombatStop(); + EnterEvadeMode(); + } + AttackedBy(done_by); + } + + void Aggro(Unit *who) {} +}; + +bool QuestAccept_npc_dashel_stonefist(Player *player, Creature *_Creature, Quest const *_Quest) +{ + if(_Quest->GetQuestId() == 1447) + { + _Creature->setFaction(168); + ((npc_dashel_stonefistAI*)_Creature->AI())->AttackStart(player); + } + return true; +} + +CreatureAI* GetAI_npc_dashel_stonefist(Creature *_creature) +{ + return new npc_dashel_stonefistAI(_creature); +} + +/*###### +## npc_general_marcus_jonathan +######*/ + +bool ReceiveEmote_npc_general_marcus_jonathan(Player *player, Creature *_Creature, uint32 emote) +{ + if(player->GetTeam() == ALLIANCE) + { + if (emote == TEXTEMOTE_SALUTE) + { + _Creature->SetOrientation(_Creature->GetAngle(player)); + _Creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + } + if (emote == TEXTEMOTE_WAVE) + { + _Creature->MonsterSay("Greetings citizen",LANG_COMMON,0); + } + } + return true; +} + +/*###### +## npc_lady_katrana_prestor +######*/ + +#define GOSSIP_ITEM_KAT_1 "Pardon the intrusion, Lady Prestor, but Highlord Bolvar suggested that I seek your advice." +#define GOSSIP_ITEM_KAT_2 "My apologies, Lady Prestor." +#define GOSSIP_ITEM_KAT_3 "Begging your pardon, Lady Prestor. That was not my intent." +#define GOSSIP_ITEM_KAT_4 "Thank you for your time, Lady Prestor." + +bool GossipHello_npc_lady_katrana_prestor(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(4185) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KAT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(2693, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_lady_katrana_prestor(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KAT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(2694, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KAT_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(2695, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KAT_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(2696, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(4185); + break; + } + 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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "npc_bartleby"; + newscript->GetAI = GetAI_npc_bartleby; + newscript->pQuestAccept = &QuestAccept_npc_bartleby; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "npc_dashel_stonefist"; + newscript->GetAI = GetAI_npc_dashel_stonefist; + newscript->pQuestAccept = &QuestAccept_npc_dashel_stonefist; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name = "npc_general_marcus_jonathan"; + newscript->pReceiveEmote = &ReceiveEmote_npc_general_marcus_jonathan; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_lady_katrana_prestor"; + newscript->pGossipHello = &GossipHello_npc_lady_katrana_prestor; + newscript->pGossipSelect = &GossipSelect_npc_lady_katrana_prestor; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stranglethorn_vale/stranglethorn_vale.cpp b/src/bindings/scripts/scripts/zone/stranglethorn_vale/stranglethorn_vale.cpp index 35fda2c6f1c..09075f16348 100644 --- a/src/bindings/scripts/scripts/zone/stranglethorn_vale/stranglethorn_vale.cpp +++ b/src/bindings/scripts/scripts/zone/stranglethorn_vale/stranglethorn_vale.cpp @@ -1,107 +1,107 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Stranglethorn_Vale -SD%Complete: 100 -SDComment: Quest support: 592 -SDCategory: Stranglethorn Vale -EndScriptData */ - -/* ContentData -mob_yenniku -EndContentData */ - -#include "precompiled.h" - -/*###### -## mob_yenniku -######*/ - -struct MANGOS_DLL_DECL mob_yennikuAI : public ScriptedAI -{ - mob_yennikuAI(Creature *c) : ScriptedAI(c) - { - bReset = false; - Reset(); - } - - uint32 Reset_Timer; - bool bReset; - - void Reset() - { - Reset_Timer = 0; - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if (caster->GetTypeId() == TYPEID_PLAYER) - { - //Yenniku's Release - if(!bReset && ((Player*)caster)->GetQuestStatus(592) == QUEST_STATUS_INCOMPLETE && spell->Id == 3607) - { - 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; - } - } - return; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if (bReset) - if(Reset_Timer < diff) - { - EnterEvadeMode(); - bReset = false; - m_creature->setFaction(28); //troll, bloodscalp - } - else Reset_Timer -= diff; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_mob_yenniku(Creature *_Creature) -{ - return new mob_yennikuAI (_Creature); -} - -/*###### -## -######*/ - -void AddSC_stranglethorn_vale() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "mob_yenniku"; - newscript->GetAI = GetAI_mob_yenniku; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Stranglethorn_Vale +SD%Complete: 100 +SDComment: Quest support: 592 +SDCategory: Stranglethorn Vale +EndScriptData */ + +/* ContentData +mob_yenniku +EndContentData */ + +#include "precompiled.h" + +/*###### +## mob_yenniku +######*/ + +struct MANGOS_DLL_DECL mob_yennikuAI : public ScriptedAI +{ + mob_yennikuAI(Creature *c) : ScriptedAI(c) + { + bReset = false; + Reset(); + } + + uint32 Reset_Timer; + bool bReset; + + void Reset() + { + Reset_Timer = 0; + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (caster->GetTypeId() == TYPEID_PLAYER) + { + //Yenniku's Release + if(!bReset && ((Player*)caster)->GetQuestStatus(592) == QUEST_STATUS_INCOMPLETE && spell->Id == 3607) + { + 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; + } + } + return; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if (bReset) + if(Reset_Timer < diff) + { + EnterEvadeMode(); + bReset = false; + m_creature->setFaction(28); //troll, bloodscalp + } + else Reset_Timer -= diff; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_mob_yenniku(Creature *_Creature) +{ + return new mob_yennikuAI (_Creature); +} + +/*###### +## +######*/ + +void AddSC_stranglethorn_vale() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "mob_yenniku"; + newscript->GetAI = GetAI_mob_yenniku; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_baron_rivendare.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_baron_rivendare.cpp index 6355588e7b8..13be5b04365 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_baron_rivendare.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_baron_rivendare.cpp @@ -1,215 +1,215 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with 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: 100 -SDComment: aura applied/defined in database -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.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.403809 -#define ADD_1Y -3339.703369 -#define ADD_1Z 115.057655 -#define ADD_1O 5.487860 - -#define ADD_2X 4013.189209 -#define ADD_2Y -3351.808350 -#define ADD_2Z 115.052254 -#define ADD_2O 0.134280 - -#define ADD_3X 4017.738037 -#define ADD_3Y -3363.478016 -#define ADD_3Z 115.057274 -#define ADD_3O 0.723313 - -#define ADD_4X 4048.877197 -#define ADD_4Y -3363.223633 -#define ADD_4Z 115.054253 -#define ADD_4O 3.627735 - -#define ADD_5X 4051.777588 -#define ADD_5Y -3350.893311 -#define ADD_5Z 115.055351 -#define ADD_5O 3.066176 - -#define ADD_6X 4048.375977 -#define ADD_6Y -3339.966309 -#define ADD_6Z 115.055222 -#define ADD_6O 2.457497 - -#define SPELL_SHADOWBOLT 18164 -#define SPELL_CLEAVE 15584 -#define SPELL_MORTALSTRIKE 13737 - -// spell 17473 should trigger -> 17471 - -//#define SPELL_RAISEDEAD 17475 -//#define SPELL_DEATHPACT 17698 -//#define SPELL_SUMMONSKELETONS 17274 - -struct MANGOS_DLL_DECL boss_baron_rivendareAI : public ScriptedAI -{ - boss_baron_rivendareAI(Creature *c) : ScriptedAI(c) {Reset();} - - 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; - - m_creature->LoadCreaturesAddon(); - } - - void Aggro(Unit *who) - { - switch (rand()%6) - { - case 0: - DoYell(SAY_0,LANG_UNIVERSAL,NULL); - break; - case 1: - DoYell(SAY_1,LANG_UNIVERSAL,NULL); - break; - case 2: - DoYell(SAY_2,LANG_UNIVERSAL,NULL); - break; - case 3: - DoYell(SAY_3,LANG_UNIVERSAL,NULL); - break; - case 4: - DoYell(SAY_4,LANG_UNIVERSAL,NULL); - break; - case 5: - DoYell(SAY_5,LANG_UNIVERSAL,NULL); - break; - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //ShadowBolt - if (ShadowBolt_Timer < diff) - { - //Cast - if (rand()%100 < 70) //70% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_SHADOWBOLT); - } - //10 seconds until we should cast this again - ShadowBolt_Timer = 10000; - }else ShadowBolt_Timer -= diff; - - //Cleave - if (Cleave_Timer < diff) - { - //Cast - if (rand()%100 < 55) //55% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - } - //13 seconds until we should cast this again - Cleave_Timer = 12000; - }else Cleave_Timer -= diff; - - //MortalStrike - if (MortalStrike_Timer < diff) - { - //Cast - if (rand()%100 < 30) //30% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); - } - //16 seconds until we should cast this again - MortalStrike_Timer = 16000; - }else MortalStrike_Timer -= diff; - - //RaiseDead - // if (RaiseDead_Timer < diff) - // { - //Cast - // DoCast(m_creature,SPELL_RAISEDEAD); - // DoSay("summon triggered",LANG_UNIVERSAL,NULL); //just a checkpoint - //45 seconds until we should cast this again - // RaiseDead_Timer = 45000; - // }else RaiseDead_Timer -= diff; - - //SummonSkeletons - //Creature* Unit::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime); - - if (SummonSkeletons_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - //Cast - Summoned = m_creature->SummonCreature(11197,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,29000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(11197,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,29000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(11197,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,29000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(11197,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,29000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(11197,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,29000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - Summoned = m_creature->SummonCreature(11197,ADD_6X,ADD_6Y,ADD_6Z,ADD_6O,TEMPSUMMON_TIMED_DESPAWN,29000); - ((CreatureAI*)Summoned->AI())->AttackStart(target); - - //34 seconds until we should cast this again - SummonSkeletons_Timer = 40000; - }else SummonSkeletons_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_baron_rivendare(Creature *_Creature) -{ - return new boss_baron_rivendareAI (_Creature); -} - - -void AddSC_boss_baron_rivendare() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_baron_rivendare"; - newscript->GetAI = GetAI_boss_baron_rivendare; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 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: 100 +SDComment: aura applied/defined in database +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.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.403809 +#define ADD_1Y -3339.703369 +#define ADD_1Z 115.057655 +#define ADD_1O 5.487860 + +#define ADD_2X 4013.189209 +#define ADD_2Y -3351.808350 +#define ADD_2Z 115.052254 +#define ADD_2O 0.134280 + +#define ADD_3X 4017.738037 +#define ADD_3Y -3363.478016 +#define ADD_3Z 115.057274 +#define ADD_3O 0.723313 + +#define ADD_4X 4048.877197 +#define ADD_4Y -3363.223633 +#define ADD_4Z 115.054253 +#define ADD_4O 3.627735 + +#define ADD_5X 4051.777588 +#define ADD_5Y -3350.893311 +#define ADD_5Z 115.055351 +#define ADD_5O 3.066176 + +#define ADD_6X 4048.375977 +#define ADD_6Y -3339.966309 +#define ADD_6Z 115.055222 +#define ADD_6O 2.457497 + +#define SPELL_SHADOWBOLT 18164 +#define SPELL_CLEAVE 15584 +#define SPELL_MORTALSTRIKE 13737 + +// spell 17473 should trigger -> 17471 + +//#define SPELL_RAISEDEAD 17475 +//#define SPELL_DEATHPACT 17698 +//#define SPELL_SUMMONSKELETONS 17274 + +struct MANGOS_DLL_DECL boss_baron_rivendareAI : public ScriptedAI +{ + boss_baron_rivendareAI(Creature *c) : ScriptedAI(c) {Reset();} + + 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; + + m_creature->LoadCreaturesAddon(); + } + + void Aggro(Unit *who) + { + switch (rand()%6) + { + case 0: + DoYell(SAY_0,LANG_UNIVERSAL,NULL); + break; + case 1: + DoYell(SAY_1,LANG_UNIVERSAL,NULL); + break; + case 2: + DoYell(SAY_2,LANG_UNIVERSAL,NULL); + break; + case 3: + DoYell(SAY_3,LANG_UNIVERSAL,NULL); + break; + case 4: + DoYell(SAY_4,LANG_UNIVERSAL,NULL); + break; + case 5: + DoYell(SAY_5,LANG_UNIVERSAL,NULL); + break; + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //ShadowBolt + if (ShadowBolt_Timer < diff) + { + //Cast + if (rand()%100 < 70) //70% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_SHADOWBOLT); + } + //10 seconds until we should cast this again + ShadowBolt_Timer = 10000; + }else ShadowBolt_Timer -= diff; + + //Cleave + if (Cleave_Timer < diff) + { + //Cast + if (rand()%100 < 55) //55% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + } + //13 seconds until we should cast this again + Cleave_Timer = 12000; + }else Cleave_Timer -= diff; + + //MortalStrike + if (MortalStrike_Timer < diff) + { + //Cast + if (rand()%100 < 30) //30% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_MORTALSTRIKE); + } + //16 seconds until we should cast this again + MortalStrike_Timer = 16000; + }else MortalStrike_Timer -= diff; + + //RaiseDead + // if (RaiseDead_Timer < diff) + // { + //Cast + // DoCast(m_creature,SPELL_RAISEDEAD); + // DoSay("summon triggered",LANG_UNIVERSAL,NULL); //just a checkpoint + //45 seconds until we should cast this again + // RaiseDead_Timer = 45000; + // }else RaiseDead_Timer -= diff; + + //SummonSkeletons + //Creature* Unit::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime); + + if (SummonSkeletons_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + //Cast + Summoned = m_creature->SummonCreature(11197,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,29000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(11197,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,29000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(11197,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,29000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(11197,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,29000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(11197,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,29000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + Summoned = m_creature->SummonCreature(11197,ADD_6X,ADD_6Y,ADD_6Z,ADD_6O,TEMPSUMMON_TIMED_DESPAWN,29000); + ((CreatureAI*)Summoned->AI())->AttackStart(target); + + //34 seconds until we should cast this again + SummonSkeletons_Timer = 40000; + }else SummonSkeletons_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_baron_rivendare(Creature *_Creature) +{ + return new boss_baron_rivendareAI (_Creature); +} + + +void AddSC_boss_baron_rivendare() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_baron_rivendare"; + newscript->GetAI = GetAI_boss_baron_rivendare; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_baroness_anastari.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_baroness_anastari.cpp index 79284eb5a26..1667375dd78 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_baroness_anastari.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_baroness_anastari.cpp @@ -1,124 +1,124 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* ScriptData -SDName: boss_baroness_anastari -SD%Complete: 90 -SDComment: MC disabled -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_BANSHEEWAIL 16565 -#define SPELL_BANSHEECURSE 16867 -#define SPELL_SILENCE 18327 -//#define SPELL_POSSESS 17244 - -struct MANGOS_DLL_DECL boss_baroness_anastariAI : public ScriptedAI -{ - boss_baroness_anastariAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 BansheeWail_Timer; - uint32 BansheeCurse_Timer; - uint32 Silence_Timer; - //uint32 Possess_Timer; - - void Reset() - { - BansheeWail_Timer = 1000; - BansheeCurse_Timer = 11000; - Silence_Timer = 13000; - //Possess_Timer = 35000; - } - - void Aggro(Unit *who) - { - } - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //BansheeWail - if (BansheeWail_Timer < diff) - { - //Cast - if (rand()%100 < 95) //95% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_BANSHEEWAIL); - } - //4 seconds until we should cast this again - BansheeWail_Timer = 4000; - }else BansheeWail_Timer -= diff; - - //BansheeCurse - if (BansheeCurse_Timer < diff) - { - //Cast - if (rand()%100 < 75) //75% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_BANSHEECURSE); - } - //18 seconds until we should cast this again - BansheeCurse_Timer = 18000; - }else BansheeCurse_Timer -= diff; - - //Silence - if (Silence_Timer < diff) - { - //Cast - if (rand()%100 < 80) //80% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_SILENCE); - } - //13 seconds until we should cast this again - Silence_Timer = 13000; - }else Silence_Timer -= diff; - - //Possess - /* if (Possess_Timer < diff) - { - //Cast - if (rand()%100 < 65) //65% chance to cast - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target)DoCast(target,SPELL_POSSESS); - } - //50 seconds until we should cast this again - Possess_Timer = 50000; - }else Possess_Timer -= diff; - */ - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_baroness_anastari(Creature *_Creature) -{ - return new boss_baroness_anastariAI (_Creature); -} - - -void AddSC_boss_baroness_anastari() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_baroness_anastari"; - newscript->GetAI = GetAI_boss_baroness_anastari; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: boss_baroness_anastari +SD%Complete: 90 +SDComment: MC disabled +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_BANSHEEWAIL 16565 +#define SPELL_BANSHEECURSE 16867 +#define SPELL_SILENCE 18327 +//#define SPELL_POSSESS 17244 + +struct MANGOS_DLL_DECL boss_baroness_anastariAI : public ScriptedAI +{ + boss_baroness_anastariAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 BansheeWail_Timer; + uint32 BansheeCurse_Timer; + uint32 Silence_Timer; + //uint32 Possess_Timer; + + void Reset() + { + BansheeWail_Timer = 1000; + BansheeCurse_Timer = 11000; + Silence_Timer = 13000; + //Possess_Timer = 35000; + } + + void Aggro(Unit *who) + { + } + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //BansheeWail + if (BansheeWail_Timer < diff) + { + //Cast + if (rand()%100 < 95) //95% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_BANSHEEWAIL); + } + //4 seconds until we should cast this again + BansheeWail_Timer = 4000; + }else BansheeWail_Timer -= diff; + + //BansheeCurse + if (BansheeCurse_Timer < diff) + { + //Cast + if (rand()%100 < 75) //75% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_BANSHEECURSE); + } + //18 seconds until we should cast this again + BansheeCurse_Timer = 18000; + }else BansheeCurse_Timer -= diff; + + //Silence + if (Silence_Timer < diff) + { + //Cast + if (rand()%100 < 80) //80% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_SILENCE); + } + //13 seconds until we should cast this again + Silence_Timer = 13000; + }else Silence_Timer -= diff; + + //Possess + /* if (Possess_Timer < diff) + { + //Cast + if (rand()%100 < 65) //65% chance to cast + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target)DoCast(target,SPELL_POSSESS); + } + //50 seconds until we should cast this again + Possess_Timer = 50000; + }else Possess_Timer -= diff; + */ + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_baroness_anastari(Creature *_Creature) +{ + return new boss_baroness_anastariAI (_Creature); +} + + +void AddSC_boss_baroness_anastari() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_baroness_anastari"; + newscript->GetAI = GetAI_boss_baroness_anastari; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_cannon_master_willey.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_cannon_master_willey.cpp index 91d4b4fd397..91b6da1fc56 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_cannon_master_willey.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_cannon_master_willey.cpp @@ -1,221 +1,221 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* ScriptData -SDName: boss_cannon_master_willey -SD%Complete: 100 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -//front, left -#define ADD_1X 3553.851807 -#define ADD_1Y -2945.885986 -#define ADD_1Z 125.001015 -#define ADD_1O 0.592007 -//front, right -#define ADD_2X 3559.206299 -#define ADD_2Y -2952.929932 -#define ADD_2Z 125.001015 -#define ADD_2O 0.592007 -//mid, left -#define ADD_3X 3552.417480 -#define ADD_3Y -2948.667236 -#define ADD_3Z 125.001015 -#define ADD_3O 0.592007 -//mid, right -#define ADD_4X 3555.651855 -#define ADD_4Y -2953.519043 -#define ADD_4Z 125.001015 -#define ADD_4O 0.592007 -//back, left -#define ADD_5X 3547.927246 -#define ADD_5Y -2950.977295 -#define ADD_5Z 125.001015 -#define ADD_5O 0.592007 -//back, mid -#define ADD_6X 3553.094697 -#define ADD_6Y -2952.123291 -#define ADD_6Z 125.001015 -#define ADD_6O 0.592007 -//back, right -#define ADD_7X 3552.727539 -#define ADD_7Y -2957.776123 -#define ADD_7Z 125.001015 -#define ADD_7O 0.592007 -//behind, left -#define ADD_8X 3547.156250 -#define ADD_8Y -2953.162354 -#define ADD_8Z 125.001015 -#define ADD_8O 0.592007 -//behind, right -#define ADD_9X 3550.202148 -#define ADD_9Y -2957.437744 -#define ADD_9Z 125.001015 -#define ADD_9O 0.592007 - -#define SPELL_KNOCKAWAY 10101 -#define SPELL_PUMMEL 15615 -#define SPELL_SHOOT 20463 -//#define SPELL_SUMMONCRIMSONRIFLEMAN 17279 - -struct MANGOS_DLL_DECL boss_cannon_master_willeyAI : public ScriptedAI -{ - boss_cannon_master_willeyAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 KnockAway_Timer; - uint32 Pummel_Timer; - uint32 Shoot_Timer; - uint32 SummonRifleman_Timer; - - void Reset() - { - Shoot_Timer = 1000; - Pummel_Timer = 7000; - KnockAway_Timer = 11000; - SummonRifleman_Timer = 15000; - } - - void JustDied(Unit* Victim) - { - 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); - } - - void Aggro(Unit *who) - { - } - - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Pummel - if (Pummel_Timer < diff) - { - //Cast - if (rand()%100 < 90) //90% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_PUMMEL); - } - //12 seconds until we should cast this again - Pummel_Timer = 12000; - }else Pummel_Timer -= diff; - - //KnockAway - if (KnockAway_Timer < diff) - { - //Cast - if (rand()%100 < 80) //80% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); - } - //14 seconds until we should cast this again - KnockAway_Timer = 14000; - }else KnockAway_Timer -= diff; - - //Shoot - if (Shoot_Timer < diff) - { - //Cast - DoCast(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 (rand()%9) - { - 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; - } - //30 seconds until we should cast this again - SummonRifleman_Timer = 30000; - }else SummonRifleman_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_cannon_master_willey(Creature *_Creature) -{ - return new boss_cannon_master_willeyAI (_Creature); -} - - -void AddSC_boss_cannon_master_willey() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_cannon_master_willey"; - newscript->GetAI = GetAI_boss_cannon_master_willey; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: boss_cannon_master_willey +SD%Complete: 100 +SDComment: +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" + +//front, left +#define ADD_1X 3553.851807 +#define ADD_1Y -2945.885986 +#define ADD_1Z 125.001015 +#define ADD_1O 0.592007 +//front, right +#define ADD_2X 3559.206299 +#define ADD_2Y -2952.929932 +#define ADD_2Z 125.001015 +#define ADD_2O 0.592007 +//mid, left +#define ADD_3X 3552.417480 +#define ADD_3Y -2948.667236 +#define ADD_3Z 125.001015 +#define ADD_3O 0.592007 +//mid, right +#define ADD_4X 3555.651855 +#define ADD_4Y -2953.519043 +#define ADD_4Z 125.001015 +#define ADD_4O 0.592007 +//back, left +#define ADD_5X 3547.927246 +#define ADD_5Y -2950.977295 +#define ADD_5Z 125.001015 +#define ADD_5O 0.592007 +//back, mid +#define ADD_6X 3553.094697 +#define ADD_6Y -2952.123291 +#define ADD_6Z 125.001015 +#define ADD_6O 0.592007 +//back, right +#define ADD_7X 3552.727539 +#define ADD_7Y -2957.776123 +#define ADD_7Z 125.001015 +#define ADD_7O 0.592007 +//behind, left +#define ADD_8X 3547.156250 +#define ADD_8Y -2953.162354 +#define ADD_8Z 125.001015 +#define ADD_8O 0.592007 +//behind, right +#define ADD_9X 3550.202148 +#define ADD_9Y -2957.437744 +#define ADD_9Z 125.001015 +#define ADD_9O 0.592007 + +#define SPELL_KNOCKAWAY 10101 +#define SPELL_PUMMEL 15615 +#define SPELL_SHOOT 20463 +//#define SPELL_SUMMONCRIMSONRIFLEMAN 17279 + +struct MANGOS_DLL_DECL boss_cannon_master_willeyAI : public ScriptedAI +{ + boss_cannon_master_willeyAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 KnockAway_Timer; + uint32 Pummel_Timer; + uint32 Shoot_Timer; + uint32 SummonRifleman_Timer; + + void Reset() + { + Shoot_Timer = 1000; + Pummel_Timer = 7000; + KnockAway_Timer = 11000; + SummonRifleman_Timer = 15000; + } + + void JustDied(Unit* Victim) + { + 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); + } + + void Aggro(Unit *who) + { + } + + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Pummel + if (Pummel_Timer < diff) + { + //Cast + if (rand()%100 < 90) //90% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_PUMMEL); + } + //12 seconds until we should cast this again + Pummel_Timer = 12000; + }else Pummel_Timer -= diff; + + //KnockAway + if (KnockAway_Timer < diff) + { + //Cast + if (rand()%100 < 80) //80% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_KNOCKAWAY); + } + //14 seconds until we should cast this again + KnockAway_Timer = 14000; + }else KnockAway_Timer -= diff; + + //Shoot + if (Shoot_Timer < diff) + { + //Cast + DoCast(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 (rand()%9) + { + 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; + } + //30 seconds until we should cast this again + SummonRifleman_Timer = 30000; + }else SummonRifleman_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_cannon_master_willey(Creature *_Creature) +{ + return new boss_cannon_master_willeyAI (_Creature); +} + + +void AddSC_boss_cannon_master_willey() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_cannon_master_willey"; + newscript->GetAI = GetAI_boss_cannon_master_willey; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_dathrohan_balnazzar.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_dathrohan_balnazzar.cpp index 0db8cff8141..30669e8c008 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_dathrohan_balnazzar.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_dathrohan_balnazzar.cpp @@ -1,316 +1,316 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* ScriptData -SDName: boss_darhrohan_balnazzar -SD%Complete: 100 -SDComment: CHECK SQL -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -//Dathrohan spells -#define SPELL_CRUSADERSHAMMER 17286 //AOE stun -#define SPELL_CRUSADERSTRIKE 17281 -#define SPELL_MINDBLAST 17287 -#define SPELL_HOLYSTRIKE 17284 //weapon dmg +3 -#define SPELL_DAZED 1604 - -//Transform -#define SPELL_BALNAZZARTRANSFORM 17288 //restore full HP/mana, trigger spell Balnazzar Transform Stun - -//Balnazzar spells -#define SPELL_SHADOWSHOCK 20603 //AOE 740-860dmg -#define SPELL_PSYCHICSCREAM 15398 //One target, might want to make a code selecting random target -#define SPELL_DEEPSLEEP 24777 //AOE, ten sec -#define SPELL_SHADOWBOLTVOLLEY 20741 //AOE, 255-345dmg -//#define SPELL_MINDCONTROL 15690 //core support needed - -//Summon -//G1 front, left -#define ADD_1X 3444.156250 -#define ADD_1Y -3090.626709 -#define ADD_1Z 135.002319 -#define ADD_1O 2.240888 -//G1 front, right -#define ADD_2X 3449.123535 -#define ADD_2Y -3087.009766 -#define ADD_2Z 135.002319 -#define ADD_2O 2.240888 -//G1 back left -#define ADD_3X 3446.246826 -#define ADD_3Y -3093.466309 -#define ADD_3Z 135.002319 -#define ADD_3O 2.240888 -//G1 back, right -#define ADD_4X 3451.160889 -#define ADD_4Y -3089.904785 -#define ADD_4Z 135.002136 -#define ADD_4O 2.240888 -//G2 front, left -#define ADD_5X 3457.995117 -#define ADD_5Y -3080.916504 -#define ADD_5Z 135.002319 -#define ADD_5O 3.784981 -//G2 front, right -#define ADD_6X 3454.302490 -#define ADD_6Y -3076.330566 -#define ADD_6Z 135.002319 -#define ADD_6O 3.784981 -//G2 back left -#define ADD_7X 3460.975098 -#define ADD_7Y -3078.901367 -#define ADD_7Z 135.002319 -#define ADD_7O 3.784981 -//G2 back, right -#define ADD_8X 3457.338867 -#define ADD_8Y -3073.979004 -#define ADD_8Z 135.002319 -#define ADD_8O 3.784981 - -struct MANGOS_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI -{ - boss_dathrohan_balnazzarAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 CrusadersHammer_Timer; - uint32 CrusaderStrike_Timer; - uint32 MindBlast_Timer; - uint32 HolyStrike_Timer; - uint32 Dazed_Timer; - uint32 ShadowShock_Timer; - uint32 PsychicScream_Timer; - uint32 DeepSleep_Timer; - uint32 ShadowBoltVolley_Timer; - // uint32 MindControl_Timer; - bool Transformed; - - void Reset() - { - CrusadersHammer_Timer = 8000; - CrusaderStrike_Timer = 14000; - MindBlast_Timer = 17000; - HolyStrike_Timer = 18000; - Dazed_Timer = 23000; - ShadowShock_Timer = 4000; - PsychicScream_Timer = 16000; - DeepSleep_Timer = 20000; - ShadowBoltVolley_Timer = 9000; - // MindControl_Timer = 10000; - Transformed = false; - - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,10545); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 1.00f); - - } - - void JustDied(Unit* Victim) - { - m_creature->SummonCreature(10698,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(10698,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(10698,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(10698,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(10698,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(10698,ADD_6X,ADD_6Y,ADD_6Z,ADD_6O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(10698,ADD_7X,ADD_7Y,ADD_7Z,ADD_7O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(10698,ADD_8X,ADD_8Y,ADD_8Z,ADD_8O,TEMPSUMMON_TIMED_DESPAWN,240000); - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //START NOT TRANSFORMED - if (!Transformed) - { - //CrusadersHammer - if (CrusadersHammer_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Cast - if (rand()%100 < 75) //50% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_CRUSADERSHAMMER); - } - //15 seconds until we should cast this again - CrusadersHammer_Timer = 12000; - }else CrusadersHammer_Timer -= diff; - - //CrusaderStrike - if (CrusaderStrike_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Cast - if (rand()%100 < 60) //50% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE); - } - //15 seconds until we should cast this again - CrusaderStrike_Timer = 15000; - }else CrusaderStrike_Timer -= diff; - - //MindBlast - if (MindBlast_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Cast - if (rand()%100 < 70) //70% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST); - } - //15 seconds until we should cast this again - MindBlast_Timer = 10000; - }else MindBlast_Timer -= diff; - - //HolyStrike - if (HolyStrike_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Cast - if (rand()%100 < 50) //50% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_HOLYSTRIKE); - } - //15 seconds until we should cast this again - HolyStrike_Timer = 15000; - }else HolyStrike_Timer -= diff; - - //Dazed - if (Dazed_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Cast - if (rand()%100 < 50) //50% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_DAZED); - } - //15 seconds until we should cast this again - Dazed_Timer = 15000; - }else Dazed_Timer -= diff; - - //BalnazzarTransform - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 40) - { - //Cast - DoCast(m_creature,SPELL_BALNAZZARTRANSFORM); //restore hp, mana and stun - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,10691); //then change disaply id - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 3.00f); //then, change size - Transformed = true; - } - - //START ELSE TRANSFORMED - } else { - - - //MindBlast - if (MindBlast_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) - { - //Cast - if (rand()%100 < 60) //70% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST); - } - //15 seconds until we should cast this again - MindBlast_Timer = 10000; - }else MindBlast_Timer -= diff; - - //ShadowShock - if (ShadowShock_Timer < diff) - { - //Cast - if (rand()%100 < 80) //80% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_SHADOWSHOCK); - } - //15 seconds until we should cast this again - ShadowShock_Timer = 11000; - }else ShadowShock_Timer -= diff; - - //PsychicScream - if (PsychicScream_Timer < diff) - { - //Cast - if (rand()%100 < 60) //60% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_PSYCHICSCREAM); - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); - } - //15 seconds until we should cast this again - PsychicScream_Timer = 20000; - }else PsychicScream_Timer -= diff; - - //DeepSleep - if (DeepSleep_Timer < diff) - { - //Cast - if (rand()%100 < 55) //55% chance to cast - { - //Cast - Unit* target = NULL; - - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - DoCast(target,SPELL_DEEPSLEEP); - } - //15 seconds until we should cast this again - DeepSleep_Timer = 15000; - }else DeepSleep_Timer -= diff; - - //ShadowBoltVolley - if (ShadowBoltVolley_Timer < diff) - { - //Cast - if (rand()%100 < 75) //75% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); - } - //15 seconds until we should cast this again - ShadowBoltVolley_Timer = 13000; - }else ShadowBoltVolley_Timer -= diff; - - //MindControl - // if (MindControl_Timer < diff) - // { - //Cast - // if (rand()%100 < 50) //50% chance to cast - // { - // DoCast(m_creature->getVictim(),SPELL_MINDCONTROL); - // } - //15 seconds until we should cast this again - // MindControl_Timer = 15000; - // }else MindControl_Timer -= diff; - - //END ELSE TRANSFORMED - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_dathrohan_balnazzar(Creature *_Creature) -{ - return new boss_dathrohan_balnazzarAI (_Creature); -} - -void AddSC_boss_dathrohan_balnazzar() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_dathrohan_balnazzar"; - newscript->GetAI = GetAI_boss_dathrohan_balnazzar; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: boss_darhrohan_balnazzar +SD%Complete: 100 +SDComment: CHECK SQL +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" + +//Dathrohan spells +#define SPELL_CRUSADERSHAMMER 17286 //AOE stun +#define SPELL_CRUSADERSTRIKE 17281 +#define SPELL_MINDBLAST 17287 +#define SPELL_HOLYSTRIKE 17284 //weapon dmg +3 +#define SPELL_DAZED 1604 + +//Transform +#define SPELL_BALNAZZARTRANSFORM 17288 //restore full HP/mana, trigger spell Balnazzar Transform Stun + +//Balnazzar spells +#define SPELL_SHADOWSHOCK 20603 //AOE 740-860dmg +#define SPELL_PSYCHICSCREAM 15398 //One target, might want to make a code selecting random target +#define SPELL_DEEPSLEEP 24777 //AOE, ten sec +#define SPELL_SHADOWBOLTVOLLEY 20741 //AOE, 255-345dmg +//#define SPELL_MINDCONTROL 15690 //core support needed + +//Summon +//G1 front, left +#define ADD_1X 3444.156250 +#define ADD_1Y -3090.626709 +#define ADD_1Z 135.002319 +#define ADD_1O 2.240888 +//G1 front, right +#define ADD_2X 3449.123535 +#define ADD_2Y -3087.009766 +#define ADD_2Z 135.002319 +#define ADD_2O 2.240888 +//G1 back left +#define ADD_3X 3446.246826 +#define ADD_3Y -3093.466309 +#define ADD_3Z 135.002319 +#define ADD_3O 2.240888 +//G1 back, right +#define ADD_4X 3451.160889 +#define ADD_4Y -3089.904785 +#define ADD_4Z 135.002136 +#define ADD_4O 2.240888 +//G2 front, left +#define ADD_5X 3457.995117 +#define ADD_5Y -3080.916504 +#define ADD_5Z 135.002319 +#define ADD_5O 3.784981 +//G2 front, right +#define ADD_6X 3454.302490 +#define ADD_6Y -3076.330566 +#define ADD_6Z 135.002319 +#define ADD_6O 3.784981 +//G2 back left +#define ADD_7X 3460.975098 +#define ADD_7Y -3078.901367 +#define ADD_7Z 135.002319 +#define ADD_7O 3.784981 +//G2 back, right +#define ADD_8X 3457.338867 +#define ADD_8Y -3073.979004 +#define ADD_8Z 135.002319 +#define ADD_8O 3.784981 + +struct MANGOS_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI +{ + boss_dathrohan_balnazzarAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 CrusadersHammer_Timer; + uint32 CrusaderStrike_Timer; + uint32 MindBlast_Timer; + uint32 HolyStrike_Timer; + uint32 Dazed_Timer; + uint32 ShadowShock_Timer; + uint32 PsychicScream_Timer; + uint32 DeepSleep_Timer; + uint32 ShadowBoltVolley_Timer; + // uint32 MindControl_Timer; + bool Transformed; + + void Reset() + { + CrusadersHammer_Timer = 8000; + CrusaderStrike_Timer = 14000; + MindBlast_Timer = 17000; + HolyStrike_Timer = 18000; + Dazed_Timer = 23000; + ShadowShock_Timer = 4000; + PsychicScream_Timer = 16000; + DeepSleep_Timer = 20000; + ShadowBoltVolley_Timer = 9000; + // MindControl_Timer = 10000; + Transformed = false; + + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,10545); + m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 1.00f); + + } + + void JustDied(Unit* Victim) + { + m_creature->SummonCreature(10698,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,240000); + m_creature->SummonCreature(10698,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,240000); + m_creature->SummonCreature(10698,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,240000); + m_creature->SummonCreature(10698,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,240000); + m_creature->SummonCreature(10698,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,240000); + m_creature->SummonCreature(10698,ADD_6X,ADD_6Y,ADD_6Z,ADD_6O,TEMPSUMMON_TIMED_DESPAWN,240000); + m_creature->SummonCreature(10698,ADD_7X,ADD_7Y,ADD_7Z,ADD_7O,TEMPSUMMON_TIMED_DESPAWN,240000); + m_creature->SummonCreature(10698,ADD_8X,ADD_8Y,ADD_8Z,ADD_8O,TEMPSUMMON_TIMED_DESPAWN,240000); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //START NOT TRANSFORMED + if (!Transformed) + { + //CrusadersHammer + if (CrusadersHammer_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Cast + if (rand()%100 < 75) //50% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_CRUSADERSHAMMER); + } + //15 seconds until we should cast this again + CrusadersHammer_Timer = 12000; + }else CrusadersHammer_Timer -= diff; + + //CrusaderStrike + if (CrusaderStrike_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Cast + if (rand()%100 < 60) //50% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE); + } + //15 seconds until we should cast this again + CrusaderStrike_Timer = 15000; + }else CrusaderStrike_Timer -= diff; + + //MindBlast + if (MindBlast_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Cast + if (rand()%100 < 70) //70% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_MINDBLAST); + } + //15 seconds until we should cast this again + MindBlast_Timer = 10000; + }else MindBlast_Timer -= diff; + + //HolyStrike + if (HolyStrike_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Cast + if (rand()%100 < 50) //50% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_HOLYSTRIKE); + } + //15 seconds until we should cast this again + HolyStrike_Timer = 15000; + }else HolyStrike_Timer -= diff; + + //Dazed + if (Dazed_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Cast + if (rand()%100 < 50) //50% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_DAZED); + } + //15 seconds until we should cast this again + Dazed_Timer = 15000; + }else Dazed_Timer -= diff; + + //BalnazzarTransform + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 40) + { + //Cast + DoCast(m_creature,SPELL_BALNAZZARTRANSFORM); //restore hp, mana and stun + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,10691); //then change disaply id + m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 3.00f); //then, change size + Transformed = true; + } + + //START ELSE TRANSFORMED + } else { + + + //MindBlast + if (MindBlast_Timer < diff && !m_creature->IsNonMeleeSpellCasted(false)) + { + //Cast + if (rand()%100 < 60) //70% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_MINDBLAST); + } + //15 seconds until we should cast this again + MindBlast_Timer = 10000; + }else MindBlast_Timer -= diff; + + //ShadowShock + if (ShadowShock_Timer < diff) + { + //Cast + if (rand()%100 < 80) //80% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_SHADOWSHOCK); + } + //15 seconds until we should cast this again + ShadowShock_Timer = 11000; + }else ShadowShock_Timer -= diff; + + //PsychicScream + if (PsychicScream_Timer < diff) + { + //Cast + if (rand()%100 < 60) //60% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_PSYCHICSCREAM); + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); + } + //15 seconds until we should cast this again + PsychicScream_Timer = 20000; + }else PsychicScream_Timer -= diff; + + //DeepSleep + if (DeepSleep_Timer < diff) + { + //Cast + if (rand()%100 < 55) //55% chance to cast + { + //Cast + Unit* target = NULL; + + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + DoCast(target,SPELL_DEEPSLEEP); + } + //15 seconds until we should cast this again + DeepSleep_Timer = 15000; + }else DeepSleep_Timer -= diff; + + //ShadowBoltVolley + if (ShadowBoltVolley_Timer < diff) + { + //Cast + if (rand()%100 < 75) //75% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); + } + //15 seconds until we should cast this again + ShadowBoltVolley_Timer = 13000; + }else ShadowBoltVolley_Timer -= diff; + + //MindControl + // if (MindControl_Timer < diff) + // { + //Cast + // if (rand()%100 < 50) //50% chance to cast + // { + // DoCast(m_creature->getVictim(),SPELL_MINDCONTROL); + // } + //15 seconds until we should cast this again + // MindControl_Timer = 15000; + // }else MindControl_Timer -= diff; + + //END ELSE TRANSFORMED + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_dathrohan_balnazzar(Creature *_Creature) +{ + return new boss_dathrohan_balnazzarAI (_Creature); +} + +void AddSC_boss_dathrohan_balnazzar() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_dathrohan_balnazzar"; + newscript->GetAI = GetAI_boss_dathrohan_balnazzar; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_magistrate_barthilas.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_magistrate_barthilas.cpp index aceb05b1614..7011c8451c1 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_magistrate_barthilas.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_magistrate_barthilas.cpp @@ -1,114 +1,114 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with 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: 100 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_DRAININGBLOW 16793 -#define SPELL_CROWDPUMMEL 10887 -#define SPELL_MIGHTYBLOW 14099 -#define SPELL_DAZED 1604 - -struct MANGOS_DLL_DECL boss_magistrate_barthilasAI : public ScriptedAI -{ - boss_magistrate_barthilasAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 DrainingBlow_Timer; - uint32 CrowdPummel_Timer; - uint32 MightyBlow_Timer; - uint32 Dazed_Timer; - - void Reset() - { - DrainingBlow_Timer = 4000; - CrowdPummel_Timer = 13000; - MightyBlow_Timer = 11000; - Dazed_Timer = 7000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //DrainingBlow - if (DrainingBlow_Timer < diff) - { - //Cast - DoCast(m_creature->getVictim(),SPELL_DRAININGBLOW); - - //4 seconds until we should cast this again - DrainingBlow_Timer = 4000; - }else DrainingBlow_Timer -= diff; - - //CrowdPummel - if (CrowdPummel_Timer < diff) - { - //Cast - DoCast(m_creature->getVictim(),SPELL_CROWDPUMMEL); - - //13 seconds until we should cast this agian - CrowdPummel_Timer = 13000; - }else CrowdPummel_Timer -= diff; - - //MightyBlow - if (MightyBlow_Timer < diff) - { - //Cast - DoCast(m_creature->getVictim(),SPELL_MIGHTYBLOW); - - //11 seconds until we should cast this again - MightyBlow_Timer = 11000; - }else MightyBlow_Timer -= diff; - - //Dazed - if (Dazed_Timer < diff) - { - //Cast - DoCast(m_creature->getVictim(),SPELL_DAZED); - - //20 seconds until we should cast this again - Dazed_Timer = 20000; - }else Dazed_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_magistrate_barthilas(Creature *_Creature) -{ - return new boss_magistrate_barthilasAI (_Creature); -} - - -void AddSC_boss_magistrate_barthilas() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_magistrate_barthilas"; - newscript->GetAI = GetAI_boss_magistrate_barthilas; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 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: 100 +SDComment: +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_DRAININGBLOW 16793 +#define SPELL_CROWDPUMMEL 10887 +#define SPELL_MIGHTYBLOW 14099 +#define SPELL_DAZED 1604 + +struct MANGOS_DLL_DECL boss_magistrate_barthilasAI : public ScriptedAI +{ + boss_magistrate_barthilasAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 DrainingBlow_Timer; + uint32 CrowdPummel_Timer; + uint32 MightyBlow_Timer; + uint32 Dazed_Timer; + + void Reset() + { + DrainingBlow_Timer = 4000; + CrowdPummel_Timer = 13000; + MightyBlow_Timer = 11000; + Dazed_Timer = 7000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //DrainingBlow + if (DrainingBlow_Timer < diff) + { + //Cast + DoCast(m_creature->getVictim(),SPELL_DRAININGBLOW); + + //4 seconds until we should cast this again + DrainingBlow_Timer = 4000; + }else DrainingBlow_Timer -= diff; + + //CrowdPummel + if (CrowdPummel_Timer < diff) + { + //Cast + DoCast(m_creature->getVictim(),SPELL_CROWDPUMMEL); + + //13 seconds until we should cast this agian + CrowdPummel_Timer = 13000; + }else CrowdPummel_Timer -= diff; + + //MightyBlow + if (MightyBlow_Timer < diff) + { + //Cast + DoCast(m_creature->getVictim(),SPELL_MIGHTYBLOW); + + //11 seconds until we should cast this again + MightyBlow_Timer = 11000; + }else MightyBlow_Timer -= diff; + + //Dazed + if (Dazed_Timer < diff) + { + //Cast + DoCast(m_creature->getVictim(),SPELL_DAZED); + + //20 seconds until we should cast this again + Dazed_Timer = 20000; + }else Dazed_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_magistrate_barthilas(Creature *_Creature) +{ + return new boss_magistrate_barthilasAI (_Creature); +} + + +void AddSC_boss_magistrate_barthilas() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_magistrate_barthilas"; + newscript->GetAI = GetAI_boss_magistrate_barthilas; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_maleki_the_pallid.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_maleki_the_pallid.cpp index 6c3c75e9bc6..d5535071f26 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_maleki_the_pallid.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_maleki_the_pallid.cpp @@ -1,119 +1,119 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* ScriptData -SDName: boss_maleki_the_pallid -SD%Complete: 100 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FROSTNOVA 22645 -#define SPELL_FROSTBOLT 17503 -#define SPELL_DRAINLIFE 20743 -#define SPELL_ICETOMB 16869 - -struct MANGOS_DLL_DECL boss_maleki_the_pallidAI : public ScriptedAI -{ - boss_maleki_the_pallidAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 FrostNova_Timer; - uint32 Frostbolt_Timer; - uint32 IceTomb_Timer; - uint32 DrainLife_Timer; - - void Reset() - { - FrostNova_Timer = 11000; - Frostbolt_Timer = 1000; - IceTomb_Timer = 16000; - DrainLife_Timer = 31000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //FrostNova - if (FrostNova_Timer < diff) - { - //Cast - DoCast(m_creature->getVictim(),SPELL_FROSTNOVA); - //23 seconds until we should cast this again - FrostNova_Timer = 23000; - }else FrostNova_Timer -= diff; - - //Frostbolt - if (Frostbolt_Timer < diff) - { - //Cast - if (rand()%100 < 90) //90% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_FROSTBOLT); - } - //3.5 seconds until we should cast this again - Frostbolt_Timer = 3500; - }else Frostbolt_Timer -= diff; - - //IceTomb - if (IceTomb_Timer < diff) - { - //Cast - if (rand()%100 < 65) //65% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_ICETOMB); - } - //28 seconds until we should cast this again - IceTomb_Timer = 28000; - }else IceTomb_Timer -= diff; - - //DrainLife - if (DrainLife_Timer < diff) - { - //Cast - if (rand()%100 < 55) //55% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_DRAINLIFE); - } - //31 seconds until we should cast this again - DrainLife_Timer = 31000; - }else DrainLife_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_maleki_the_pallid(Creature *_Creature) -{ - return new boss_maleki_the_pallidAI (_Creature); -} - - -void AddSC_boss_maleki_the_pallid() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_maleki_the_pallid"; - newscript->GetAI = GetAI_boss_maleki_the_pallid; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: boss_maleki_the_pallid +SD%Complete: 100 +SDComment: +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_FROSTNOVA 22645 +#define SPELL_FROSTBOLT 17503 +#define SPELL_DRAINLIFE 20743 +#define SPELL_ICETOMB 16869 + +struct MANGOS_DLL_DECL boss_maleki_the_pallidAI : public ScriptedAI +{ + boss_maleki_the_pallidAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 FrostNova_Timer; + uint32 Frostbolt_Timer; + uint32 IceTomb_Timer; + uint32 DrainLife_Timer; + + void Reset() + { + FrostNova_Timer = 11000; + Frostbolt_Timer = 1000; + IceTomb_Timer = 16000; + DrainLife_Timer = 31000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //FrostNova + if (FrostNova_Timer < diff) + { + //Cast + DoCast(m_creature->getVictim(),SPELL_FROSTNOVA); + //23 seconds until we should cast this again + FrostNova_Timer = 23000; + }else FrostNova_Timer -= diff; + + //Frostbolt + if (Frostbolt_Timer < diff) + { + //Cast + if (rand()%100 < 90) //90% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_FROSTBOLT); + } + //3.5 seconds until we should cast this again + Frostbolt_Timer = 3500; + }else Frostbolt_Timer -= diff; + + //IceTomb + if (IceTomb_Timer < diff) + { + //Cast + if (rand()%100 < 65) //65% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_ICETOMB); + } + //28 seconds until we should cast this again + IceTomb_Timer = 28000; + }else IceTomb_Timer -= diff; + + //DrainLife + if (DrainLife_Timer < diff) + { + //Cast + if (rand()%100 < 55) //55% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_DRAINLIFE); + } + //31 seconds until we should cast this again + DrainLife_Timer = 31000; + }else DrainLife_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_maleki_the_pallid(Creature *_Creature) +{ + return new boss_maleki_the_pallidAI (_Creature); +} + + +void AddSC_boss_maleki_the_pallid() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_maleki_the_pallid"; + newscript->GetAI = GetAI_boss_maleki_the_pallid; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_nerubenkan.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_nerubenkan.cpp index 59bd632836c..273c2f60961 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_nerubenkan.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_nerubenkan.cpp @@ -1,138 +1,138 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with 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: 100 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_ENCASINGWEBS 4962 -#define SPELL_PIERCEARMOR 6016 -#define SPELL_VIRULENTPOISON 16427 -//#define SPELL_RAISEUNDEADSCARAB 17235 - -struct MANGOS_DLL_DECL boss_nerubenkanAI : public ScriptedAI -{ - boss_nerubenkanAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 EncasingWebs_Timer; - uint32 PierceArmor_Timer; - uint32 VirulentPoison_Timer; - uint32 RaiseUndeadScarab_Timer; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - VirulentPoison_Timer = 3000; - EncasingWebs_Timer = 7000; - PierceArmor_Timer = 19000; - RaiseUndeadScarab_Timer = 11000; - } - - void Aggro(Unit *who) - { - } - - void RaiseUndeadScarab(Unit* victim) - { - Rand = rand()%10; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%10; - switch (rand()%2) - { - 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) - ((CreatureAI*)Summoned->AI())->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //EncasingWebs - if (EncasingWebs_Timer < diff) - { - //Cast - DoCast(m_creature->getVictim(),SPELL_ENCASINGWEBS); - //30 seconds until we should cast this again - EncasingWebs_Timer = 30000; - }else EncasingWebs_Timer -= diff; - - //PierceArmor - if (PierceArmor_Timer < diff) - { - //Cast - if (rand()%100 < 75) //75% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_PIERCEARMOR); - } - //35 seconds until we should cast this again - PierceArmor_Timer = 35000; - }else PierceArmor_Timer -= diff; - - //VirulentPoison - if (VirulentPoison_Timer < diff) - { - //Cast - DoCast(m_creature->getVictim(),SPELL_VIRULENTPOISON); - //20 seconds until we should cast this again - VirulentPoison_Timer = 20000; - }else VirulentPoison_Timer -= diff; - - //RaiseUndeadScarab - if (RaiseUndeadScarab_Timer < diff) - { - //Cast - RaiseUndeadScarab(m_creature->getVictim()); - //16 seconds until we should cast this again - RaiseUndeadScarab_Timer = 16000; - }else RaiseUndeadScarab_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_nerubenkan(Creature *_Creature) -{ - return new boss_nerubenkanAI (_Creature); -} - - -void AddSC_boss_nerubenkan() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_nerubenkan"; - newscript->GetAI = GetAI_boss_nerubenkan; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 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: 100 +SDComment: +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_ENCASINGWEBS 4962 +#define SPELL_PIERCEARMOR 6016 +#define SPELL_VIRULENTPOISON 16427 +//#define SPELL_RAISEUNDEADSCARAB 17235 + +struct MANGOS_DLL_DECL boss_nerubenkanAI : public ScriptedAI +{ + boss_nerubenkanAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 EncasingWebs_Timer; + uint32 PierceArmor_Timer; + uint32 VirulentPoison_Timer; + uint32 RaiseUndeadScarab_Timer; + int Rand; + int RandX; + int RandY; + Creature* Summoned; + + void Reset() + { + VirulentPoison_Timer = 3000; + EncasingWebs_Timer = 7000; + PierceArmor_Timer = 19000; + RaiseUndeadScarab_Timer = 11000; + } + + void Aggro(Unit *who) + { + } + + void RaiseUndeadScarab(Unit* victim) + { + Rand = rand()%10; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%10; + switch (rand()%2) + { + 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) + ((CreatureAI*)Summoned->AI())->AttackStart(victim); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //EncasingWebs + if (EncasingWebs_Timer < diff) + { + //Cast + DoCast(m_creature->getVictim(),SPELL_ENCASINGWEBS); + //30 seconds until we should cast this again + EncasingWebs_Timer = 30000; + }else EncasingWebs_Timer -= diff; + + //PierceArmor + if (PierceArmor_Timer < diff) + { + //Cast + if (rand()%100 < 75) //75% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_PIERCEARMOR); + } + //35 seconds until we should cast this again + PierceArmor_Timer = 35000; + }else PierceArmor_Timer -= diff; + + //VirulentPoison + if (VirulentPoison_Timer < diff) + { + //Cast + DoCast(m_creature->getVictim(),SPELL_VIRULENTPOISON); + //20 seconds until we should cast this again + VirulentPoison_Timer = 20000; + }else VirulentPoison_Timer -= diff; + + //RaiseUndeadScarab + if (RaiseUndeadScarab_Timer < diff) + { + //Cast + RaiseUndeadScarab(m_creature->getVictim()); + //16 seconds until we should cast this again + RaiseUndeadScarab_Timer = 16000; + }else RaiseUndeadScarab_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_nerubenkan(Creature *_Creature) +{ + return new boss_nerubenkanAI (_Creature); +} + + +void AddSC_boss_nerubenkan() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_nerubenkan"; + newscript->GetAI = GetAI_boss_nerubenkan; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_order_of_silver_hand.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_order_of_silver_hand.cpp index 9da5b48e55c..685d523a12e 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_order_of_silver_hand.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_order_of_silver_hand.cpp @@ -1,161 +1,161 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* 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) -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" -#include "def_stratholme.h" - -/*##### -# Additional: -# Although this is a working solution, the correct would be in addition to check if Aurius is dead. -# Once player extinguish the eternal flame (cast spell 31497->start event 11206) Aurius should become hostile. -# 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 - -#define SPELL_HOLY_LIGHT 25263 -#define SPELL_DIVINE_SHIELD 13874 - -struct MANGOS_DLL_DECL boss_silver_hand_bossesAI : public ScriptedAI -{ - boss_silver_hand_bossesAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 HolyLight_Timer; - uint32 DivineShield_Timer; - - void Reset() - { - HolyLight_Timer = 20000; - DivineShield_Timer = 20000; - - if(pInstance) - { - switch(m_creature->GetEntry()) - { - case SH_AELMAR: - pInstance->SetData(TYPE_SH_AELMAR, 0); - break; - case SH_CATHELA: - pInstance->SetData(TYPE_SH_CATHELA, 0); - break; - case SH_GREGOR: - pInstance->SetData(TYPE_SH_GREGOR, 0); - break; - case SH_NEMAS: - pInstance->SetData(TYPE_SH_NEMAS, 0); - break; - case SH_VICAR: - pInstance->SetData(TYPE_SH_VICAR, 0); - break; - } - } - } - - void Aggro(Unit* who) - { - } - - void JustDied(Unit* Killer) - { - if(pInstance) - { - switch(m_creature->GetEntry()) - { - case SH_AELMAR: - pInstance->SetData(TYPE_SH_AELMAR, 2); - break; - case SH_CATHELA: - pInstance->SetData(TYPE_SH_CATHELA, 2); - break; - case SH_GREGOR: - pInstance->SetData(TYPE_SH_GREGOR, 2); - break; - case SH_NEMAS: - pInstance->SetData(TYPE_SH_NEMAS, 2); - break; - case SH_VICAR: - pInstance->SetData(TYPE_SH_VICAR, 2); - break; - } - if(pInstance->GetData(TYPE_SH_QUEST) && Killer->GetTypeId() == TYPEID_PLAYER) - ((Player*)Killer)->KilledMonster(SH_QUEST_CREDIT,m_creature->GetGUID()); - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if (HolyLight_Timer < diff) - { - if (m_creature->GetHealth()*5 < m_creature->GetMaxHealth()) - { - DoCast(m_creature, SPELL_HOLY_LIGHT); - HolyLight_Timer = 20000; - } - }else HolyLight_Timer -= diff; - - if (DivineShield_Timer < diff) - { - if (m_creature->GetHealth()*20 < m_creature->GetMaxHealth()) - { - DoCast(m_creature, SPELL_DIVINE_SHIELD); - DivineShield_Timer = 40000; - } - }else DivineShield_Timer -= diff; - - DoMeleeAttackIfReady(); - } - -}; -CreatureAI* GetAI_boss_silver_hand_bossesAI(Creature *_Creature) -{ - return new boss_silver_hand_bossesAI (_Creature); -} - -/*##### -# -#####*/ - -void AddSC_boss_order_of_silver_hand() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_silver_hand_bosses"; - newscript->GetAI = GetAI_boss_silver_hand_bossesAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* 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) +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" +#include "def_stratholme.h" + +/*##### +# Additional: +# Although this is a working solution, the correct would be in addition to check if Aurius is dead. +# Once player extinguish the eternal flame (cast spell 31497->start event 11206) Aurius should become hostile. +# 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 + +#define SPELL_HOLY_LIGHT 25263 +#define SPELL_DIVINE_SHIELD 13874 + +struct MANGOS_DLL_DECL boss_silver_hand_bossesAI : public ScriptedAI +{ + boss_silver_hand_bossesAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 HolyLight_Timer; + uint32 DivineShield_Timer; + + void Reset() + { + HolyLight_Timer = 20000; + DivineShield_Timer = 20000; + + if(pInstance) + { + switch(m_creature->GetEntry()) + { + case SH_AELMAR: + pInstance->SetData(TYPE_SH_AELMAR, 0); + break; + case SH_CATHELA: + pInstance->SetData(TYPE_SH_CATHELA, 0); + break; + case SH_GREGOR: + pInstance->SetData(TYPE_SH_GREGOR, 0); + break; + case SH_NEMAS: + pInstance->SetData(TYPE_SH_NEMAS, 0); + break; + case SH_VICAR: + pInstance->SetData(TYPE_SH_VICAR, 0); + break; + } + } + } + + void Aggro(Unit* who) + { + } + + void JustDied(Unit* Killer) + { + if(pInstance) + { + switch(m_creature->GetEntry()) + { + case SH_AELMAR: + pInstance->SetData(TYPE_SH_AELMAR, 2); + break; + case SH_CATHELA: + pInstance->SetData(TYPE_SH_CATHELA, 2); + break; + case SH_GREGOR: + pInstance->SetData(TYPE_SH_GREGOR, 2); + break; + case SH_NEMAS: + pInstance->SetData(TYPE_SH_NEMAS, 2); + break; + case SH_VICAR: + pInstance->SetData(TYPE_SH_VICAR, 2); + break; + } + if(pInstance->GetData(TYPE_SH_QUEST) && Killer->GetTypeId() == TYPEID_PLAYER) + ((Player*)Killer)->KilledMonster(SH_QUEST_CREDIT,m_creature->GetGUID()); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if (HolyLight_Timer < diff) + { + if (m_creature->GetHealth()*5 < m_creature->GetMaxHealth()) + { + DoCast(m_creature, SPELL_HOLY_LIGHT); + HolyLight_Timer = 20000; + } + }else HolyLight_Timer -= diff; + + if (DivineShield_Timer < diff) + { + if (m_creature->GetHealth()*20 < m_creature->GetMaxHealth()) + { + DoCast(m_creature, SPELL_DIVINE_SHIELD); + DivineShield_Timer = 40000; + } + }else DivineShield_Timer -= diff; + + DoMeleeAttackIfReady(); + } + +}; +CreatureAI* GetAI_boss_silver_hand_bossesAI(Creature *_Creature) +{ + return new boss_silver_hand_bossesAI (_Creature); +} + +/*##### +# +#####*/ + +void AddSC_boss_order_of_silver_hand() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_silver_hand_bosses"; + newscript->GetAI = GetAI_boss_silver_hand_bossesAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_postmaster_malown.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_postmaster_malown.cpp index c303207101d..f8ba61c42ed 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_postmaster_malown.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_postmaster_malown.cpp @@ -1,144 +1,144 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //WailingDead - if (WailingDead_Timer < diff) - { - //Cast - if (rand()%100 < 65) //65% chance to cast - { - DoCast(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 - { - DoCast(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 - { - DoCast(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 - { - DoCast(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 - { - DoCast(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 *_Creature) -{ - return new boss_postmaster_malownAI (_Creature); -} - - -void AddSC_boss_postmaster_malown() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_postmaster_malown"; - newscript->GetAI = GetAI_boss_postmaster_malown; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 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 *c) : ScriptedAI(c) {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 Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //WailingDead + if (WailingDead_Timer < diff) + { + //Cast + if (rand()%100 < 65) //65% chance to cast + { + DoCast(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 + { + DoCast(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 + { + DoCast(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 + { + DoCast(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 + { + DoCast(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 *_Creature) +{ + return new boss_postmaster_malownAI (_Creature); +} + + +void AddSC_boss_postmaster_malown() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_postmaster_malown"; + newscript->GetAI = GetAI_boss_postmaster_malown; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_ramstein_the_gorger.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_ramstein_the_gorger.cpp index 7b175f5b9ff..8e482024cd2 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_ramstein_the_gorger.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_ramstein_the_gorger.cpp @@ -1,92 +1,92 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with 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: 100 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_TRAMPLE 15550 -#define SPELL_KNOCKOUT 17307 - -struct MANGOS_DLL_DECL boss_ramstein_the_gorgerAI : public ScriptedAI -{ - boss_ramstein_the_gorgerAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Trample_Timer; - uint32 Knockout_Timer; - - void Reset() - { - Trample_Timer = 3000; - Knockout_Timer = 12000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Trample - if (Trample_Timer < diff) - { - //Cast - if (rand()%100 < 75) //75% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_TRAMPLE); - } - //7 seconds until we should cast this again - Trample_Timer = 7000; - }else Trample_Timer -= diff; - - //Knockout - if (Knockout_Timer < diff) - { - //Cast - if (rand()%100 < 70) //70% chance to cast - { - DoCast(m_creature->getVictim(),SPELL_KNOCKOUT); - } - //10 seconds until we should cast this again - Knockout_Timer = 10000; - }else Knockout_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ramstein_the_gorger(Creature *_Creature) -{ - return new boss_ramstein_the_gorgerAI (_Creature); -} - - -void AddSC_boss_ramstein_the_gorger() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ramstein_the_gorger"; - newscript->GetAI = GetAI_boss_ramstein_the_gorger; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 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: 100 +SDComment: +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_TRAMPLE 15550 +#define SPELL_KNOCKOUT 17307 + +struct MANGOS_DLL_DECL boss_ramstein_the_gorgerAI : public ScriptedAI +{ + boss_ramstein_the_gorgerAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Trample_Timer; + uint32 Knockout_Timer; + + void Reset() + { + Trample_Timer = 3000; + Knockout_Timer = 12000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Trample + if (Trample_Timer < diff) + { + //Cast + if (rand()%100 < 75) //75% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_TRAMPLE); + } + //7 seconds until we should cast this again + Trample_Timer = 7000; + }else Trample_Timer -= diff; + + //Knockout + if (Knockout_Timer < diff) + { + //Cast + if (rand()%100 < 70) //70% chance to cast + { + DoCast(m_creature->getVictim(),SPELL_KNOCKOUT); + } + //10 seconds until we should cast this again + Knockout_Timer = 10000; + }else Knockout_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_ramstein_the_gorger(Creature *_Creature) +{ + return new boss_ramstein_the_gorgerAI (_Creature); +} + + +void AddSC_boss_ramstein_the_gorger() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ramstein_the_gorger"; + newscript->GetAI = GetAI_boss_ramstein_the_gorger; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp index 1fc4eedc5f5..a4ca4cd6a7d 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp @@ -1,103 +1,103 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with 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 *c) : ScriptedAI(c) {Reset();} - - uint32 RavenousClaw_Timer; - bool HasYelled; - - void Reset() - { - RavenousClaw_Timer = 10000; - HasYelled = false; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!HasYelled) - { - DoYell(SAY_SPAWN,LANG_UNIVERSAL,NULL); - HasYelled = true; - } - - //Begin melee attack if we are within range - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //RavenousClaw - if (RavenousClaw_Timer < diff) - { - //Cast - DoCast(m_creature->getVictim(),SPELL_RAVENOUSCLAW); - //15 seconds until we should cast this again - RavenousClaw_Timer = 15000; - }else RavenousClaw_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_timmy_the_cruel(Creature *_Creature) -{ - return new boss_timmy_the_cruelAI (_Creature); -} - - -void AddSC_boss_timmy_the_cruel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_timmy_the_cruel"; - newscript->GetAI = GetAI_boss_timmy_the_cruel; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 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 *c) : ScriptedAI(c) {Reset();} + + uint32 RavenousClaw_Timer; + bool HasYelled; + + void Reset() + { + RavenousClaw_Timer = 10000; + HasYelled = false; + } + + void Aggro(Unit *who) + { + } + + void MoveInLineOfSight(Unit *who) + { + 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(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!HasYelled) + { + DoYell(SAY_SPAWN,LANG_UNIVERSAL,NULL); + HasYelled = true; + } + + //Begin melee attack if we are within range + DoStartAttackAndMovement(who); + } + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //RavenousClaw + if (RavenousClaw_Timer < diff) + { + //Cast + DoCast(m_creature->getVictim(),SPELL_RAVENOUSCLAW); + //15 seconds until we should cast this again + RavenousClaw_Timer = 15000; + }else RavenousClaw_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_timmy_the_cruel(Creature *_Creature) +{ + return new boss_timmy_the_cruelAI (_Creature); +} + + +void AddSC_boss_timmy_the_cruel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_timmy_the_cruel"; + newscript->GetAI = GetAI_boss_timmy_the_cruel; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/def_stratholme.h b/src/bindings/scripts/scripts/zone/stratholme/def_stratholme.h index 27c181a77f5..26283d7b0fd 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/def_stratholme.h +++ b/src/bindings/scripts/scripts/zone/stratholme/def_stratholme.h @@ -1,14 +1,14 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software licensed under GPL version 2 -* Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_STRATHOLME_H -#define DEF_STRATHOLME_H - -#define TYPE_SH_AELMAR 1 -#define TYPE_SH_CATHELA 2 -#define TYPE_SH_GREGOR 3 -#define TYPE_SH_NEMAS 4 -#define TYPE_SH_VICAR 5 -#define TYPE_SH_QUEST 6 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software licensed under GPL version 2 +* Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_STRATHOLME_H +#define DEF_STRATHOLME_H + +#define TYPE_SH_AELMAR 1 +#define TYPE_SH_CATHELA 2 +#define TYPE_SH_GREGOR 3 +#define TYPE_SH_NEMAS 4 +#define TYPE_SH_VICAR 5 +#define TYPE_SH_QUEST 6 +#endif diff --git a/src/bindings/scripts/scripts/zone/stratholme/instance_stratholme.cpp b/src/bindings/scripts/scripts/zone/stratholme/instance_stratholme.cpp index 8277d6e043a..bd93cc9ca75 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/instance_stratholme.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/instance_stratholme.cpp @@ -1,77 +1,77 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along 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_stratholme -SD%Complete: 100 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" -#include "def_stratholme.h" - -struct MANGOS_DLL_DECL instance_stratholme : public ScriptedInstance -{ - instance_stratholme(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - bool IsSilverHandDead[5]; - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case TYPE_SH_AELMAR: - IsSilverHandDead[0] = (data) ? true : false; - break; - case TYPE_SH_CATHELA: - IsSilverHandDead[1] = (data) ? true : false; - break; - case TYPE_SH_GREGOR: - IsSilverHandDead[2] = (data) ? true : false; - break; - case TYPE_SH_NEMAS: - IsSilverHandDead[3] = (data) ? true : false; - break; - case TYPE_SH_VICAR: - IsSilverHandDead[4] = (data) ? true : false; - break; - } - } - - uint32 GetData(uint32 type) - { - if(type == TYPE_SH_QUEST) - if(IsSilverHandDead[0] && IsSilverHandDead[1] && IsSilverHandDead[2] && IsSilverHandDead[3] && IsSilverHandDead[4]) - return true; - - return false; - } -}; - -InstanceData* GetInstanceData_instance_stratholme(Map* map) -{ - return new instance_stratholme(map); -} - -void AddSC_instance_stratholme() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_stratholme"; - newscript->GetInstanceData = GetInstanceData_instance_stratholme; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along 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_stratholme +SD%Complete: 100 +SDComment: +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" +#include "def_stratholme.h" + +struct MANGOS_DLL_DECL instance_stratholme : public ScriptedInstance +{ + instance_stratholme(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + bool IsSilverHandDead[5]; + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case TYPE_SH_AELMAR: + IsSilverHandDead[0] = (data) ? true : false; + break; + case TYPE_SH_CATHELA: + IsSilverHandDead[1] = (data) ? true : false; + break; + case TYPE_SH_GREGOR: + IsSilverHandDead[2] = (data) ? true : false; + break; + case TYPE_SH_NEMAS: + IsSilverHandDead[3] = (data) ? true : false; + break; + case TYPE_SH_VICAR: + IsSilverHandDead[4] = (data) ? true : false; + break; + } + } + + uint32 GetData(uint32 type) + { + if(type == TYPE_SH_QUEST) + if(IsSilverHandDead[0] && IsSilverHandDead[1] && IsSilverHandDead[2] && IsSilverHandDead[3] && IsSilverHandDead[4]) + return true; + + return false; + } +}; + +InstanceData* GetInstanceData_instance_stratholme(Map* map) +{ + return new instance_stratholme(map); +} + +void AddSC_instance_stratholme() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_stratholme"; + newscript->GetInstanceData = GetInstanceData_instance_stratholme; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/stratholme/stratholme.cpp b/src/bindings/scripts/scripts/zone/stratholme/stratholme.cpp index 33e88bc04be..d5f7fc85831 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/stratholme.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/stratholme.cpp @@ -1,335 +1,335 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* ScriptData -SDName: Stratholme -SD%Complete: 100 -SDComment: trash mobs for strat. Simple AI mobs converted to EAI (except Mindless Skeleton and Thuzadin Acolyte) -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" -#include "../../creature/simple_ai.h" - -/*###### -## mob_freed_soul -######*/ - -//Possibly more of these quotes around. -#define SAY_ZAPPED0 "Thanks to Egan" -#define SAY_ZAPPED1 "Rivendare must die" -#define SAY_ZAPPED2 "Who you gonna call?" -#define SAY_ZAPPED3 "Don't cross those beams!" - -struct MANGOS_DLL_DECL mob_freed_soulAI : public ScriptedAI -{ - mob_freed_soulAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - - switch (rand()%4) - { - case 0: - DoSay(SAY_ZAPPED0,LANG_UNIVERSAL,NULL); - break; - case 1: - DoSay(SAY_ZAPPED1,LANG_UNIVERSAL,NULL); - break; - case 2: - DoSay(SAY_ZAPPED2,LANG_UNIVERSAL,NULL); - break; - case 3: - DoSay(SAY_ZAPPED3,LANG_UNIVERSAL,NULL); - break; - } - } - - void Aggro(Unit* who) - { - } -}; -CreatureAI* GetAI_mob_freed_soul(Creature *_Creature) -{ - return new mob_freed_soulAI (_Creature); -} -/*###### -## mob_restless_soul -######*/ - -struct MANGOS_DLL_DECL mob_restless_soulAI : public ScriptedAI -{ - mob_restless_soulAI(Creature *c) : ScriptedAI(c) {Reset();} - - Unit* PlayerHolder; - uint32 Die_Timer; - bool OkToDie; - - void Reset() - { - Die_Timer = 10000; - OkToDie = false; - - PlayerHolder = NULL; - } - - void Aggro(Unit* who) - { - } - - void SummonFreedSoul(Unit* victim) - { - int Rand; - int RandX; - int RandY; - - Rand = rand()%1; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%1; - switch (rand()%2) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - DoSpawnCreature(11136, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 300000); - } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if (caster->GetTypeId() == TYPEID_PLAYER) - { - if(!PlayerHolder && !OkToDie && spell->Id == 17368 && ((Player*)caster)->GetQuestStatus(5282) == QUEST_STATUS_INCOMPLETE) - { - PlayerHolder = caster; - OkToDie = true; - Die_Timer = 5000; - } - } - return; - } - - void JustDied(Unit* Killer) - { - if (Killer->GetTypeId() == TYPEID_PLAYER) - { - //check quest status - if(PlayerHolder == ((Player*)Killer) && ((Player*)Killer)->GetQuestStatus(5282) == QUEST_STATUS_INCOMPLETE) - { - SummonFreedSoul(m_creature->getVictim()); - } - } - } - - void UpdateAI(const uint32 diff) - { - if (PlayerHolder && OkToDie && Die_Timer < diff) - { - PlayerHolder->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - else Die_Timer -= diff; - - return; - } -}; -CreatureAI* GetAI_mob_restless_soul(Creature *_Creature) -{ - return new mob_restless_soulAI (_Creature); -} - -/*###### -## mobs_spectral_ghostly_citizen -######*/ - -struct MANGOS_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI -{ - mobs_spectral_ghostly_citizenAI(Creature *c) : ScriptedAI(c) {Reset();} - - Unit* PlayerHolder; - uint32 Die_Timer; - bool OkToDie; - - void Reset() - { - Die_Timer = 5000; - OkToDie = false; - PlayerHolder = NULL; - } - - void Aggro(Unit* who) - { - } - - void SummonRestlessSoul(Unit* victim) - { - int Rand; - int RandX; - int RandY; - - Rand = rand()%7; - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%7; - switch (rand()%2) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - DoSpawnCreature(11122, RandX, RandY, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 600000); - } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if (caster->GetTypeId() == TYPEID_PLAYER) - { - if(!PlayerHolder && !OkToDie && spell->Id == 17368 && ((Player*)caster)->GetQuestStatus(5282) == QUEST_STATUS_INCOMPLETE) - { - PlayerHolder = caster; - OkToDie = true; - Die_Timer = 5000; - } - } - return; - } - - void JustDied(Unit* Killer) - { - if (Killer->GetTypeId() == TYPEID_PLAYER) - { - //check quest status - if(PlayerHolder == ((Player*)Killer) && ((Player*)Killer)->GetQuestStatus(5282) == QUEST_STATUS_INCOMPLETE) - { - SummonRestlessSoul(m_creature->getVictim()); //always one - if (rand()%100 < 90) SummonRestlessSoul(m_creature->getVictim()); //90% a second - if (rand()%100 < 50) SummonRestlessSoul(m_creature->getVictim()); //50% a third - if (rand()%100 < 30) SummonRestlessSoul(m_creature->getVictim()); //30% a fourth - } - } - } - - void UpdateAI(const uint32 diff) - { - if (PlayerHolder && OkToDie && Die_Timer < diff) - { - PlayerHolder->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - else Die_Timer -= diff; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_mobs_spectral_ghostly_citizen(Creature *_Creature) -{ - return new mobs_spectral_ghostly_citizenAI (_Creature); -} -bool ReciveEmote_mobs_spectral_ghostly_citizen(Player *player, Creature *_Creature, uint32 emote) -{ - _Creature->HandleEmoteCommand(emote); - - if (emote == TEXTEMOTE_DANCE) - ((mobs_spectral_ghostly_citizenAI*)_Creature->AI())->EnterEvadeMode(); - - return true; -} - -/*###### -## mob_mindless_skeleton -######*/ - -CreatureAI* GetAI_mob_mindless_skeleton(Creature *_Creature) -{ - SimpleAI* ai = new SimpleAI (_Creature); - - //dazed - ai->Spell[0].Enabled = true; - ai->Spell[0].Spell_Id = 13496; - ai->Spell[0].Cooldown = 15000; - ai->Spell[0].First_Cast = 3000; - ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; - - ai->EnterEvadeMode(); - - return ai; -} - -/*###### -## mob_thuzadin_acolyte -######*/ - -CreatureAI* GetAI_mob_thuzadin_acolyte(Creature *_Creature) -{ - SimpleAI* ai = new SimpleAI (_Creature); - - //dazed - ai->Spell[0].Enabled = true; - ai->Spell[0].Spell_Id = 13496; - ai->Spell[0].Cooldown = 15000; - ai->Spell[0].First_Cast = 1000; - ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; - - ai->EnterEvadeMode(); - - return ai; -} - -/*###### -## -######*/ - -void AddSC_stratholme() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_freed_soul"; - newscript->GetAI = GetAI_mob_freed_soul; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_restless_soul"; - newscript->GetAI = GetAI_mob_restless_soul; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mobs_spectral_ghostly_citizen"; - newscript->GetAI = GetAI_mobs_spectral_ghostly_citizen; - newscript->pReceiveEmote = &ReciveEmote_mobs_spectral_ghostly_citizen; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_mindless_skeleton"; - newscript->GetAI = GetAI_mob_mindless_skeleton; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_thuzadin_acolyte"; - newscript->GetAI = GetAI_mob_thuzadin_acolyte; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ScriptData +SDName: Stratholme +SD%Complete: 100 +SDComment: trash mobs for strat. Simple AI mobs converted to EAI (except Mindless Skeleton and Thuzadin Acolyte) +SDCategory: Stratholme +EndScriptData */ + +#include "precompiled.h" +#include "../../creature/simple_ai.h" + +/*###### +## mob_freed_soul +######*/ + +//Possibly more of these quotes around. +#define SAY_ZAPPED0 "Thanks to Egan" +#define SAY_ZAPPED1 "Rivendare must die" +#define SAY_ZAPPED2 "Who you gonna call?" +#define SAY_ZAPPED3 "Don't cross those beams!" + +struct MANGOS_DLL_DECL mob_freed_soulAI : public ScriptedAI +{ + mob_freed_soulAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + + switch (rand()%4) + { + case 0: + DoSay(SAY_ZAPPED0,LANG_UNIVERSAL,NULL); + break; + case 1: + DoSay(SAY_ZAPPED1,LANG_UNIVERSAL,NULL); + break; + case 2: + DoSay(SAY_ZAPPED2,LANG_UNIVERSAL,NULL); + break; + case 3: + DoSay(SAY_ZAPPED3,LANG_UNIVERSAL,NULL); + break; + } + } + + void Aggro(Unit* who) + { + } +}; +CreatureAI* GetAI_mob_freed_soul(Creature *_Creature) +{ + return new mob_freed_soulAI (_Creature); +} +/*###### +## mob_restless_soul +######*/ + +struct MANGOS_DLL_DECL mob_restless_soulAI : public ScriptedAI +{ + mob_restless_soulAI(Creature *c) : ScriptedAI(c) {Reset();} + + Unit* PlayerHolder; + uint32 Die_Timer; + bool OkToDie; + + void Reset() + { + Die_Timer = 10000; + OkToDie = false; + + PlayerHolder = NULL; + } + + void Aggro(Unit* who) + { + } + + void SummonFreedSoul(Unit* victim) + { + int Rand; + int RandX; + int RandY; + + Rand = rand()%1; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%1; + switch (rand()%2) + { + case 0: RandY = 0 - Rand; break; + case 1: RandY = 0 + Rand; break; + } + Rand = 0; + DoSpawnCreature(11136, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 300000); + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (caster->GetTypeId() == TYPEID_PLAYER) + { + if(!PlayerHolder && !OkToDie && spell->Id == 17368 && ((Player*)caster)->GetQuestStatus(5282) == QUEST_STATUS_INCOMPLETE) + { + PlayerHolder = caster; + OkToDie = true; + Die_Timer = 5000; + } + } + return; + } + + void JustDied(Unit* Killer) + { + if (Killer->GetTypeId() == TYPEID_PLAYER) + { + //check quest status + if(PlayerHolder == ((Player*)Killer) && ((Player*)Killer)->GetQuestStatus(5282) == QUEST_STATUS_INCOMPLETE) + { + SummonFreedSoul(m_creature->getVictim()); + } + } + } + + void UpdateAI(const uint32 diff) + { + if (PlayerHolder && OkToDie && Die_Timer < diff) + { + PlayerHolder->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + else Die_Timer -= diff; + + return; + } +}; +CreatureAI* GetAI_mob_restless_soul(Creature *_Creature) +{ + return new mob_restless_soulAI (_Creature); +} + +/*###### +## mobs_spectral_ghostly_citizen +######*/ + +struct MANGOS_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI +{ + mobs_spectral_ghostly_citizenAI(Creature *c) : ScriptedAI(c) {Reset();} + + Unit* PlayerHolder; + uint32 Die_Timer; + bool OkToDie; + + void Reset() + { + Die_Timer = 5000; + OkToDie = false; + PlayerHolder = NULL; + } + + void Aggro(Unit* who) + { + } + + void SummonRestlessSoul(Unit* victim) + { + int Rand; + int RandX; + int RandY; + + Rand = rand()%7; + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = rand()%7; + switch (rand()%2) + { + case 0: RandY = 0 - Rand; break; + case 1: RandY = 0 + Rand; break; + } + Rand = 0; + DoSpawnCreature(11122, RandX, RandY, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 600000); + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (caster->GetTypeId() == TYPEID_PLAYER) + { + if(!PlayerHolder && !OkToDie && spell->Id == 17368 && ((Player*)caster)->GetQuestStatus(5282) == QUEST_STATUS_INCOMPLETE) + { + PlayerHolder = caster; + OkToDie = true; + Die_Timer = 5000; + } + } + return; + } + + void JustDied(Unit* Killer) + { + if (Killer->GetTypeId() == TYPEID_PLAYER) + { + //check quest status + if(PlayerHolder == ((Player*)Killer) && ((Player*)Killer)->GetQuestStatus(5282) == QUEST_STATUS_INCOMPLETE) + { + SummonRestlessSoul(m_creature->getVictim()); //always one + if (rand()%100 < 90) SummonRestlessSoul(m_creature->getVictim()); //90% a second + if (rand()%100 < 50) SummonRestlessSoul(m_creature->getVictim()); //50% a third + if (rand()%100 < 30) SummonRestlessSoul(m_creature->getVictim()); //30% a fourth + } + } + } + + void UpdateAI(const uint32 diff) + { + if (PlayerHolder && OkToDie && Die_Timer < diff) + { + PlayerHolder->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + else Die_Timer -= diff; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_mobs_spectral_ghostly_citizen(Creature *_Creature) +{ + return new mobs_spectral_ghostly_citizenAI (_Creature); +} +bool ReciveEmote_mobs_spectral_ghostly_citizen(Player *player, Creature *_Creature, uint32 emote) +{ + _Creature->HandleEmoteCommand(emote); + + if (emote == TEXTEMOTE_DANCE) + ((mobs_spectral_ghostly_citizenAI*)_Creature->AI())->EnterEvadeMode(); + + return true; +} + +/*###### +## mob_mindless_skeleton +######*/ + +CreatureAI* GetAI_mob_mindless_skeleton(Creature *_Creature) +{ + SimpleAI* ai = new SimpleAI (_Creature); + + //dazed + ai->Spell[0].Enabled = true; + ai->Spell[0].Spell_Id = 13496; + ai->Spell[0].Cooldown = 15000; + ai->Spell[0].First_Cast = 3000; + ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; + + ai->EnterEvadeMode(); + + return ai; +} + +/*###### +## mob_thuzadin_acolyte +######*/ + +CreatureAI* GetAI_mob_thuzadin_acolyte(Creature *_Creature) +{ + SimpleAI* ai = new SimpleAI (_Creature); + + //dazed + ai->Spell[0].Enabled = true; + ai->Spell[0].Spell_Id = 13496; + ai->Spell[0].Cooldown = 15000; + ai->Spell[0].First_Cast = 1000; + ai->Spell[0].Cast_Target_Type = CAST_HOSTILE_TARGET; + + ai->EnterEvadeMode(); + + return ai; +} + +/*###### +## +######*/ + +void AddSC_stratholme() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_freed_soul"; + newscript->GetAI = GetAI_mob_freed_soul; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_restless_soul"; + newscript->GetAI = GetAI_mob_restless_soul; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mobs_spectral_ghostly_citizen"; + newscript->GetAI = GetAI_mobs_spectral_ghostly_citizen; + newscript->pReceiveEmote = &ReciveEmote_mobs_spectral_ghostly_citizen; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_mindless_skeleton"; + newscript->GetAI = GetAI_mob_mindless_skeleton; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_thuzadin_acolyte"; + newscript->GetAI = GetAI_mob_thuzadin_acolyte; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_brutallus.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_brutallus.cpp index 36a8238cf45..fdd57ce1ac7 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_brutallus.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_brutallus.cpp @@ -1,188 +1,188 @@ -/* Copyright © 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Brutallus -SD%Complete: 80 -SDComment: Needs intro. Talk to the dragon. -EndScriptData */ - -#include "precompiled.h" -#include "def_sunwell_plateau.h" - -// Yells and Sounds used by boss. -#define YELL_AGGRO "Ahh! More lambs to the slaughter!" -#define SOUND_AGGRO 12463 - -#define YELL_BERSERK "So much for a real challenge... Die!" -#define SOUND_BERSERK 12470 - -#define YELL_KILL1 "Perish, insect!" -#define SOUND_KILL1 12464 - -#define YELL_KILL2 "You are meat!" -#define SOUND_KILL2 12465 - -#define YELL_KILL3 "Too easy!" -#define SOUND_KILL3 12466 - -#define YELL_CHARGE "I will crush you!" //I think it use this for stomp. No? -#define SOUND_CHARGE 12460 - -#define YELL_DEATH "Gah! Well done... Now... this gets... interesting..." -#define SOUND_DEATH 12471 - -#define YELL_LOVE1 "Bring the fight to me!" -#define SOUND_LOVE1 12467 - -#define YELL_LOVE2 "Another day, another glorious battle!" -#define SOUND_LOVE2 12468 - -#define YELL_LOVE3 "I live for this!" -#define SOUND_LOVE3 12469 - -// Boss spells. -#define METEOR_SLASH 45150 -#define BURN 46394 -#define STOMP 45185 -#define BERSERK 26662 - -struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI -{ - boss_brutallusAI(Creature *c) : ScriptedAI(c) { Reset(); } - - uint32 SlashTimer; - uint32 BurnTimer; - uint32 StompTimer; - uint32 BerserkTimer; - uint32 LoveTimer; - - void Reset() - { - SlashTimer = 11000; - StompTimer = 30000; - BurnTimer = 60000; - BerserkTimer = 360000; - LoveTimer = 10000 + rand()%7000; - } - - void Aggro(Unit *who) - { - DoYell(YELL_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%3) - { - case 0: - DoYell(YELL_KILL1,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL1); - break; - case 1: - DoYell(YELL_KILL2,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL2); - break; - case 2: - DoYell(YELL_KILL3,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL3); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(YELL_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if(LoveTimer < diff) - { - switch(rand()%3) - { - case 0: - DoYell(YELL_LOVE1,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_LOVE1); - break; - case 1: - DoYell(YELL_LOVE2,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_LOVE2); - break; - case 2: - DoYell(YELL_LOVE3,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_LOVE3); - break; - } - LoveTimer = 15000 + rand()%8000; - }else LoveTimer -= diff; - - if(SlashTimer < diff) - { - DoCast(m_creature->getVictim(),METEOR_SLASH); - SlashTimer = 11000; - }else SlashTimer -= diff; - - if(StompTimer < diff) - { - DoYell(YELL_CHARGE,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CHARGE); - Unit *Target = m_creature->getVictim(); - DoCast(Target,STOMP); - if(Target->HasAura(45151,0)) Target->RemoveAura(45151,0); - StompTimer = 30000; - }else StompTimer -= diff; - - if(BurnTimer < diff) - { - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); - DoCast(target,BURN); - BurnTimer = 60000; - } - else BurnTimer -= diff; - - DoMeleeAttackIfReady(); - - if(BerserkTimer < diff) - { - DoYell(YELL_BERSERK,LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_BERSERK); - DoCast(m_creature,BERSERK); - BerserkTimer = 20000; - } - else BerserkTimer -= diff; - } - -}; - -CreatureAI* GetAI_boss_brutallus(Creature *_Creature) -{ - return new boss_brutallusAI (_Creature); -} - -void AddSC_boss_brutallus() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_brutallus"; - newscript->GetAI = GetAI_boss_brutallus; - m_scripts[nrscripts++] = newscript; -} +/* Copyright © 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Brutallus +SD%Complete: 80 +SDComment: Needs intro. Talk to the dragon. +EndScriptData */ + +#include "precompiled.h" +#include "def_sunwell_plateau.h" + +// Yells and Sounds used by boss. +#define YELL_AGGRO "Ahh! More lambs to the slaughter!" +#define SOUND_AGGRO 12463 + +#define YELL_BERSERK "So much for a real challenge... Die!" +#define SOUND_BERSERK 12470 + +#define YELL_KILL1 "Perish, insect!" +#define SOUND_KILL1 12464 + +#define YELL_KILL2 "You are meat!" +#define SOUND_KILL2 12465 + +#define YELL_KILL3 "Too easy!" +#define SOUND_KILL3 12466 + +#define YELL_CHARGE "I will crush you!" //I think it use this for stomp. No? +#define SOUND_CHARGE 12460 + +#define YELL_DEATH "Gah! Well done... Now... this gets... interesting..." +#define SOUND_DEATH 12471 + +#define YELL_LOVE1 "Bring the fight to me!" +#define SOUND_LOVE1 12467 + +#define YELL_LOVE2 "Another day, another glorious battle!" +#define SOUND_LOVE2 12468 + +#define YELL_LOVE3 "I live for this!" +#define SOUND_LOVE3 12469 + +// Boss spells. +#define METEOR_SLASH 45150 +#define BURN 46394 +#define STOMP 45185 +#define BERSERK 26662 + +struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI +{ + boss_brutallusAI(Creature *c) : ScriptedAI(c) { Reset(); } + + uint32 SlashTimer; + uint32 BurnTimer; + uint32 StompTimer; + uint32 BerserkTimer; + uint32 LoveTimer; + + void Reset() + { + SlashTimer = 11000; + StompTimer = 30000; + BurnTimer = 60000; + BerserkTimer = 360000; + LoveTimer = 10000 + rand()%7000; + } + + void Aggro(Unit *who) + { + DoYell(YELL_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%3) + { + case 0: + DoYell(YELL_KILL1,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL1); + break; + case 1: + DoYell(YELL_KILL2,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL2); + break; + case 2: + DoYell(YELL_KILL3,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL3); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(YELL_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if(LoveTimer < diff) + { + switch(rand()%3) + { + case 0: + DoYell(YELL_LOVE1,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_LOVE1); + break; + case 1: + DoYell(YELL_LOVE2,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_LOVE2); + break; + case 2: + DoYell(YELL_LOVE3,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_LOVE3); + break; + } + LoveTimer = 15000 + rand()%8000; + }else LoveTimer -= diff; + + if(SlashTimer < diff) + { + DoCast(m_creature->getVictim(),METEOR_SLASH); + SlashTimer = 11000; + }else SlashTimer -= diff; + + if(StompTimer < diff) + { + DoYell(YELL_CHARGE,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CHARGE); + Unit *Target = m_creature->getVictim(); + DoCast(Target,STOMP); + if(Target->HasAura(45151,0)) Target->RemoveAura(45151,0); + StompTimer = 30000; + }else StompTimer -= diff; + + if(BurnTimer < diff) + { + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); + DoCast(target,BURN); + BurnTimer = 60000; + } + else BurnTimer -= diff; + + DoMeleeAttackIfReady(); + + if(BerserkTimer < diff) + { + DoYell(YELL_BERSERK,LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_BERSERK); + DoCast(m_creature,BERSERK); + BerserkTimer = 20000; + } + else BerserkTimer -= diff; + } + +}; + +CreatureAI* GetAI_boss_brutallus(Creature *_Creature) +{ + return new boss_brutallusAI (_Creature); +} + +void AddSC_boss_brutallus() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_brutallus"; + newscript->GetAI = GetAI_boss_brutallus; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kalecgos.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kalecgos.cpp index 6b35c91ac58..15fc4efd936 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kalecgos.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kalecgos.cpp @@ -1,657 +1,657 @@ -/* Copyright ? 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Kalecgos -SD%Complete: 0 -SDComment: VERIFY SCRIPT -SDCategory: Sunwell Plateau -EndScriptData */ - -#include "precompiled.h" -#include "WorldPacket.h" -#include "def_sunwell_plateau.h" - -#define SAY_KALECGOS_AGGRO "Aggh! No longer will I be a slave to Malygos! Challenge me and you will be destroyed!" -#define SOUND_KALECGOS_AGGRO 12422 -#define SAY_KALECGOS_SPELL1 "I will purge you!" -#define SOUND_KALECGOS_SPELL1 12423 -#define SAY_KALECGOS_SPELL2 "Your pain has only begun!" -#define SOUND_KALECGOS_SPELL2 12424 -#define SAY_KALECGOS_SLAY1 "In the name of Kil'jaeden!" -#define SOUND_KALECGOS_SLAY1 12425 -#define SAY_KALECGOS_SLAY2 "You were warned!" -#define SOUND_KALECGOS_SLAY2 12426 -#define SAY_KALECGOS_ENRAGE "My awakening is complete! You shall all perish!" -#define SOUND_KALECGOS_ENRAGE 12427 - -#define SAY_SATH_AGGRO "There will be no reprieve. My work here is nearly finished." -#define SOUND_SATH_AGGRO 12451 -#define SAY_SATH_DEATH "I'm... never on... the losing... side..." -#define SOUND_SATH_DEATH 12452 -#define SAY_SATH_SPELL1 "Your misery is my delight!" -#define SOUND_SATH_SPELL1 12453 -#define SAY_SATH_SPELL2 "I will watch you bleed!" -#define SOUND_SATH_SPELL2 12454 -#define SAY_SATH_SLAY1 "Pitious mortal!" -#define SOUND_SATH_SLAY1 12455 -#define SAY_SATH_SLAY2 "Haven't you heard? I always win!" -#define SOUND_SATH_SLAY2 12456 -#define SAY_SATH_ENRAGE "I have toyed with you long enough!" -#define SOUND_SATH_ENRAGE 12457 - -#define SAY_KALEC_AGGRO "I need... your help... Cannot... resist him... much longer..." -#define SOUND_KALEC_AGGRO 12428 -#define SAY_KALEC_NEAR_DEATH "Aaahhh! Help me, before I lose my mind!" -#define SOUND_KALEC_NEAR_DEATH 12429 - //??? -#define SAY_KALEC_NEAR_DEATH2 "Hurry! There is not much of me left!" -#define SOUND_KALEC_NEAR_DEATH2 12430 -#define SAY_KALEC_PLRWIN "I am forever in your debt. Once we have triumphed over Kil'jaeden, this entire world will be in your debt as well." -#define SOUND_KALEC_PLRWIN 12431 - -#define SPELL_SPECTRAL_EXHAUSTION 44867 -#define SPELL_TELEPORT_SPECTRAL_REALM 46019 -#define SPELL_SPECTRAL_REALM 46021 - -#define NOTIFY_SPECTRALLY_EXHAUSTED "Your body is too exhausted to travel to the Spectral Realm." -#define ERROR_INST_DATA "SD2: Instance Data not set properly for Sunwell Plateau. Kalecgos Encounter will be buggy." -#define ERROR_INST_DATA_PLR "SD2 ERROR: Instance Data not set properly for Sunwell Plateau. Please report this to your administrator." -#define ERROR_UNABLE_TO_TELEPORT "SD2: Unable to select target for Spectral Blast. Threatlist has too few players." -#define ERROR_MISSING_TELEPORT_GUID "SD2: [Kalecgos] Invalid TeleportTargetGUID. Unable to teleport player." -#define ERROR_KALECGOS_NOT_FOUND "SD2: Unable to create pointer to Kalecgos from Sathrovarr." - -#define KALECGOS_ARENA_X 1704.34 -#define KALECGOS_ARENA_Y 928.17 -#define KALECGOS_ARENA_Z 53.08 - -/*** Kalecgos ****/ -#define SPELL_SPECTRAL_BLAST 44866 -#define SPELL_ARCANE_BUFFET 45018 -#define SPELL_FROST_BREATH 44799 -#define SPELL_HEROIC_STRIKE 45026 -#define SPELL_REVITALIZE 45027 -#define SPELL_TAIL_LASH 45122 -#define SPELL_TRANSFORM_KALEC 45027 -#define SPELL_CRAZED_RAGE 44806 -uint32 WildMagic[]= { 44978, 45001, 45002, 45004, 45006, 45010 }; - -/*** Sathrovarr ***/ -#define SPELL_CORRUPTING_STRIKE 45029 -#define SPELL_CURSE_OF_BOUNDLESS_AGONY 45032 -#define SPELL_SHADOW_BOLT_VOLLEY 45031 - -/*** Misc ***/ -#define SPELL_BANISH 44836 - -void TeleportToInnerVeil(Player* plr) -{ - if(plr->HasAura(SPELL_SPECTRAL_EXHAUSTION, 0)) - { - plr->GetSession()->SendNotification(NOTIFY_SPECTRALLY_EXHAUSTED); - return; - } - - ScriptedInstance* pInstance = ((ScriptedInstance*)plr->GetInstanceData()); - if(!pInstance) - { - error_log(ERROR_INST_DATA); - plr->GetSession()->SendNotification(ERROR_INST_DATA_PLR); - return; - } - - pInstance->SetData64(DATA_PLAYER_SPECTRAL_REALM, plr->GetGUID()); - // Remove the player from Kalecgos' Threat List - Creature* Kalecgos = ((Creature*)Unit::GetUnit(*plr, pInstance->GetData64(DATA_KALECGOS_DRAGON))); - if(Kalecgos) - { - HostilReference* ref = Kalecgos->getThreatManager().getOnlineContainer().getReferenceByTarget(plr); - if(ref) - ref->removeReference(); - } - - // Add the player to Sathrovarr's Threat List - Creature* Sathrovarr = ((Creature*)Unit::GetUnit(*plr, pInstance->GetData64(DATA_SATHROVARR))); - if(Sathrovarr) - Sathrovarr->AddThreat(plr, 1.0f); - - // 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) - plr->CastSpell(plr, SPELL_SPECTRAL_REALM, true); - plr->CastSpell(plr, SPELL_TELEPORT_SPECTRAL_REALM, true); -} - -bool GOHello_GO_Spectral_Portal(Player* plr, GameObject* go) -{ - TeleportToInnerVeil(plr); - - return true; -} - -struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI -{ - boss_kalecgosAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint64 TeleportTargetGUID; - - uint32 ArcaneBuffetTimer; - uint32 FrostBreathTimer; - uint32 WildMagicTimer; - uint32 SpectralBlastTimer; - uint32 SpectralTeleportTimer; - uint32 ForceFieldTimer; - uint32 ExitTimer; - - bool LockedArena; - bool Uncorrupted; - bool Banished; - bool Checked; - bool Enraged; - - void Reset() - { - TeleportTargetGUID = 0; - - // TODO: Fix timers - ArcaneBuffetTimer = 8000; - FrostBreathTimer = 24000; - WildMagicTimer = 18000; - SpectralBlastTimer = 30000; - SpectralTeleportTimer = SpectralBlastTimer + 2000; - - ForceFieldTimer = 20000; - ExitTimer = 0; - - LockedArena = false; - Uncorrupted = false; - Banished = false; - Checked = false; - Enraged = false; - - // Reset Sathrovarr too - if(pInstance) - if(Creature* Sath = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_SATHROVARR)))) - Sath->AI()->EnterEvadeMode(); - } - - void Aggro(Unit* who) - { - DoYell(SAY_KALECGOS_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KALECGOS_AGGRO); - - if(pInstance) - pInstance->SetData(DATA_KALECGOS_EVENT, IN_PROGRESS); - } - - void DamageTaken(Unit* done_by, uint32 &damage) - { - if(damage > m_creature->GetHealth() && done_by != m_creature) - { - if(!Uncorrupted) - { - damage = 0; - Banished = true; - DoCast(m_creature, SPELL_BANISH, true); - m_creature->GetMotionMaster()->MoveIdle(); - } - else - { - damage = 0; - BeginOutro(); - } - } - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KALECGOS_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_KALECGOS_SLAY1); - break; - case 1: - DoYell(SAY_KALECGOS_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_KALECGOS_SLAY2); - break; - } - } - - void BeginOutro() - { - debug_log("SD2: KALEC: Beginning Outro"); - - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - Unit* Sathrovarr = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_SATHROVARR)); - if(Sathrovarr) - { - Sathrovarr->DealDamage(Sathrovarr, Sathrovarr->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - Sathrovarr->Relocate(KALECGOS_ARENA_X, KALECGOS_ARENA_Y, KALECGOS_ARENA_Z); - Sathrovarr->SendMonsterMove(KALECGOS_ARENA_X, KALECGOS_ARENA_Y, KALECGOS_ARENA_Z, 0, 0, 0); - } - - Creature* Kalec = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_KALECGOS_HUMAN))); - if(Kalec) - { - Kalec->DeleteThreatList(); - Kalec->SetVisibility(VISIBILITY_OFF); - } - - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->setFaction(35); - } - - void MovementInform(uint32 type, uint32 id) - { - if(type != POINT_MOTION_TYPE) - return; - - if(id) - { - if(pInstance) - { - GameObject* ForceField = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GO_FORCEFIELD)); - if(ForceField) - ForceField->SetGoState(1); - - pInstance->SetData(DATA_KALECGOS_EVENT, DONE); - } - else error_log(ERROR_INST_DATA); - - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->getVictim() || !m_creature->SelectHostilTarget() || Banished) - return; - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !Enraged) - { - Unit* Sathrovarr = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_SATHROVARR)); - if(Sathrovarr) - Sathrovarr->CastSpell(Sathrovarr, SPELL_CRAZED_RAGE, true); - DoCast(m_creature, SPELL_CRAZED_RAGE, true); - Enraged = true; - } - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 1) && !Checked) - { - Checked = true; - - if(!Uncorrupted) - { - Banished = true; - DoCast(m_creature, SPELL_BANISH, true); - m_creature->GetMotionMaster()->MoveIdle(); - } - else - BeginOutro(); - } - - if(ExitTimer) - if(ExitTimer <= diff) - { - debug_log("SD2: KALEC: Exiting the arena"); - DoYell(SAY_KALEC_PLRWIN, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KALEC_PLRWIN); - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); - float x, y, z; - float iniX, iniY, iniZ; - m_creature->GetPosition(iniX, iniY, iniZ); - m_creature->GetRandomPoint(iniX, iniY, iniZ, 30, x, y, z); - z = 70; - m_creature->GetMotionMaster()->MovePoint(1, x, y, z); - }else ExitTimer -= diff; - - if(!LockedArena) - if(ForceFieldTimer < diff) - { - if(pInstance) - { - GameObject* ForceField = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GO_FORCEFIELD)); - if(ForceField) - ForceField->SetUInt32Value(GAMEOBJECT_STATE, 0); - - LockedArena = true; - }else error_log(ERROR_INST_DATA); - }else ForceFieldTimer -= diff; - - if(ArcaneBuffetTimer < diff) - { - if(rand()%3 == 0) - { - DoYell(SAY_KALECGOS_SPELL1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KALECGOS_SPELL1); - } - DoCast(m_creature->getVictim(), SPELL_ARCANE_BUFFET); - ArcaneBuffetTimer = 20000; - }else ArcaneBuffetTimer -= diff; - - if(FrostBreathTimer < diff) - { - if(rand()%2 == 0) - { - DoYell(SAY_KALECGOS_SPELL2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KALECGOS_SPELL2); - } - DoCast(m_creature->getVictim(), SPELL_FROST_BREATH); - FrostBreathTimer = 25000; - }else FrostBreathTimer -= diff; - - if(WildMagicTimer < diff) - { - DoCast(m_creature->getVictim(), WildMagic[rand()%6]); - WildMagicTimer = 19000; - }else WildMagicTimer -= diff; - - if(SpectralBlastTimer < diff) - { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1)) - { - TeleportTargetGUID = target->GetGUID(); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, TeleportTargetGUID); - SpectralBlastTimer = 30000; - SpectralTeleportTimer = 2000; - } - }else SpectralBlastTimer -= diff; - - if(SpectralTeleportTimer < diff) - { - if(TeleportTargetGUID) - { - Unit* pUnit = Unit::GetUnit((*m_creature), TeleportTargetGUID); - if(pUnit) - { - pUnit->CastSpell(pUnit, SPELL_SPECTRAL_BLAST, true); - TeleportToInnerVeil((Player*)pUnit); - } - else error_log(ERROR_MISSING_TELEPORT_GUID); - } - else error_log(ERROR_MISSING_TELEPORT_GUID); - - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID()); - TeleportTargetGUID = 0; - SpectralTeleportTimer = SpectralBlastTimer + 2000; - - }else SpectralTeleportTimer -= diff; - - if(!Banished) DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI -{ - boss_sathrovarrAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 CorruptingStrikeTimer; - uint32 CurseOfBoundlessAgonyTimer; - uint32 ShadowBoltVolleyTimer; - bool Banished; - bool Enraged; - - void Reset() - { - // FIXME: Timers - CorruptingStrikeTimer = 5000; - CurseOfBoundlessAgonyTimer = 15000; - ShadowBoltVolleyTimer = 10000; - - Banished = false; - Enraged = false; - - DoCast(m_creature, SPELL_SPECTRAL_REALM, true); - } - - void Aggro(Unit* who) - { - DoYell(SAY_SATH_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SATH_AGGRO); - - Creature* Kalec = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_KALECGOS_HUMAN))); - if(Kalec) - { - m_creature->AddThreat(Kalec, 10000000.0f); - Kalec->AddThreat(m_creature, 10000000.0f); - } - } - - void DamageTaken(Unit* done_by, uint32 &damage) - { - if(damage > m_creature->GetHealth()) - { - damage = 0; - DoCast(m_creature, SPELL_BANISH, true); - Banished = true; - - DoYell(SAY_SATH_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SATH_DEATH); - - if(!pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - pInstance->SetData(DATA_SET_SPECTRAL_CHECK, 5000); - - Creature* Kalecgos = ((Creature*)Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KALECGOS_DRAGON))); - if(Kalecgos) - { - ((boss_kalecgosAI*)Kalecgos->AI())->Checked = false; - ((boss_kalecgosAI*)Kalecgos->AI())->Uncorrupted = true; - } - else error_log(ERROR_KALECGOS_NOT_FOUND); - } - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SATH_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SATH_SLAY1); - break; - case 1: - DoYell(SAY_SATH_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SATH_SLAY2); - break; - } - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->getVictim() || !m_creature->SelectHostilTarget() || Banished) - return; - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !Enraged) - { - Unit* Kalecgos = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_KALECGOS_DRAGON)); - if(Kalecgos) - Kalecgos->CastSpell(Kalecgos, SPELL_CRAZED_RAGE, true); - DoCast(m_creature, SPELL_CRAZED_RAGE, true); - Enraged = true; - } - - if(CorruptingStrikeTimer < diff) - { - if(rand()%2 == 0) - { - DoYell(SAY_SATH_SPELL2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SATH_SPELL2); - } - DoCast(m_creature->getVictim(), SPELL_CORRUPTING_STRIKE); - CorruptingStrikeTimer = 13000; - }else CorruptingStrikeTimer -= diff; - - if(CurseOfBoundlessAgonyTimer < diff) - { - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_CURSE_OF_BOUNDLESS_AGONY); - CurseOfBoundlessAgonyTimer = 35000; - DoCast(m_creature, SPELL_SPECTRAL_REALM, true); - }else CurseOfBoundlessAgonyTimer -= diff; - - if(ShadowBoltVolleyTimer < diff) - { - if(rand()%2 == 0) - { - DoYell(SAY_SATH_SPELL1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SATH_SPELL1); - } - DoCast(m_creature->getVictim(), SPELL_SHADOW_BOLT_VOLLEY); - ShadowBoltVolleyTimer = 15000; - }else ShadowBoltVolleyTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_kalecAI : public ScriptedAI -{ - boss_kalecAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 RevitalizeTimer; - uint32 HeroicStrikeTimer; - - bool HasYelled10Percent; - bool HasYelled20Percent; - - void Reset() - { - //TODO: Times! - RevitalizeTimer = 30000; - HeroicStrikeTimer = 8000; - - HasYelled10Percent = false; - HasYelled20Percent = false; - - DoCast(m_creature, SPELL_SPECTRAL_REALM, true); - } - - void Aggro(Unit* who) - { - DoYell(SAY_KALEC_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KALEC_AGGRO); - } - - void JustDied(Unit* killer) - { - // Whatever happens when Kalec (Half-elf) dies - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->getVictim() || !m_creature->SelectHostilTarget()) - return; - - if(RevitalizeTimer < diff) - { - if(pInstance) - { - Unit* pUnit = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_RANDOM_SPECTRAL_PLAYER)); - if(pUnit) - DoCast(pUnit, SPELL_REVITALIZE); - RevitalizeTimer = 30000; - } - }else RevitalizeTimer -= diff; - - if(HeroicStrikeTimer < diff) - { - DoCast(m_creature->getVictim(), SPELL_HEROIC_STRIKE); - HeroicStrikeTimer = 30000; - }else HeroicStrikeTimer -= diff; - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) && !HasYelled20Percent) - { - DoYell(SAY_KALEC_NEAR_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KALEC_NEAR_DEATH); - HasYelled20Percent = true; - } - - if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !HasYelled10Percent) - { - DoYell(SAY_KALEC_NEAR_DEATH2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KALEC_NEAR_DEATH2); - HasYelled10Percent = true; - } - } -}; - -CreatureAI* GetAI_boss_kalecgos(Creature* c) -{ - return new boss_kalecgosAI(c); -} - -CreatureAI* GetAI_boss_sathrovarr(Creature* c) -{ - return new boss_sathrovarrAI(c); -} - -CreatureAI* GetAI_boss_kalec(Creature* c) -{ - return new boss_kalecAI(c); -} - -void AddSC_boss_kalecgos() -{ - Script* newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_kalecgos; - newscript->Name = "boss_kalecgos"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_sathrovarr; - newscript->Name = "boss_sathrovarr"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->GetAI = GetAI_boss_kalec; - newscript->Name = "boss_kalec"; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->pGOHello = GOHello_GO_Spectral_Portal; - newscript->Name = "go_spectral_portal"; - m_scripts[nrscripts++] = newscript; -} +/* Copyright ? 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Kalecgos +SD%Complete: 0 +SDComment: VERIFY SCRIPT +SDCategory: Sunwell Plateau +EndScriptData */ + +#include "precompiled.h" +#include "WorldPacket.h" +#include "def_sunwell_plateau.h" + +#define SAY_KALECGOS_AGGRO "Aggh! No longer will I be a slave to Malygos! Challenge me and you will be destroyed!" +#define SOUND_KALECGOS_AGGRO 12422 +#define SAY_KALECGOS_SPELL1 "I will purge you!" +#define SOUND_KALECGOS_SPELL1 12423 +#define SAY_KALECGOS_SPELL2 "Your pain has only begun!" +#define SOUND_KALECGOS_SPELL2 12424 +#define SAY_KALECGOS_SLAY1 "In the name of Kil'jaeden!" +#define SOUND_KALECGOS_SLAY1 12425 +#define SAY_KALECGOS_SLAY2 "You were warned!" +#define SOUND_KALECGOS_SLAY2 12426 +#define SAY_KALECGOS_ENRAGE "My awakening is complete! You shall all perish!" +#define SOUND_KALECGOS_ENRAGE 12427 + +#define SAY_SATH_AGGRO "There will be no reprieve. My work here is nearly finished." +#define SOUND_SATH_AGGRO 12451 +#define SAY_SATH_DEATH "I'm... never on... the losing... side..." +#define SOUND_SATH_DEATH 12452 +#define SAY_SATH_SPELL1 "Your misery is my delight!" +#define SOUND_SATH_SPELL1 12453 +#define SAY_SATH_SPELL2 "I will watch you bleed!" +#define SOUND_SATH_SPELL2 12454 +#define SAY_SATH_SLAY1 "Pitious mortal!" +#define SOUND_SATH_SLAY1 12455 +#define SAY_SATH_SLAY2 "Haven't you heard? I always win!" +#define SOUND_SATH_SLAY2 12456 +#define SAY_SATH_ENRAGE "I have toyed with you long enough!" +#define SOUND_SATH_ENRAGE 12457 + +#define SAY_KALEC_AGGRO "I need... your help... Cannot... resist him... much longer..." +#define SOUND_KALEC_AGGRO 12428 +#define SAY_KALEC_NEAR_DEATH "Aaahhh! Help me, before I lose my mind!" +#define SOUND_KALEC_NEAR_DEATH 12429 + //??? +#define SAY_KALEC_NEAR_DEATH2 "Hurry! There is not much of me left!" +#define SOUND_KALEC_NEAR_DEATH2 12430 +#define SAY_KALEC_PLRWIN "I am forever in your debt. Once we have triumphed over Kil'jaeden, this entire world will be in your debt as well." +#define SOUND_KALEC_PLRWIN 12431 + +#define SPELL_SPECTRAL_EXHAUSTION 44867 +#define SPELL_TELEPORT_SPECTRAL_REALM 46019 +#define SPELL_SPECTRAL_REALM 46021 + +#define NOTIFY_SPECTRALLY_EXHAUSTED "Your body is too exhausted to travel to the Spectral Realm." +#define ERROR_INST_DATA "SD2: Instance Data not set properly for Sunwell Plateau. Kalecgos Encounter will be buggy." +#define ERROR_INST_DATA_PLR "SD2 ERROR: Instance Data not set properly for Sunwell Plateau. Please report this to your administrator." +#define ERROR_UNABLE_TO_TELEPORT "SD2: Unable to select target for Spectral Blast. Threatlist has too few players." +#define ERROR_MISSING_TELEPORT_GUID "SD2: [Kalecgos] Invalid TeleportTargetGUID. Unable to teleport player." +#define ERROR_KALECGOS_NOT_FOUND "SD2: Unable to create pointer to Kalecgos from Sathrovarr." + +#define KALECGOS_ARENA_X 1704.34 +#define KALECGOS_ARENA_Y 928.17 +#define KALECGOS_ARENA_Z 53.08 + +/*** Kalecgos ****/ +#define SPELL_SPECTRAL_BLAST 44866 +#define SPELL_ARCANE_BUFFET 45018 +#define SPELL_FROST_BREATH 44799 +#define SPELL_HEROIC_STRIKE 45026 +#define SPELL_REVITALIZE 45027 +#define SPELL_TAIL_LASH 45122 +#define SPELL_TRANSFORM_KALEC 45027 +#define SPELL_CRAZED_RAGE 44806 +uint32 WildMagic[]= { 44978, 45001, 45002, 45004, 45006, 45010 }; + +/*** Sathrovarr ***/ +#define SPELL_CORRUPTING_STRIKE 45029 +#define SPELL_CURSE_OF_BOUNDLESS_AGONY 45032 +#define SPELL_SHADOW_BOLT_VOLLEY 45031 + +/*** Misc ***/ +#define SPELL_BANISH 44836 + +void TeleportToInnerVeil(Player* plr) +{ + if(plr->HasAura(SPELL_SPECTRAL_EXHAUSTION, 0)) + { + plr->GetSession()->SendNotification(NOTIFY_SPECTRALLY_EXHAUSTED); + return; + } + + ScriptedInstance* pInstance = ((ScriptedInstance*)plr->GetInstanceData()); + if(!pInstance) + { + error_log(ERROR_INST_DATA); + plr->GetSession()->SendNotification(ERROR_INST_DATA_PLR); + return; + } + + pInstance->SetData64(DATA_PLAYER_SPECTRAL_REALM, plr->GetGUID()); + // Remove the player from Kalecgos' Threat List + Creature* Kalecgos = ((Creature*)Unit::GetUnit(*plr, pInstance->GetData64(DATA_KALECGOS_DRAGON))); + if(Kalecgos) + { + HostilReference* ref = Kalecgos->getThreatManager().getOnlineContainer().getReferenceByTarget(plr); + if(ref) + ref->removeReference(); + } + + // Add the player to Sathrovarr's Threat List + Creature* Sathrovarr = ((Creature*)Unit::GetUnit(*plr, pInstance->GetData64(DATA_SATHROVARR))); + if(Sathrovarr) + Sathrovarr->AddThreat(plr, 1.0f); + + // 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) + plr->CastSpell(plr, SPELL_SPECTRAL_REALM, true); + plr->CastSpell(plr, SPELL_TELEPORT_SPECTRAL_REALM, true); +} + +bool GOHello_GO_Spectral_Portal(Player* plr, GameObject* go) +{ + TeleportToInnerVeil(plr); + + return true; +} + +struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI +{ + boss_kalecgosAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint64 TeleportTargetGUID; + + uint32 ArcaneBuffetTimer; + uint32 FrostBreathTimer; + uint32 WildMagicTimer; + uint32 SpectralBlastTimer; + uint32 SpectralTeleportTimer; + uint32 ForceFieldTimer; + uint32 ExitTimer; + + bool LockedArena; + bool Uncorrupted; + bool Banished; + bool Checked; + bool Enraged; + + void Reset() + { + TeleportTargetGUID = 0; + + // TODO: Fix timers + ArcaneBuffetTimer = 8000; + FrostBreathTimer = 24000; + WildMagicTimer = 18000; + SpectralBlastTimer = 30000; + SpectralTeleportTimer = SpectralBlastTimer + 2000; + + ForceFieldTimer = 20000; + ExitTimer = 0; + + LockedArena = false; + Uncorrupted = false; + Banished = false; + Checked = false; + Enraged = false; + + // Reset Sathrovarr too + if(pInstance) + if(Creature* Sath = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_SATHROVARR)))) + Sath->AI()->EnterEvadeMode(); + } + + void Aggro(Unit* who) + { + DoYell(SAY_KALECGOS_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KALECGOS_AGGRO); + + if(pInstance) + pInstance->SetData(DATA_KALECGOS_EVENT, IN_PROGRESS); + } + + void DamageTaken(Unit* done_by, uint32 &damage) + { + if(damage > m_creature->GetHealth() && done_by != m_creature) + { + if(!Uncorrupted) + { + damage = 0; + Banished = true; + DoCast(m_creature, SPELL_BANISH, true); + m_creature->GetMotionMaster()->MoveIdle(); + } + else + { + damage = 0; + BeginOutro(); + } + } + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KALECGOS_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_KALECGOS_SLAY1); + break; + case 1: + DoYell(SAY_KALECGOS_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_KALECGOS_SLAY2); + break; + } + } + + void BeginOutro() + { + debug_log("SD2: KALEC: Beginning Outro"); + + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + Unit* Sathrovarr = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_SATHROVARR)); + if(Sathrovarr) + { + Sathrovarr->DealDamage(Sathrovarr, Sathrovarr->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + Sathrovarr->Relocate(KALECGOS_ARENA_X, KALECGOS_ARENA_Y, KALECGOS_ARENA_Z); + Sathrovarr->SendMonsterMove(KALECGOS_ARENA_X, KALECGOS_ARENA_Y, KALECGOS_ARENA_Z, 0, 0, 0); + } + + Creature* Kalec = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_KALECGOS_HUMAN))); + if(Kalec) + { + Kalec->DeleteThreatList(); + Kalec->SetVisibility(VISIBILITY_OFF); + } + + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->setFaction(35); + } + + void MovementInform(uint32 type, uint32 id) + { + if(type != POINT_MOTION_TYPE) + return; + + if(id) + { + if(pInstance) + { + GameObject* ForceField = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GO_FORCEFIELD)); + if(ForceField) + ForceField->SetGoState(1); + + pInstance->SetData(DATA_KALECGOS_EVENT, DONE); + } + else error_log(ERROR_INST_DATA); + + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->getVictim() || !m_creature->SelectHostilTarget() || Banished) + return; + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !Enraged) + { + Unit* Sathrovarr = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_SATHROVARR)); + if(Sathrovarr) + Sathrovarr->CastSpell(Sathrovarr, SPELL_CRAZED_RAGE, true); + DoCast(m_creature, SPELL_CRAZED_RAGE, true); + Enraged = true; + } + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 1) && !Checked) + { + Checked = true; + + if(!Uncorrupted) + { + Banished = true; + DoCast(m_creature, SPELL_BANISH, true); + m_creature->GetMotionMaster()->MoveIdle(); + } + else + BeginOutro(); + } + + if(ExitTimer) + if(ExitTimer <= diff) + { + debug_log("SD2: KALEC: Exiting the arena"); + DoYell(SAY_KALEC_PLRWIN, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KALEC_PLRWIN); + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); + float x, y, z; + float iniX, iniY, iniZ; + m_creature->GetPosition(iniX, iniY, iniZ); + m_creature->GetRandomPoint(iniX, iniY, iniZ, 30, x, y, z); + z = 70; + m_creature->GetMotionMaster()->MovePoint(1, x, y, z); + }else ExitTimer -= diff; + + if(!LockedArena) + if(ForceFieldTimer < diff) + { + if(pInstance) + { + GameObject* ForceField = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GO_FORCEFIELD)); + if(ForceField) + ForceField->SetUInt32Value(GAMEOBJECT_STATE, 0); + + LockedArena = true; + }else error_log(ERROR_INST_DATA); + }else ForceFieldTimer -= diff; + + if(ArcaneBuffetTimer < diff) + { + if(rand()%3 == 0) + { + DoYell(SAY_KALECGOS_SPELL1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KALECGOS_SPELL1); + } + DoCast(m_creature->getVictim(), SPELL_ARCANE_BUFFET); + ArcaneBuffetTimer = 20000; + }else ArcaneBuffetTimer -= diff; + + if(FrostBreathTimer < diff) + { + if(rand()%2 == 0) + { + DoYell(SAY_KALECGOS_SPELL2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KALECGOS_SPELL2); + } + DoCast(m_creature->getVictim(), SPELL_FROST_BREATH); + FrostBreathTimer = 25000; + }else FrostBreathTimer -= diff; + + if(WildMagicTimer < diff) + { + DoCast(m_creature->getVictim(), WildMagic[rand()%6]); + WildMagicTimer = 19000; + }else WildMagicTimer -= diff; + + if(SpectralBlastTimer < diff) + { + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1)) + { + TeleportTargetGUID = target->GetGUID(); + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, TeleportTargetGUID); + SpectralBlastTimer = 30000; + SpectralTeleportTimer = 2000; + } + }else SpectralBlastTimer -= diff; + + if(SpectralTeleportTimer < diff) + { + if(TeleportTargetGUID) + { + Unit* pUnit = Unit::GetUnit((*m_creature), TeleportTargetGUID); + if(pUnit) + { + pUnit->CastSpell(pUnit, SPELL_SPECTRAL_BLAST, true); + TeleportToInnerVeil((Player*)pUnit); + } + else error_log(ERROR_MISSING_TELEPORT_GUID); + } + else error_log(ERROR_MISSING_TELEPORT_GUID); + + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID()); + TeleportTargetGUID = 0; + SpectralTeleportTimer = SpectralBlastTimer + 2000; + + }else SpectralTeleportTimer -= diff; + + if(!Banished) DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI +{ + boss_sathrovarrAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 CorruptingStrikeTimer; + uint32 CurseOfBoundlessAgonyTimer; + uint32 ShadowBoltVolleyTimer; + bool Banished; + bool Enraged; + + void Reset() + { + // FIXME: Timers + CorruptingStrikeTimer = 5000; + CurseOfBoundlessAgonyTimer = 15000; + ShadowBoltVolleyTimer = 10000; + + Banished = false; + Enraged = false; + + DoCast(m_creature, SPELL_SPECTRAL_REALM, true); + } + + void Aggro(Unit* who) + { + DoYell(SAY_SATH_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SATH_AGGRO); + + Creature* Kalec = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_KALECGOS_HUMAN))); + if(Kalec) + { + m_creature->AddThreat(Kalec, 10000000.0f); + Kalec->AddThreat(m_creature, 10000000.0f); + } + } + + void DamageTaken(Unit* done_by, uint32 &damage) + { + if(damage > m_creature->GetHealth()) + { + damage = 0; + DoCast(m_creature, SPELL_BANISH, true); + Banished = true; + + DoYell(SAY_SATH_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SATH_DEATH); + + if(!pInstance) + { + error_log(ERROR_INST_DATA); + return; + } + + pInstance->SetData(DATA_SET_SPECTRAL_CHECK, 5000); + + Creature* Kalecgos = ((Creature*)Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KALECGOS_DRAGON))); + if(Kalecgos) + { + ((boss_kalecgosAI*)Kalecgos->AI())->Checked = false; + ((boss_kalecgosAI*)Kalecgos->AI())->Uncorrupted = true; + } + else error_log(ERROR_KALECGOS_NOT_FOUND); + } + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SATH_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SATH_SLAY1); + break; + case 1: + DoYell(SAY_SATH_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SATH_SLAY2); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->getVictim() || !m_creature->SelectHostilTarget() || Banished) + return; + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !Enraged) + { + Unit* Kalecgos = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_KALECGOS_DRAGON)); + if(Kalecgos) + Kalecgos->CastSpell(Kalecgos, SPELL_CRAZED_RAGE, true); + DoCast(m_creature, SPELL_CRAZED_RAGE, true); + Enraged = true; + } + + if(CorruptingStrikeTimer < diff) + { + if(rand()%2 == 0) + { + DoYell(SAY_SATH_SPELL2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SATH_SPELL2); + } + DoCast(m_creature->getVictim(), SPELL_CORRUPTING_STRIKE); + CorruptingStrikeTimer = 13000; + }else CorruptingStrikeTimer -= diff; + + if(CurseOfBoundlessAgonyTimer < diff) + { + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_CURSE_OF_BOUNDLESS_AGONY); + CurseOfBoundlessAgonyTimer = 35000; + DoCast(m_creature, SPELL_SPECTRAL_REALM, true); + }else CurseOfBoundlessAgonyTimer -= diff; + + if(ShadowBoltVolleyTimer < diff) + { + if(rand()%2 == 0) + { + DoYell(SAY_SATH_SPELL1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SATH_SPELL1); + } + DoCast(m_creature->getVictim(), SPELL_SHADOW_BOLT_VOLLEY); + ShadowBoltVolleyTimer = 15000; + }else ShadowBoltVolleyTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_kalecAI : public ScriptedAI +{ + boss_kalecAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 RevitalizeTimer; + uint32 HeroicStrikeTimer; + + bool HasYelled10Percent; + bool HasYelled20Percent; + + void Reset() + { + //TODO: Times! + RevitalizeTimer = 30000; + HeroicStrikeTimer = 8000; + + HasYelled10Percent = false; + HasYelled20Percent = false; + + DoCast(m_creature, SPELL_SPECTRAL_REALM, true); + } + + void Aggro(Unit* who) + { + DoYell(SAY_KALEC_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KALEC_AGGRO); + } + + void JustDied(Unit* killer) + { + // Whatever happens when Kalec (Half-elf) dies + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->getVictim() || !m_creature->SelectHostilTarget()) + return; + + if(RevitalizeTimer < diff) + { + if(pInstance) + { + Unit* pUnit = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_RANDOM_SPECTRAL_PLAYER)); + if(pUnit) + DoCast(pUnit, SPELL_REVITALIZE); + RevitalizeTimer = 30000; + } + }else RevitalizeTimer -= diff; + + if(HeroicStrikeTimer < diff) + { + DoCast(m_creature->getVictim(), SPELL_HEROIC_STRIKE); + HeroicStrikeTimer = 30000; + }else HeroicStrikeTimer -= diff; + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) && !HasYelled20Percent) + { + DoYell(SAY_KALEC_NEAR_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KALEC_NEAR_DEATH); + HasYelled20Percent = true; + } + + if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 10) && !HasYelled10Percent) + { + DoYell(SAY_KALEC_NEAR_DEATH2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KALEC_NEAR_DEATH2); + HasYelled10Percent = true; + } + } +}; + +CreatureAI* GetAI_boss_kalecgos(Creature* c) +{ + return new boss_kalecgosAI(c); +} + +CreatureAI* GetAI_boss_sathrovarr(Creature* c) +{ + return new boss_sathrovarrAI(c); +} + +CreatureAI* GetAI_boss_kalec(Creature* c) +{ + return new boss_kalecAI(c); +} + +void AddSC_boss_kalecgos() +{ + Script* newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_kalecgos; + newscript->Name = "boss_kalecgos"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_sathrovarr; + newscript->Name = "boss_sathrovarr"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->GetAI = GetAI_boss_kalec; + newscript->Name = "boss_kalec"; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->pGOHello = GOHello_GO_Spectral_Portal; + newscript->Name = "go_spectral_portal"; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/def_sunwell_plateau.h b/src/bindings/scripts/scripts/zone/sunwell_plateau/def_sunwell_plateau.h index 316b13062f0..5b6ae7fcf9a 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/def_sunwell_plateau.h +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/def_sunwell_plateau.h @@ -1,43 +1,43 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * 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 - -/*** Encounters ***/ -#define DATA_KALECGOS_EVENT 0 -#define DATA_BRUTALLUS_EVENT 1 -#define DATA_FELMYST_EVENT 2 -#define DATA_EREDAR_TWINS_EVENT 3 -#define DATA_MURU_EVENT 4 -#define DATA_KILJAEDEN_EVENT 5 - -/*** Creatures ***/ -#define DATA_KALECGOS_DRAGON 6 -#define DATA_KALECGOS_HUMAN 7 -#define DATA_SATHROVARR 8 -#define DATA_BRUTALLUS 9 -#define DATA_FELMYST 10 -#define DATA_ALYTHESS 11 -#define DATA_SACROLASH 12 -#define DATA_MURU 13 -#define DATA_KILJAEDEN 14 -#define DATA_KILJAEDEN_CONTROLLER 15 -#define DATA_ANVEENA 16 - -/*** GameObjects ***/ -#define DATA_GO_FORCEFIELD 17 -#define DATA_GO_FIRE_BARRIER 18 -#define DATA_GATE_1 19 -#define DATA_GATE_2 20 -#define DATA_GATE_3 21 -#define DATA_GATE_4 22 -#define DATA_GATE_5 23 - -/*** Misc ***/ -#define DATA_PLAYER_SPECTRAL_REALM 24 -#define DATA_SET_SPECTRAL_CHECK 25 -#define DATA_RANDOM_SPECTRAL_PLAYER 26 -#define DATA_INST_EJECT_PLAYERS 27 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * 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 + +/*** Encounters ***/ +#define DATA_KALECGOS_EVENT 0 +#define DATA_BRUTALLUS_EVENT 1 +#define DATA_FELMYST_EVENT 2 +#define DATA_EREDAR_TWINS_EVENT 3 +#define DATA_MURU_EVENT 4 +#define DATA_KILJAEDEN_EVENT 5 + +/*** Creatures ***/ +#define DATA_KALECGOS_DRAGON 6 +#define DATA_KALECGOS_HUMAN 7 +#define DATA_SATHROVARR 8 +#define DATA_BRUTALLUS 9 +#define DATA_FELMYST 10 +#define DATA_ALYTHESS 11 +#define DATA_SACROLASH 12 +#define DATA_MURU 13 +#define DATA_KILJAEDEN 14 +#define DATA_KILJAEDEN_CONTROLLER 15 +#define DATA_ANVEENA 16 + +/*** GameObjects ***/ +#define DATA_GO_FORCEFIELD 17 +#define DATA_GO_FIRE_BARRIER 18 +#define DATA_GATE_1 19 +#define DATA_GATE_2 20 +#define DATA_GATE_3 21 +#define DATA_GATE_4 22 +#define DATA_GATE_5 23 + +/*** Misc ***/ +#define DATA_PLAYER_SPECTRAL_REALM 24 +#define DATA_SET_SPECTRAL_CHECK 25 +#define DATA_RANDOM_SPECTRAL_PLAYER 26 +#define DATA_INST_EJECT_PLAYERS 27 +#endif diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/instance_sunwell_plateau.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/instance_sunwell_plateau.cpp index d5c419520ec..44b060ff646 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/instance_sunwell_plateau.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/instance_sunwell_plateau.cpp @@ -1,275 +1,275 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -/* ScriptData -SDName: instance_sunwell_plateau -SD%Complete: 0 -SDComment: VERIFY SCRIPT -SDCategory: Sunwell_Plateau -EndScriptData */ - -#include "precompiled.h" -#include "def_sunwell_plateau.h" - -#define ENCOUNTERS 6 - -#define SPELL_SPECTRAL_REALM 46021 -#define SPELL_TELEPORT_NORMAL_REALM 46020 -#define SPELL_SPECTRAL_EXHAUSTION 44867 - -/* Sunwell Plateau: -0 - Kalecgos and Sathrovarr -1 - Brutallus -2 - Felmyst -3 - Eredar Twins (Alythess and Sacrolash) -4 - M'uru -5 - Kil'Jaeden -*/ - -struct MANGOS_DLL_DECL instance_sunwell_plateau : public ScriptedInstance -{ - instance_sunwell_plateau(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint32 Encounters[ENCOUNTERS]; - - /** Creatures **/ - uint64 Kalecgos_Dragon; - uint64 Kalecgos_Human; - uint64 Sathrovarr; - uint64 Brutallus; - uint64 Felmyst; - uint64 Alythess; - uint64 Sacrolash; - uint64 Muru; - uint64 KilJaeden; - uint64 KilJaedenController; - uint64 Anveena; - - /** GameObjects **/ - uint64 ForceField; // Kalecgos Encounter - uint64 FireBarrier; // Brutallus Encounter - uint64 Gate[5]; // Rename this to be more specific after door placement is verified. - - /*** Misc ***/ - uint32 SpectralRealmTimer; - std::vector SpectralRealmList; - - void Initialize() - { - /*** Creatures ***/ - Kalecgos_Dragon = 0; - Kalecgos_Human = 0; - Sathrovarr = 0; - Brutallus = 0; - Felmyst = 0; - Alythess = 0; - Sacrolash = 0; - Muru = 0; - KilJaeden = 0; - KilJaedenController = 0; - Anveena = 0; - - /*** GameObjects ***/ - ForceField = 0; - FireBarrier = 0; - Gate[0] = 0; // TODO: Rename Gate[n] with gate_ for better specificity - Gate[1] = 0; - Gate[2] = 0; - Gate[3] = 0; - Gate[4] = 0; - - /*** Encounters ***/ - for(uint8 i = 0; i < ENCOUNTERS; ++i) - Encounters[i] = NOT_STARTED; - - /*** Misc ***/ - SpectralRealmTimer = 5000; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; ++i) - if(Encounters[i] == IN_PROGRESS) - return true; - - return false; - } - - void OnCreatureCreate(Creature* creature, uint32 entry) - { - switch(entry) - { - case 24850: Kalecgos_Dragon = creature->GetGUID(); break; - case 24891: Kalecgos_Human = creature->GetGUID(); break; - case 24892: Sathrovarr = creature->GetGUID(); break; - case 24882: Brutallus = creature->GetGUID(); break; - case 25038: Felmyst = creature->GetGUID(); break; - case 25166: Alythess = creature->GetGUID(); break; - case 25165: Sacrolash = creature->GetGUID(); break; - case 25741: Muru = creature->GetGUID(); break; - case 25315: KilJaeden = creature->GetGUID(); break; - case 25608: KilJaedenController = creature->GetGUID(); break; - case 26046: Anveena = creature->GetGUID(); break; - } - } - - void OnObjectCreate(GameObject* gobj) - { - switch(gobj->GetEntry()) - { - case 188421: ForceField = gobj->GetGUID(); break; - case 188075: FireBarrier = gobj->GetGUID(); break; - case 187979: Gate[0] = gobj->GetGUID(); break; - case 187770: Gate[1] = gobj->GetGUID(); break; - case 187896: Gate[2] = gobj->GetGUID(); break; - case 187990: Gate[3] = gobj->GetGUID(); break; - case 188118: Gate[4] = gobj->GetGUID(); break; - } - } - - uint32 GetData(uint32 id) - { - switch(id) - { - case DATA_KALECGOS_EVENT: return Encounters[0]; break; - case DATA_BRUTALLUS_EVENT: return Encounters[1]; break; - case DATA_FELMYST_EVENT: return Encounters[2]; break; - case DATA_EREDAR_TWINS_EVENT: return Encounters[3]; break; - case DATA_MURU_EVENT: return Encounters[4]; break; - case DATA_KILJAEDEN_EVENT: return Encounters[5]; break; - } - - return 0; - } - - uint64 GetData64(uint32 id) - { - switch(id) - { - case DATA_KALECGOS_DRAGON: return Kalecgos_Dragon; break; - case DATA_KALECGOS_HUMAN: return Kalecgos_Human; break; - case DATA_SATHROVARR: return Sathrovarr; break; - case DATA_BRUTALLUS: return Brutallus; break; - case DATA_FELMYST: return Felmyst; break; - case DATA_ALYTHESS: return Alythess; break; - case DATA_SACROLASH: return Sacrolash; break; - case DATA_MURU: return Muru; break; - case DATA_KILJAEDEN: return KilJaeden; break; - case DATA_KILJAEDEN_CONTROLLER: return KilJaedenController; break; - case DATA_ANVEENA: return Anveena; break; - - case DATA_RANDOM_SPECTRAL_PLAYER: - return *(SpectralRealmList.begin() + rand()%SpectralRealmList.size()); - break; - } - return 0; - } - - void SetData(uint32 id, uint32 data) - { - switch(id) - { - case DATA_KALECGOS_EVENT: Encounters[0] = data; break; - case DATA_BRUTALLUS_EVENT: Encounters[1] = data; break; - case DATA_FELMYST_EVENT: Encounters[2] = data; break; - case DATA_EREDAR_TWINS_EVENT: Encounters[3] = data; break; - case DATA_MURU_EVENT: Encounters[4] = data; break; - case DATA_KILJAEDEN_EVENT: Encounters[5] = data; break; - - case DATA_SET_SPECTRAL_CHECK: SpectralRealmTimer = data; break; - case DATA_INST_EJECT_PLAYERS: EjectPlayers(); break; - } - } - - void SetData64(uint32 id, uint64 guid) - { - switch(id) - { - case DATA_PLAYER_SPECTRAL_REALM: - SpectralRealmList.push_back(guid); - break; - } - } - - // Dirty Hack as we can't use Unit::GetUnit in instance scripts due to lack of a WorldObject. - Player* DirtyHackToGetPlayerFromSpectralList(uint64 guid) - { - Player* first = ((InstanceMap*)instance)->GetPlayers().front(); - if(!first) - return NULL; - - Player* plr = ((Player*)Unit::GetUnit(*first, guid)); - if(plr) - return plr; - - return NULL; - } - - void EjectPlayer(Player* plr) - { - debug_log("SD2: INST: Ejecting Player %s from Spectral Realm", plr->GetName()); - // Remove player from Sathrovarr's threat list - Creature* Sath = ((Creature*)Unit::GetUnit(*plr, Sathrovarr)); - if(Sath && Sath->isAlive()) - { - HostilReference* ref = Sath->getThreatManager().getOnlineContainer().getReferenceByTarget(plr); - if(ref) - { - ref->removeReference(); - debug_log("SD2: INST: Deleting %s from Sathrovarr's threatlist", plr->GetName()); - } - } - - // Put player back in Kalecgos(Dragon)'s threat list - Creature* Kalecgos = ((Creature*)Unit::GetUnit(*plr, Kalecgos_Dragon)); - if(Kalecgos && Kalecgos->isAlive()) - { - debug_log("SD2: INST: Putting %s in Kalecgos' threatlist", plr->GetName()); - Kalecgos->AddThreat(plr, 1.0f); - } - - plr->CastSpell(plr, SPELL_TELEPORT_NORMAL_REALM, true); - plr->CastSpell(plr, SPELL_SPECTRAL_EXHAUSTION, true); - } - - void EjectPlayers() - { - for(uint8 i = 0; i < SpectralRealmList.size(); ++i) - { - Player* plr = DirtyHackToGetPlayerFromSpectralList(SpectralRealmList[i]); - if(plr && !plr->HasAura(SPELL_SPECTRAL_REALM, 0)) - { - EjectPlayer(plr); - SpectralRealmList.erase(SpectralRealmList.begin() + i); - } - } - - SpectralRealmList.clear(); - } - - void Update(uint32 diff) - { - // Only check for Spectral Realm if Kalecgos Encounter is running - if(Encounters[0] == IN_PROGRESS) - if(SpectralRealmTimer < diff) - { - EjectPlayers(); - SpectralRealmTimer = 5000; - }else SpectralRealmTimer -= diff; - } -}; - -InstanceData* GetInstanceData_instance_sunwell_plateau(Map* map) -{ - return new instance_sunwell_plateau(map); -} - -void AddSC_instance_sunwell_plateau() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_sunwell_plateau"; - newscript->GetInstanceData = GetInstanceData_instance_sunwell_plateau; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +/* ScriptData +SDName: instance_sunwell_plateau +SD%Complete: 0 +SDComment: VERIFY SCRIPT +SDCategory: Sunwell_Plateau +EndScriptData */ + +#include "precompiled.h" +#include "def_sunwell_plateau.h" + +#define ENCOUNTERS 6 + +#define SPELL_SPECTRAL_REALM 46021 +#define SPELL_TELEPORT_NORMAL_REALM 46020 +#define SPELL_SPECTRAL_EXHAUSTION 44867 + +/* Sunwell Plateau: +0 - Kalecgos and Sathrovarr +1 - Brutallus +2 - Felmyst +3 - Eredar Twins (Alythess and Sacrolash) +4 - M'uru +5 - Kil'Jaeden +*/ + +struct MANGOS_DLL_DECL instance_sunwell_plateau : public ScriptedInstance +{ + instance_sunwell_plateau(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 Encounters[ENCOUNTERS]; + + /** Creatures **/ + uint64 Kalecgos_Dragon; + uint64 Kalecgos_Human; + uint64 Sathrovarr; + uint64 Brutallus; + uint64 Felmyst; + uint64 Alythess; + uint64 Sacrolash; + uint64 Muru; + uint64 KilJaeden; + uint64 KilJaedenController; + uint64 Anveena; + + /** GameObjects **/ + uint64 ForceField; // Kalecgos Encounter + uint64 FireBarrier; // Brutallus Encounter + uint64 Gate[5]; // Rename this to be more specific after door placement is verified. + + /*** Misc ***/ + uint32 SpectralRealmTimer; + std::vector SpectralRealmList; + + void Initialize() + { + /*** Creatures ***/ + Kalecgos_Dragon = 0; + Kalecgos_Human = 0; + Sathrovarr = 0; + Brutallus = 0; + Felmyst = 0; + Alythess = 0; + Sacrolash = 0; + Muru = 0; + KilJaeden = 0; + KilJaedenController = 0; + Anveena = 0; + + /*** GameObjects ***/ + ForceField = 0; + FireBarrier = 0; + Gate[0] = 0; // TODO: Rename Gate[n] with gate_ for better specificity + Gate[1] = 0; + Gate[2] = 0; + Gate[3] = 0; + Gate[4] = 0; + + /*** Encounters ***/ + for(uint8 i = 0; i < ENCOUNTERS; ++i) + Encounters[i] = NOT_STARTED; + + /*** Misc ***/ + SpectralRealmTimer = 5000; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; ++i) + if(Encounters[i] == IN_PROGRESS) + return true; + + return false; + } + + void OnCreatureCreate(Creature* creature, uint32 entry) + { + switch(entry) + { + case 24850: Kalecgos_Dragon = creature->GetGUID(); break; + case 24891: Kalecgos_Human = creature->GetGUID(); break; + case 24892: Sathrovarr = creature->GetGUID(); break; + case 24882: Brutallus = creature->GetGUID(); break; + case 25038: Felmyst = creature->GetGUID(); break; + case 25166: Alythess = creature->GetGUID(); break; + case 25165: Sacrolash = creature->GetGUID(); break; + case 25741: Muru = creature->GetGUID(); break; + case 25315: KilJaeden = creature->GetGUID(); break; + case 25608: KilJaedenController = creature->GetGUID(); break; + case 26046: Anveena = creature->GetGUID(); break; + } + } + + void OnObjectCreate(GameObject* gobj) + { + switch(gobj->GetEntry()) + { + case 188421: ForceField = gobj->GetGUID(); break; + case 188075: FireBarrier = gobj->GetGUID(); break; + case 187979: Gate[0] = gobj->GetGUID(); break; + case 187770: Gate[1] = gobj->GetGUID(); break; + case 187896: Gate[2] = gobj->GetGUID(); break; + case 187990: Gate[3] = gobj->GetGUID(); break; + case 188118: Gate[4] = gobj->GetGUID(); break; + } + } + + uint32 GetData(uint32 id) + { + switch(id) + { + case DATA_KALECGOS_EVENT: return Encounters[0]; break; + case DATA_BRUTALLUS_EVENT: return Encounters[1]; break; + case DATA_FELMYST_EVENT: return Encounters[2]; break; + case DATA_EREDAR_TWINS_EVENT: return Encounters[3]; break; + case DATA_MURU_EVENT: return Encounters[4]; break; + case DATA_KILJAEDEN_EVENT: return Encounters[5]; break; + } + + return 0; + } + + uint64 GetData64(uint32 id) + { + switch(id) + { + case DATA_KALECGOS_DRAGON: return Kalecgos_Dragon; break; + case DATA_KALECGOS_HUMAN: return Kalecgos_Human; break; + case DATA_SATHROVARR: return Sathrovarr; break; + case DATA_BRUTALLUS: return Brutallus; break; + case DATA_FELMYST: return Felmyst; break; + case DATA_ALYTHESS: return Alythess; break; + case DATA_SACROLASH: return Sacrolash; break; + case DATA_MURU: return Muru; break; + case DATA_KILJAEDEN: return KilJaeden; break; + case DATA_KILJAEDEN_CONTROLLER: return KilJaedenController; break; + case DATA_ANVEENA: return Anveena; break; + + case DATA_RANDOM_SPECTRAL_PLAYER: + return *(SpectralRealmList.begin() + rand()%SpectralRealmList.size()); + break; + } + return 0; + } + + void SetData(uint32 id, uint32 data) + { + switch(id) + { + case DATA_KALECGOS_EVENT: Encounters[0] = data; break; + case DATA_BRUTALLUS_EVENT: Encounters[1] = data; break; + case DATA_FELMYST_EVENT: Encounters[2] = data; break; + case DATA_EREDAR_TWINS_EVENT: Encounters[3] = data; break; + case DATA_MURU_EVENT: Encounters[4] = data; break; + case DATA_KILJAEDEN_EVENT: Encounters[5] = data; break; + + case DATA_SET_SPECTRAL_CHECK: SpectralRealmTimer = data; break; + case DATA_INST_EJECT_PLAYERS: EjectPlayers(); break; + } + } + + void SetData64(uint32 id, uint64 guid) + { + switch(id) + { + case DATA_PLAYER_SPECTRAL_REALM: + SpectralRealmList.push_back(guid); + break; + } + } + + // Dirty Hack as we can't use Unit::GetUnit in instance scripts due to lack of a WorldObject. + Player* DirtyHackToGetPlayerFromSpectralList(uint64 guid) + { + Player* first = ((InstanceMap*)instance)->GetPlayers().front(); + if(!first) + return NULL; + + Player* plr = ((Player*)Unit::GetUnit(*first, guid)); + if(plr) + return plr; + + return NULL; + } + + void EjectPlayer(Player* plr) + { + debug_log("SD2: INST: Ejecting Player %s from Spectral Realm", plr->GetName()); + // Remove player from Sathrovarr's threat list + Creature* Sath = ((Creature*)Unit::GetUnit(*plr, Sathrovarr)); + if(Sath && Sath->isAlive()) + { + HostilReference* ref = Sath->getThreatManager().getOnlineContainer().getReferenceByTarget(plr); + if(ref) + { + ref->removeReference(); + debug_log("SD2: INST: Deleting %s from Sathrovarr's threatlist", plr->GetName()); + } + } + + // Put player back in Kalecgos(Dragon)'s threat list + Creature* Kalecgos = ((Creature*)Unit::GetUnit(*plr, Kalecgos_Dragon)); + if(Kalecgos && Kalecgos->isAlive()) + { + debug_log("SD2: INST: Putting %s in Kalecgos' threatlist", plr->GetName()); + Kalecgos->AddThreat(plr, 1.0f); + } + + plr->CastSpell(plr, SPELL_TELEPORT_NORMAL_REALM, true); + plr->CastSpell(plr, SPELL_SPECTRAL_EXHAUSTION, true); + } + + void EjectPlayers() + { + for(uint8 i = 0; i < SpectralRealmList.size(); ++i) + { + Player* plr = DirtyHackToGetPlayerFromSpectralList(SpectralRealmList[i]); + if(plr && !plr->HasAura(SPELL_SPECTRAL_REALM, 0)) + { + EjectPlayer(plr); + SpectralRealmList.erase(SpectralRealmList.begin() + i); + } + } + + SpectralRealmList.clear(); + } + + void Update(uint32 diff) + { + // Only check for Spectral Realm if Kalecgos Encounter is running + if(Encounters[0] == IN_PROGRESS) + if(SpectralRealmTimer < diff) + { + EjectPlayers(); + SpectralRealmTimer = 5000; + }else SpectralRealmTimer -= diff; + } +}; + +InstanceData* GetInstanceData_instance_sunwell_plateau(Map* map) +{ + return new instance_sunwell_plateau(map); +} + +void AddSC_instance_sunwell_plateau() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_sunwell_plateau"; + newscript->GetInstanceData = GetInstanceData_instance_sunwell_plateau; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tanaris/tanaris.cpp b/src/bindings/scripts/scripts/zone/tanaris/tanaris.cpp index a5e74587a51..5def6196fa1 100644 --- a/src/bindings/scripts/scripts/zone/tanaris/tanaris.cpp +++ b/src/bindings/scripts/scripts/zone/tanaris/tanaris.cpp @@ -1,402 +1,402 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Tanaris -SD%Complete: 80 -SDComment: Quest support: 2954, 4005, 10277, 10279(Special flight path). Noggenfogger vendor -SDCategory: Tanaris -EndScriptData */ - -/* ContentData -mob_aquementas -npc_custodian_of_time -npc_marin_noggenfogger -npc_steward_of_time -npc_stone_watcher_of_norgannon -EndContentData */ - -#include "precompiled.h" -#include "../../npc/npc_escortAI.h" - -/*###### -## mob_aquementas -######*/ - -#define AGGRO_YELL_AQUE "Who dares awaken Aquementas?" - -#define SPELL_AQUA_JET 13586 -#define SPELL_FROST_SHOCK 15089 - -struct MANGOS_DLL_DECL mob_aquementasAI : public ScriptedAI -{ - mob_aquementasAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 SendItem_Timer; - uint32 SwitchFaction_Timer; - bool isFriendly; - - uint32 FrostShock_Timer; - uint32 AquaJet_Timer; - - void Reset() - { - SendItem_Timer = 0; - SwitchFaction_Timer = 10000; - m_creature->setFaction(35); - isFriendly = true; - - AquaJet_Timer = 5000; - FrostShock_Timer = 1000; - } - - void SendItem(Unit* receiver) - { - 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)) - { - ItemPosCountVec dest; - uint8 msg = ((Player*)receiver)->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 11522, 1, false); - if( msg == EQUIP_ERR_OK ) - ((Player*)receiver)->StoreNewItem( dest, 11522, 1, true); - } - } - - void Aggro(Unit* who) - { - DoYell(AGGRO_YELL_AQUE,LANG_UNIVERSAL,who); - } - - void UpdateAI(const uint32 diff) - { - if( isFriendly ) - { - if( SwitchFaction_Timer < diff ) - { - m_creature->setFaction(91); - isFriendly = false; - }else SwitchFaction_Timer -= diff; - } - - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( !isFriendly ) - { - if( SendItem_Timer < diff ) - { - if( m_creature->getVictim()->GetTypeId() == TYPEID_PLAYER ) - SendItem(m_creature->getVictim()); - SendItem_Timer = 5000; - }else SendItem_Timer -= diff; - } - - if( FrostShock_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_FROST_SHOCK); - FrostShock_Timer = 15000; - }else FrostShock_Timer -= diff; - - if( AquaJet_Timer < diff ) - { - DoCast(m_creature,SPELL_AQUA_JET); - AquaJet_Timer = 15000; - }else AquaJet_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_mob_aquementas(Creature *_Creature) -{ - return new mob_aquementasAI (_Creature); -} - -/*###### -## npc_custodian_of_time -######*/ - -#define WHISPER_CUSTODIAN_1 "Greetings, $N. I will guide you through the cavern. Please try and keep up." -#define WHISPER_CUSTODIAN_2 "We do not know if the Caverns of Time have always been accessible to mortals. Truly, it is impossible to tell as the Timeless One is in perpetual motion, changing our timeways as he sees fit. What you see now may very well not exist tomorrow. You may wake up and have no memory of this place." -#define WHISPER_CUSTODIAN_3 "It is strange, I know... Most mortals cannot actually comprehend what they see here, as often, what they see is not anchored within their own perception of reality." -#define WHISPER_CUSTODIAN_4 "Follow me, please." -#define WHISPER_CUSTODIAN_5 "There are only two truths to be found here: First, that time is chaotic, always in flux, and completely malleable and second, perception does not dictate reality." -#define WHISPER_CUSTODIAN_6 "As custodians of time, we watch over and care for Nozdormu's realm. The master is away at the moment, which means that attempts are being made to dramatically alter time. The master never meddles in the affairs of mortals but instead corrects the alterations made to time by others. He is reactionary in this regard." -#define WHISPER_CUSTODIAN_7 "For normal maintenance of time, the Keepers of Time are sufficient caretakers. We are able to deal with most ordinary disturbances. I speak of little things, such as rogue mages changing something in the past to elevate their status or wealth in the present." -#define WHISPER_CUSTODIAN_8 "These tunnels that you see are called timeways. They are infinite in number. The ones that currently exist in your reality are what the master has deemed as 'trouble spots.' These trouble spots may differ completely in theme but they always share a cause. That is, their existence is a result of the same temporal disturbance. Remember that should you venture inside one..." -#define WHISPER_CUSTODIAN_9 "This timeway is in great disarray! We have agents inside right now attempting to restore order. What information I have indicates that Thrall's freedom is in jeopardy. A malevolent organization known as the Infinite Dragonflight is trying to prevent his escape. I fear without outside assistance, all will be lost." -#define WHISPER_CUSTODIAN_10 "We have very little information on this timeway. Sa'at has been dispatched and is currently inside. The data we have gathered from his correspondence is that the Infinite Dragonflight are once again attempting to alter time. Could it be that the opening of the Dark Portal is being targeted for sabotage? Let us hope not..." -#define WHISPER_CUSTODIAN_11 "This timeway is currently collapsing. What that may hold for the past, present and future is currently unknown..." -#define WHISPER_CUSTODIAN_12 "The timeways are currently ranked in order from least catastrophic to most catastrophic. Note that they are all classified as catastrophic, meaning that any single one of these timeways collapsing would mean that your world would end. We only classify them in such a way so that the heroes and adventurers that are sent here know which timeway best suits their abilities." -#define WHISPER_CUSTODIAN_13 "All we know of this timeway is that it leads to Mount Hyjal. The Infinite Dragonflight have gone to great lengths to prevent our involvement. We know next to nothing, mortal. Soridormi is currently attempting to break through the timeway's defenses but has thus far been unsuccessful. You might be our only hope of breaking through and resolving the conflict." -#define WHISPER_CUSTODIAN_14 "Our time is at an end $N. I would wish you luck, if such a thing existed." - -struct MANGOS_DLL_DECL npc_custodian_of_timeAI : public npc_escortAI -{ - npc_custodian_of_timeAI(Creature *c) : npc_escortAI(c) { Reset(); } - - void WaypointReached(uint32 i) - { - Unit *pTemp = Unit::GetUnit(*m_creature,PlayerGUID); - if( !pTemp ) - return; - - switch( i ) - { - case 0: DoWhisper(WHISPER_CUSTODIAN_1, pTemp); break; - case 1: DoWhisper(WHISPER_CUSTODIAN_2, pTemp); break; - case 2: DoWhisper(WHISPER_CUSTODIAN_3, pTemp); break; - case 3: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; - case 5: DoWhisper(WHISPER_CUSTODIAN_5, pTemp); break; - case 6: DoWhisper(WHISPER_CUSTODIAN_6, pTemp); break; - case 7: DoWhisper(WHISPER_CUSTODIAN_7, pTemp); break; - case 8: DoWhisper(WHISPER_CUSTODIAN_8, pTemp); break; - case 9: DoWhisper(WHISPER_CUSTODIAN_9, pTemp); break; - case 10: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; - case 13: DoWhisper(WHISPER_CUSTODIAN_10, pTemp); break; - case 14: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; - case 16: DoWhisper(WHISPER_CUSTODIAN_11, pTemp); break; - case 17: DoWhisper(WHISPER_CUSTODIAN_12, pTemp); break; - case 18: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; - case 22: DoWhisper(WHISPER_CUSTODIAN_13, pTemp); break; - case 23: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; - case 24: - DoWhisper(WHISPER_CUSTODIAN_14, pTemp); - DoCast(pTemp,34883); - //below here is temporary workaround, to be removed when spell works properly - ((Player*)pTemp)->AreaExploredOrEventHappens(10277); - break; - } - } - - void MoveInLineOfSight(Unit *who) - { - if( IsBeingEscorted ) - return; - - if( who->GetTypeId() == TYPEID_PLAYER ) - { - if( ((Player*)who)->HasAura(34877,1) && ((Player*)who)->GetQuestStatus(10277) == QUEST_STATUS_INCOMPLETE ) - { - float Radius = 10.0; - if( m_creature->IsWithinDistInMap(who, Radius) ) - { - ((npc_escortAI*)(m_creature->AI()))->Start(false, false, false, who->GetGUID()); - } - } - } - } - - void Aggro(Unit* who) { } - void Reset() { } - - void UpdateAI(const uint32 diff) - { - npc_escortAI::UpdateAI(diff); - } -}; - -CreatureAI* GetAI_npc_custodian_of_time(Creature *_Creature) -{ - npc_custodian_of_timeAI* custodian_of_timeAI = new npc_custodian_of_timeAI(_Creature); - - custodian_of_timeAI->AddWaypoint(0, -8374.93,-4250.21, -204.38,5000); - custodian_of_timeAI->AddWaypoint(1, -8374.93,-4250.21, -204.38,16000); - custodian_of_timeAI->AddWaypoint(2, -8374.93,-4250.21, -204.38,10000); - custodian_of_timeAI->AddWaypoint(3, -8374.93,-4250.21, -204.38,2000); - custodian_of_timeAI->AddWaypoint(4, -8439.40,-4180.05, -209.25); - custodian_of_timeAI->AddWaypoint(5, -8437.82,-4120.84, -208.59,10000); - custodian_of_timeAI->AddWaypoint(6, -8437.82,-4120.84, -208.59,16000); - custodian_of_timeAI->AddWaypoint(7, -8437.82,-4120.84, -208.59,13000); - custodian_of_timeAI->AddWaypoint(8, -8437.82,-4120.84, -208.59,18000); - custodian_of_timeAI->AddWaypoint(9, -8437.82,-4120.84, -208.59,15000); - custodian_of_timeAI->AddWaypoint(10, -8437.82,-4120.84, -208.59,2000); - custodian_of_timeAI->AddWaypoint(11, -8467.26,-4198.63, -214.21); - custodian_of_timeAI->AddWaypoint(12, -8667.76,-4252.13, -209.56); - custodian_of_timeAI->AddWaypoint(13, -8703.71,-4234.58, -209.5,14000); - custodian_of_timeAI->AddWaypoint(14, -8703.71,-4234.58, -209.5,2000); - custodian_of_timeAI->AddWaypoint(15, -8642.81,-4304.37, -209.57); - custodian_of_timeAI->AddWaypoint(16, -8649.06,-4394.36, -208.46,6000); - custodian_of_timeAI->AddWaypoint(17, -8649.06,-4394.36, -208.46,18000); - custodian_of_timeAI->AddWaypoint(18, -8649.06,-4394.36, -208.46,2000); - custodian_of_timeAI->AddWaypoint(19, -8468.72,-4437.67, -215.45); - custodian_of_timeAI->AddWaypoint(20, -8427.54,-4426, -211.13); - custodian_of_timeAI->AddWaypoint(21, -8364.83,-4393.32, -205.91); - custodian_of_timeAI->AddWaypoint(22, -8304.54,-4357.2, -208.2,18000); - custodian_of_timeAI->AddWaypoint(23, -8304.54,-4357.2, -208.2,2000); - custodian_of_timeAI->AddWaypoint(24, -8375.42,-4250.41, -205.14,5000); - custodian_of_timeAI->AddWaypoint(25, -8375.42,-4250.41, -205.14,5000); - - return (CreatureAI*)custodian_of_timeAI; -} - -/*###### -## npc_marin_noggenfogger -######*/ - -bool GossipHello_npc_marin_noggenfogger(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( _Creature->isVendor() && player->GetQuestRewardStatus(2662) ) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_marin_noggenfogger(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if( action == GOSSIP_ACTION_TRADE ) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - - 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 *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->GetQuestStatus(10279) == QUEST_STATUS_INCOMPLETE || player->GetQuestRewardStatus(10279) ) - { - player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_FLIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(9978,_Creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(9977,_Creature->GetGUID()); - - return true; -} - -bool QuestAccept_npc_steward_of_time(Player *player, Creature *creature, Quest const *quest ) -{ - if( quest->GetQuestId() == 10279 ) //Quest: To The Master's Lair - player->CastSpell(player,34891,true); //(Flight through Caverns) - - return false; -} - -bool GossipSelect_npc_steward_of_time(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_INFO_DEF + 1 ) - player->CastSpell(player,34891,true); //(Flight through Caverns) - - return true; -} - -/*###### -## npc_stone_watcher_of_norgannon -######*/ - -#define GOSSIP_ITEM_NORGANNON_1 "What function do you serve?" -#define GOSSIP_ITEM_NORGANNON_2 "What are the Plates of Uldum?" -#define GOSSIP_ITEM_NORGANNON_3 "Where are the Plates of Uldum?" -#define GOSSIP_ITEM_NORGANNON_4 "Excuse me? We've been \"reschedueled for visitations\"? What does that mean?!" -#define GOSSIP_ITEM_NORGANNON_5 "So, what's inside Uldum?" -#define GOSSIP_ITEM_NORGANNON_6 "I will return when i have the Plates of Uldum." - -bool GossipHello_npc_stone_watcher_of_norgannon(Player *player, Creature *_Creature) -{ - if( _Creature->isQuestGiver() ) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->GetQuestStatus(2954) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(1674, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_stone_watcher_of_norgannon(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(1675, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(1676, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(1677, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(1678, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(1679, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(2954); - break; - } - return true; -} - -/*###### -## AddSC -######*/ - -void AddSC_tanaris() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_aquementas"; - newscript->GetAI = GetAI_mob_aquementas; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_custodian_of_time"; - newscript->GetAI = GetAI_npc_custodian_of_time; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_marin_noggenfogger"; - newscript->pGossipHello = &GossipHello_npc_marin_noggenfogger; - newscript->pGossipSelect = &GossipSelect_npc_marin_noggenfogger; - m_scripts[nrscripts++] = newscript; - - 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; - m_scripts[nrscripts++] = newscript; - - 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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Tanaris +SD%Complete: 80 +SDComment: Quest support: 2954, 4005, 10277, 10279(Special flight path). Noggenfogger vendor +SDCategory: Tanaris +EndScriptData */ + +/* ContentData +mob_aquementas +npc_custodian_of_time +npc_marin_noggenfogger +npc_steward_of_time +npc_stone_watcher_of_norgannon +EndContentData */ + +#include "precompiled.h" +#include "../../npc/npc_escortAI.h" + +/*###### +## mob_aquementas +######*/ + +#define AGGRO_YELL_AQUE "Who dares awaken Aquementas?" + +#define SPELL_AQUA_JET 13586 +#define SPELL_FROST_SHOCK 15089 + +struct MANGOS_DLL_DECL mob_aquementasAI : public ScriptedAI +{ + mob_aquementasAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 SendItem_Timer; + uint32 SwitchFaction_Timer; + bool isFriendly; + + uint32 FrostShock_Timer; + uint32 AquaJet_Timer; + + void Reset() + { + SendItem_Timer = 0; + SwitchFaction_Timer = 10000; + m_creature->setFaction(35); + isFriendly = true; + + AquaJet_Timer = 5000; + FrostShock_Timer = 1000; + } + + void SendItem(Unit* receiver) + { + 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)) + { + ItemPosCountVec dest; + uint8 msg = ((Player*)receiver)->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 11522, 1, false); + if( msg == EQUIP_ERR_OK ) + ((Player*)receiver)->StoreNewItem( dest, 11522, 1, true); + } + } + + void Aggro(Unit* who) + { + DoYell(AGGRO_YELL_AQUE,LANG_UNIVERSAL,who); + } + + void UpdateAI(const uint32 diff) + { + if( isFriendly ) + { + if( SwitchFaction_Timer < diff ) + { + m_creature->setFaction(91); + isFriendly = false; + }else SwitchFaction_Timer -= diff; + } + + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( !isFriendly ) + { + if( SendItem_Timer < diff ) + { + if( m_creature->getVictim()->GetTypeId() == TYPEID_PLAYER ) + SendItem(m_creature->getVictim()); + SendItem_Timer = 5000; + }else SendItem_Timer -= diff; + } + + if( FrostShock_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_FROST_SHOCK); + FrostShock_Timer = 15000; + }else FrostShock_Timer -= diff; + + if( AquaJet_Timer < diff ) + { + DoCast(m_creature,SPELL_AQUA_JET); + AquaJet_Timer = 15000; + }else AquaJet_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_mob_aquementas(Creature *_Creature) +{ + return new mob_aquementasAI (_Creature); +} + +/*###### +## npc_custodian_of_time +######*/ + +#define WHISPER_CUSTODIAN_1 "Greetings, $N. I will guide you through the cavern. Please try and keep up." +#define WHISPER_CUSTODIAN_2 "We do not know if the Caverns of Time have always been accessible to mortals. Truly, it is impossible to tell as the Timeless One is in perpetual motion, changing our timeways as he sees fit. What you see now may very well not exist tomorrow. You may wake up and have no memory of this place." +#define WHISPER_CUSTODIAN_3 "It is strange, I know... Most mortals cannot actually comprehend what they see here, as often, what they see is not anchored within their own perception of reality." +#define WHISPER_CUSTODIAN_4 "Follow me, please." +#define WHISPER_CUSTODIAN_5 "There are only two truths to be found here: First, that time is chaotic, always in flux, and completely malleable and second, perception does not dictate reality." +#define WHISPER_CUSTODIAN_6 "As custodians of time, we watch over and care for Nozdormu's realm. The master is away at the moment, which means that attempts are being made to dramatically alter time. The master never meddles in the affairs of mortals but instead corrects the alterations made to time by others. He is reactionary in this regard." +#define WHISPER_CUSTODIAN_7 "For normal maintenance of time, the Keepers of Time are sufficient caretakers. We are able to deal with most ordinary disturbances. I speak of little things, such as rogue mages changing something in the past to elevate their status or wealth in the present." +#define WHISPER_CUSTODIAN_8 "These tunnels that you see are called timeways. They are infinite in number. The ones that currently exist in your reality are what the master has deemed as 'trouble spots.' These trouble spots may differ completely in theme but they always share a cause. That is, their existence is a result of the same temporal disturbance. Remember that should you venture inside one..." +#define WHISPER_CUSTODIAN_9 "This timeway is in great disarray! We have agents inside right now attempting to restore order. What information I have indicates that Thrall's freedom is in jeopardy. A malevolent organization known as the Infinite Dragonflight is trying to prevent his escape. I fear without outside assistance, all will be lost." +#define WHISPER_CUSTODIAN_10 "We have very little information on this timeway. Sa'at has been dispatched and is currently inside. The data we have gathered from his correspondence is that the Infinite Dragonflight are once again attempting to alter time. Could it be that the opening of the Dark Portal is being targeted for sabotage? Let us hope not..." +#define WHISPER_CUSTODIAN_11 "This timeway is currently collapsing. What that may hold for the past, present and future is currently unknown..." +#define WHISPER_CUSTODIAN_12 "The timeways are currently ranked in order from least catastrophic to most catastrophic. Note that they are all classified as catastrophic, meaning that any single one of these timeways collapsing would mean that your world would end. We only classify them in such a way so that the heroes and adventurers that are sent here know which timeway best suits their abilities." +#define WHISPER_CUSTODIAN_13 "All we know of this timeway is that it leads to Mount Hyjal. The Infinite Dragonflight have gone to great lengths to prevent our involvement. We know next to nothing, mortal. Soridormi is currently attempting to break through the timeway's defenses but has thus far been unsuccessful. You might be our only hope of breaking through and resolving the conflict." +#define WHISPER_CUSTODIAN_14 "Our time is at an end $N. I would wish you luck, if such a thing existed." + +struct MANGOS_DLL_DECL npc_custodian_of_timeAI : public npc_escortAI +{ + npc_custodian_of_timeAI(Creature *c) : npc_escortAI(c) { Reset(); } + + void WaypointReached(uint32 i) + { + Unit *pTemp = Unit::GetUnit(*m_creature,PlayerGUID); + if( !pTemp ) + return; + + switch( i ) + { + case 0: DoWhisper(WHISPER_CUSTODIAN_1, pTemp); break; + case 1: DoWhisper(WHISPER_CUSTODIAN_2, pTemp); break; + case 2: DoWhisper(WHISPER_CUSTODIAN_3, pTemp); break; + case 3: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; + case 5: DoWhisper(WHISPER_CUSTODIAN_5, pTemp); break; + case 6: DoWhisper(WHISPER_CUSTODIAN_6, pTemp); break; + case 7: DoWhisper(WHISPER_CUSTODIAN_7, pTemp); break; + case 8: DoWhisper(WHISPER_CUSTODIAN_8, pTemp); break; + case 9: DoWhisper(WHISPER_CUSTODIAN_9, pTemp); break; + case 10: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; + case 13: DoWhisper(WHISPER_CUSTODIAN_10, pTemp); break; + case 14: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; + case 16: DoWhisper(WHISPER_CUSTODIAN_11, pTemp); break; + case 17: DoWhisper(WHISPER_CUSTODIAN_12, pTemp); break; + case 18: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; + case 22: DoWhisper(WHISPER_CUSTODIAN_13, pTemp); break; + case 23: DoWhisper(WHISPER_CUSTODIAN_4, pTemp); break; + case 24: + DoWhisper(WHISPER_CUSTODIAN_14, pTemp); + DoCast(pTemp,34883); + //below here is temporary workaround, to be removed when spell works properly + ((Player*)pTemp)->AreaExploredOrEventHappens(10277); + break; + } + } + + void MoveInLineOfSight(Unit *who) + { + if( IsBeingEscorted ) + return; + + if( who->GetTypeId() == TYPEID_PLAYER ) + { + if( ((Player*)who)->HasAura(34877,1) && ((Player*)who)->GetQuestStatus(10277) == QUEST_STATUS_INCOMPLETE ) + { + float Radius = 10.0; + if( m_creature->IsWithinDistInMap(who, Radius) ) + { + ((npc_escortAI*)(m_creature->AI()))->Start(false, false, false, who->GetGUID()); + } + } + } + } + + void Aggro(Unit* who) { } + void Reset() { } + + void UpdateAI(const uint32 diff) + { + npc_escortAI::UpdateAI(diff); + } +}; + +CreatureAI* GetAI_npc_custodian_of_time(Creature *_Creature) +{ + npc_custodian_of_timeAI* custodian_of_timeAI = new npc_custodian_of_timeAI(_Creature); + + custodian_of_timeAI->AddWaypoint(0, -8374.93,-4250.21, -204.38,5000); + custodian_of_timeAI->AddWaypoint(1, -8374.93,-4250.21, -204.38,16000); + custodian_of_timeAI->AddWaypoint(2, -8374.93,-4250.21, -204.38,10000); + custodian_of_timeAI->AddWaypoint(3, -8374.93,-4250.21, -204.38,2000); + custodian_of_timeAI->AddWaypoint(4, -8439.40,-4180.05, -209.25); + custodian_of_timeAI->AddWaypoint(5, -8437.82,-4120.84, -208.59,10000); + custodian_of_timeAI->AddWaypoint(6, -8437.82,-4120.84, -208.59,16000); + custodian_of_timeAI->AddWaypoint(7, -8437.82,-4120.84, -208.59,13000); + custodian_of_timeAI->AddWaypoint(8, -8437.82,-4120.84, -208.59,18000); + custodian_of_timeAI->AddWaypoint(9, -8437.82,-4120.84, -208.59,15000); + custodian_of_timeAI->AddWaypoint(10, -8437.82,-4120.84, -208.59,2000); + custodian_of_timeAI->AddWaypoint(11, -8467.26,-4198.63, -214.21); + custodian_of_timeAI->AddWaypoint(12, -8667.76,-4252.13, -209.56); + custodian_of_timeAI->AddWaypoint(13, -8703.71,-4234.58, -209.5,14000); + custodian_of_timeAI->AddWaypoint(14, -8703.71,-4234.58, -209.5,2000); + custodian_of_timeAI->AddWaypoint(15, -8642.81,-4304.37, -209.57); + custodian_of_timeAI->AddWaypoint(16, -8649.06,-4394.36, -208.46,6000); + custodian_of_timeAI->AddWaypoint(17, -8649.06,-4394.36, -208.46,18000); + custodian_of_timeAI->AddWaypoint(18, -8649.06,-4394.36, -208.46,2000); + custodian_of_timeAI->AddWaypoint(19, -8468.72,-4437.67, -215.45); + custodian_of_timeAI->AddWaypoint(20, -8427.54,-4426, -211.13); + custodian_of_timeAI->AddWaypoint(21, -8364.83,-4393.32, -205.91); + custodian_of_timeAI->AddWaypoint(22, -8304.54,-4357.2, -208.2,18000); + custodian_of_timeAI->AddWaypoint(23, -8304.54,-4357.2, -208.2,2000); + custodian_of_timeAI->AddWaypoint(24, -8375.42,-4250.41, -205.14,5000); + custodian_of_timeAI->AddWaypoint(25, -8375.42,-4250.41, -205.14,5000); + + return (CreatureAI*)custodian_of_timeAI; +} + +/*###### +## npc_marin_noggenfogger +######*/ + +bool GossipHello_npc_marin_noggenfogger(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( _Creature->isVendor() && player->GetQuestRewardStatus(2662) ) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_marin_noggenfogger(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if( action == GOSSIP_ACTION_TRADE ) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + + 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 *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->GetQuestStatus(10279) == QUEST_STATUS_INCOMPLETE || player->GetQuestRewardStatus(10279) ) + { + player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM_FLIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(9978,_Creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(9977,_Creature->GetGUID()); + + return true; +} + +bool QuestAccept_npc_steward_of_time(Player *player, Creature *creature, Quest const *quest ) +{ + if( quest->GetQuestId() == 10279 ) //Quest: To The Master's Lair + player->CastSpell(player,34891,true); //(Flight through Caverns) + + return false; +} + +bool GossipSelect_npc_steward_of_time(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF + 1 ) + player->CastSpell(player,34891,true); //(Flight through Caverns) + + return true; +} + +/*###### +## npc_stone_watcher_of_norgannon +######*/ + +#define GOSSIP_ITEM_NORGANNON_1 "What function do you serve?" +#define GOSSIP_ITEM_NORGANNON_2 "What are the Plates of Uldum?" +#define GOSSIP_ITEM_NORGANNON_3 "Where are the Plates of Uldum?" +#define GOSSIP_ITEM_NORGANNON_4 "Excuse me? We've been \"reschedueled for visitations\"? What does that mean?!" +#define GOSSIP_ITEM_NORGANNON_5 "So, what's inside Uldum?" +#define GOSSIP_ITEM_NORGANNON_6 "I will return when i have the Plates of Uldum." + +bool GossipHello_npc_stone_watcher_of_norgannon(Player *player, Creature *_Creature) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->GetQuestStatus(2954) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(1674, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_stone_watcher_of_norgannon(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(1675, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(1676, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(1677, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(1678, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_NORGANNON_6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(1679, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(2954); + break; + } + return true; +} + +/*###### +## AddSC +######*/ + +void AddSC_tanaris() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_aquementas"; + newscript->GetAI = GetAI_mob_aquementas; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_custodian_of_time"; + newscript->GetAI = GetAI_npc_custodian_of_time; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_marin_noggenfogger"; + newscript->pGossipHello = &GossipHello_npc_marin_noggenfogger; + newscript->pGossipSelect = &GossipSelect_npc_marin_noggenfogger; + m_scripts[nrscripts++] = newscript; + + 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; + m_scripts[nrscripts++] = newscript; + + 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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp index abff86b24dd..4be37887e3d 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp @@ -1,612 +1,612 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Arcatraz -SD%Complete: 60 -SDComment: Warden Mellichar, event controller for Skyriss event. Millhouse Manastorm. TODO: make better combatAI for Millhouse. -SDCategory: Tempest Keep, The Arcatraz -EndScriptData */ - -/* ContentData -npc_millhouse_manastorm -npc_warden_mellichar -mob_zerekethvoidzone -EndContentData */ - -#include "precompiled.h" -#include "def_arcatraz.h" - -/*##### -# npc_millhouse_manastorm -#####*/ - -#define SAY_INTRO_1 "Where in Bonzo's brass buttons am I? And who are-- yaaghh, that's one mother of a headache!" -#define SOUND_INTRO_1 11171 -#define SAY_INTRO_2 "\"Lowly\"? I don't care who you are friend, no one refers to the mighty Millhouse Manastorm as \"Lowly\"! I have no idea what goes on here, but I will gladly join your fight against this impudent imbecile! Prepare to defend yourself, cretin!" -#define SOUND_INTRO_2 11172 - -#define SAY_WATER "I just need to get some things ready first. You guys go ahead and get started. I need to summon up some water..." -#define SOUND_WATER 11173 - -#define SAY_BUFFS "Fantastic! Next, some protective spells. Yes! Now we're cookin'" -#define SOUND_BUFFS 11174 - -#define SAY_DRINK "And of course i'll need some mana. You guys are gonna love this, just wait." -#define SOUND_DRINK 11175 - -#define SAY_READY "Aaalllriiiight!! Who ordered up an extra large can of whoop-ass?" -#define SOUND_READY 11176 - -#define SAY_KILL_1 "I didn't even break a sweat on that one." -#define SOUND_KILL_1 11177 -#define SAY_KILL_2 "You guys, feel free to jump in anytime." -#define SOUND_KILL_2 11178 - -#define SAY_PYRO "I'm gonna light you up, sweet cheeks!" -#define SOUND_PYRO 11179 - -#define SAY_ICEBLOCK "Ice, ice, baby!" -#define SOUND_ICEBLOCK 11180 - -#define SAY_LOWHP "Heal me! Oh, for the love of all that is holy, HEAL me! I'm dying!" -#define SOUND_LOWHP 11181 - -#define SAY_DEATH "You'll be hearing from my lawyer..." -#define SOUND_DEATH 11182 - -#define SAY_COMPLETE "Who's bad? Who's bad? That's right: we bad!" -#define SOUND_COMPLETE 11183 - -#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 -{ - npc_millhouse_manastormAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 EventProgress_Timer; - uint32 Phase; - bool Init; - bool LowHp; - - uint32 Pyroblast_Timer; - uint32 Fireball_Timer; - - void Reset() - { - EventProgress_Timer = 2000; - LowHp = false; - Init = false; - Phase = 1; - - Pyroblast_Timer = 1000; - Fireball_Timer = 2500; - - if( pInstance ) - { - if( pInstance->GetData(TYPE_WARDEN_2) == DONE ) - Init = true; - - if( pInstance->GetData(TYPE_HARBINGERSKYRISS) == DONE ) - { - DoYell(SAY_COMPLETE,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_COMPLETE); - } - } - } - - void MoveInLineOfSight(Unit *who) - { - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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) ) - { - DoStartAttackNoMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void AttackStart(Unit* who) - { - if (who->isTargetableForAttack()) - { - DoStartAttackNoMovement(who); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - - void Aggro(Unit *who) - { - } - - void KilledUnit(Unit *victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL_1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_2); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,0); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - - /*for questId 10886 (heroic mode only) - if( pInstance && pInstance->GetData(TYPE_HARBINGERSKYRISS) != DONE ) - ->FailQuest();*/ - } - - void UpdateAI(const uint32 diff) - { - if( !Init ) - { - if( EventProgress_Timer < diff ) - { - if( Phase < 8 ) - { - switch( Phase ) - { - case 1: - DoYell(SAY_INTRO_1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_INTRO_1); - EventProgress_Timer = 18000; - break; - case 2: - DoYell(SAY_INTRO_2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_INTRO_2); - EventProgress_Timer = 18000; - break; - case 3: - DoYell(SAY_WATER,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_WATER); - DoCast(m_creature,SPELL_CONJURE_WATER); - EventProgress_Timer = 7000; - break; - case 4: - DoYell(SAY_BUFFS,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_BUFFS); - DoCast(m_creature,SPELL_ICE_ARMOR); - EventProgress_Timer = 7000; - break; - case 5: - DoYell(SAY_DRINK,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DRINK); - DoCast(m_creature,SPELL_ARCANE_INTELLECT); - EventProgress_Timer = 7000; - break; - case 6: - DoYell(SAY_READY,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_READY); - EventProgress_Timer = 6000; - break; - case 7: - if( pInstance ) - pInstance->SetData(TYPE_WARDEN_2,DONE); - Init = true; - break; - } - ++Phase; - } - } else EventProgress_Timer -= diff; - } - - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( !LowHp && ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) ) - { - DoYell(SAY_LOWHP,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_LOWHP); - LowHp = true; - } - - if( Pyroblast_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - return; - - DoYell(SAY_PYRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_PYRO); - - DoCast(m_creature->getVictim(),SPELL_PYROBLAST); - Pyroblast_Timer = 40000; - }else Pyroblast_Timer -=diff; - - if( Fireball_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_FIREBALL); - Fireball_Timer = 4000; - }else Fireball_Timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_npc_millhouse_manastorm(Creature *_Creature) -{ - return new npc_millhouse_manastormAI (_Creature); -} - -/*##### -# npc_warden_mellichar -#####*/ - -#define YELL_INTRO1 "I knew the prince would be angry but, I... I have not been myself. I had to let them out! The great one speaks to me, you see. Wait--outsiders. Kael'thas did not send you! Good... I'll just tell the prince you released the prisoners!" -#define SOUND_INTRO1 11222 - -#define YELL_INTRO2 "The naaru kept some of the most dangerous beings in existence here in these cells. Let me introduce you to another...." -#define SOUND_INTRO2 11223 - -#define YELL_RELEASE1 "Yes, yes... another! Your will is mine!" -#define SOUND_RELEASE1 11224 - -#define YELL_RELEASE2A "Behold another terrifying creature of incomprehensible power!" -#define SOUND_RELEASE2A 11225 -#define YELL_RELEASE2B "What is this? A lowly gnome? I will do better, O'great one." -#define SOUND_RELEASE2B 11226 - -#define YELL_RELEASE3 "Anarchy! Bedlam! Oh, you are so wise! Yes, I see it now, of course!" -#define SOUND_RELEASE3 11227 - -#define YELL_RELEASE4 "One final cell remains. Yes, O'great one, right away!" -#define SOUND_RELEASE4 11228 - -#define YELL_WELCOME "Welcome, O'great one. I am your humble servant." -#define SOUND_WELCOME 11229 - -//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 - -struct MANGOS_DLL_DECL npc_warden_mellicharAI : public ScriptedAI -{ - npc_warden_mellicharAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - bool IsRunning; - bool CanSpawn; - - uint32 EventProgress_Timer; - uint32 Phase; - - void Reset() - { - IsRunning = false; - CanSpawn = false; - - EventProgress_Timer = 22000; - Phase = 1; - - m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NON_ATTACKABLE); - DoCast(m_creature,SPELL_TARGET_OMEGA); - - if( pInstance ) - pInstance->SetData(TYPE_HARBINGERSKYRISS,NOT_STARTED); - } - - void AttackStart(Unit* who) { } - - void MoveInLineOfSight(Unit *who) - { - if( IsRunning ) - return; - - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) - return; - if (who->GetTypeId() != TYPEID_PLAYER) - return; - - float attackRadius = m_creature->GetAttackDistance(who)/10; - if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) - Aggro(who); - } - } - - void Aggro(Unit *who) - { - DoYell(YELL_INTRO1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_INTRO1); - //possibly wrong spell OR should also cast second spell to make bubble appear (visual for this spell appear to be the correct) - DoCast(m_creature,SPELL_BUBBLE_VISUAL); - - if( pInstance ) - { - pInstance->SetData(TYPE_HARBINGERSKYRISS,IN_PROGRESS); - IsRunning = true; - } - } - - uint32 CanProgress() - { - if( pInstance ) - { - if( Phase == 7 && pInstance->GetData(TYPE_WARDEN_4) == DONE ) - return true; - if( Phase == 6 && pInstance->GetData(TYPE_WARDEN_3) == DONE ) - return true; - if( Phase == 5 && pInstance->GetData(TYPE_WARDEN_2) == DONE ) - return true; - if( Phase == 4 ) - return true; - if( Phase == 3 && pInstance->GetData(TYPE_WARDEN_1) == DONE ) - return true; - if( Phase == 2 && pInstance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS ) - return true; - if( Phase == 1 && pInstance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS ) - return true; - return false; - } - return false; - } - - void DoPrepareForPhase() - { - if( pInstance ) - { - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveSpellsCausingAura(SPELL_AURA_DUMMY); - - switch( Phase ) - { - case 2: - DoCast(m_creature,SPELL_TARGET_ALPHA); - pInstance->SetData(TYPE_WARDEN_1,IN_PROGRESS); - break; - case 3: - DoCast(m_creature,SPELL_TARGET_BETA); - pInstance->SetData(TYPE_WARDEN_2,IN_PROGRESS); - break; - case 5: - DoCast(m_creature,SPELL_TARGET_DELTA); - pInstance->SetData(TYPE_WARDEN_3,IN_PROGRESS); - break; - case 6: - DoCast(m_creature,SPELL_TARGET_GAMMA); - pInstance->SetData(TYPE_WARDEN_4,IN_PROGRESS); - break; - case 7: - pInstance->SetData(TYPE_WARDEN_5,IN_PROGRESS); - break; - default: - break; - } - CanSpawn = true; - } - } - - void UpdateAI(const uint32 diff) - { - if( !IsRunning ) - return; - - if( EventProgress_Timer < diff ) - { - if( pInstance ) - { - if( pInstance->GetData(TYPE_HARBINGERSKYRISS) == FAIL ) - Reset(); - } - - if( CanSpawn ) - { - //continue beam omega pod, unless we are about to summon skyriss - if( Phase != 7 ) - DoCast(m_creature,SPELL_TARGET_OMEGA); - - switch( Phase ) - { - case 2: - switch( rand()%2 ) - { - case 0: m_creature->SummonCreature(ENTRY_TRICKSTER,478.326,-148.505,42.56,3.19,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - case 1: m_creature->SummonCreature(ENTRY_PH_HUNTER,478.326,-148.505,42.56,3.19,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - } - break; - case 3: - m_creature->SummonCreature(ENTRY_MILLHOUSE,413.292,-148.378,42.56,6.27,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - break; - case 4: - DoYell(YELL_RELEASE2B,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RELEASE2B); - break; - case 5: - switch( rand()%2 ) - { - case 0: m_creature->SummonCreature(ENTRY_AKKIRIS,420.179,-174.396,42.58,0.02,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - case 1: m_creature->SummonCreature(ENTRY_SULFURON,420.179,-174.396,42.58,0.02,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - } - break; - case 6: - switch( rand()%2 ) - { - case 0: m_creature->SummonCreature(ENTRY_TW_DRAK,471.795,-174.58,42.58,3.06,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - case 1: m_creature->SummonCreature(ENTRY_BL_DRAK,471.795,-174.58,42.58,3.06,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - } - break; - case 7: - m_creature->SummonCreature(ENTRY_SKYRISS,445.763,-191.639,44.64,1.60,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - DoYell(YELL_WELCOME,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_WELCOME); - break; - default: - break; - } - CanSpawn = false; - ++Phase; - } - if( CanProgress() ) - { - switch( Phase ) - { - case 1: - DoYell(YELL_INTRO2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_INTRO2); - EventProgress_Timer = 10000; - ++Phase; - break; - case 2: - DoYell(YELL_RELEASE1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RELEASE1); - DoPrepareForPhase(); - EventProgress_Timer = 7000; - break; - case 3: - DoYell(YELL_RELEASE2A,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RELEASE2A); - DoPrepareForPhase(); - EventProgress_Timer = 10000; - break; - case 4: - DoPrepareForPhase(); - EventProgress_Timer = 15000; - break; - case 5: - DoYell(YELL_RELEASE3,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RELEASE3); - DoPrepareForPhase(); - EventProgress_Timer = 15000; - break; - case 6: - DoYell(YELL_RELEASE4,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_RELEASE4); - DoPrepareForPhase(); - EventProgress_Timer = 15000; - break; - case 7: - DoPrepareForPhase(); - EventProgress_Timer = 15000; - break; - default: - break; - } - } - } else EventProgress_Timer -= diff; - } -}; -CreatureAI* GetAI_npc_warden_mellichar(Creature *_Creature) -{ - return new npc_warden_mellicharAI (_Creature); -} - -/*##### -# 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 -{ - mob_zerekethvoidzoneAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() - { - m_creature->SetUInt32Value(UNIT_NPC_FLAGS,0); - m_creature->setFaction(16); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - DoCast(m_creature,SPELL_VOID_ZONE_DAMAGE); - } - - void Aggro(Unit* who) {} -}; -CreatureAI* GetAI_mob_zerekethvoidzoneAI(Creature *_Creature) -{ - return new mob_zerekethvoidzoneAI (_Creature); -} - -void AddSC_arcatraz() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_millhouse_manastorm"; - newscript->GetAI = GetAI_npc_millhouse_manastorm; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_warden_mellichar"; - newscript->GetAI = GetAI_npc_warden_mellichar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_zerekethvoidzone"; - newscript->GetAI = GetAI_mob_zerekethvoidzoneAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Arcatraz +SD%Complete: 60 +SDComment: Warden Mellichar, event controller for Skyriss event. Millhouse Manastorm. TODO: make better combatAI for Millhouse. +SDCategory: Tempest Keep, The Arcatraz +EndScriptData */ + +/* ContentData +npc_millhouse_manastorm +npc_warden_mellichar +mob_zerekethvoidzone +EndContentData */ + +#include "precompiled.h" +#include "def_arcatraz.h" + +/*##### +# npc_millhouse_manastorm +#####*/ + +#define SAY_INTRO_1 "Where in Bonzo's brass buttons am I? And who are-- yaaghh, that's one mother of a headache!" +#define SOUND_INTRO_1 11171 +#define SAY_INTRO_2 "\"Lowly\"? I don't care who you are friend, no one refers to the mighty Millhouse Manastorm as \"Lowly\"! I have no idea what goes on here, but I will gladly join your fight against this impudent imbecile! Prepare to defend yourself, cretin!" +#define SOUND_INTRO_2 11172 + +#define SAY_WATER "I just need to get some things ready first. You guys go ahead and get started. I need to summon up some water..." +#define SOUND_WATER 11173 + +#define SAY_BUFFS "Fantastic! Next, some protective spells. Yes! Now we're cookin'" +#define SOUND_BUFFS 11174 + +#define SAY_DRINK "And of course i'll need some mana. You guys are gonna love this, just wait." +#define SOUND_DRINK 11175 + +#define SAY_READY "Aaalllriiiight!! Who ordered up an extra large can of whoop-ass?" +#define SOUND_READY 11176 + +#define SAY_KILL_1 "I didn't even break a sweat on that one." +#define SOUND_KILL_1 11177 +#define SAY_KILL_2 "You guys, feel free to jump in anytime." +#define SOUND_KILL_2 11178 + +#define SAY_PYRO "I'm gonna light you up, sweet cheeks!" +#define SOUND_PYRO 11179 + +#define SAY_ICEBLOCK "Ice, ice, baby!" +#define SOUND_ICEBLOCK 11180 + +#define SAY_LOWHP "Heal me! Oh, for the love of all that is holy, HEAL me! I'm dying!" +#define SOUND_LOWHP 11181 + +#define SAY_DEATH "You'll be hearing from my lawyer..." +#define SOUND_DEATH 11182 + +#define SAY_COMPLETE "Who's bad? Who's bad? That's right: we bad!" +#define SOUND_COMPLETE 11183 + +#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 +{ + npc_millhouse_manastormAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 EventProgress_Timer; + uint32 Phase; + bool Init; + bool LowHp; + + uint32 Pyroblast_Timer; + uint32 Fireball_Timer; + + void Reset() + { + EventProgress_Timer = 2000; + LowHp = false; + Init = false; + Phase = 1; + + Pyroblast_Timer = 1000; + Fireball_Timer = 2500; + + if( pInstance ) + { + if( pInstance->GetData(TYPE_WARDEN_2) == DONE ) + Init = true; + + if( pInstance->GetData(TYPE_HARBINGERSKYRISS) == DONE ) + { + DoYell(SAY_COMPLETE,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_COMPLETE); + } + } + } + + void MoveInLineOfSight(Unit *who) + { + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + { + DoStartAttackNoMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void AttackStart(Unit* who) + { + if (who->isTargetableForAttack()) + { + DoStartAttackNoMovement(who); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + + void Aggro(Unit *who) + { + } + + void KilledUnit(Unit *victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL_1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_2); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,0); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + + /*for questId 10886 (heroic mode only) + if( pInstance && pInstance->GetData(TYPE_HARBINGERSKYRISS) != DONE ) + ->FailQuest();*/ + } + + void UpdateAI(const uint32 diff) + { + if( !Init ) + { + if( EventProgress_Timer < diff ) + { + if( Phase < 8 ) + { + switch( Phase ) + { + case 1: + DoYell(SAY_INTRO_1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_INTRO_1); + EventProgress_Timer = 18000; + break; + case 2: + DoYell(SAY_INTRO_2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_INTRO_2); + EventProgress_Timer = 18000; + break; + case 3: + DoYell(SAY_WATER,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_WATER); + DoCast(m_creature,SPELL_CONJURE_WATER); + EventProgress_Timer = 7000; + break; + case 4: + DoYell(SAY_BUFFS,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_BUFFS); + DoCast(m_creature,SPELL_ICE_ARMOR); + EventProgress_Timer = 7000; + break; + case 5: + DoYell(SAY_DRINK,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DRINK); + DoCast(m_creature,SPELL_ARCANE_INTELLECT); + EventProgress_Timer = 7000; + break; + case 6: + DoYell(SAY_READY,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_READY); + EventProgress_Timer = 6000; + break; + case 7: + if( pInstance ) + pInstance->SetData(TYPE_WARDEN_2,DONE); + Init = true; + break; + } + ++Phase; + } + } else EventProgress_Timer -= diff; + } + + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( !LowHp && ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20) ) + { + DoYell(SAY_LOWHP,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_LOWHP); + LowHp = true; + } + + if( Pyroblast_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + return; + + DoYell(SAY_PYRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_PYRO); + + DoCast(m_creature->getVictim(),SPELL_PYROBLAST); + Pyroblast_Timer = 40000; + }else Pyroblast_Timer -=diff; + + if( Fireball_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_FIREBALL); + Fireball_Timer = 4000; + }else Fireball_Timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_millhouse_manastorm(Creature *_Creature) +{ + return new npc_millhouse_manastormAI (_Creature); +} + +/*##### +# npc_warden_mellichar +#####*/ + +#define YELL_INTRO1 "I knew the prince would be angry but, I... I have not been myself. I had to let them out! The great one speaks to me, you see. Wait--outsiders. Kael'thas did not send you! Good... I'll just tell the prince you released the prisoners!" +#define SOUND_INTRO1 11222 + +#define YELL_INTRO2 "The naaru kept some of the most dangerous beings in existence here in these cells. Let me introduce you to another...." +#define SOUND_INTRO2 11223 + +#define YELL_RELEASE1 "Yes, yes... another! Your will is mine!" +#define SOUND_RELEASE1 11224 + +#define YELL_RELEASE2A "Behold another terrifying creature of incomprehensible power!" +#define SOUND_RELEASE2A 11225 +#define YELL_RELEASE2B "What is this? A lowly gnome? I will do better, O'great one." +#define SOUND_RELEASE2B 11226 + +#define YELL_RELEASE3 "Anarchy! Bedlam! Oh, you are so wise! Yes, I see it now, of course!" +#define SOUND_RELEASE3 11227 + +#define YELL_RELEASE4 "One final cell remains. Yes, O'great one, right away!" +#define SOUND_RELEASE4 11228 + +#define YELL_WELCOME "Welcome, O'great one. I am your humble servant." +#define SOUND_WELCOME 11229 + +//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 + +struct MANGOS_DLL_DECL npc_warden_mellicharAI : public ScriptedAI +{ + npc_warden_mellicharAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + bool IsRunning; + bool CanSpawn; + + uint32 EventProgress_Timer; + uint32 Phase; + + void Reset() + { + IsRunning = false; + CanSpawn = false; + + EventProgress_Timer = 22000; + Phase = 1; + + m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NON_ATTACKABLE); + DoCast(m_creature,SPELL_TARGET_OMEGA); + + if( pInstance ) + pInstance->SetData(TYPE_HARBINGERSKYRISS,NOT_STARTED); + } + + void AttackStart(Unit* who) { } + + void MoveInLineOfSight(Unit *who) + { + 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; + if (who->GetTypeId() != TYPEID_PLAYER) + return; + + float attackRadius = m_creature->GetAttackDistance(who)/10; + if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + Aggro(who); + } + } + + void Aggro(Unit *who) + { + DoYell(YELL_INTRO1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_INTRO1); + //possibly wrong spell OR should also cast second spell to make bubble appear (visual for this spell appear to be the correct) + DoCast(m_creature,SPELL_BUBBLE_VISUAL); + + if( pInstance ) + { + pInstance->SetData(TYPE_HARBINGERSKYRISS,IN_PROGRESS); + IsRunning = true; + } + } + + uint32 CanProgress() + { + if( pInstance ) + { + if( Phase == 7 && pInstance->GetData(TYPE_WARDEN_4) == DONE ) + return true; + if( Phase == 6 && pInstance->GetData(TYPE_WARDEN_3) == DONE ) + return true; + if( Phase == 5 && pInstance->GetData(TYPE_WARDEN_2) == DONE ) + return true; + if( Phase == 4 ) + return true; + if( Phase == 3 && pInstance->GetData(TYPE_WARDEN_1) == DONE ) + return true; + if( Phase == 2 && pInstance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS ) + return true; + if( Phase == 1 && pInstance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS ) + return true; + return false; + } + return false; + } + + void DoPrepareForPhase() + { + if( pInstance ) + { + m_creature->InterruptNonMeleeSpells(true); + m_creature->RemoveSpellsCausingAura(SPELL_AURA_DUMMY); + + switch( Phase ) + { + case 2: + DoCast(m_creature,SPELL_TARGET_ALPHA); + pInstance->SetData(TYPE_WARDEN_1,IN_PROGRESS); + break; + case 3: + DoCast(m_creature,SPELL_TARGET_BETA); + pInstance->SetData(TYPE_WARDEN_2,IN_PROGRESS); + break; + case 5: + DoCast(m_creature,SPELL_TARGET_DELTA); + pInstance->SetData(TYPE_WARDEN_3,IN_PROGRESS); + break; + case 6: + DoCast(m_creature,SPELL_TARGET_GAMMA); + pInstance->SetData(TYPE_WARDEN_4,IN_PROGRESS); + break; + case 7: + pInstance->SetData(TYPE_WARDEN_5,IN_PROGRESS); + break; + default: + break; + } + CanSpawn = true; + } + } + + void UpdateAI(const uint32 diff) + { + if( !IsRunning ) + return; + + if( EventProgress_Timer < diff ) + { + if( pInstance ) + { + if( pInstance->GetData(TYPE_HARBINGERSKYRISS) == FAIL ) + Reset(); + } + + if( CanSpawn ) + { + //continue beam omega pod, unless we are about to summon skyriss + if( Phase != 7 ) + DoCast(m_creature,SPELL_TARGET_OMEGA); + + switch( Phase ) + { + case 2: + switch( rand()%2 ) + { + case 0: m_creature->SummonCreature(ENTRY_TRICKSTER,478.326,-148.505,42.56,3.19,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; + case 1: m_creature->SummonCreature(ENTRY_PH_HUNTER,478.326,-148.505,42.56,3.19,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; + } + break; + case 3: + m_creature->SummonCreature(ENTRY_MILLHOUSE,413.292,-148.378,42.56,6.27,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + break; + case 4: + DoYell(YELL_RELEASE2B,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RELEASE2B); + break; + case 5: + switch( rand()%2 ) + { + case 0: m_creature->SummonCreature(ENTRY_AKKIRIS,420.179,-174.396,42.58,0.02,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; + case 1: m_creature->SummonCreature(ENTRY_SULFURON,420.179,-174.396,42.58,0.02,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; + } + break; + case 6: + switch( rand()%2 ) + { + case 0: m_creature->SummonCreature(ENTRY_TW_DRAK,471.795,-174.58,42.58,3.06,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; + case 1: m_creature->SummonCreature(ENTRY_BL_DRAK,471.795,-174.58,42.58,3.06,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; + } + break; + case 7: + m_creature->SummonCreature(ENTRY_SKYRISS,445.763,-191.639,44.64,1.60,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + DoYell(YELL_WELCOME,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_WELCOME); + break; + default: + break; + } + CanSpawn = false; + ++Phase; + } + if( CanProgress() ) + { + switch( Phase ) + { + case 1: + DoYell(YELL_INTRO2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_INTRO2); + EventProgress_Timer = 10000; + ++Phase; + break; + case 2: + DoYell(YELL_RELEASE1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RELEASE1); + DoPrepareForPhase(); + EventProgress_Timer = 7000; + break; + case 3: + DoYell(YELL_RELEASE2A,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RELEASE2A); + DoPrepareForPhase(); + EventProgress_Timer = 10000; + break; + case 4: + DoPrepareForPhase(); + EventProgress_Timer = 15000; + break; + case 5: + DoYell(YELL_RELEASE3,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RELEASE3); + DoPrepareForPhase(); + EventProgress_Timer = 15000; + break; + case 6: + DoYell(YELL_RELEASE4,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_RELEASE4); + DoPrepareForPhase(); + EventProgress_Timer = 15000; + break; + case 7: + DoPrepareForPhase(); + EventProgress_Timer = 15000; + break; + default: + break; + } + } + } else EventProgress_Timer -= diff; + } +}; +CreatureAI* GetAI_npc_warden_mellichar(Creature *_Creature) +{ + return new npc_warden_mellicharAI (_Creature); +} + +/*##### +# 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 +{ + mob_zerekethvoidzoneAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() + { + m_creature->SetUInt32Value(UNIT_NPC_FLAGS,0); + m_creature->setFaction(16); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + DoCast(m_creature,SPELL_VOID_ZONE_DAMAGE); + } + + void Aggro(Unit* who) {} +}; +CreatureAI* GetAI_mob_zerekethvoidzoneAI(Creature *_Creature) +{ + return new mob_zerekethvoidzoneAI (_Creature); +} + +void AddSC_arcatraz() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_millhouse_manastorm"; + newscript->GetAI = GetAI_npc_millhouse_manastorm; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_warden_mellichar"; + newscript->GetAI = GetAI_npc_warden_mellichar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_zerekethvoidzone"; + newscript->GetAI = GetAI_mob_zerekethvoidzoneAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp index 650a6a8979e..739bf237e16 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp @@ -1,380 +1,380 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Harbinger_Skyriss -SD%Complete: 45 -SDComment: CombatAI not fully implemented. Timers will need adjustments. Need better method to "kill" the warden. Need more docs on how event fully work. Reset all event and force start over if fail at one point? -SDCategory: Tempest Keep, The Arcatraz -EndScriptData */ - -/* ContentData -boss_harbinger_skyriss -boss_harbinger_skyriss_illusion -EndContentData */ - -#include "precompiled.h" -#include "def_arcatraz.h" - -#define SAY_INTRO "It is a small matter to control the mind of the weak... for I bear allegiance to powers untouched by time, unmoved by fate. No force on this world or beyond harbors the strength to bend our knee... not even the mighty Legion!" -#define SOUND_INTRO 11122 - -#define SAY_AGGRO "Bear witness to the agent of your demise!" -#define SOUND_AGGRO 11123 - -#define SAY_KILL_1 "Your fate is written!" -#define SOUND_KILL_1 11124 -#define SAY_KILL_2 "The chaos I have sown here is but a taste...." -#define SOUND_KILL_2 11125 - -#define SAY_MIND_1 "You will do my bidding, weakling." -#define SOUND_MIND_1 11127 -#define SAY_MIND_2 "Your will is no longer your own." -#define SOUND_MIND_2 11128 - -#define SAY_FEAR_1 "Flee in terror!" -#define SOUND_FEAR_1 11129 -#define SAY_FEAR_2 "I will show you horrors undreamed of!" -#define SOUND_FEAR_2 11130 - -#define SAY_IMAGE "We span the universe, as countless as the stars!" -#define SOUND_IMAGE 11131 - -#define SAY_DEATH "I am merely one of... infinite multitudes." -#define SOUND_DEATH 11126 - -#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 - -struct MANGOS_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI -{ - boss_harbinger_skyrissAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - HeroicMode = m_creature->GetMap()->IsHeroic(); - Reset(); - } - - ScriptedInstance *pInstance; - bool HeroicMode; - - bool Intro; - bool IsImage33; - bool IsImage66; - - uint32 Intro_Phase; - uint32 Intro_Timer; - uint32 MindRend_Timer; - uint32 Fear_Timer; - uint32 Domination_Timer; - uint32 ManaBurn_Timer; - - void Reset() - { - m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_UNKNOWN2); - - if( Intro ) - Intro = true; - else - Intro = false; - - IsImage33 = false; - IsImage66 = false; - - Intro_Phase = 1; - Intro_Timer = 5000; - MindRend_Timer = 3000; - Fear_Timer = 15000; - Domination_Timer = 30000; - ManaBurn_Timer = 25000; - } - - void MoveInLineOfSight(Unit *who) - { - if( !Intro ) - return; - - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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) ) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void AttackStart(Unit* who) - { - if( !Intro ) - return; - - if( who->isTargetableForAttack() ) - { - DoStartAttackAndMovement(who); - - if( !InCombat ) - { - Aggro(who); - InCombat = true; - } - } - } - - void Aggro(Unit *who) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_UNKNOWN2); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - if( pInstance ) - pInstance->SetData(TYPE_HARBINGERSKYRISS,DONE); - } - - void KilledUnit(Unit* victim) - { - /*if( victim->GetEntry() == 21436 ) - return;*/ - - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_2); - break; - } - } - - void JustSummoned(Creature *summoned) - { - summoned->AI()->AttackStart(m_creature->getVictim()); - } - - void DoSplit(uint32 val) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(false); - - DoYell(SAY_IMAGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_IMAGE); - - if( val == 66 ) - DoCast(m_creature, SPELL_66_ILLUSION); - else - DoCast(m_creature, SPELL_33_ILLUSION); - } - - void UpdateAI(const uint32 diff) - { - if( !Intro && !InCombat ) - { - if( !pInstance ) - return; - - if( Intro_Timer < diff ) - { - switch( Intro_Phase ) - { - case 1: - DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_INTRO); - ++Intro_Phase; - Intro_Timer = 25000; - break; - case 2: - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - if( Unit *mellic = Unit::GetUnit(*m_creature,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; - default: - break; - } - }else Intro_Timer -=diff; - } - - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( !IsImage66 && ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 66) ) - { - DoSplit(66); - IsImage66 = true; - } - if( !IsImage33 && ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 33) ) - { - DoSplit(33); - IsImage33 = true; - } - - if( MindRend_Timer < diff ) - { - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) - DoCast(target,HeroicMode ? H_SPELL_MIND_REND : SPELL_MIND_REND); - else - DoCast(m_creature->getVictim(),HeroicMode ? H_SPELL_MIND_REND : SPELL_MIND_REND); - - MindRend_Timer = 8000; - }else MindRend_Timer -=diff; - - if( Fear_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_FEAR_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_FEAR_1); - break; - case 1: - DoYell(SAY_FEAR_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_FEAR_2); - break; - } - - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) - DoCast(target,SPELL_FEAR); - else - DoCast(m_creature->getVictim(),SPELL_FEAR); - - Fear_Timer = 25000; - }else Fear_Timer -=diff; - - if( Domination_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_MIND_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_MIND_1); - break; - case 1: - DoYell(SAY_MIND_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_MIND_2); - break; - } - - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) - DoCast(target,HeroicMode ? H_SPELL_DOMINATION : SPELL_DOMINATION); - else - DoCast(m_creature->getVictim(),HeroicMode ? H_SPELL_DOMINATION : SPELL_DOMINATION); - - Domination_Timer = 16000+rand()%16000; - }else Domination_Timer -=diff; - - if( HeroicMode ) - { - if( ManaBurn_Timer < diff ) - { - if( m_creature->IsNonMeleeSpellCasted(false) ) - return; - - if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) - DoCast(target,H_SPELL_MANA_BURN); - - ManaBurn_Timer = 16000+rand()%16000; - }else ManaBurn_Timer -=diff; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_harbinger_skyriss(Creature *_Creature) -{ - return new boss_harbinger_skyrissAI (_Creature); -} - -#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 *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - HeroicMode = m_creature->GetMap()->IsHeroic(); - Reset(); - } - - ScriptedInstance *pInstance; - bool HeroicMode; - - void Reset() { } - - void Aggro(Unit *who) { } -}; - -CreatureAI* GetAI_boss_harbinger_skyriss_illusion(Creature *_Creature) -{ - return new boss_harbinger_skyriss_illusionAI (_Creature); -} - -void AddSC_boss_harbinger_skyriss() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_harbinger_skyriss"; - newscript->GetAI = GetAI_boss_harbinger_skyriss; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_harbinger_skyriss_illusion"; - newscript->GetAI = GetAI_boss_harbinger_skyriss_illusion; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Harbinger_Skyriss +SD%Complete: 45 +SDComment: CombatAI not fully implemented. Timers will need adjustments. Need better method to "kill" the warden. Need more docs on how event fully work. Reset all event and force start over if fail at one point? +SDCategory: Tempest Keep, The Arcatraz +EndScriptData */ + +/* ContentData +boss_harbinger_skyriss +boss_harbinger_skyriss_illusion +EndContentData */ + +#include "precompiled.h" +#include "def_arcatraz.h" + +#define SAY_INTRO "It is a small matter to control the mind of the weak... for I bear allegiance to powers untouched by time, unmoved by fate. No force on this world or beyond harbors the strength to bend our knee... not even the mighty Legion!" +#define SOUND_INTRO 11122 + +#define SAY_AGGRO "Bear witness to the agent of your demise!" +#define SOUND_AGGRO 11123 + +#define SAY_KILL_1 "Your fate is written!" +#define SOUND_KILL_1 11124 +#define SAY_KILL_2 "The chaos I have sown here is but a taste...." +#define SOUND_KILL_2 11125 + +#define SAY_MIND_1 "You will do my bidding, weakling." +#define SOUND_MIND_1 11127 +#define SAY_MIND_2 "Your will is no longer your own." +#define SOUND_MIND_2 11128 + +#define SAY_FEAR_1 "Flee in terror!" +#define SOUND_FEAR_1 11129 +#define SAY_FEAR_2 "I will show you horrors undreamed of!" +#define SOUND_FEAR_2 11130 + +#define SAY_IMAGE "We span the universe, as countless as the stars!" +#define SOUND_IMAGE 11131 + +#define SAY_DEATH "I am merely one of... infinite multitudes." +#define SOUND_DEATH 11126 + +#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 + +struct MANGOS_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI +{ + boss_harbinger_skyrissAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + HeroicMode = m_creature->GetMap()->IsHeroic(); + Reset(); + } + + ScriptedInstance *pInstance; + bool HeroicMode; + + bool Intro; + bool IsImage33; + bool IsImage66; + + uint32 Intro_Phase; + uint32 Intro_Timer; + uint32 MindRend_Timer; + uint32 Fear_Timer; + uint32 Domination_Timer; + uint32 ManaBurn_Timer; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_UNKNOWN2); + + if( Intro ) + Intro = true; + else + Intro = false; + + IsImage33 = false; + IsImage66 = false; + + Intro_Phase = 1; + Intro_Timer = 5000; + MindRend_Timer = 3000; + Fear_Timer = 15000; + Domination_Timer = 30000; + ManaBurn_Timer = 25000; + } + + void MoveInLineOfSight(Unit *who) + { + if( !Intro ) + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void AttackStart(Unit* who) + { + if( !Intro ) + return; + + if( who->isTargetableForAttack() ) + { + DoStartAttackAndMovement(who); + + if( !InCombat ) + { + Aggro(who); + InCombat = true; + } + } + } + + void Aggro(Unit *who) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_UNKNOWN2); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + if( pInstance ) + pInstance->SetData(TYPE_HARBINGERSKYRISS,DONE); + } + + void KilledUnit(Unit* victim) + { + /*if( victim->GetEntry() == 21436 ) + return;*/ + + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_2); + break; + } + } + + void JustSummoned(Creature *summoned) + { + summoned->AI()->AttackStart(m_creature->getVictim()); + } + + void DoSplit(uint32 val) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(false); + + DoYell(SAY_IMAGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_IMAGE); + + if( val == 66 ) + DoCast(m_creature, SPELL_66_ILLUSION); + else + DoCast(m_creature, SPELL_33_ILLUSION); + } + + void UpdateAI(const uint32 diff) + { + if( !Intro && !InCombat ) + { + if( !pInstance ) + return; + + if( Intro_Timer < diff ) + { + switch( Intro_Phase ) + { + case 1: + DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_INTRO); + ++Intro_Phase; + Intro_Timer = 25000; + break; + case 2: + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + if( Unit *mellic = Unit::GetUnit(*m_creature,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; + default: + break; + } + }else Intro_Timer -=diff; + } + + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( !IsImage66 && ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 66) ) + { + DoSplit(66); + IsImage66 = true; + } + if( !IsImage33 && ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 33) ) + { + DoSplit(33); + IsImage33 = true; + } + + if( MindRend_Timer < diff ) + { + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) + DoCast(target,HeroicMode ? H_SPELL_MIND_REND : SPELL_MIND_REND); + else + DoCast(m_creature->getVictim(),HeroicMode ? H_SPELL_MIND_REND : SPELL_MIND_REND); + + MindRend_Timer = 8000; + }else MindRend_Timer -=diff; + + if( Fear_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_FEAR_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_FEAR_1); + break; + case 1: + DoYell(SAY_FEAR_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_FEAR_2); + break; + } + + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) + DoCast(target,SPELL_FEAR); + else + DoCast(m_creature->getVictim(),SPELL_FEAR); + + Fear_Timer = 25000; + }else Fear_Timer -=diff; + + if( Domination_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_MIND_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_MIND_1); + break; + case 1: + DoYell(SAY_MIND_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_MIND_2); + break; + } + + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) + DoCast(target,HeroicMode ? H_SPELL_DOMINATION : SPELL_DOMINATION); + else + DoCast(m_creature->getVictim(),HeroicMode ? H_SPELL_DOMINATION : SPELL_DOMINATION); + + Domination_Timer = 16000+rand()%16000; + }else Domination_Timer -=diff; + + if( HeroicMode ) + { + if( ManaBurn_Timer < diff ) + { + if( m_creature->IsNonMeleeSpellCasted(false) ) + return; + + if( Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1) ) + DoCast(target,H_SPELL_MANA_BURN); + + ManaBurn_Timer = 16000+rand()%16000; + }else ManaBurn_Timer -=diff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_harbinger_skyriss(Creature *_Creature) +{ + return new boss_harbinger_skyrissAI (_Creature); +} + +#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 *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + HeroicMode = m_creature->GetMap()->IsHeroic(); + Reset(); + } + + ScriptedInstance *pInstance; + bool HeroicMode; + + void Reset() { } + + void Aggro(Unit *who) { } +}; + +CreatureAI* GetAI_boss_harbinger_skyriss_illusion(Creature *_Creature) +{ + return new boss_harbinger_skyriss_illusionAI (_Creature); +} + +void AddSC_boss_harbinger_skyriss() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_harbinger_skyriss"; + newscript->GetAI = GetAI_boss_harbinger_skyriss; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_harbinger_skyriss_illusion"; + newscript->GetAI = GetAI_boss_harbinger_skyriss_illusion; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h index 8868a36d70c..fc6cde1ebaa 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h +++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h @@ -1,19 +1,19 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_ARCATRAZ_H -#define DEF_ARCATRAZ_H - -#define TYPE_ZEREKETH 1 -#define TYPE_DALLIAH 2 -#define TYPE_SOCCOTHRATES 3 -#define TYPE_HARBINGERSKYRISS 4 -#define TYPE_WARDEN_1 5 -#define TYPE_WARDEN_2 6 -#define TYPE_WARDEN_3 7 -#define TYPE_WARDEN_4 8 -#define TYPE_WARDEN_5 9 - -#define DATA_MELLICHAR 10 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_ARCATRAZ_H +#define DEF_ARCATRAZ_H + +#define TYPE_ZEREKETH 1 +#define TYPE_DALLIAH 2 +#define TYPE_SOCCOTHRATES 3 +#define TYPE_HARBINGERSKYRISS 4 +#define TYPE_WARDEN_1 5 +#define TYPE_WARDEN_2 6 +#define TYPE_WARDEN_3 7 +#define TYPE_WARDEN_4 8 +#define TYPE_WARDEN_5 9 + +#define DATA_MELLICHAR 10 +#endif diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp index 7fc1c573ab6..024781d0c41 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp @@ -1,224 +1,224 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Arcatraz -SD%Complete: 80 -SDComment: Mainly Harbringer Skyriss event -SDCategory: Tempest Keep, The Arcatraz -EndScriptData */ - -#include "precompiled.h" -#include "def_arcatraz.h" - -#define ENCOUNTERS 9 - -#define CONTAINMENT_CORE_SECURITY_FIELD_ALPHA 184318 //door opened when Wrath-Scryer Soccothrates dies -#define CONTAINMENT_CORE_SECURITY_FIELD_BETA 184319 //door opened when Dalliah the Doomsayer dies -#define POD_ALPHA 183961 //pod first boss wave -#define POD_BETA 183963 //pod second boss wave -#define POD_DELTA 183964 //pod third boss wave -#define POD_GAMMA 183962 //pod fourth boss wave -#define POD_OMEGA 183965 //pod fifth boss wave - -#define MELLICHAR 21436 //skyriss will kill this unit - -/* Arcatraz encounters: -1 - Zereketh the Unbound event -2 - Dalliah the Doomsayer event -3 - Wrath-Scryer Soccothrates event -4 - Harbinger Skyriss event, 5 sub-events -*/ - -struct MANGOS_DLL_DECL instance_arcatraz : public ScriptedInstance -{ - instance_arcatraz(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint32 Encounter[ENCOUNTERS]; - - GameObject *Containment_Core_Security_Field_Alpha; - GameObject *Containment_Core_Security_Field_Beta; - GameObject *Pod_Alpha; - GameObject *Pod_Gamma; - GameObject *Pod_Beta; - GameObject *Pod_Delta; - GameObject *Pod_Omega; - - uint64 Mellichar; - - void Initialize() - { - Containment_Core_Security_Field_Alpha = NULL; - Containment_Core_Security_Field_Beta = NULL; - Pod_Alpha = NULL; - Pod_Beta = NULL; - Pod_Delta = NULL; - Pod_Gamma = NULL; - Pod_Omega = NULL; - - Mellichar = 0; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounter[i] = NOT_STARTED; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; i++) - if(Encounter[i]) return true; - - return false; - } - - void OnObjectCreate(GameObject *go) - { - switch(go->GetEntry()) - { - case CONTAINMENT_CORE_SECURITY_FIELD_ALPHA: Containment_Core_Security_Field_Alpha = go; break; - case CONTAINMENT_CORE_SECURITY_FIELD_BETA: Containment_Core_Security_Field_Beta = go; break; - case POD_ALPHA: Pod_Alpha = go; break; - case POD_BETA: Pod_Beta = go; break; - case POD_DELTA: Pod_Delta = go; break; - case POD_GAMMA: Pod_Gamma = go; break; - case POD_OMEGA: Pod_Omega = go; break; - } - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case MELLICHAR: - Mellichar = creature->GetGUID(); - break; - } - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case TYPE_ZEREKETH: - Encounter[0] = data; - break; - - case TYPE_DALLIAH: - if( data == DONE ) - if( Containment_Core_Security_Field_Beta ) - Containment_Core_Security_Field_Beta->UseDoorOrButton(); - Encounter[1] = data; - break; - - case TYPE_SOCCOTHRATES: - if( data == DONE ) - if( Containment_Core_Security_Field_Alpha ) - Containment_Core_Security_Field_Alpha->UseDoorOrButton(); - Encounter[2] = data; - break; - - case TYPE_HARBINGERSKYRISS: - if( data == NOT_STARTED || data == FAIL ) - { - Encounter[4] = NOT_STARTED; - Encounter[5] = NOT_STARTED; - Encounter[6] = NOT_STARTED; - Encounter[7] = NOT_STARTED; - Encounter[8] = NOT_STARTED; - } - Encounter[3] = data; - break; - - case TYPE_WARDEN_1: - if( data == IN_PROGRESS ) - if( Pod_Alpha ) - Pod_Alpha->UseDoorOrButton(); - Encounter[4] = data; - break; - - case TYPE_WARDEN_2: - if( data == IN_PROGRESS ) - if( Pod_Beta ) - Pod_Beta->UseDoorOrButton(); - Encounter[5] = data; - break; - - case TYPE_WARDEN_3: - if( data == IN_PROGRESS ) - if( Pod_Delta ) - Pod_Delta->UseDoorOrButton(); - Encounter[6] = data; - break; - - case TYPE_WARDEN_4: - if( data == IN_PROGRESS ) - if( Pod_Gamma ) - Pod_Gamma->UseDoorOrButton(); - Encounter[7] = data; - break; - - case TYPE_WARDEN_5: - if( data == IN_PROGRESS ) - if( Pod_Omega ) - Pod_Omega->UseDoorOrButton(); - Encounter[8] = data; - break; - } - } - - uint32 GetData(uint32 data) - { - switch(data) - { - case TYPE_HARBINGERSKYRISS: - return Encounter[3]; - case TYPE_WARDEN_1: - return Encounter[4]; - case TYPE_WARDEN_2: - return Encounter[5]; - case TYPE_WARDEN_3: - return Encounter[6]; - case TYPE_WARDEN_4: - return Encounter[7]; - case TYPE_WARDEN_5: - return Encounter[8]; - } - return 0; - } - - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_MELLICHAR: - return Mellichar; - } - return 0; - } -}; - -InstanceData* GetInstanceData_instance_arcatraz(Map* map) -{ - return new instance_arcatraz(map); -} - -void AddSC_instance_arcatraz() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_arcatraz"; - newscript->GetInstanceData = GetInstanceData_instance_arcatraz; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Arcatraz +SD%Complete: 80 +SDComment: Mainly Harbringer Skyriss event +SDCategory: Tempest Keep, The Arcatraz +EndScriptData */ + +#include "precompiled.h" +#include "def_arcatraz.h" + +#define ENCOUNTERS 9 + +#define CONTAINMENT_CORE_SECURITY_FIELD_ALPHA 184318 //door opened when Wrath-Scryer Soccothrates dies +#define CONTAINMENT_CORE_SECURITY_FIELD_BETA 184319 //door opened when Dalliah the Doomsayer dies +#define POD_ALPHA 183961 //pod first boss wave +#define POD_BETA 183963 //pod second boss wave +#define POD_DELTA 183964 //pod third boss wave +#define POD_GAMMA 183962 //pod fourth boss wave +#define POD_OMEGA 183965 //pod fifth boss wave + +#define MELLICHAR 21436 //skyriss will kill this unit + +/* Arcatraz encounters: +1 - Zereketh the Unbound event +2 - Dalliah the Doomsayer event +3 - Wrath-Scryer Soccothrates event +4 - Harbinger Skyriss event, 5 sub-events +*/ + +struct MANGOS_DLL_DECL instance_arcatraz : public ScriptedInstance +{ + instance_arcatraz(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 Encounter[ENCOUNTERS]; + + GameObject *Containment_Core_Security_Field_Alpha; + GameObject *Containment_Core_Security_Field_Beta; + GameObject *Pod_Alpha; + GameObject *Pod_Gamma; + GameObject *Pod_Beta; + GameObject *Pod_Delta; + GameObject *Pod_Omega; + + uint64 Mellichar; + + void Initialize() + { + Containment_Core_Security_Field_Alpha = NULL; + Containment_Core_Security_Field_Beta = NULL; + Pod_Alpha = NULL; + Pod_Beta = NULL; + Pod_Delta = NULL; + Pod_Gamma = NULL; + Pod_Omega = NULL; + + Mellichar = 0; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounter[i] = NOT_STARTED; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounter[i]) return true; + + return false; + } + + void OnObjectCreate(GameObject *go) + { + switch(go->GetEntry()) + { + case CONTAINMENT_CORE_SECURITY_FIELD_ALPHA: Containment_Core_Security_Field_Alpha = go; break; + case CONTAINMENT_CORE_SECURITY_FIELD_BETA: Containment_Core_Security_Field_Beta = go; break; + case POD_ALPHA: Pod_Alpha = go; break; + case POD_BETA: Pod_Beta = go; break; + case POD_DELTA: Pod_Delta = go; break; + case POD_GAMMA: Pod_Gamma = go; break; + case POD_OMEGA: Pod_Omega = go; break; + } + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case MELLICHAR: + Mellichar = creature->GetGUID(); + break; + } + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case TYPE_ZEREKETH: + Encounter[0] = data; + break; + + case TYPE_DALLIAH: + if( data == DONE ) + if( Containment_Core_Security_Field_Beta ) + Containment_Core_Security_Field_Beta->UseDoorOrButton(); + Encounter[1] = data; + break; + + case TYPE_SOCCOTHRATES: + if( data == DONE ) + if( Containment_Core_Security_Field_Alpha ) + Containment_Core_Security_Field_Alpha->UseDoorOrButton(); + Encounter[2] = data; + break; + + case TYPE_HARBINGERSKYRISS: + if( data == NOT_STARTED || data == FAIL ) + { + Encounter[4] = NOT_STARTED; + Encounter[5] = NOT_STARTED; + Encounter[6] = NOT_STARTED; + Encounter[7] = NOT_STARTED; + Encounter[8] = NOT_STARTED; + } + Encounter[3] = data; + break; + + case TYPE_WARDEN_1: + if( data == IN_PROGRESS ) + if( Pod_Alpha ) + Pod_Alpha->UseDoorOrButton(); + Encounter[4] = data; + break; + + case TYPE_WARDEN_2: + if( data == IN_PROGRESS ) + if( Pod_Beta ) + Pod_Beta->UseDoorOrButton(); + Encounter[5] = data; + break; + + case TYPE_WARDEN_3: + if( data == IN_PROGRESS ) + if( Pod_Delta ) + Pod_Delta->UseDoorOrButton(); + Encounter[6] = data; + break; + + case TYPE_WARDEN_4: + if( data == IN_PROGRESS ) + if( Pod_Gamma ) + Pod_Gamma->UseDoorOrButton(); + Encounter[7] = data; + break; + + case TYPE_WARDEN_5: + if( data == IN_PROGRESS ) + if( Pod_Omega ) + Pod_Omega->UseDoorOrButton(); + Encounter[8] = data; + break; + } + } + + uint32 GetData(uint32 data) + { + switch(data) + { + case TYPE_HARBINGERSKYRISS: + return Encounter[3]; + case TYPE_WARDEN_1: + return Encounter[4]; + case TYPE_WARDEN_2: + return Encounter[5]; + case TYPE_WARDEN_3: + return Encounter[6]; + case TYPE_WARDEN_4: + return Encounter[7]; + case TYPE_WARDEN_5: + return Encounter[8]; + } + return 0; + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_MELLICHAR: + return Mellichar; + } + return 0; + } +}; + +InstanceData* GetInstanceData_instance_arcatraz(Map* map) +{ + return new instance_arcatraz(map); +} + +void AddSC_instance_arcatraz() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_arcatraz"; + newscript->GetInstanceData = GetInstanceData_instance_arcatraz; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_high_botanist_freywinn.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_high_botanist_freywinn.cpp index 3dfc0782512..baa9a018d5c 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_high_botanist_freywinn.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_high_botanist_freywinn.cpp @@ -1,215 +1,215 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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_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) -SDCategory: Tempest Keep, The Botanica -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO "What are you doing? These specimens are very delicate!" -#define SOUND_AGGRO 11144 - -#define SAY_KILL_1 "Your life cycle is now concluded!" -#define SOUND_KILL_1 11145 -#define SAY_KILL_2 "You will feed the worms." -#define SOUND_KILL_2 11146 - -#define SAY_TREE_1 "Endorel aluminor!" -#define SOUND_TREE_1 11147 -#define SAY_TREE_2 "Nature bends to my will!" -#define SOUND_TREE_2 11148 - -#define SAY_DEATH "The specimens...must be preserved." -#define SOUND_DEATH 11149 - -#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 - -struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI -{ - boss_high_botanist_freywinnAI(Creature *c) : ScriptedAI(c) { Reset(); } - - std::list Adds_List; - - uint32 SummonSeedling_Timer; - uint32 TreeForm_Timer; - uint32 MoveCheck_Timer; - uint32 DeadAddsCount; - bool MoveFree; - - void Reset() - { - Adds_List.clear(); - - SummonSeedling_Timer = 6000; - TreeForm_Timer = 30000; - MoveCheck_Timer = 1000; - DeadAddsCount = 0; - MoveFree = true; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void JustSummoned(Creature *summoned) - { - if( summoned->GetEntry() == ENTRY_FRAYER ) - Adds_List.push_back(summoned->GetGUID()); - } - - void DoSummonSeedling() - { - switch(rand()%4) - { - case 0: DoCast(m_creature,SPELL_PLANT_WHITE); break; - case 1: DoCast(m_creature,SPELL_PLANT_GREEN); break; - case 2: DoCast(m_creature,SPELL_PLANT_BLUE); break; - case 3: DoCast(m_creature,SPELL_PLANT_RED); break; - } - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_1); - break; - case 1: - DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_KILL_2); - break; - } - } - - void UpdateAI(const uint32 diff) - { - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( TreeForm_Timer < diff ) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_TREE_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_TREE_1); - break; - case 1: - DoYell(SAY_TREE_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_TREE_2); - break; - } - - if( m_creature->IsNonMeleeSpellCasted(false) ) - m_creature->InterruptNonMeleeSpells(true); - - m_creature->RemoveAllAuras(); - - DoCast(m_creature,SPELL_SUMMON_FRAYER,true); - DoCast(m_creature,SPELL_TRANQUILITY,true); - DoCast(m_creature,SPELL_TREE_FORM,true); - - m_creature->GetMotionMaster()->MoveIdle(); - MoveFree = false; - - TreeForm_Timer = 75000; - }else TreeForm_Timer -= diff; - - if( !MoveFree ) - { - if( MoveCheck_Timer < diff ) - { - if( !Adds_List.empty() ) - { - for(std::list::iterator itr = Adds_List.begin(); itr != Adds_List.end(); ++itr) - { - if( Unit *temp = Unit::GetUnit(*m_creature,*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(); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - MoveFree = true; - } - MoveCheck_Timer = 500; - } - else MoveCheck_Timer -= diff; - - return; - } - - /*if( m_creature->HasAura(SPELL_TREE_FORM,0) || m_creature->HasAura(SPELL_TRANQUILITY,0) ) - return;*/ - - //one random seedling every 5 secs, but not in tree form - if( SummonSeedling_Timer < diff ) - { - DoSummonSeedling(); - SummonSeedling_Timer = 6000; - }else SummonSeedling_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_high_botanist_freywinn(Creature *_Creature) -{ - return new boss_high_botanist_freywinnAI (_Creature); -} - -void AddSC_boss_high_botanist_freywinn() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_high_botanist_freywinn"; - newscript->GetAI = GetAI_boss_high_botanist_freywinn; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_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) +SDCategory: Tempest Keep, The Botanica +EndScriptData */ + +#include "precompiled.h" + +#define SAY_AGGRO "What are you doing? These specimens are very delicate!" +#define SOUND_AGGRO 11144 + +#define SAY_KILL_1 "Your life cycle is now concluded!" +#define SOUND_KILL_1 11145 +#define SAY_KILL_2 "You will feed the worms." +#define SOUND_KILL_2 11146 + +#define SAY_TREE_1 "Endorel aluminor!" +#define SOUND_TREE_1 11147 +#define SAY_TREE_2 "Nature bends to my will!" +#define SOUND_TREE_2 11148 + +#define SAY_DEATH "The specimens...must be preserved." +#define SOUND_DEATH 11149 + +#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 + +struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI +{ + boss_high_botanist_freywinnAI(Creature *c) : ScriptedAI(c) { Reset(); } + + std::list Adds_List; + + uint32 SummonSeedling_Timer; + uint32 TreeForm_Timer; + uint32 MoveCheck_Timer; + uint32 DeadAddsCount; + bool MoveFree; + + void Reset() + { + Adds_List.clear(); + + SummonSeedling_Timer = 6000; + TreeForm_Timer = 30000; + MoveCheck_Timer = 1000; + DeadAddsCount = 0; + MoveFree = true; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void JustSummoned(Creature *summoned) + { + if( summoned->GetEntry() == ENTRY_FRAYER ) + Adds_List.push_back(summoned->GetGUID()); + } + + void DoSummonSeedling() + { + switch(rand()%4) + { + case 0: DoCast(m_creature,SPELL_PLANT_WHITE); break; + case 1: DoCast(m_creature,SPELL_PLANT_GREEN); break; + case 2: DoCast(m_creature,SPELL_PLANT_BLUE); break; + case 3: DoCast(m_creature,SPELL_PLANT_RED); break; + } + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_KILL_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_1); + break; + case 1: + DoYell(SAY_KILL_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_KILL_2); + break; + } + } + + void UpdateAI(const uint32 diff) + { + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( TreeForm_Timer < diff ) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_TREE_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_TREE_1); + break; + case 1: + DoYell(SAY_TREE_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_TREE_2); + break; + } + + if( m_creature->IsNonMeleeSpellCasted(false) ) + m_creature->InterruptNonMeleeSpells(true); + + m_creature->RemoveAllAuras(); + + DoCast(m_creature,SPELL_SUMMON_FRAYER,true); + DoCast(m_creature,SPELL_TRANQUILITY,true); + DoCast(m_creature,SPELL_TREE_FORM,true); + + m_creature->GetMotionMaster()->MoveIdle(); + MoveFree = false; + + TreeForm_Timer = 75000; + }else TreeForm_Timer -= diff; + + if( !MoveFree ) + { + if( MoveCheck_Timer < diff ) + { + if( !Adds_List.empty() ) + { + for(std::list::iterator itr = Adds_List.begin(); itr != Adds_List.end(); ++itr) + { + if( Unit *temp = Unit::GetUnit(*m_creature,*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(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + MoveFree = true; + } + MoveCheck_Timer = 500; + } + else MoveCheck_Timer -= diff; + + return; + } + + /*if( m_creature->HasAura(SPELL_TREE_FORM,0) || m_creature->HasAura(SPELL_TRANQUILITY,0) ) + return;*/ + + //one random seedling every 5 secs, but not in tree form + if( SummonSeedling_Timer < diff ) + { + DoSummonSeedling(); + SummonSeedling_Timer = 6000; + }else SummonSeedling_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_high_botanist_freywinn(Creature *_Creature) +{ + return new boss_high_botanist_freywinnAI (_Creature); +} + +void AddSC_boss_high_botanist_freywinn() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_high_botanist_freywinn"; + newscript->GetAI = GetAI_boss_high_botanist_freywinn; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_laj.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_laj.cpp index f0bc53e7264..825d16eeb54 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_laj.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_laj.cpp @@ -1,198 +1,198 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Laj -SD%Complete: 95 -SDComment: Immunities _may_ be applied by spells, but this has _not_ been confirmed to be proper way. Most spells require database support. -SDCategory: Tempest Keep, The Botanica -EndScriptData */ - -#include "precompiled.h" - -#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 EMOTE_SUMMON "emits a strange noise." - -#define MODEL_DEFAULT 13109 -#define MODEL_ARCANE 14213 -#define MODEL_FIRE 13110 -#define MODEL_FROST 14112 -#define MODEL_NATURE 14214 - -struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI -{ - boss_lajAI(Creature *c) : ScriptedAI(c) { Reset(); } - - bool CanSummon; - uint32 Teleport_Timer; - uint32 Summon_Timer; - uint32 Transform_Timer; - uint32 Allergic_Timer; - - void Reset() - { - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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; - } - - void DoTransform() - { - switch(rand()%5) - { - case 0: - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); - break; - case 1: - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); - break; - case 2: - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); - break; - case 3: - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); - break; - case 4: - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); - break; - } - } - - void DoSummons() - { - switch(rand()%4) - { - case 0: - DoCast(m_creature,SPELL_SUMMON_LASHER_1,true); - DoCast(m_creature,SPELL_SUMMON_FLAYER_1,true); - break; - case 1: - DoCast(m_creature,SPELL_SUMMON_LASHER_2,true); - DoCast(m_creature,SPELL_SUMMON_FLAYER_2,true); - break; - case 2: - DoCast(m_creature,SPELL_SUMMON_LASHER_3,true); - DoCast(m_creature,SPELL_SUMMON_FLAYER_3,true); - break; - case 3: - DoCast(m_creature,SPELL_SUMMON_LASHER_4,true); - DoCast(m_creature,SPELL_SUMMON_FLAYER_4,true); - break; - } - CanSummon = false; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( CanSummon ) - { - if( Summon_Timer < diff ) - { - DoTextEmote(EMOTE_SUMMON,NULL); - DoSummons(); - Summon_Timer = 2500; - }else Summon_Timer -= diff; - } - - if( Allergic_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_ALLERGIC_REACTION); - Allergic_Timer = 25000+rand()%15000; - }else Allergic_Timer -= diff; - - if( Teleport_Timer < diff ) - { - DoCast(m_creature,SPELL_TELEPORT_SELF); - Teleport_Timer = 30000+rand()%10000; - CanSummon = true; - }else Teleport_Timer -= diff; - - if( Transform_Timer < diff ) - { - DoTransform(); - Transform_Timer = 25000+rand()%15000; - }else Transform_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_laj(Creature *_Creature) -{ - return new boss_lajAI (_Creature); -} - -void AddSC_boss_laj() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_laj"; - newscript->GetAI = GetAI_boss_laj; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Laj +SD%Complete: 95 +SDComment: Immunities _may_ be applied by spells, but this has _not_ been confirmed to be proper way. Most spells require database support. +SDCategory: Tempest Keep, The Botanica +EndScriptData */ + +#include "precompiled.h" + +#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 EMOTE_SUMMON "emits a strange noise." + +#define MODEL_DEFAULT 13109 +#define MODEL_ARCANE 14213 +#define MODEL_FIRE 13110 +#define MODEL_FROST 14112 +#define MODEL_NATURE 14214 + +struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI +{ + boss_lajAI(Creature *c) : ScriptedAI(c) { Reset(); } + + bool CanSummon; + uint32 Teleport_Timer; + uint32 Summon_Timer; + uint32 Transform_Timer; + uint32 Allergic_Timer; + + void Reset() + { + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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; + } + + void DoTransform() + { + switch(rand()%5) + { + case 0: + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); + break; + case 1: + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); + break; + case 2: + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); + break; + case 3: + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); + break; + case 4: + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,MODEL_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); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + break; + } + } + + void DoSummons() + { + switch(rand()%4) + { + case 0: + DoCast(m_creature,SPELL_SUMMON_LASHER_1,true); + DoCast(m_creature,SPELL_SUMMON_FLAYER_1,true); + break; + case 1: + DoCast(m_creature,SPELL_SUMMON_LASHER_2,true); + DoCast(m_creature,SPELL_SUMMON_FLAYER_2,true); + break; + case 2: + DoCast(m_creature,SPELL_SUMMON_LASHER_3,true); + DoCast(m_creature,SPELL_SUMMON_FLAYER_3,true); + break; + case 3: + DoCast(m_creature,SPELL_SUMMON_LASHER_4,true); + DoCast(m_creature,SPELL_SUMMON_FLAYER_4,true); + break; + } + CanSummon = false; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( CanSummon ) + { + if( Summon_Timer < diff ) + { + DoTextEmote(EMOTE_SUMMON,NULL); + DoSummons(); + Summon_Timer = 2500; + }else Summon_Timer -= diff; + } + + if( Allergic_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_ALLERGIC_REACTION); + Allergic_Timer = 25000+rand()%15000; + }else Allergic_Timer -= diff; + + if( Teleport_Timer < diff ) + { + DoCast(m_creature,SPELL_TELEPORT_SELF); + Teleport_Timer = 30000+rand()%10000; + CanSummon = true; + }else Teleport_Timer -= diff; + + if( Transform_Timer < diff ) + { + DoTransform(); + Transform_Timer = 25000+rand()%15000; + }else Transform_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_laj(Creature *_Creature) +{ + return new boss_lajAI (_Creature); +} + +void AddSC_boss_laj() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_laj"; + newscript->GetAI = GetAI_boss_laj; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_warp_splinter.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_warp_splinter.cpp index ed1f6458faa..a9eb4a7cc17 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_warp_splinter.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/botanica/boss_warp_splinter.cpp @@ -1,288 +1,288 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Warp_Splinter -SD%Complete: 80 -SDComment: Includes Sapling (need some better control with these). Spells for boss possibly need some rework. -SDCategory: Tempest Keep, The Botanica -EndScriptData */ - -#include "precompiled.h" - -/*##### -# mob_treant (Sapling) -#####*/ - -struct MANGOS_DLL_DECL mob_treantAI : public ScriptedAI -{ - mob_treantAI (Creature *c) : ScriptedAI(c) - { - WarpGuid = 0; - Reset(); - } - - uint64 WarpGuid; - - void Reset() - { - m_creature->SetSpeed( MOVE_RUN, 0.5f, true); - m_creature->SetUnitMovementFlags(0); - } - - void Aggro(Unit *who) - { - return; - } - - void MoveInLineOfSight(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if (m_creature->getVictim()->GetGUID() != WarpGuid) - DoMeleeAttackIfReady(); - } -}; - -/*##### -# boss_warp_splinter -#####*/ - -#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 35059 //37078, 34785 //must additional script them (because Splinter eats them after 20 sec ^) -#define SPELL_HEAL_FATHER 6262 - -#define CREATURE_TREANT 19949 - -#define SAY_COMBAT_START "Who disturbs this sanctuary?" -#define SOUND_COMBAT_START 11230 - -#define SAY_SLAY_1 "You must die! But wait: this does not-- No, no... you must die!" -#define SOUND_SLAY_1 11231 -#define SAY_SLAY_2 "What am I doing? Why do I..." -#define SOUND_SLAY_2 11232 - -#define SAY_SUMMON_1 "Children, come to me!" -#define SOUND_SUMMON_1 11233 -#define SAY_SUMMON_2 "Maybe this is not-- No, we fight! Come to my aid." -#define SOUND_SUMMON_2 11234 - -#define SAY_DEATH "So... confused. Do not... belong here!" -#define SOUND_DEATH 11235 - -#define TREANT_SPAWN_DIST 50 //50 yards from Warp Splinter's spawn point - -float treant_pos[6][3] = -{ - {24.301233, 427.221100, -27.060635}, - {16.795492, 359.678802, -27.355425}, - {53.493484, 345.381470, -26.196192}, - {61.867096, 439.362732, -25.921030}, - {109.861877, 423.201630, -27.356019}, - {106.780159, 355.582581, -27.593357} -}; - -struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI -{ - boss_warp_splinterAI(Creature *c) : ScriptedAI(c) - { - Treant_Spawn_Pos_X = c->GetPositionX(); - Treant_Spawn_Pos_Y = c->GetPositionY(); - Reset(); - } - - uint32 War_Stomp_Timer; - uint32 Summon_Treants_Timer; - uint32 Arcane_Volley_Timer; - uint32 CheckTreantLOS_Timer; - uint32 TreantLife_Timer; - uint64 Treant_GUIDs[6]; - - float Treant_Spawn_Pos_X; - float Treant_Spawn_Pos_Y; - - - void Reset() - { - War_Stomp_Timer = 60000; - Summon_Treants_Timer = 45000; - Arcane_Volley_Timer = 140000; - CheckTreantLOS_Timer = 1000; - TreantLife_Timer = 999999; - - for(int i = 0; i < 6; ++i) - Treant_GUIDs[i] = 0; - - m_creature->SetSpeed( MOVE_RUN, 0.7f, true); - } - - void Aggro(Unit *who) - { - DoYell(SAY_COMBAT_START,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_COMBAT_START); - } - - // On Killed Unit - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY_1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY_2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void SummonTreants() - { - 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); - - 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); - if(pTreant) - { - //pTreant->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature)); - pTreant->AddThreat(m_creature, 0.1f); - Treant_GUIDs[i] = pTreant->GetGUID(); - ((mob_treantAI*)pTreant->AI())->WarpGuid = m_creature->GetGUID(); - } - } - - switch(rand()%2) - { - case 0: - DoYell(SAY_SUMMON_1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SUMMON_1); - break; - case 1: - DoYell(SAY_SUMMON_2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SUMMON_2); - break; - } - } - - // Warp Splinter eat treants if they are near him - void EatTreant() - { - for( int i=0; i<6; ++i ) - { - Unit *pTreant = Unit::GetUnit(*m_creature, 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); - } - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Check for War Stomp - if(War_Stomp_Timer < diff) - { - DoCast(m_creature->getVictim(),WAR_STOMP); - War_Stomp_Timer = 60000; - } - else War_Stomp_Timer -= diff; - - //Check for Arcane Volley - if(Arcane_Volley_Timer < diff) - { - DoCast(m_creature->getVictim(),ARCANE_VOLLEY); - Arcane_Volley_Timer = 40000+((rand()%20)*1000); - } - else Arcane_Volley_Timer -= diff; - - //Check for Summon Treants - if(Summon_Treants_Timer < diff) - { - SummonTreants(); - Summon_Treants_Timer = 45000; - } - else Summon_Treants_Timer -= diff; - - // 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(); - } -}; - -CreatureAI* GetAI_boss_warp_splinter(Creature *_Creature) -{ - return new boss_warp_splinterAI (_Creature); -} - -CreatureAI* GetAI_mob_treant(Creature *_Creature) -{ - return new mob_treantAI (_Creature); -} - -void AddSC_boss_warp_splinter() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_warp_splinter"; - newscript->GetAI = GetAI_boss_warp_splinter; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_warp_splinter_treant"; - newscript->GetAI = GetAI_mob_treant; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Warp_Splinter +SD%Complete: 80 +SDComment: Includes Sapling (need some better control with these). Spells for boss possibly need some rework. +SDCategory: Tempest Keep, The Botanica +EndScriptData */ + +#include "precompiled.h" + +/*##### +# mob_treant (Sapling) +#####*/ + +struct MANGOS_DLL_DECL mob_treantAI : public ScriptedAI +{ + mob_treantAI (Creature *c) : ScriptedAI(c) + { + WarpGuid = 0; + Reset(); + } + + uint64 WarpGuid; + + void Reset() + { + m_creature->SetSpeed( MOVE_RUN, 0.5f, true); + m_creature->SetUnitMovementFlags(0); + } + + void Aggro(Unit *who) + { + return; + } + + void MoveInLineOfSight(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if (m_creature->getVictim()->GetGUID() != WarpGuid) + DoMeleeAttackIfReady(); + } +}; + +/*##### +# boss_warp_splinter +#####*/ + +#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 35059 //37078, 34785 //must additional script them (because Splinter eats them after 20 sec ^) +#define SPELL_HEAL_FATHER 6262 + +#define CREATURE_TREANT 19949 + +#define SAY_COMBAT_START "Who disturbs this sanctuary?" +#define SOUND_COMBAT_START 11230 + +#define SAY_SLAY_1 "You must die! But wait: this does not-- No, no... you must die!" +#define SOUND_SLAY_1 11231 +#define SAY_SLAY_2 "What am I doing? Why do I..." +#define SOUND_SLAY_2 11232 + +#define SAY_SUMMON_1 "Children, come to me!" +#define SOUND_SUMMON_1 11233 +#define SAY_SUMMON_2 "Maybe this is not-- No, we fight! Come to my aid." +#define SOUND_SUMMON_2 11234 + +#define SAY_DEATH "So... confused. Do not... belong here!" +#define SOUND_DEATH 11235 + +#define TREANT_SPAWN_DIST 50 //50 yards from Warp Splinter's spawn point + +float treant_pos[6][3] = +{ + {24.301233, 427.221100, -27.060635}, + {16.795492, 359.678802, -27.355425}, + {53.493484, 345.381470, -26.196192}, + {61.867096, 439.362732, -25.921030}, + {109.861877, 423.201630, -27.356019}, + {106.780159, 355.582581, -27.593357} +}; + +struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI +{ + boss_warp_splinterAI(Creature *c) : ScriptedAI(c) + { + Treant_Spawn_Pos_X = c->GetPositionX(); + Treant_Spawn_Pos_Y = c->GetPositionY(); + Reset(); + } + + uint32 War_Stomp_Timer; + uint32 Summon_Treants_Timer; + uint32 Arcane_Volley_Timer; + uint32 CheckTreantLOS_Timer; + uint32 TreantLife_Timer; + uint64 Treant_GUIDs[6]; + + float Treant_Spawn_Pos_X; + float Treant_Spawn_Pos_Y; + + + void Reset() + { + War_Stomp_Timer = 60000; + Summon_Treants_Timer = 45000; + Arcane_Volley_Timer = 140000; + CheckTreantLOS_Timer = 1000; + TreantLife_Timer = 999999; + + for(int i = 0; i < 6; ++i) + Treant_GUIDs[i] = 0; + + m_creature->SetSpeed( MOVE_RUN, 0.7f, true); + } + + void Aggro(Unit *who) + { + DoYell(SAY_COMBAT_START,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_COMBAT_START); + } + + // On Killed Unit + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY_1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY_2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void SummonTreants() + { + 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); + + 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); + if(pTreant) + { + //pTreant->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature)); + pTreant->AddThreat(m_creature, 0.1f); + Treant_GUIDs[i] = pTreant->GetGUID(); + ((mob_treantAI*)pTreant->AI())->WarpGuid = m_creature->GetGUID(); + } + } + + switch(rand()%2) + { + case 0: + DoYell(SAY_SUMMON_1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SUMMON_1); + break; + case 1: + DoYell(SAY_SUMMON_2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SUMMON_2); + break; + } + } + + // Warp Splinter eat treants if they are near him + void EatTreant() + { + for( int i=0; i<6; ++i ) + { + Unit *pTreant = Unit::GetUnit(*m_creature, 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); + } + } + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Check for War Stomp + if(War_Stomp_Timer < diff) + { + DoCast(m_creature->getVictim(),WAR_STOMP); + War_Stomp_Timer = 60000; + } + else War_Stomp_Timer -= diff; + + //Check for Arcane Volley + if(Arcane_Volley_Timer < diff) + { + DoCast(m_creature->getVictim(),ARCANE_VOLLEY); + Arcane_Volley_Timer = 40000+((rand()%20)*1000); + } + else Arcane_Volley_Timer -= diff; + + //Check for Summon Treants + if(Summon_Treants_Timer < diff) + { + SummonTreants(); + Summon_Treants_Timer = 45000; + } + else Summon_Treants_Timer -= diff; + + // 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(); + } +}; + +CreatureAI* GetAI_boss_warp_splinter(Creature *_Creature) +{ + return new boss_warp_splinterAI (_Creature); +} + +CreatureAI* GetAI_mob_treant(Creature *_Creature) +{ + return new mob_treantAI (_Creature); +} + +void AddSC_boss_warp_splinter() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_warp_splinter"; + newscript->GetAI = GetAI_boss_warp_splinter; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_warp_splinter_treant"; + newscript->GetAI = GetAI_mob_treant; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp index c671343ad2c..987e9939f3d 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp @@ -1,563 +1,545 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: boss_astromancer -SD%Complete: 75 -SDComment: -SDCategory: Tempest Keep, The Eye -EndScriptData */ - -#include "precompiled.h" -#include "def_the_eye.h" - -#define SPELL_ARCANE_MISSILES 33031 -#define SPELL_MARK_OF_THE_ASTROMANCER 33045 -#define MARK_OF_SOLARIAN 33023 -#define SPELL_BLINDING_LIGHT 33009 -#define SPELL_FEAR 29321 -#define SPELL_VOID_BOLT 39329 - -#define SAY_PHASE1 "Tal anu'men no Sin'dorei!" -#define SOUND_PHASE1 11134 -#define SAY_PHASE2 "I will crush your delusions of grandeur!" -#define SOUND_PHASE2 11140 -#define SAY_PHASE21 "Ha ha ha! You are hopelessly outmatched!" -#define SOUND_PHASE21 11139 - -#define SAY_VOID "Enough of this! Now I call upon the fury of the cosmos itself." -//#define SOUND_VOID Not found :( -#define SAY_VOID1 "I become ONE... with the VOID!" -//#define SOUND_VOID1 Not found :( - -#define SAY_KILL1 "Your soul belongs to the Abyss!" -#define SOUND_KILL1 11136 -#define SAY_KILL2 "By the blood of the Highborne!" -#define SOUND_KILL2 11137 -#define SAY_KILL3 "For the Sunwell!" -#define SOUND_KILL3 11138 -#define SAY_DEATH "The warmth of the sun... awaits." -#define SOUND_DEATH 11135 - -#define CENTER_X 432.909f -#define CENTER_Y -373.424f -#define CENTER_Z 17.9608f -#define CENTER_O 1.06421f -#define SMALL_PORTAL_RADIUS 12.6f -#define LARGE_PORTAL_RADIUS 26.0f -#define PORTAL_Z 17.005f - -#define SOLARIUM_AGENT 18925 -#define SOLARIUM_PRIEST 18806 -#define ASTROMANCER_SOLARIAN_SPOTLIGHT 18928 -#define SPELL_SPOTLIGHT 25824 -#define MODEL_HUMAN 18239 -#define MODEL_VOIDWALKER 18988 - -#define SOLARIUM_HEAL 41378 -#define SOLARIUM_SMITE 31740 -#define SOLARIUM_SILENCE 37160 - -#define WV_ARMOR 31000 -#define MIN_RANGE_FOR_DOT_JUMP 20.0f - -struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI -{ - boss_high_astromancer_solarianAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - - defaultarmor=m_creature->GetArmor(); - defaultsize=m_creature->GetFloatValue(OBJECT_FIELD_SCALE_X); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 ArcaneMissiles_Timer; - uint32 MarkOfTheAstromancer_Timer; - uint32 BlindingLight_Timer; - uint32 Fear_Timer; - uint32 VoidBolt_Timer; - uint32 Phase1_Timer; - uint32 Phase2_Timer; - uint32 Phase3_Timer; - uint32 AppearDelay_Timer; - uint32 MarkOfTheSolarian_Timer; - uint32 Jump_Timer; - uint32 defaultarmor; - - float defaultsize; - - bool AppearDelay; - - uint8 Phase; - - uint64 WrathTarget; - - float Portals[3][3]; - - void Reset() - { - WrathTarget=0; - ArcaneMissiles_Timer = 2000; - MarkOfTheAstromancer_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; - MarkOfTheSolarian_Timer=45000; - Jump_Timer=8000; - Phase = 1; - - if(pInstance) - pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, NOT_STARTED); - - 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->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_HUMAN); - } - - void StartEvent() - { - DoYell(SAY_PHASE1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE1); - - if(pInstance) - pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_KILL1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL1); - break; - case 1: - DoYell(SAY_KILL2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL2); - break; - case 2: - DoYell(SAY_KILL3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_KILL3); - break; - } - } - - void JustDied(Unit *victim) - { - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, defaultsize); - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_HUMAN); - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if(pInstance) - pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, NOT_STARTED); - } - - void Aggro(Unit *who) - { - StartEvent(); - } - - void SummonMinion(uint32 entry, float x, float y, float z) - { - Creature* Summoned = m_creature->SummonCreature(entry, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - if(Summoned) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - Summoned->AI()->AttackStart(target); - } - } - - float Portal_X(float radius) - { - if ((rand()%2)==1) radius = -radius; - return (radius * (float)(rand()%100)/100.0f + CENTER_X); - } - - float Portal_Y(float x, float radius) - { - float z; - - switch(rand()%2) - { - case 0: z = 1; break; - case 1: z = -1; break; - } - return (z*sqrt(radius*radius - (x - CENTER_X)*(x - CENTER_X)) + CENTER_Y); - } - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if (AppearDelay) - { - m_creature->StopMoving(); - m_creature->AttackStop(); - if (AppearDelay_Timer < diff) - { - AppearDelay = false; - if (Phase == 2) - { - switch (rand()%2) - { - case 0: - DoYell(SAY_PHASE2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE2); - break; - case 1: - DoYell(SAY_PHASE21, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE21); - break; - } - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_OFF); - } - if (Phase == 3) - Phase = 1; - - AppearDelay_Timer = 2000; - }else AppearDelay_Timer -= diff; - } - - //the jumping of the dot part of the wrath of the astromancer - if(WrathTarget) - { - if(Jump_Timer< diff) - { - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - bool hasJumped = false; - - Unit* target = Unit::GetUnit((*m_creature),WrathTarget); - if(target && target->isAlive()) - { - for(std::list::iterator iter = m_threatlist.begin();iter!=m_threatlist.end();++iter) - { - Unit* currentUnit=Unit::GetUnit((*m_creature),(*iter)->getUnitGuid()); - if(currentUnit) - { - if(currentUnit->IsWithinDistInMap(target,MIN_RANGE_FOR_DOT_JUMP)&¤tUnit->isAlive()&¤tUnit!=target) - { - m_creature->CastSpell(currentUnit,SPELL_MARK_OF_THE_ASTROMANCER, false,0,0,m_creature->GetGUID()); - - Jump_Timer=8000; - WrathTarget=currentUnit->GetGUID(); - hasJumped = true; - break; - } - } - } - } - - if(!hasJumped) - WrathTarget = 0; - }else Jump_Timer -= diff; - } - - if (Phase == 1) - { - //ArcaneMissiles_Timer - if (ArcaneMissiles_Timer < diff) - { - //Solarian casts Arcane Missiles on on random targets in the raid. - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (!m_creature->HasInArc(2.5f, target)) - target = m_creature->getVictim(); - if (target) - DoCast(target, SPELL_ARCANE_MISSILES); - - ArcaneMissiles_Timer = 3000; - }else ArcaneMissiles_Timer -= diff; - - //MarkOfTheSolarian_Timer - if (MarkOfTheSolarian_Timer < diff) - { - DoCast(m_creature->getVictim(), MARK_OF_SOLARIAN); - MarkOfTheSolarian_Timer = 45000; - }else MarkOfTheSolarian_Timer -= diff; - - //MarkOfTheAstromancer_Timer - if (MarkOfTheAstromancer_Timer < diff) - { - //A debuff that lasts for 5 seconds, cast several times each phase on a random raid member, but not the main tank - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - - if(target) - { - DoCast(target, SPELL_MARK_OF_THE_ASTROMANCER); - - WrathTarget=target->GetGUID(); - Jump_Timer=8000; - } - - MarkOfTheAstromancer_Timer = 15000; - }else MarkOfTheAstromancer_Timer -= diff; - - //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. - DoCast(m_creature->getVictim(), SPELL_BLINDING_LIGHT); - - BlindingLight_Timer = 45000; - }else BlindingLight_Timer -= diff; - - //Phase1_Timer - if (Phase1_Timer < diff) - { - Phase = 2; - Phase1_Timer = 50000; - //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->Relocate(CENTER_X, CENTER_Y, CENTER_Z, CENTER_O); - for(int i=0; i<=2; i++) - { - if (!i) - { - Portals[i][0] = Portal_X(SMALL_PORTAL_RADIUS); - Portals[i][1] = Portal_Y(Portals[i][0], SMALL_PORTAL_RADIUS); - Portals[i][2] = CENTER_Z; - }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; - } - } - if((abs(Portals[2][0] - Portals[1][0]) < 7) - && (abs(Portals[2][1] - Portals[1][1]) < 7)) - { - int i=1; - if(abs(CENTER_X + 26.0f - 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); - } - for (int i=0; i<=2; i++) - { - Creature* Summoned = m_creature->SummonCreature(ASTROMANCER_SOLARIAN_SPOTLIGHT, Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O, TEMPSUMMON_TIMED_DESPAWN, Phase2_Timer+Phase3_Timer+AppearDelay_Timer+1700); - if(Summoned) - { - Summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Summoned->CastSpell(Summoned, SPELL_SPOTLIGHT, false); - } - } - AppearDelay = true; - }else Phase1_Timer-=diff; - } - else if(Phase == 2) - { - //10 seconds after Solarian disappears, 12 mobs spawn out of the three portals. - m_creature->AttackStop(); - m_creature->StopMoving(); - if (Phase2_Timer < diff) - { - Phase = 3; - for (int i=0; i<=2; i++) - for (int j=1; j<=4; j++) - SummonMinion(SOLARIUM_AGENT, Portals[i][0], Portals[i][1], Portals[i][2]); - Phase2_Timer = 10000; - } else Phase2_Timer -= diff; - } - else if(Phase == 3) - { - //Check Phase3_Timer - if(Phase3_Timer < diff) - { - //15 seconds later Solarian reappears out of one of the 3 portals. Simultaneously, 2 healers appear in the two other portals. - m_creature->AttackStop(); - m_creature->StopMoving(); - int i = rand()%3; - m_creature->GetMotionMaster()->Clear(); - m_creature->Relocate(Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O); - - for (int j=0; j<=2; j++) - if (j!=i) - SummonMinion(SOLARIUM_PRIEST, Portals[j][0], Portals[j][1], Portals[j][2]); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_ON); - - DoYell(SAY_PHASE1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE1); - AppearDelay = true; - Phase3_Timer = 15000; - }else Phase3_Timer -= diff; - } - else if(Phase == 4) - { - //Fear_Timer - if (Fear_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_FEAR); - Fear_Timer = 20000; - }else Fear_Timer -= diff; - - //VoidBolt_Timer - if (VoidBolt_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_VOID_BOLT); - VoidBolt_Timer = 10000; - }else VoidBolt_Timer -= diff; - } - - //When Solarian reaches 20% she will transform into a huge void walker. - if(Phase != 4 && ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth())<20)) - { - 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); - switch(rand()%2) - { - case 0: - DoYell(SAY_VOID, LANG_UNIVERSAL, NULL); - break; - case 1: - DoYell(SAY_VOID1, LANG_UNIVERSAL, NULL); - break; - } - - m_creature->SetArmor(WV_ARMOR); - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_VOIDWALKER); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, defaultsize*2.5f); - } - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_solarium_priestAI : public ScriptedAI -{ - mob_solarium_priestAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 healTimer; - uint32 holysmiteTimer; - uint32 aoesilenceTimer; - - void Reset() - { - healTimer = 9000; - holysmiteTimer = 1; - aoesilenceTimer = 15000; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (healTimer < diff) - { - Unit* target = NULL; - - switch(rand()%2) - { - case 0: - if(pInstance) - target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ASTROMANCER)); - break; - case 1: - target = m_creature; - break; - } - - if(target) - { - DoCast(target,SOLARIUM_HEAL); - healTimer = 9000; - } - } else healTimer -= diff; - - if(holysmiteTimer < diff) - { - DoCast(m_creature->getVictim(), SOLARIUM_SMITE); - holysmiteTimer = 4000; - } else holysmiteTimer -= diff; - - if (aoesilenceTimer < diff) - { - DoCast(m_creature->getVictim(), SOLARIUM_SILENCE); - aoesilenceTimer = 13000; - } else aoesilenceTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_solarium_priest(Creature *_Creature) -{ - return new mob_solarium_priestAI (_Creature); -} - -CreatureAI* GetAI_boss_high_astromancer_solarian(Creature *_Creature) -{ - return new boss_high_astromancer_solarianAI (_Creature); -} - -void AddSC_boss_high_astromancer_solarian() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_high_astromancer_solarian"; - newscript->GetAI = GetAI_boss_high_astromancer_solarian; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_solarium_priest"; - newscript->GetAI = GetAI_mob_solarium_priest; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_astromancer +SD%Complete: 75 +SDComment: +SDCategory: Tempest Keep, The Eye +EndScriptData */ + +#include "precompiled.h" +#include "def_the_eye.h" + +#define SPELL_ARCANE_MISSILES 33031 +#define SPELL_MARK_OF_THE_ASTROMANCER 33045 +#define MARK_OF_SOLARIAN 33023 +#define SPELL_BLINDING_LIGHT 33009 +#define SPELL_FEAR 29321 +#define SPELL_VOID_BOLT 39329 + +#define SAY_PHASE1 "Tal anu'men no Sin'dorei!" +#define SOUND_PHASE1 11134 +#define SAY_PHASE2 "I will crush your delusions of grandeur!" +#define SOUND_PHASE2 11140 +#define SAY_PHASE21 "Ha ha ha! You are hopelessly outmatched!" +#define SOUND_PHASE21 11139 + +#define SAY_VOID "Enough of this! Now I call upon the fury of the cosmos itself." +//#define SOUND_VOID Not found :( +#define SAY_VOID1 "I become ONE... with the VOID!" +//#define SOUND_VOID1 Not found :( + +#define SAY_KILL1 "Your soul belongs to the Abyss!" +#define SOUND_KILL1 11136 +#define SAY_KILL2 "By the blood of the Highborne!" +#define SOUND_KILL2 11137 +#define SAY_KILL3 "For the Sunwell!" +#define SOUND_KILL3 11138 +#define SAY_DEATH "The warmth of the sun... awaits." +#define SOUND_DEATH 11135 + +#define CENTER_X 432.909f +#define CENTER_Y -373.424f +#define CENTER_Z 17.9608f +#define CENTER_O 1.06421f +#define SMALL_PORTAL_RADIUS 12.6f +#define LARGE_PORTAL_RADIUS 26.0f +#define PORTAL_Z 17.005f + +#define SOLARIUM_AGENT 18925 +#define SOLARIUM_PRIEST 18806 +#define ASTROMANCER_SOLARIAN_SPOTLIGHT 18928 +#define SPELL_SPOTLIGHT 25824 +#define MODEL_HUMAN 18239 +#define MODEL_VOIDWALKER 18988 + +#define SOLARIUM_HEAL 41378 +#define SOLARIUM_SMITE 31740 +#define SOLARIUM_SILENCE 37160 + +#define WV_ARMOR 31000 +#define MIN_RANGE_FOR_DOT_JUMP 20.0f + +struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI +{ + boss_high_astromancer_solarianAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + + defaultarmor=m_creature->GetArmor(); + defaultsize=m_creature->GetFloatValue(OBJECT_FIELD_SCALE_X); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 ArcaneMissiles_Timer; + uint32 MarkOfTheAstromancer_Timer; + uint32 BlindingLight_Timer; + uint32 Fear_Timer; + uint32 VoidBolt_Timer; + uint32 Phase1_Timer; + uint32 Phase2_Timer; + uint32 Phase3_Timer; + uint32 AppearDelay_Timer; + uint32 MarkOfTheSolarian_Timer; + uint32 Jump_Timer; + uint32 defaultarmor; + + float defaultsize; + + bool AppearDelay; + + uint8 Phase; + + uint64 WrathTarget; + + float Portals[3][3]; + + void Reset() + { + WrathTarget=0; + ArcaneMissiles_Timer = 2000; + MarkOfTheAstromancer_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; + MarkOfTheSolarian_Timer=45000; + Jump_Timer=8000; + Phase = 1; + + if(pInstance) + pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, NOT_STARTED); + + 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->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_HUMAN); + } + + void StartEvent() + { + DoYell(SAY_PHASE1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE1); + + if(pInstance) + pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_KILL1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL1); + break; + case 1: + DoYell(SAY_KILL2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL2); + break; + case 2: + DoYell(SAY_KILL3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_KILL3); + break; + } + } + + void JustDied(Unit *victim) + { + m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, defaultsize); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_HUMAN); + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if(pInstance) + pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, NOT_STARTED); + } + + void Aggro(Unit *who) + { + StartEvent(); + } + + void SummonMinion(uint32 entry, float x, float y, float z) + { + Creature* Summoned = m_creature->SummonCreature(entry, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + if(Summoned) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + Summoned->AI()->AttackStart(target); + } + } + + float Portal_X(float radius) + { + if ((rand()%2)==1) radius = -radius; + return (radius * (float)(rand()%100)/100.0f + CENTER_X); + } + + float Portal_Y(float x, float radius) + { + float z; + + switch(rand()%2) + { + case 0: z = 1; break; + case 1: z = -1; break; + } + return (z*sqrt(radius*radius - (x - CENTER_X)*(x - CENTER_X)) + CENTER_Y); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if (AppearDelay) + { + m_creature->StopMoving(); + m_creature->AttackStop(); + if (AppearDelay_Timer < diff) + { + AppearDelay = false; + if (Phase == 2) + { + switch (rand()%2) + { + case 0: + DoYell(SAY_PHASE2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE2); + break; + case 1: + DoYell(SAY_PHASE21, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE21); + break; + } + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetVisibility(VISIBILITY_OFF); + } + if (Phase == 3) + Phase = 1; + + AppearDelay_Timer = 2000; + }else AppearDelay_Timer -= diff; + } + + //the jumping of the dot part of the wrath of the astromancer + if(WrathTarget) + { + if(Jump_Timer< diff) + { + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + bool hasJumped = false; + + Unit* target = Unit::GetUnit((*m_creature),WrathTarget); + if(target && target->isAlive()) + { + for(std::list::iterator iter = m_threatlist.begin();iter!=m_threatlist.end();++iter) + { + Unit* currentUnit=Unit::GetUnit((*m_creature),(*iter)->getUnitGuid()); + if(currentUnit) + { + if(currentUnit->IsWithinDistInMap(target,MIN_RANGE_FOR_DOT_JUMP)&¤tUnit->isAlive()&¤tUnit!=target) + { + m_creature->CastSpell(currentUnit,SPELL_MARK_OF_THE_ASTROMANCER, false,0,0,m_creature->GetGUID()); + + Jump_Timer=8000; + WrathTarget=currentUnit->GetGUID(); + hasJumped = true; + break; + } + } + } + } + + if(!hasJumped) + WrathTarget = 0; + }else Jump_Timer -= diff; + } + + if (Phase == 1) + { + //ArcaneMissiles_Timer + if (ArcaneMissiles_Timer < diff) + { + //Solarian casts Arcane Missiles on on random targets in the raid. + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (!m_creature->HasInArc(2.5f, target)) + target = m_creature->getVictim(); + if (target) + DoCast(target, SPELL_ARCANE_MISSILES); + + ArcaneMissiles_Timer = 3000; + }else ArcaneMissiles_Timer -= diff; + + //MarkOfTheSolarian_Timer + if (MarkOfTheSolarian_Timer < diff) + { + DoCast(m_creature->getVictim(), MARK_OF_SOLARIAN); + MarkOfTheSolarian_Timer = 45000; + }else MarkOfTheSolarian_Timer -= diff; + + //MarkOfTheAstromancer_Timer + if (MarkOfTheAstromancer_Timer < diff) + { + //A debuff that lasts for 5 seconds, cast several times each phase on a random raid member, but not the main tank + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + + if(target) + { + DoCast(target, SPELL_MARK_OF_THE_ASTROMANCER); + + WrathTarget=target->GetGUID(); + Jump_Timer=8000; + } + + MarkOfTheAstromancer_Timer = 15000; + }else MarkOfTheAstromancer_Timer -= diff; + + //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. + DoCast(m_creature->getVictim(), SPELL_BLINDING_LIGHT); + + BlindingLight_Timer = 45000; + }else BlindingLight_Timer -= diff; + + //Phase1_Timer + if (Phase1_Timer < diff) + { + Phase = 2; + Phase1_Timer = 50000; + //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->Relocate(CENTER_X, CENTER_Y, CENTER_Z, CENTER_O); + for(int i=0; i<=2; i++) + { + if (!i) + { + Portals[i][0] = Portal_X(SMALL_PORTAL_RADIUS); + Portals[i][1] = Portal_Y(Portals[i][0], SMALL_PORTAL_RADIUS); + Portals[i][2] = CENTER_Z; + }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; + } + } + if((abs(Portals[2][0] - Portals[1][0]) < 7) + && (abs(Portals[2][1] - Portals[1][1]) < 7)) + { + int i=1; + if(abs(CENTER_X + 26.0f - 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); + } + for (int i=0; i<=2; i++) + { + Creature* Summoned = m_creature->SummonCreature(ASTROMANCER_SOLARIAN_SPOTLIGHT, Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O, TEMPSUMMON_TIMED_DESPAWN, Phase2_Timer+Phase3_Timer+AppearDelay_Timer+1700); + if(Summoned) + { + Summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Summoned->CastSpell(Summoned, SPELL_SPOTLIGHT, false); + } + } + AppearDelay = true; + }else Phase1_Timer-=diff; + } + else if(Phase == 2) + { + //10 seconds after Solarian disappears, 12 mobs spawn out of the three portals. + m_creature->AttackStop(); + m_creature->StopMoving(); + if (Phase2_Timer < diff) + { + Phase = 3; + for (int i=0; i<=2; i++) + for (int j=1; j<=4; j++) + SummonMinion(SOLARIUM_AGENT, Portals[i][0], Portals[i][1], Portals[i][2]); + Phase2_Timer = 10000; + } else Phase2_Timer -= diff; + } + else if(Phase == 3) + { + //Check Phase3_Timer + if(Phase3_Timer < diff) + { + //15 seconds later Solarian reappears out of one of the 3 portals. Simultaneously, 2 healers appear in the two other portals. + m_creature->AttackStop(); + m_creature->StopMoving(); + int i = rand()%3; + m_creature->GetMotionMaster()->Clear(); + m_creature->Relocate(Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O); + + for (int j=0; j<=2; j++) + if (j!=i) + SummonMinion(SOLARIUM_PRIEST, Portals[j][0], Portals[j][1], Portals[j][2]); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetVisibility(VISIBILITY_ON); + + DoYell(SAY_PHASE1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE1); + AppearDelay = true; + Phase3_Timer = 15000; + }else Phase3_Timer -= diff; + } + else if(Phase == 4) + { + //Fear_Timer + if (Fear_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FEAR); + Fear_Timer = 20000; + }else Fear_Timer -= diff; + + //VoidBolt_Timer + if (VoidBolt_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_VOID_BOLT); + VoidBolt_Timer = 10000; + }else VoidBolt_Timer -= diff; + } + + //When Solarian reaches 20% she will transform into a huge void walker. + if(Phase != 4 && ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth())<20)) + { + 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); + switch(rand()%2) + { + case 0: + DoYell(SAY_VOID, LANG_UNIVERSAL, NULL); + break; + case 1: + DoYell(SAY_VOID1, LANG_UNIVERSAL, NULL); + break; + } + + m_creature->SetArmor(WV_ARMOR); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, MODEL_VOIDWALKER); + m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, defaultsize*2.5f); + } + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_solarium_priestAI : public ScriptedAI +{ + mob_solarium_priestAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 healTimer; + uint32 holysmiteTimer; + uint32 aoesilenceTimer; + + void Reset() + { + healTimer = 9000; + holysmiteTimer = 1; + aoesilenceTimer = 15000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (healTimer < diff) + { + Unit* target = NULL; + + switch(rand()%2) + { + case 0: + if(pInstance) + target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ASTROMANCER)); + break; + case 1: + target = m_creature; + break; + } + + if(target) + { + DoCast(target,SOLARIUM_HEAL); + healTimer = 9000; + } + } else healTimer -= diff; + + if(holysmiteTimer < diff) + { + DoCast(m_creature->getVictim(), SOLARIUM_SMITE); + holysmiteTimer = 4000; + } else holysmiteTimer -= diff; + + if (aoesilenceTimer < diff) + { + DoCast(m_creature->getVictim(), SOLARIUM_SILENCE); + aoesilenceTimer = 13000; + } else aoesilenceTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_solarium_priest(Creature *_Creature) +{ + return new mob_solarium_priestAI (_Creature); +} + +CreatureAI* GetAI_boss_high_astromancer_solarian(Creature *_Creature) +{ + return new boss_high_astromancer_solarianAI (_Creature); +} + +void AddSC_boss_high_astromancer_solarian() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_high_astromancer_solarian"; + newscript->GetAI = GetAI_boss_high_astromancer_solarian; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_solarium_priest"; + newscript->GetAI = GetAI_mob_solarium_priest; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp index 4e88e44f799..78eabcde19f 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp @@ -1,1639 +1,1621 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: boss_Kaelthas -SD%Complete: 60 -SDComment: SQL, phase 2, phase 3, Mind Control, taunt immunity -SDCategory: Tempest Keep, The Eye -EndScriptData */ - -#include "precompiled.h" -#include "def_the_eye.h" -#include "WorldPacket.h" - -//Phase 2 spells (Not used) -#define SPELL_SUMMON_WEAPONS 36976 -#define SPELL_SUMMON_WEAPONA 36958 -#define SPELL_SUMMON_WEAPONB 36959 -#define SPELL_SUMMON_WEAPONC 36960 -#define SPELL_SUMMON_WEAPOND 36961 -#define SPELL_SUMMON_WEAPONE 36962 -#define SPELL_SUMMON_WEAPONF 36963 -#define SPELL_SUMMON_WEAPONG 36964 -#define SPELL_RES_VISUAL 24171 -#define SPELL_WEAPON_SPAWN 41236 -//Phase 4 spells -#define SPELL_FIREBALL 22088 //wrong but works with CastCustomSpell -#define SPELL_PYROBLAST 36819 -#define SPELL_FLAME_STRIKE 36735 -#define SPELL_FLAME_STRIKE_VIS 36730 -#define SPELL_FLAME_STRIKE_DMG 36731 -#define SPELL_ARCANE_DISRUPTION 36834 -#define SPELL_SHOCK_BARRIER 36815 -#define SPELL_PHOENIX_ANIMATION 36723 -#define SPELL_MIND_CONTROL 32830 -//Phase 5 spells -#define SPELL_EXPLODE 36092 -#define SPELL_FULLPOWER 36187 -#define SPELL_KNOCKBACK 11027 -#define SPELL_GRAVITY_LAPSE 34480 -#define SPELL_GRAVITY_LAPSE_AURA 39432 -#define SPELL_NETHER_BEAM 35873 -//Thaladred the Darkener spells -#define SPELL_PSYCHIC_BLOW 10689 -#define SPELL_SILENCE 30225 -//Lord Sanguinar spells -#define SPELL_BELLOWING_ROAR 40636 -//Grand Astromancer Capernian spells -#define CAPERNIAN_DISTANCE 20 //she casts away from the target -#define SPELL_CAPERNIAN_FIREBALL 36971 -#define SPELL_CONFLAGRATION 37018 -#define SPELL_ARCANE_EXPLOSION 36970 -//Master Engineer Telonicus spells -#define SPELL_BOMB 37036 -#define SPELL_REMOTE_TOY 37027 -//Nether Vapor spell -#define SPELL_NETHER_VAPOR 35859 -//Phoenix spell -#define SPELL_BURN 36721 - -//kael'thas Speech -#define SAY_INTRO "Energy. Power. My people are addicted to it... a dependence made manifest after the Sunwell was destroyed. Welcome... to the future. A pity you are too late to stop it. No one can stop me now! Selama ashal'anore!" -#define SOUND_INTRO 11256 - -#define SAY_ASTROMANCER_CAPERNIAN "Capernian will see to it that your stay here is a short one." -#define SOUND_ASTROMANCER_CAPERNIAN 11257 - -#define SAY_ENGINEER_TELONICUS "Well done, you have proven worthy to test your skills against my master engineer, Telonicus." -#define SOUND_ENGINEER_TELONICUS 11258 - -#define SAY_THALADRED_THE_DARKENER "Let us see how your nerves hold up against the Darkener, Thaladred" -#define SOUND_THALADRED_THE_DARKENER 11259 - -#define SAY_LORD_SANGUINAR "You have persevered against some of my best advisors... but none can withstand the might of the Blood Hammer. Behold, Lord Sanguinar!" -#define SOUND_LORD_SANGUINAR 11260 - -#define SAY_PHASE2 "As you see, I have many weapons in my arsenal...." -#define SOUND_PHASE2 11261 - -#define SAY_PHASE3 "Perhaps I underestimated you. It would be unfair to make you fight all four advisors at once, but... fair treatment was never shown to my people. I'm just returning the favor." -#define SOUND_PHASE3 11262 - -#define SAY_PHASE4 "Alas, sometimes one must take matters into one's own hands. Balamore shanal!" -#define SOUND_PHASE4 11263 - -#define SAY_PHASE5 "I have not come this far to be stopped! The future I have planned will not be jeopardized! Now you will taste true power!!" -#define SOUND_PHASE5 11273 - -#define SAY_SLAY1 "You will not prevail." -#define SOUND_SLAY1 11270 - -#define SAY_SLAY2 "You gambled...and lost." -#define SOUND_SLAY2 11271 - -#define SAY_MINDCONTROL1 "Obey me." -#define SOUND_MINDCONTROL1 11268 - -#define SAY_MINDCONTROL2 "Bow to my will." -#define SOUND_MINDCONTROL2 11269 - -#define SAY_GRAVITYLAPSE1 "Let us see how you fare when your world is turned upside down." -#define SOUND_GRAVITYLAPSE1 11264 - -#define SAY_GRAVITYLAPSE2 "Having trouble staying grounded?" -#define SOUND_GRAVITYLAPSE2 11265 - -#define SAY_SUMMON_PHOENIX1 "Anara'nel belore!" -#define SOUND_SUMMON_PHOENIX1 11267 - -#define SAY_SUMMON_PHOENIX2 "By the power of the sun!" -#define SOUND_SUMMON_PHOENIX2 11266 - -#define SAY_DEATH "For...Quel...thalas!" -#define SOUND_DEATH 11274 - -//Thaladred the Darkener speech -#define SAY_THALADRED_AGGRO "Prepare yourselves!" -#define SOUND_THALADRED_AGGRO 11203 -#define SAY_THALADRED_DEATH "Forgive me, my prince! I have... failed." -#define SOUND_THALADRED_DEATH 11204 -#define EMOTE_THALADRED_GAZE "sets his gaze on $N!" - -//Lord Sanguinar speech -#define SAY_SANGUINAR_AGGRO "Blood for blood!" -#define SOUND_SANGUINAR_AGGRO 11152 -#define SAY_SANGUINAR_DEATH "NO! I ...will... not..." -#define SOUND_SANGUINAR_DEATH 11153 - -//Grand Astromancer Capernian speech -#define SAY_CAPERNIAN_AGGRO "The sin'dore reign supreme!" -#define SOUND_CAPERNIAN_AGGRO 11117 -#define SAY_CAPERNIAN_DEATH "This is not over!" -#define SOUND_CAPERNIAN_DEATH 11118 - -//Master Engineer Telonicus speech -#define SAY_TELONICUS_AGGRO "Anar'alah belore!" -#define SOUND_TELONICUS_AGGRO 11157 -#define SAY_TELONICUS_DEATH "More perils... await" -#define SOUND_TELONICUS_DEATH 11158 - -//Creature IDs -#define PHOENIX 21362 -#define PHOENIX_EGG 21364 - -//Phoenix egg and phoenix model -#define PHOENIX_MODEL 19682 -#define PHOENIX_EGG_MODEL 20245 - -//#define PI 3.141592 -#define TEMP_MC_WHISPER "[SD2 Debug] You would be mind controlled here!" - -//weapon id + position -float KaelthasWeapons[7][5] = -{ - {21270, 794.38, 15, 48.72, 2.9}, //[Cosmic Infuser] - {21269, 785.47, 12.12, 48.72, 3.14}, //[Devastation] - {21271, 781.25, 4.39, 48.72, 3.14}, //[Infinity Blade] - {21273, 777.38, -0.81, 48.72, 3.06}, //[Phaseshift Bulwark] - {21274, 781.48, -6.08, 48.72, 3.9}, //[Staff of Disintegration] - {21272, 785.42, -13.59, 48.72, 3.4}, //[Warp Slicer] - {21268, 793.06, -16.61, 48.72, 3.10} //[Netherstrand Longbow] -}; - -#define GRAVITY_X 795.0f -#define GRAVITY_Y 0.0f -#define GRAVITY_Z 70.0f - -#define TIME_PHASE_2_3 120000 -#define TIME_PHASE_3_4 120000 - -#define KAEL_VISIBLE_RANGE 50.0f - -//Base AI for Advisors -struct MANGOS_DLL_DECL advisorbase_ai : public ScriptedAI -{ - ScriptedInstance* pInstance; - bool FakeDeath; - uint32 DelayRes_Timer; - uint64 DelayRes_Target; - - advisorbase_ai(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || FakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) - { - if (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) ) - { - DoStartAttackAndMovement(who); - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - } - - void AttackStart(Unit* who) - { - if (!who || FakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (who->isTargetableForAttack()) - { - //Begin attack - DoStartAttackAndMovement(who); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - - void Reset() - { - FakeDeath = false; - DelayRes_Timer = 0; - DelayRes_Target = 0; - - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - //reset encounter - if(pInstance && (pInstance->GetData(DATA_KAELTHASEVENT) == 1 || pInstance->GetData(DATA_KAELTHASEVENT) == 3)) - { - Creature *Kaelthas = NULL; - Kaelthas = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KAELTHAS))); - - if(Kaelthas) - Kaelthas->AI()->EnterEvadeMode(); - } - } - - void Revive(Unit* Target) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetHealth(m_creature->GetMaxHealth()); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - DoCast(m_creature, SPELL_RES_VISUAL, false); - DelayRes_Timer = 2000; - } - - void DamageTaken(Unit* pKiller, uint32 &damage) - { - if (damage < m_creature->GetHealth()) - return; - - //Prevent glitch if in fake death - if (FakeDeath) - { - damage = 0; - return; - } - //Don't really die in phase 1 & 3, only die after that - if(pInstance && pInstance->GetData(DATA_KAELTHASEVENT) != 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->SetUInt32Value(UNIT_FIELD_BYTES_1,PLAYER_STATE_DEAD); - - if (pInstance->GetData(DATA_KAELTHASEVENT) == 3) - JustDied(pKiller); - } - } - - void UpdateAI(const uint32 diff) - { - if (DelayRes_Timer) - if (DelayRes_Timer <= diff) - { - DelayRes_Timer = 0; - FakeDeath = false; - - Unit* Target = Unit::GetUnit((*m_creature), DelayRes_Target); - if (!Target)Target = m_creature->getVictim(); - DoResetThreat(); - AttackStart(Target); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(Target); - m_creature->AddThreat(Target, 0.0f); - }else DelayRes_Timer -= diff; - } - -}; - -//Kael'thas AI -struct MANGOS_DLL_DECL boss_kaelthasAI : public ScriptedAI -{ - boss_kaelthasAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - AdvisorGuid[0] = 0; - AdvisorGuid[1] = 0; - AdvisorGuid[2] = 0; - AdvisorGuid[3] = 0; - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 Fireball_Timer; - uint32 ArcaneDisruption_Timer; - uint32 Phoenix_Timer; - uint32 ShockBarrier_Timer; - uint32 GravityLapse_Timer; - uint32 GravityLapse_Phase; - uint32 NetherBeam_Timer; - uint32 NetherVapor_Timer; - uint32 FlameStrike_Timer; - uint32 MindControl_Timer; - uint32 Phase; - uint32 PhaseSubphase; //generic - uint32 Phase_Timer; //generic timer - uint32 PyrosCasted; - - bool InGravityLapse; - bool IsCastingFireball; - bool ChainPyros; - - uint64 AdvisorGuid[4]; - - void Reset() - { - Fireball_Timer = 5000+rand()%10000; - ArcaneDisruption_Timer = 45000; - MindControl_Timer = 40000; - Phoenix_Timer = 50000; - ShockBarrier_Timer = 60000; - FlameStrike_Timer = 30000; - GravityLapse_Timer = 20000; - GravityLapse_Phase = 0; - NetherBeam_Timer = 8000; - NetherVapor_Timer = 10000; - PyrosCasted = 0; - Phase = 0; - InGravityLapse = false; - IsCastingFireball = false; - ChainPyros = false; - - if(InCombat) - PrepareAdvisors(); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - if(pInstance) - pInstance->SetData(DATA_KAELTHASEVENT, 0); - } - - void PrepareAdvisors() - { - Creature *pCreature; - for(uint8 i = 0; i < 4; i++) - { - pCreature = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[i])); - if(pCreature) - { - pCreature->Respawn(); - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pCreature->setFaction(m_creature->getFaction()); - pCreature->AI()->EnterEvadeMode(); - } - } - } - - void StartEvent() - { - if(!pInstance) - return; - - AdvisorGuid[0] = pInstance->GetData64(DATA_THALADREDTHEDARKENER); - AdvisorGuid[1] = pInstance->GetData64(DATA_LORDSANGUINAR); - AdvisorGuid[2] = pInstance->GetData64(DATA_GRANDASTROMANCERCAPERNIAN); - AdvisorGuid[3] = pInstance->GetData64(DATA_MASTERENGINEERTELONICUS); - - if(!AdvisorGuid[0] || !AdvisorGuid[1] || !AdvisorGuid[2] || !AdvisorGuid[3]) - { - error_log("SD2: Kael'Thas One or more advisors missing, Skipping Phases 1-3"); - DoYell("SD2: Kael'Thas One or more advisors missing, Skipping Phases 1-3", LANG_UNIVERSAL, NULL); - - DoYell(SAY_PHASE4, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE4); - Phase = 4; - - pInstance->SetData(DATA_KAELTHASEVENT, 4); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - DoStartAttackAndMovement(target); - } - }else - { - PrepareAdvisors(); - - DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_INTRO); - - pInstance->SetData(DATA_KAELTHASEVENT, 1); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - PhaseSubphase = 0; - Phase_Timer = 23000; - Phase = 1; - } - } - - void KilledUnit() - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY2); - break; - } - } - - void JustDied(Unit* Killer) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - - if(pInstance) - pInstance->SetData(DATA_KAELTHASEVENT, 0); - - Creature *pCreature; - for(uint8 i = 0; i < 4; i++) - { - pCreature = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[i])); - if(pCreature) - { - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - } - } - - void Aggro(Unit *who) - { - if (pInstance && !pInstance->GetData(DATA_KAELTHASEVENT) && !Phase) - StartEvent(); - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || m_creature->getVictim()) - return; - - if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) - { - float attackRadius = m_creature->GetAttackDistance(who); - if (Phase >= 4 && m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who)) - { - if(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - else if(who->isAlive()) - { - if (pInstance && !pInstance->GetData(DATA_KAELTHASEVENT) && !Phase && m_creature->IsWithinDistInMap(who, 60.0f)) - StartEvent(); - - //add to the threat list, so we can use SelectTarget - m_creature->AddThreat(who,0.0f); - } - } - } - - void UpdateAI(const uint32 diff) - { - //Phase 1 - switch (Phase) - { - case 1: - { - Unit *target; - Creature* Advisor; - - //Subphase switch - switch(PhaseSubphase) - { - //Subphase 1 - Start - case 0: - if(Phase_Timer < diff) - { - DoYell(SAY_THALADRED_THE_DARKENER, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_THALADRED_THE_DARKENER); - - //start advisor within 7 seconds - Phase_Timer = 7000; - - PhaseSubphase++; - }else Phase_Timer -= diff; - break; - - //Subphase 1 - Unlock advisor - case 1: - if(Phase_Timer < diff) - { - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[0])); - - if(Advisor) - { - Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Advisor->setFaction(m_creature->getFaction()); - - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - Advisor->AI()->AttackStart(target); - } - - PhaseSubphase++; - }else Phase_Timer -= diff; - break; - - //Subphase 2 - Start - case 2: - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[0])); - if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == PLAYER_STATE_DEAD)) - { - DoYell(SAY_LORD_SANGUINAR, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_LORD_SANGUINAR); - - //start advisor within 12.5 seconds - Phase_Timer = 12500; - - PhaseSubphase++; - } - break; - - //Subphase 2 - Unlock advisor - case 3: - if(Phase_Timer < diff) - { - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[1])); - - if(Advisor) - { - Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Advisor->setFaction(m_creature->getFaction()); - - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - Advisor->AI()->AttackStart(target); - } - - PhaseSubphase++; - }else Phase_Timer -= diff; - break; - - //Subphase 3 - Start - case 4: - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[1])); - if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == PLAYER_STATE_DEAD)) - { - DoYell(SAY_ASTROMANCER_CAPERNIAN, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ASTROMANCER_CAPERNIAN); - - //start advisor within 7 seconds - Phase_Timer = 7000; - - PhaseSubphase++; - } - break; - - //Subphase 3 - Unlock advisor - case 5: - if(Phase_Timer < diff) - { - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[2])); - - if(Advisor) - { - Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Advisor->setFaction(m_creature->getFaction()); - - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - Advisor->AI()->AttackStart(target); - } - - PhaseSubphase++; - }else Phase_Timer -= diff; - break; - - //Subphase 4 - Start - case 6: - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[2])); - if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == PLAYER_STATE_DEAD)) - { - DoYell(SAY_ENGINEER_TELONICUS, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_ENGINEER_TELONICUS); - - //start advisor within 8.4 seconds - Phase_Timer = 8400; - - PhaseSubphase++; - } - break; - - //Subphase 4 - Unlock advisor - case 7: - if(Phase_Timer < diff) - { - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[3])); - - if(Advisor) - { - Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Advisor->setFaction(m_creature->getFaction()); - - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - Advisor->AI()->AttackStart(target); - } - - Phase_Timer = 3000; - - PhaseSubphase++; - }else Phase_Timer -= diff; - break; - - //End of phase 1 - case 8: - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[3])); - if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == PLAYER_STATE_DEAD)) - { - Phase = 2; - pInstance->SetData(DATA_KAELTHASEVENT, 2); - - DoYell(SAY_PHASE2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE2); - PhaseSubphase = 0; - Phase_Timer = 3500; - DoCast(m_creature, SPELL_SUMMON_WEAPONS); - } - break; - } - }break; - - case 2: - { - if (PhaseSubphase == 0) - { - if (Phase_Timer < diff) - { - PhaseSubphase = 1; - }else Phase_Timer -= diff; - } - - //Spawn weapons - if (PhaseSubphase == 1) - { - Unit* Target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - Creature* Weapon; - for (uint32 i = 0; i < 7; i++) - { - Weapon = m_creature->SummonCreature(((uint32)KaelthasWeapons[i][0]),KaelthasWeapons[i][1],KaelthasWeapons[i][2],KaelthasWeapons[i][3],0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); - - if (!Weapon) - error_log("SD2: Kael'thas weapon %i could not be spawned", i); - else - { - Weapon->setFaction(m_creature->getFaction()); - Weapon->AI()->AttackStart(Target); - Weapon->CastSpell(Weapon, SPELL_WEAPON_SPAWN, false); - } - } - - PhaseSubphase = 2; - Phase_Timer = TIME_PHASE_2_3; - } - - if (PhaseSubphase == 2) - if (Phase_Timer < diff) - { - DoYell(SAY_PHASE3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE3); - pInstance->SetData(DATA_KAELTHASEVENT, 3); - Phase = 3; - PhaseSubphase = 0; - }else Phase_Timer -= diff; - }break; - - case 3: - { - if (PhaseSubphase == 0) - { - //Respawn advisors - Unit* Target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - Creature* Advisor; - for (uint32 i = 0; i < 4; i++) - { - Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[i])); - if (!Advisor) - error_log("SD2: Kael'Thas Advisor %u does not exist. Possibly despawned? Incorrectly Killed?", i); - else ((advisorbase_ai*)Advisor->AI())->Revive(Target); - } - - PhaseSubphase = 1; - Phase_Timer = TIME_PHASE_3_4; - } - - if(Phase_Timer < diff) - { - DoYell(SAY_PHASE4, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE4); - Phase = 4; - - pInstance->SetData(DATA_KAELTHASEVENT, 4); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - DoStartAttackAndMovement(target); - } - Phase_Timer = 30000; - }else Phase_Timer -= diff; - } - break; - - case 4: - case 5: - case 6: - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Fireball_Timer - if(!InGravityLapse && !ChainPyros && Phase != 5) - { - if(Fireball_Timer < diff) - { - if(!IsCastingFireball) - { - if(!m_creature->IsNonMeleeSpellCasted(false)) - { - //interruptable - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false); - int32 dmg = 20000+rand()%5000; - m_creature->CastCustomSpell(m_creature->getVictim(), SPELL_FIREBALL, &dmg, 0, 0, false); - IsCastingFireball = true; - Fireball_Timer = 2500; - } - } - else - { - //apply resistance - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); - IsCastingFireball = false; - Fireball_Timer = 5000+rand()%10000; - } - }else Fireball_Timer -= diff; - - //ArcaneDisruption_Timer - if(ArcaneDisruption_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ARCANE_DISRUPTION, true); - - ArcaneDisruption_Timer = 60000; - }else ArcaneDisruption_Timer -= diff; - - if (FlameStrike_Timer < diff) - { - Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0); - DoCast(pUnit, SPELL_FLAME_STRIKE); - - FlameStrike_Timer = 30000; - }FlameStrike_Timer -= diff; - - if (MindControl_Timer < diff) - { - if (m_creature->getThreatManager().getThreatList().size() >= 2) - for (uint32 i = 0; i < 3; i++) - { - debug_log("SD2: Kael'Thas mind control not supported."); - //DoCast(pUnit, SPELL_MIND_CONTROL); - } - - MindControl_Timer = 60000; - }MindControl_Timer -= diff; - } - - //Phoenix_Timer - if(Phoenix_Timer < diff) - { - DoCast(m_creature, SPELL_PHOENIX_ANIMATION); - Creature *Phoenix = DoSpawnCreature(PHOENIX, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); - - if(Phoenix) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (target) - Phoenix->AI()->AttackStart(target); - }else error_log("SD2: Kael'Thas Phoenix could not be spawned"); - - switch(rand()%2) - { - case 0: - DoYell(SAY_SUMMON_PHOENIX1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON_PHOENIX1); - break; - - case 1: - DoYell(SAY_SUMMON_PHOENIX2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SUMMON_PHOENIX2); - break; - - default: - break; - } - - Phoenix_Timer = 60000; - }else Phoenix_Timer -= diff; - - //Phase 4 specific spells - if(Phase == 4) - { - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50) - { - pInstance->SetData(DATA_KAELTHASEVENT, 4); - Phase = 5; - Phase_Timer = 10000; - - DoYell(SAY_PHASE5, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_PHASE5); - - m_creature->StopMoving(); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->Relocate(GRAVITY_X, GRAVITY_Y, GRAVITY_Z, 0); - m_creature->SendMonsterMove(GRAVITY_X, GRAVITY_Y,GRAVITY_Z, 0, 0, 0); - - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature, SPELL_FULLPOWER); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - //ShockBarrier_Timer - if(ShockBarrier_Timer < diff) - { - DoCast(m_creature, SPELL_SHOCK_BARRIER); - ChainPyros = true; - PyrosCasted = 0; - - ShockBarrier_Timer = 60000; - }else ShockBarrier_Timer -= diff; - - //Chain Pyros (3 of them max) - if (ChainPyros && !m_creature->IsNonMeleeSpellCasted(false)) - { - if (PyrosCasted < 3) - { - DoCast(m_creature->getVictim(), SPELL_PYROBLAST); - PyrosCasted++; - - }else - { - ChainPyros = false; - Fireball_Timer = 2500; - ArcaneDisruption_Timer = 60000; - } - } - } - - if (Phase == 5) - { - if(Phase_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - m_creature->RemoveAurasDueToSpell(SPELL_FULLPOWER); - DoCast(m_creature, SPELL_EXPLODE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Phase = 6; - DoStartAttackAndMovement(m_creature->getVictim()); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - - }else Phase_Timer -= diff; - } - - //Phase 5 - if(Phase == 6) - { - - //GravityLapse_Timer - if(GravityLapse_Timer < diff) - { - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - switch(GravityLapse_Phase) - { - case 0: - m_creature->StopMoving(); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->Relocate(GRAVITY_X, GRAVITY_Y, GRAVITY_Z, 0); - m_creature->SendMonsterMove(GRAVITY_X, GRAVITY_Y, GRAVITY_Z, 0, 0, 0); - // 1) Kael'thas will portal the whole raid right into his body - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) - { - //Use work around packet to prevent player from being dropped from combat - DoTeleportPlayer(pUnit, GRAVITY_X, GRAVITY_Y, GRAVITY_Z, pUnit->GetOrientation()); - } - } - GravityLapse_Timer = 500; - ++GravityLapse_Phase; - InGravityLapse = true; - ShockBarrier_Timer = 1000; - NetherBeam_Timer = 5000; - break; - - case 1: - switch(rand()%2) - { - case 0: - DoYell(SAY_GRAVITYLAPSE1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_GRAVITYLAPSE1); - break; - - case 1: - DoYell(SAY_GRAVITYLAPSE2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_GRAVITYLAPSE2); - break; - } - - // 2) At that point he will put a Gravity Lapse debuff on everyone - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();i++) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit) - { - 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()); - - //Using packet workaround - WorldPacket data(12); - data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); - data.append(pUnit->GetPackGUID()); - data << uint32(0); - pUnit->SendMessageToSet(&data, true); - } - } - GravityLapse_Timer = 10000; - GravityLapse_Phase++; - break; - - case 2: - //Cast nether vapor aura on self - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature, SPELL_NETHER_VAPOR); - - GravityLapse_Timer = 20000; - GravityLapse_Phase++; - break; - - case 3: - //Remove flight - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();i++) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if(pUnit) - { - //Using packet workaround - WorldPacket data(12); - data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); - data.append(pUnit->GetPackGUID()); - data << uint32(0); - pUnit->SendMessageToSet(&data, true); - } - } - m_creature->RemoveAurasDueToSpell(SPELL_NETHER_VAPOR); - InGravityLapse = false; - GravityLapse_Timer = 60000; - GravityLapse_Phase = 0; - DoStartAttackAndMovement(m_creature->getVictim()); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - DoResetThreat(); - break; - } - }else GravityLapse_Timer -= diff; - - if(InGravityLapse) - { - //ShockBarrier_Timer - if(ShockBarrier_Timer < diff) - { - DoCast(m_creature, SPELL_SHOCK_BARRIER); - - ShockBarrier_Timer = 20000; - }else ShockBarrier_Timer -= diff; - - //NetherBeam_Timer - if(NetherBeam_Timer < diff) - { - Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0); - DoCast(pUnit, SPELL_NETHER_BEAM); - - NetherBeam_Timer = 4000; - }else NetherBeam_Timer -= diff; - } - } - - if (!InGravityLapse) - DoMeleeAttackIfReady(); - } - } - } -}; - -//Thaladred the Darkener AI -struct MANGOS_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai -{ - boss_thaladred_the_darkenerAI(Creature *c) : advisorbase_ai(c) {} - - uint32 Gaze_Timer; - uint32 Silence_Timer; - uint32 PsychicBlow_Timer; - - void Reset() - { - Gaze_Timer = 100; - Silence_Timer = 20000; - PsychicBlow_Timer = 10000; - - advisorbase_ai::Reset(); - } - - void JustDied(Unit* pKiller) - { - DoPlaySoundToSet(m_creature, SOUND_THALADRED_DEATH); - DoYell(SAY_THALADRED_DEATH, LANG_UNIVERSAL, NULL); - } - - void Aggro(Unit *who) - { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (!who || FakeDeath) - return; - - DoYell(SAY_THALADRED_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_THALADRED_AGGRO); - m_creature->AddThreat(who, 5000000.0f); - } - - void UpdateAI(const uint32 diff) - { - advisorbase_ai::UpdateAI(diff); - - //Faking death, don't do anything - if (FakeDeath) - return; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Gaze_Timer - if(Gaze_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - DoResetThreat(); - m_creature->AddThreat(target, 5000000.0f); - DoTextEmote(EMOTE_THALADRED_GAZE, target); - Gaze_Timer = 8500; - } - }else Gaze_Timer -= diff; - - //Silence_Timer - if(Silence_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SILENCE); - Silence_Timer = 20000; - }else Silence_Timer -= diff; - - //PsychicBlow_Timer - if(PsychicBlow_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_PSYCHIC_BLOW); - PsychicBlow_Timer = 20000+rand()%5000; - }else PsychicBlow_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Lord Sanguinar AI -struct MANGOS_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai -{ - boss_lord_sanguinarAI(Creature *c) : advisorbase_ai(c){} - - uint32 Fear_Timer; - - void Reset() - { - Fear_Timer = 20000; - advisorbase_ai::Reset(); - } - - void JustDied(Unit* Killer) - { - DoPlaySoundToSet(m_creature, SOUND_SANGUINAR_DEATH); - DoYell(SAY_SANGUINAR_DEATH, LANG_UNIVERSAL, NULL); - } - - void Aggro(Unit *who) - { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (!who || FakeDeath) - return; - - DoYell(SAY_SANGUINAR_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SANGUINAR_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - advisorbase_ai::UpdateAI(diff); - - //Faking death, don't do anything - if (FakeDeath) - return; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Fear_Timer - if(Fear_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_BELLOWING_ROAR); - Fear_Timer = 25000+rand()%10000; //approximately every 30 seconds - }else Fear_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Grand Astromancer Capernian AI -struct MANGOS_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ai -{ - boss_grand_astromancer_capernianAI(Creature *c) : advisorbase_ai(c){} - - uint32 Fireball_Timer; - uint32 Conflagration_Timer; - uint32 ArcaneExplosion_Timer; - uint32 Yell_Timer; - bool Yell; - - void Reset() - { - Fireball_Timer = 2000; - Conflagration_Timer = 20000; - ArcaneExplosion_Timer = 5000; - Yell_Timer = 2000; - Yell = false; - - advisorbase_ai::Reset(); - } - - void JustDied(Unit* pKiller) - { - DoPlaySoundToSet(m_creature, SOUND_CAPERNIAN_DEATH); - DoYell(SAY_CAPERNIAN_DEATH, LANG_UNIVERSAL, NULL); - } - - void AttackStart(Unit* who) - { - if (!who || FakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (who->isTargetableForAttack()) - { - //Begin attack - DoStartAttackAndMovement(who, CAPERNIAN_DISTANCE, M_PI/2); - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } - - void Aggro(Unit *who) - { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (!who || FakeDeath) - return; - } - - void UpdateAI(const uint32 diff) - { - advisorbase_ai::UpdateAI(diff); - - //Faking Death, don't do anything - if (FakeDeath) - return; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Yell_Timer - if(!Yell) - if(Yell_Timer < diff) - { - DoYell(SAY_CAPERNIAN_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_CAPERNIAN_AGGRO); - - Yell = true; - }else Yell_Timer -= diff; - - //Fireball_Timer - if(Fireball_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CAPERNIAN_FIREBALL); - Fireball_Timer = 4000; - }else Fireball_Timer -= diff; - - //Conflagration_Timer - if(Conflagration_Timer < diff) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if(target && m_creature->IsWithinDistInMap(target, 30)) - DoCast(target, SPELL_CONFLAGRATION); - else - DoCast(m_creature->getVictim(), SPELL_CONFLAGRATION); - - Conflagration_Timer = 10000+rand()%5000; - }else Conflagration_Timer -= diff; - - //ArcaneExplosion_Timer - if(ArcaneExplosion_Timer < diff) - { - bool InMeleeRange = false; - Unit *target = NULL; - std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); - for (std::list::iterator i = m_threatlist.begin(); i!= m_threatlist.end();++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - //if in melee range - if(pUnit && pUnit->IsWithinDistInMap(m_creature, 5)) - { - InMeleeRange = true; - target = pUnit; - break; - } - } - - if(InMeleeRange) - DoCast(target, SPELL_ARCANE_EXPLOSION); - - ArcaneExplosion_Timer = 4000+rand()%2000; - }else ArcaneExplosion_Timer -= diff; - - //Do NOT deal any melee damage. - } -}; - -//Master Engineer Telonicus AI -struct MANGOS_DLL_DECL boss_master_engineer_telonicusAI : public advisorbase_ai -{ - boss_master_engineer_telonicusAI(Creature *c) : advisorbase_ai(c){} - - uint32 Bomb_Timer; - uint32 RemoteToy_Timer; - - void Reset() - { - Bomb_Timer = 10000; - RemoteToy_Timer = 5000; - - advisorbase_ai::Reset(); - } - - void JustDied(Unit* pKiller) - { - DoPlaySoundToSet(m_creature, SOUND_TELONICUS_DEATH); - DoYell(SAY_TELONICUS_DEATH, LANG_UNIVERSAL, NULL); - } - - void Aggro(Unit *who) - { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (!who || FakeDeath) - return; - - DoYell(SAY_TELONICUS_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_TELONICUS_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - advisorbase_ai::UpdateAI(diff); - - //Faking Death, do nothing - if (FakeDeath) - return; - - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Bomb_Timer - if(Bomb_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_BOMB); - Bomb_Timer = 25000; - }else Bomb_Timer -= diff; - - //RemoteToy_Timer - if(RemoteToy_Timer < diff) - { - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if(target) - DoCast(target, SPELL_REMOTE_TOY); - - RemoteToy_Timer = 10000+rand()%5000; - }else RemoteToy_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Flame Strike AI -struct MANGOS_DLL_DECL mob_kael_flamestrikeAI : public ScriptedAI -{ - mob_kael_flamestrikeAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Timer; - bool Casting; - bool KillSelf; - - void Reset() - { - Timer = 5000; - Casting = false; - KillSelf = false; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(14); - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!Casting) - { - DoCast(m_creature, SPELL_FLAME_STRIKE_VIS); - Casting = true; - } - - //Timer - if(Timer < diff) - { - if (!KillSelf) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature, SPELL_FLAME_STRIKE_DMG); - }else m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - KillSelf = true; - Timer = 1000; - }else Timer -= diff; - } -}; - -//Phoenix AI -struct MANGOS_DLL_DECL mob_phoenixAI : public ScriptedAI -{ - mob_phoenixAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Burn_Timer; - uint32 Hatch_Timer; - uint32 EggVis_Timer; - bool IsEgg; - - void Reset() - { - Burn_Timer = 1000; - Hatch_Timer = 15000; - EggVis_Timer = 0; - IsEgg = false; - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, PHOENIX_MODEL); - } - - void Hatch() - { - IsEgg = false; - m_creature->SetHealth(m_creature->GetMaxHealth()); - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, PHOENIX_MODEL); - Burn_Timer = 1000; - Hatch_Timer = 15000; - EggVis_Timer = 0; - AttackStart(m_creature->getVictim()); - } - - void DamageTaken(Unit* pKiller, uint32 &damage) - { - if (damage < m_creature->GetHealth()) - return; - - //Bird cannot die, only egg - if (!IsEgg) - { - //prevent death - damage = 0; - IsEgg = true; - - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetHealth(m_creature->GetMaxHealth()); - EggVis_Timer = 1000; - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,PLAYER_STATE_DEAD); - } - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - AttackStart(who); - } - } - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a current target - if (!IsEgg) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (Burn_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_BURN); - Burn_Timer = 1000; - }else Burn_Timer -= diff; - - DoMeleeAttackIfReady(); - } - else - { - if (EggVis_Timer) - if (EggVis_Timer <= diff) - { - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, PHOENIX_EGG_MODEL); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - EggVis_Timer = 0; - }else EggVis_Timer -= diff; - - if (Hatch_Timer < diff) - { - Hatch(); - }else Hatch_Timer -= diff; - } - } -}; - -CreatureAI* GetAI_boss_kaelthas(Creature *_Creature) -{ - return new boss_kaelthasAI (_Creature); -} - -CreatureAI* GetAI_boss_thaladred_the_darkener(Creature *_Creature) -{ - return new boss_thaladred_the_darkenerAI (_Creature); -} - -CreatureAI* GetAI_boss_lord_sanguinar(Creature *_Creature) -{ - return new boss_lord_sanguinarAI (_Creature); -} - -CreatureAI* GetAI_boss_grand_astromancer_capernian(Creature *_Creature) -{ - return new boss_grand_astromancer_capernianAI (_Creature); -} - -CreatureAI* GetAI_boss_master_engineer_telonicus(Creature *_Creature) -{ - return new boss_master_engineer_telonicusAI (_Creature); -} - -CreatureAI* GetAI_mob_kael_flamestrike(Creature *_Creature) -{ - return new mob_kael_flamestrikeAI (_Creature); -} - -CreatureAI* GetAI_mob_phoenix(Creature *_Creature) -{ - return new mob_phoenixAI (_Creature); -} - -void AddSC_boss_kaelthas() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_kaelthas"; - newscript->GetAI = GetAI_boss_kaelthas; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_thaladred_the_darkener"; - newscript->GetAI = GetAI_boss_thaladred_the_darkener; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_lord_sanguinar"; - newscript->GetAI = GetAI_boss_lord_sanguinar; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_grand_astromancer_capernian"; - newscript->GetAI = GetAI_boss_grand_astromancer_capernian; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_master_engineer_telonicus"; - newscript->GetAI = GetAI_boss_master_engineer_telonicus; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name= "mob_kael_flamestrike"; - newscript->GetAI = GetAI_mob_kael_flamestrike; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_phoenix"; - newscript->GetAI = GetAI_mob_phoenix; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_Kaelthas +SD%Complete: 60 +SDComment: SQL, phase 2, phase 3, Mind Control, taunt immunity +SDCategory: Tempest Keep, The Eye +EndScriptData */ + +#include "precompiled.h" +#include "def_the_eye.h" +#include "WorldPacket.h" + +//Phase 2 spells (Not used) +#define SPELL_SUMMON_WEAPONS 36976 +#define SPELL_SUMMON_WEAPONA 36958 +#define SPELL_SUMMON_WEAPONB 36959 +#define SPELL_SUMMON_WEAPONC 36960 +#define SPELL_SUMMON_WEAPOND 36961 +#define SPELL_SUMMON_WEAPONE 36962 +#define SPELL_SUMMON_WEAPONF 36963 +#define SPELL_SUMMON_WEAPONG 36964 +#define SPELL_RES_VISUAL 24171 +#define SPELL_WEAPON_SPAWN 41236 +//Phase 4 spells +#define SPELL_FIREBALL 22088 //wrong but works with CastCustomSpell +#define SPELL_PYROBLAST 36819 +#define SPELL_FLAME_STRIKE 36735 +#define SPELL_FLAME_STRIKE_VIS 36730 +#define SPELL_FLAME_STRIKE_DMG 36731 +#define SPELL_ARCANE_DISRUPTION 36834 +#define SPELL_SHOCK_BARRIER 36815 +#define SPELL_PHOENIX_ANIMATION 36723 +#define SPELL_MIND_CONTROL 32830 +//Phase 5 spells +#define SPELL_EXPLODE 36092 +#define SPELL_FULLPOWER 36187 +#define SPELL_KNOCKBACK 11027 +#define SPELL_GRAVITY_LAPSE 34480 +#define SPELL_GRAVITY_LAPSE_AURA 39432 +#define SPELL_NETHER_BEAM 35873 +//Thaladred the Darkener spells +#define SPELL_PSYCHIC_BLOW 10689 +#define SPELL_SILENCE 30225 +//Lord Sanguinar spells +#define SPELL_BELLOWING_ROAR 40636 +//Grand Astromancer Capernian spells +#define CAPERNIAN_DISTANCE 20 //she casts away from the target +#define SPELL_CAPERNIAN_FIREBALL 36971 +#define SPELL_CONFLAGRATION 37018 +#define SPELL_ARCANE_EXPLOSION 36970 +//Master Engineer Telonicus spells +#define SPELL_BOMB 37036 +#define SPELL_REMOTE_TOY 37027 +//Nether Vapor spell +#define SPELL_NETHER_VAPOR 35859 +//Phoenix spell +#define SPELL_BURN 36721 + +//kael'thas Speech +#define SAY_INTRO "Energy. Power. My people are addicted to it... a dependence made manifest after the Sunwell was destroyed. Welcome... to the future. A pity you are too late to stop it. No one can stop me now! Selama ashal'anore!" +#define SOUND_INTRO 11256 + +#define SAY_ASTROMANCER_CAPERNIAN "Capernian will see to it that your stay here is a short one." +#define SOUND_ASTROMANCER_CAPERNIAN 11257 + +#define SAY_ENGINEER_TELONICUS "Well done, you have proven worthy to test your skills against my master engineer, Telonicus." +#define SOUND_ENGINEER_TELONICUS 11258 + +#define SAY_THALADRED_THE_DARKENER "Let us see how your nerves hold up against the Darkener, Thaladred" +#define SOUND_THALADRED_THE_DARKENER 11259 + +#define SAY_LORD_SANGUINAR "You have persevered against some of my best advisors... but none can withstand the might of the Blood Hammer. Behold, Lord Sanguinar!" +#define SOUND_LORD_SANGUINAR 11260 + +#define SAY_PHASE2 "As you see, I have many weapons in my arsenal...." +#define SOUND_PHASE2 11261 + +#define SAY_PHASE3 "Perhaps I underestimated you. It would be unfair to make you fight all four advisors at once, but... fair treatment was never shown to my people. I'm just returning the favor." +#define SOUND_PHASE3 11262 + +#define SAY_PHASE4 "Alas, sometimes one must take matters into one's own hands. Balamore shanal!" +#define SOUND_PHASE4 11263 + +#define SAY_PHASE5 "I have not come this far to be stopped! The future I have planned will not be jeopardized! Now you will taste true power!!" +#define SOUND_PHASE5 11273 + +#define SAY_SLAY1 "You will not prevail." +#define SOUND_SLAY1 11270 + +#define SAY_SLAY2 "You gambled...and lost." +#define SOUND_SLAY2 11271 + +#define SAY_MINDCONTROL1 "Obey me." +#define SOUND_MINDCONTROL1 11268 + +#define SAY_MINDCONTROL2 "Bow to my will." +#define SOUND_MINDCONTROL2 11269 + +#define SAY_GRAVITYLAPSE1 "Let us see how you fare when your world is turned upside down." +#define SOUND_GRAVITYLAPSE1 11264 + +#define SAY_GRAVITYLAPSE2 "Having trouble staying grounded?" +#define SOUND_GRAVITYLAPSE2 11265 + +#define SAY_SUMMON_PHOENIX1 "Anara'nel belore!" +#define SOUND_SUMMON_PHOENIX1 11267 + +#define SAY_SUMMON_PHOENIX2 "By the power of the sun!" +#define SOUND_SUMMON_PHOENIX2 11266 + +#define SAY_DEATH "For...Quel...thalas!" +#define SOUND_DEATH 11274 + +//Thaladred the Darkener speech +#define SAY_THALADRED_AGGRO "Prepare yourselves!" +#define SOUND_THALADRED_AGGRO 11203 +#define SAY_THALADRED_DEATH "Forgive me, my prince! I have... failed." +#define SOUND_THALADRED_DEATH 11204 +#define EMOTE_THALADRED_GAZE "sets his gaze on $N!" + +//Lord Sanguinar speech +#define SAY_SANGUINAR_AGGRO "Blood for blood!" +#define SOUND_SANGUINAR_AGGRO 11152 +#define SAY_SANGUINAR_DEATH "NO! I ...will... not..." +#define SOUND_SANGUINAR_DEATH 11153 + +//Grand Astromancer Capernian speech +#define SAY_CAPERNIAN_AGGRO "The sin'dore reign supreme!" +#define SOUND_CAPERNIAN_AGGRO 11117 +#define SAY_CAPERNIAN_DEATH "This is not over!" +#define SOUND_CAPERNIAN_DEATH 11118 + +//Master Engineer Telonicus speech +#define SAY_TELONICUS_AGGRO "Anar'alah belore!" +#define SOUND_TELONICUS_AGGRO 11157 +#define SAY_TELONICUS_DEATH "More perils... await" +#define SOUND_TELONICUS_DEATH 11158 + +//Creature IDs +#define PHOENIX 21362 +#define PHOENIX_EGG 21364 + +//Phoenix egg and phoenix model +#define PHOENIX_MODEL 19682 +#define PHOENIX_EGG_MODEL 20245 + +//#define PI 3.141592 +#define TEMP_MC_WHISPER "[SD2 Debug] You would be mind controlled here!" + +//weapon id + position +float KaelthasWeapons[7][5] = +{ + {21270, 794.38, 15, 48.72, 2.9}, //[Cosmic Infuser] + {21269, 785.47, 12.12, 48.72, 3.14}, //[Devastation] + {21271, 781.25, 4.39, 48.72, 3.14}, //[Infinity Blade] + {21273, 777.38, -0.81, 48.72, 3.06}, //[Phaseshift Bulwark] + {21274, 781.48, -6.08, 48.72, 3.9}, //[Staff of Disintegration] + {21272, 785.42, -13.59, 48.72, 3.4}, //[Warp Slicer] + {21268, 793.06, -16.61, 48.72, 3.10} //[Netherstrand Longbow] +}; + +#define GRAVITY_X 795.0f +#define GRAVITY_Y 0.0f +#define GRAVITY_Z 70.0f + +#define TIME_PHASE_2_3 120000 +#define TIME_PHASE_3_4 120000 + +#define KAEL_VISIBLE_RANGE 50.0f + +//Base AI for Advisors +struct MANGOS_DLL_DECL advisorbase_ai : public ScriptedAI +{ + ScriptedInstance* pInstance; + bool FakeDeath; + uint32 DelayRes_Timer; + uint64 DelayRes_Target; + + advisorbase_ai(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + void MoveInLineOfSight(Unit *who) + { + if (!who || FakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + 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; + + float attackRadius = m_creature->GetAttackDistance(who); + if(m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) + { + DoStartAttackAndMovement(who); + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + } + + void AttackStart(Unit* who) + { + if (!who || FakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (who->isTargetableForAttack()) + { + //Begin attack + DoStartAttackAndMovement(who); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + + void Reset() + { + FakeDeath = false; + DelayRes_Timer = 0; + DelayRes_Target = 0; + + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + //reset encounter + if(pInstance && (pInstance->GetData(DATA_KAELTHASEVENT) == 1 || pInstance->GetData(DATA_KAELTHASEVENT) == 3)) + { + Creature *Kaelthas = NULL; + Kaelthas = (Creature*)(Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KAELTHAS))); + + if(Kaelthas) + Kaelthas->AI()->EnterEvadeMode(); + } + } + + void Revive(Unit* Target) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + DoCast(m_creature, SPELL_RES_VISUAL, false); + DelayRes_Timer = 2000; + } + + void DamageTaken(Unit* pKiller, uint32 &damage) + { + if (damage < m_creature->GetHealth()) + return; + + //Prevent glitch if in fake death + if (FakeDeath) + { + damage = 0; + return; + } + //Don't really die in phase 1 & 3, only die after that + if(pInstance && pInstance->GetData(DATA_KAELTHASEVENT) != 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->SetUInt32Value(UNIT_FIELD_BYTES_1,PLAYER_STATE_DEAD); + + if (pInstance->GetData(DATA_KAELTHASEVENT) == 3) + JustDied(pKiller); + } + } + + void UpdateAI(const uint32 diff) + { + if (DelayRes_Timer) + if (DelayRes_Timer <= diff) + { + DelayRes_Timer = 0; + FakeDeath = false; + + Unit* Target = Unit::GetUnit((*m_creature), DelayRes_Target); + if (!Target)Target = m_creature->getVictim(); + DoResetThreat(); + AttackStart(Target); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(Target); + m_creature->AddThreat(Target, 0.0f); + }else DelayRes_Timer -= diff; + } + +}; + +//Kael'thas AI +struct MANGOS_DLL_DECL boss_kaelthasAI : public ScriptedAI +{ + boss_kaelthasAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + AdvisorGuid[0] = 0; + AdvisorGuid[1] = 0; + AdvisorGuid[2] = 0; + AdvisorGuid[3] = 0; + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 Fireball_Timer; + uint32 ArcaneDisruption_Timer; + uint32 Phoenix_Timer; + uint32 ShockBarrier_Timer; + uint32 GravityLapse_Timer; + uint32 GravityLapse_Phase; + uint32 NetherBeam_Timer; + uint32 NetherVapor_Timer; + uint32 FlameStrike_Timer; + uint32 MindControl_Timer; + uint32 Phase; + uint32 PhaseSubphase; //generic + uint32 Phase_Timer; //generic timer + uint32 PyrosCasted; + + bool InGravityLapse; + bool IsCastingFireball; + bool ChainPyros; + + uint64 AdvisorGuid[4]; + + void Reset() + { + Fireball_Timer = 5000+rand()%10000; + ArcaneDisruption_Timer = 45000; + MindControl_Timer = 40000; + Phoenix_Timer = 50000; + ShockBarrier_Timer = 60000; + FlameStrike_Timer = 30000; + GravityLapse_Timer = 20000; + GravityLapse_Phase = 0; + NetherBeam_Timer = 8000; + NetherVapor_Timer = 10000; + PyrosCasted = 0; + Phase = 0; + InGravityLapse = false; + IsCastingFireball = false; + ChainPyros = false; + + if(InCombat) + PrepareAdvisors(); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if(pInstance) + pInstance->SetData(DATA_KAELTHASEVENT, 0); + } + + void PrepareAdvisors() + { + Creature *pCreature; + for(uint8 i = 0; i < 4; i++) + { + pCreature = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[i])); + if(pCreature) + { + pCreature->Respawn(); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pCreature->setFaction(m_creature->getFaction()); + pCreature->AI()->EnterEvadeMode(); + } + } + } + + void StartEvent() + { + if(!pInstance) + return; + + AdvisorGuid[0] = pInstance->GetData64(DATA_THALADREDTHEDARKENER); + AdvisorGuid[1] = pInstance->GetData64(DATA_LORDSANGUINAR); + AdvisorGuid[2] = pInstance->GetData64(DATA_GRANDASTROMANCERCAPERNIAN); + AdvisorGuid[3] = pInstance->GetData64(DATA_MASTERENGINEERTELONICUS); + + if(!AdvisorGuid[0] || !AdvisorGuid[1] || !AdvisorGuid[2] || !AdvisorGuid[3]) + { + error_log("SD2: Kael'Thas One or more advisors missing, Skipping Phases 1-3"); + DoYell("SD2: Kael'Thas One or more advisors missing, Skipping Phases 1-3", LANG_UNIVERSAL, NULL); + + DoYell(SAY_PHASE4, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE4); + Phase = 4; + + pInstance->SetData(DATA_KAELTHASEVENT, 4); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + DoStartAttackAndMovement(target); + } + }else + { + PrepareAdvisors(); + + DoYell(SAY_INTRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_INTRO); + + pInstance->SetData(DATA_KAELTHASEVENT, 1); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + PhaseSubphase = 0; + Phase_Timer = 23000; + Phase = 1; + } + } + + void KilledUnit() + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY2); + break; + } + } + + void JustDied(Unit* Killer) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + + if(pInstance) + pInstance->SetData(DATA_KAELTHASEVENT, 0); + + Creature *pCreature; + for(uint8 i = 0; i < 4; i++) + { + pCreature = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[i])); + if(pCreature) + { + pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + } + + void Aggro(Unit *who) + { + if (pInstance && !pInstance->GetData(DATA_KAELTHASEVENT) && !Phase) + StartEvent(); + } + + void MoveInLineOfSight(Unit *who) + { + if (!m_creature->getVictim() && 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 (Phase >= 4 && m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) + { + if(who->HasStealthAura()) + who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + DoStartAttackAndMovement(who); + } + else if(who->isAlive()) + { + if (pInstance && !pInstance->GetData(DATA_KAELTHASEVENT) && !Phase && m_creature->IsWithinDistInMap(who, 60.0f)) + StartEvent(); + + //add to the threat list, so we can use SelectTarget + m_creature->AddThreat(who,0.0f); + } + } + } + + void UpdateAI(const uint32 diff) + { + //Phase 1 + switch (Phase) + { + case 1: + { + Unit *target; + Creature* Advisor; + + //Subphase switch + switch(PhaseSubphase) + { + //Subphase 1 - Start + case 0: + if(Phase_Timer < diff) + { + DoYell(SAY_THALADRED_THE_DARKENER, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_THALADRED_THE_DARKENER); + + //start advisor within 7 seconds + Phase_Timer = 7000; + + PhaseSubphase++; + }else Phase_Timer -= diff; + break; + + //Subphase 1 - Unlock advisor + case 1: + if(Phase_Timer < diff) + { + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[0])); + + if(Advisor) + { + Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Advisor->setFaction(m_creature->getFaction()); + + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + Advisor->AI()->AttackStart(target); + } + + PhaseSubphase++; + }else Phase_Timer -= diff; + break; + + //Subphase 2 - Start + case 2: + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[0])); + if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == PLAYER_STATE_DEAD)) + { + DoYell(SAY_LORD_SANGUINAR, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_LORD_SANGUINAR); + + //start advisor within 12.5 seconds + Phase_Timer = 12500; + + PhaseSubphase++; + } + break; + + //Subphase 2 - Unlock advisor + case 3: + if(Phase_Timer < diff) + { + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[1])); + + if(Advisor) + { + Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Advisor->setFaction(m_creature->getFaction()); + + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + Advisor->AI()->AttackStart(target); + } + + PhaseSubphase++; + }else Phase_Timer -= diff; + break; + + //Subphase 3 - Start + case 4: + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[1])); + if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == PLAYER_STATE_DEAD)) + { + DoYell(SAY_ASTROMANCER_CAPERNIAN, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ASTROMANCER_CAPERNIAN); + + //start advisor within 7 seconds + Phase_Timer = 7000; + + PhaseSubphase++; + } + break; + + //Subphase 3 - Unlock advisor + case 5: + if(Phase_Timer < diff) + { + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[2])); + + if(Advisor) + { + Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Advisor->setFaction(m_creature->getFaction()); + + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + Advisor->AI()->AttackStart(target); + } + + PhaseSubphase++; + }else Phase_Timer -= diff; + break; + + //Subphase 4 - Start + case 6: + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[2])); + if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == PLAYER_STATE_DEAD)) + { + DoYell(SAY_ENGINEER_TELONICUS, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_ENGINEER_TELONICUS); + + //start advisor within 8.4 seconds + Phase_Timer = 8400; + + PhaseSubphase++; + } + break; + + //Subphase 4 - Unlock advisor + case 7: + if(Phase_Timer < diff) + { + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[3])); + + if(Advisor) + { + Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Advisor->setFaction(m_creature->getFaction()); + + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + Advisor->AI()->AttackStart(target); + } + + Phase_Timer = 3000; + + PhaseSubphase++; + }else Phase_Timer -= diff; + break; + + //End of phase 1 + case 8: + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[3])); + if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == PLAYER_STATE_DEAD)) + { + Phase = 2; + pInstance->SetData(DATA_KAELTHASEVENT, 2); + + DoYell(SAY_PHASE2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE2); + PhaseSubphase = 0; + Phase_Timer = 3500; + DoCast(m_creature, SPELL_SUMMON_WEAPONS); + } + break; + } + }break; + + case 2: + { + if (PhaseSubphase == 0) + { + if (Phase_Timer < diff) + { + PhaseSubphase = 1; + }else Phase_Timer -= diff; + } + + //Spawn weapons + if (PhaseSubphase == 1) + { + Unit* Target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + Creature* Weapon; + for (uint32 i = 0; i < 7; i++) + { + Weapon = m_creature->SummonCreature(((uint32)KaelthasWeapons[i][0]),KaelthasWeapons[i][1],KaelthasWeapons[i][2],KaelthasWeapons[i][3],0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + + if (!Weapon) + error_log("SD2: Kael'thas weapon %i could not be spawned", i); + else + { + Weapon->setFaction(m_creature->getFaction()); + Weapon->AI()->AttackStart(Target); + Weapon->CastSpell(Weapon, SPELL_WEAPON_SPAWN, false); + } + } + + PhaseSubphase = 2; + Phase_Timer = TIME_PHASE_2_3; + } + + if (PhaseSubphase == 2) + if (Phase_Timer < diff) + { + DoYell(SAY_PHASE3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE3); + pInstance->SetData(DATA_KAELTHASEVENT, 3); + Phase = 3; + PhaseSubphase = 0; + }else Phase_Timer -= diff; + }break; + + case 3: + { + if (PhaseSubphase == 0) + { + //Respawn advisors + Unit* Target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + Creature* Advisor; + for (uint32 i = 0; i < 4; i++) + { + Advisor = (Creature*)(Unit::GetUnit((*m_creature), AdvisorGuid[i])); + if (!Advisor) + error_log("SD2: Kael'Thas Advisor %u does not exist. Possibly despawned? Incorrectly Killed?", i); + else ((advisorbase_ai*)Advisor->AI())->Revive(Target); + } + + PhaseSubphase = 1; + Phase_Timer = TIME_PHASE_3_4; + } + + if(Phase_Timer < diff) + { + DoYell(SAY_PHASE4, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE4); + Phase = 4; + + pInstance->SetData(DATA_KAELTHASEVENT, 4); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + DoStartAttackAndMovement(target); + } + Phase_Timer = 30000; + }else Phase_Timer -= diff; + } + break; + + case 4: + case 5: + case 6: + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Fireball_Timer + if(!InGravityLapse && !ChainPyros && Phase != 5) + { + if(Fireball_Timer < diff) + { + if(!IsCastingFireball) + { + if(!m_creature->IsNonMeleeSpellCasted(false)) + { + //interruptable + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false); + int32 dmg = 20000+rand()%5000; + m_creature->CastCustomSpell(m_creature->getVictim(), SPELL_FIREBALL, &dmg, 0, 0, false); + IsCastingFireball = true; + Fireball_Timer = 2500; + } + } + else + { + //apply resistance + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); + IsCastingFireball = false; + Fireball_Timer = 5000+rand()%10000; + } + }else Fireball_Timer -= diff; + + //ArcaneDisruption_Timer + if(ArcaneDisruption_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ARCANE_DISRUPTION, true); + + ArcaneDisruption_Timer = 60000; + }else ArcaneDisruption_Timer -= diff; + + if (FlameStrike_Timer < diff) + { + Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0); + DoCast(pUnit, SPELL_FLAME_STRIKE); + + FlameStrike_Timer = 30000; + }FlameStrike_Timer -= diff; + + if (MindControl_Timer < diff) + { + if (m_creature->getThreatManager().getThreatList().size() >= 2) + for (uint32 i = 0; i < 3; i++) + { + debug_log("SD2: Kael'Thas mind control not supported."); + //DoCast(pUnit, SPELL_MIND_CONTROL); + } + + MindControl_Timer = 60000; + }MindControl_Timer -= diff; + } + + //Phoenix_Timer + if(Phoenix_Timer < diff) + { + DoCast(m_creature, SPELL_PHOENIX_ANIMATION); + Creature *Phoenix = DoSpawnCreature(PHOENIX, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); + + if(Phoenix) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (target) + Phoenix->AI()->AttackStart(target); + }else error_log("SD2: Kael'Thas Phoenix could not be spawned"); + + switch(rand()%2) + { + case 0: + DoYell(SAY_SUMMON_PHOENIX1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON_PHOENIX1); + break; + + case 1: + DoYell(SAY_SUMMON_PHOENIX2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMON_PHOENIX2); + break; + + default: + break; + } + + Phoenix_Timer = 60000; + }else Phoenix_Timer -= diff; + + //Phase 4 specific spells + if(Phase == 4) + { + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50) + { + pInstance->SetData(DATA_KAELTHASEVENT, 4); + Phase = 5; + Phase_Timer = 10000; + + DoYell(SAY_PHASE5, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_PHASE5); + + m_creature->StopMoving(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->Relocate(GRAVITY_X, GRAVITY_Y, GRAVITY_Z, 0); + m_creature->SendMonsterMove(GRAVITY_X, GRAVITY_Y,GRAVITY_Z, 0, 0, 0); + + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_FULLPOWER); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + //ShockBarrier_Timer + if(ShockBarrier_Timer < diff) + { + DoCast(m_creature, SPELL_SHOCK_BARRIER); + ChainPyros = true; + PyrosCasted = 0; + + ShockBarrier_Timer = 60000; + }else ShockBarrier_Timer -= diff; + + //Chain Pyros (3 of them max) + if (ChainPyros && !m_creature->IsNonMeleeSpellCasted(false)) + { + if (PyrosCasted < 3) + { + DoCast(m_creature->getVictim(), SPELL_PYROBLAST); + PyrosCasted++; + + }else + { + ChainPyros = false; + Fireball_Timer = 2500; + ArcaneDisruption_Timer = 60000; + } + } + } + + if (Phase == 5) + { + if(Phase_Timer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + m_creature->RemoveAurasDueToSpell(SPELL_FULLPOWER); + DoCast(m_creature, SPELL_EXPLODE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Phase = 6; + DoStartAttackAndMovement(m_creature->getVictim()); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + }else Phase_Timer -= diff; + } + + //Phase 5 + if(Phase == 6) + { + + //GravityLapse_Timer + if(GravityLapse_Timer < diff) + { + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + switch(GravityLapse_Phase) + { + case 0: + m_creature->StopMoving(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->Relocate(GRAVITY_X, GRAVITY_Y, GRAVITY_Z, 0); + m_creature->SendMonsterMove(GRAVITY_X, GRAVITY_Y, GRAVITY_Z, 0, 0, 0); + // 1) Kael'thas will portal the whole raid right into his body + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) + { + //Use work around packet to prevent player from being dropped from combat + DoTeleportPlayer(pUnit, GRAVITY_X, GRAVITY_Y, GRAVITY_Z, pUnit->GetOrientation()); + } + } + GravityLapse_Timer = 500; + ++GravityLapse_Phase; + InGravityLapse = true; + ShockBarrier_Timer = 1000; + NetherBeam_Timer = 5000; + break; + + case 1: + switch(rand()%2) + { + case 0: + DoYell(SAY_GRAVITYLAPSE1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_GRAVITYLAPSE1); + break; + + case 1: + DoYell(SAY_GRAVITYLAPSE2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_GRAVITYLAPSE2); + break; + } + + // 2) At that point he will put a Gravity Lapse debuff on everyone + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();i++) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit) + { + 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()); + + //Using packet workaround + WorldPacket data(12); + data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); + data.append(pUnit->GetPackGUID()); + data << uint32(0); + pUnit->SendMessageToSet(&data, true); + } + } + GravityLapse_Timer = 10000; + GravityLapse_Phase++; + break; + + case 2: + //Cast nether vapor aura on self + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_NETHER_VAPOR); + + GravityLapse_Timer = 20000; + GravityLapse_Phase++; + break; + + case 3: + //Remove flight + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();i++) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if(pUnit) + { + //Using packet workaround + WorldPacket data(12); + data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); + data.append(pUnit->GetPackGUID()); + data << uint32(0); + pUnit->SendMessageToSet(&data, true); + } + } + m_creature->RemoveAurasDueToSpell(SPELL_NETHER_VAPOR); + InGravityLapse = false; + GravityLapse_Timer = 60000; + GravityLapse_Phase = 0; + DoStartAttackAndMovement(m_creature->getVictim()); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + DoResetThreat(); + break; + } + }else GravityLapse_Timer -= diff; + + if(InGravityLapse) + { + //ShockBarrier_Timer + if(ShockBarrier_Timer < diff) + { + DoCast(m_creature, SPELL_SHOCK_BARRIER); + + ShockBarrier_Timer = 20000; + }else ShockBarrier_Timer -= diff; + + //NetherBeam_Timer + if(NetherBeam_Timer < diff) + { + Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0); + DoCast(pUnit, SPELL_NETHER_BEAM); + + NetherBeam_Timer = 4000; + }else NetherBeam_Timer -= diff; + } + } + + if (!InGravityLapse) + DoMeleeAttackIfReady(); + } + } + } +}; + +//Thaladred the Darkener AI +struct MANGOS_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai +{ + boss_thaladred_the_darkenerAI(Creature *c) : advisorbase_ai(c) {} + + uint32 Gaze_Timer; + uint32 Silence_Timer; + uint32 PsychicBlow_Timer; + + void Reset() + { + Gaze_Timer = 100; + Silence_Timer = 20000; + PsychicBlow_Timer = 10000; + + advisorbase_ai::Reset(); + } + + void JustDied(Unit* pKiller) + { + DoPlaySoundToSet(m_creature, SOUND_THALADRED_DEATH); + DoYell(SAY_THALADRED_DEATH, LANG_UNIVERSAL, NULL); + } + + void Aggro(Unit *who) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (!who || FakeDeath) + return; + + DoYell(SAY_THALADRED_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_THALADRED_AGGRO); + m_creature->AddThreat(who, 5000000.0f); + } + + void UpdateAI(const uint32 diff) + { + advisorbase_ai::UpdateAI(diff); + + //Faking death, don't do anything + if (FakeDeath) + return; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Gaze_Timer + if(Gaze_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + DoResetThreat(); + m_creature->AddThreat(target, 5000000.0f); + DoTextEmote(EMOTE_THALADRED_GAZE, target); + Gaze_Timer = 8500; + } + }else Gaze_Timer -= diff; + + //Silence_Timer + if(Silence_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SILENCE); + Silence_Timer = 20000; + }else Silence_Timer -= diff; + + //PsychicBlow_Timer + if(PsychicBlow_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_PSYCHIC_BLOW); + PsychicBlow_Timer = 20000+rand()%5000; + }else PsychicBlow_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Lord Sanguinar AI +struct MANGOS_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai +{ + boss_lord_sanguinarAI(Creature *c) : advisorbase_ai(c){} + + uint32 Fear_Timer; + + void Reset() + { + Fear_Timer = 20000; + advisorbase_ai::Reset(); + } + + void JustDied(Unit* Killer) + { + DoPlaySoundToSet(m_creature, SOUND_SANGUINAR_DEATH); + DoYell(SAY_SANGUINAR_DEATH, LANG_UNIVERSAL, NULL); + } + + void Aggro(Unit *who) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (!who || FakeDeath) + return; + + DoYell(SAY_SANGUINAR_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SANGUINAR_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + advisorbase_ai::UpdateAI(diff); + + //Faking death, don't do anything + if (FakeDeath) + return; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Fear_Timer + if(Fear_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_BELLOWING_ROAR); + Fear_Timer = 25000+rand()%10000; //approximately every 30 seconds + }else Fear_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Grand Astromancer Capernian AI +struct MANGOS_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ai +{ + boss_grand_astromancer_capernianAI(Creature *c) : advisorbase_ai(c){} + + uint32 Fireball_Timer; + uint32 Conflagration_Timer; + uint32 ArcaneExplosion_Timer; + uint32 Yell_Timer; + bool Yell; + + void Reset() + { + Fireball_Timer = 2000; + Conflagration_Timer = 20000; + ArcaneExplosion_Timer = 5000; + Yell_Timer = 2000; + Yell = false; + + advisorbase_ai::Reset(); + } + + void JustDied(Unit* pKiller) + { + DoPlaySoundToSet(m_creature, SOUND_CAPERNIAN_DEATH); + DoYell(SAY_CAPERNIAN_DEATH, LANG_UNIVERSAL, NULL); + } + + void AttackStart(Unit* who) + { + if (!who || FakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (who->isTargetableForAttack()) + { + //Begin attack + DoStartAttackAndMovement(who, CAPERNIAN_DISTANCE, M_PI/2); + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } + + void Aggro(Unit *who) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (!who || FakeDeath) + return; + } + + void UpdateAI(const uint32 diff) + { + advisorbase_ai::UpdateAI(diff); + + //Faking Death, don't do anything + if (FakeDeath) + return; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Yell_Timer + if(!Yell) + if(Yell_Timer < diff) + { + DoYell(SAY_CAPERNIAN_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_CAPERNIAN_AGGRO); + + Yell = true; + }else Yell_Timer -= diff; + + //Fireball_Timer + if(Fireball_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CAPERNIAN_FIREBALL); + Fireball_Timer = 4000; + }else Fireball_Timer -= diff; + + //Conflagration_Timer + if(Conflagration_Timer < diff) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if(target && m_creature->IsWithinDistInMap(target, 30)) + DoCast(target, SPELL_CONFLAGRATION); + else + DoCast(m_creature->getVictim(), SPELL_CONFLAGRATION); + + Conflagration_Timer = 10000+rand()%5000; + }else Conflagration_Timer -= diff; + + //ArcaneExplosion_Timer + if(ArcaneExplosion_Timer < diff) + { + bool InMeleeRange = false; + Unit *target = NULL; + std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); + for (std::list::iterator i = m_threatlist.begin(); i!= m_threatlist.end();++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + //if in melee range + if(pUnit && pUnit->IsWithinDistInMap(m_creature, 5)) + { + InMeleeRange = true; + target = pUnit; + break; + } + } + + if(InMeleeRange) + DoCast(target, SPELL_ARCANE_EXPLOSION); + + ArcaneExplosion_Timer = 4000+rand()%2000; + }else ArcaneExplosion_Timer -= diff; + + //Do NOT deal any melee damage. + } +}; + +//Master Engineer Telonicus AI +struct MANGOS_DLL_DECL boss_master_engineer_telonicusAI : public advisorbase_ai +{ + boss_master_engineer_telonicusAI(Creature *c) : advisorbase_ai(c){} + + uint32 Bomb_Timer; + uint32 RemoteToy_Timer; + + void Reset() + { + Bomb_Timer = 10000; + RemoteToy_Timer = 5000; + + advisorbase_ai::Reset(); + } + + void JustDied(Unit* pKiller) + { + DoPlaySoundToSet(m_creature, SOUND_TELONICUS_DEATH); + DoYell(SAY_TELONICUS_DEATH, LANG_UNIVERSAL, NULL); + } + + void Aggro(Unit *who) + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (!who || FakeDeath) + return; + + DoYell(SAY_TELONICUS_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TELONICUS_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + advisorbase_ai::UpdateAI(diff); + + //Faking Death, do nothing + if (FakeDeath) + return; + + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Bomb_Timer + if(Bomb_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_BOMB); + Bomb_Timer = 25000; + }else Bomb_Timer -= diff; + + //RemoteToy_Timer + if(RemoteToy_Timer < diff) + { + Unit *target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if(target) + DoCast(target, SPELL_REMOTE_TOY); + + RemoteToy_Timer = 10000+rand()%5000; + }else RemoteToy_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Flame Strike AI +struct MANGOS_DLL_DECL mob_kael_flamestrikeAI : public ScriptedAI +{ + mob_kael_flamestrikeAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Timer; + bool Casting; + bool KillSelf; + + void Reset() + { + Timer = 5000; + Casting = false; + KillSelf = false; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->setFaction(14); + } + + void Aggro(Unit *who) + { + } + + void MoveInLineOfSight(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!Casting) + { + DoCast(m_creature, SPELL_FLAME_STRIKE_VIS); + Casting = true; + } + + //Timer + if(Timer < diff) + { + if (!KillSelf) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_FLAME_STRIKE_DMG); + }else m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + KillSelf = true; + Timer = 1000; + }else Timer -= diff; + } +}; + +//Phoenix AI +struct MANGOS_DLL_DECL mob_phoenixAI : public ScriptedAI +{ + mob_phoenixAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Burn_Timer; + uint32 Hatch_Timer; + uint32 EggVis_Timer; + bool IsEgg; + + void Reset() + { + Burn_Timer = 1000; + Hatch_Timer = 15000; + EggVis_Timer = 0; + IsEgg = false; + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, PHOENIX_MODEL); + } + + void Hatch() + { + IsEgg = false; + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, PHOENIX_MODEL); + Burn_Timer = 1000; + Hatch_Timer = 15000; + EggVis_Timer = 0; + AttackStart(m_creature->getVictim()); + } + + void DamageTaken(Unit* pKiller, uint32 &damage) + { + if (damage < m_creature->GetHealth()) + return; + + //Bird cannot die, only egg + if (!IsEgg) + { + //prevent death + damage = 0; + IsEgg = true; + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetHealth(m_creature->GetMaxHealth()); + EggVis_Timer = 1000; + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,PLAYER_STATE_DEAD); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Check if we have a current target + if (!IsEgg) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (Burn_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_BURN); + Burn_Timer = 1000; + }else Burn_Timer -= diff; + + DoMeleeAttackIfReady(); + } + else + { + if (EggVis_Timer) + if (EggVis_Timer <= diff) + { + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, PHOENIX_EGG_MODEL); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + EggVis_Timer = 0; + }else EggVis_Timer -= diff; + + if (Hatch_Timer < diff) + { + Hatch(); + }else Hatch_Timer -= diff; + } + } +}; + +CreatureAI* GetAI_boss_kaelthas(Creature *_Creature) +{ + return new boss_kaelthasAI (_Creature); +} + +CreatureAI* GetAI_boss_thaladred_the_darkener(Creature *_Creature) +{ + return new boss_thaladred_the_darkenerAI (_Creature); +} + +CreatureAI* GetAI_boss_lord_sanguinar(Creature *_Creature) +{ + return new boss_lord_sanguinarAI (_Creature); +} + +CreatureAI* GetAI_boss_grand_astromancer_capernian(Creature *_Creature) +{ + return new boss_grand_astromancer_capernianAI (_Creature); +} + +CreatureAI* GetAI_boss_master_engineer_telonicus(Creature *_Creature) +{ + return new boss_master_engineer_telonicusAI (_Creature); +} + +CreatureAI* GetAI_mob_kael_flamestrike(Creature *_Creature) +{ + return new mob_kael_flamestrikeAI (_Creature); +} + +CreatureAI* GetAI_mob_phoenix(Creature *_Creature) +{ + return new mob_phoenixAI (_Creature); +} + +void AddSC_boss_kaelthas() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_kaelthas"; + newscript->GetAI = GetAI_boss_kaelthas; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_thaladred_the_darkener"; + newscript->GetAI = GetAI_boss_thaladred_the_darkener; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_lord_sanguinar"; + newscript->GetAI = GetAI_boss_lord_sanguinar; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_grand_astromancer_capernian"; + newscript->GetAI = GetAI_boss_grand_astromancer_capernian; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_master_engineer_telonicus"; + newscript->GetAI = GetAI_boss_master_engineer_telonicus; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name= "mob_kael_flamestrike"; + newscript->GetAI = GetAI_mob_kael_flamestrike; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_phoenix"; + newscript->GetAI = GetAI_mob_phoenix; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp index 43072b1947d..0dbf7d66761 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp @@ -1,203 +1,203 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Void_Reaver -SD%Complete: 100 -SDComment: -SDCategory: Tempest Keep, The Eye -EndScriptData */ - -#include "precompiled.h" -#include "def_the_eye.h" - -#define SPELL_POUNDING 34162 -#define SPELL_ARCANE_ORB_TRIGGER 34172 -#define SPELL_KNOCK_AWAY 11130 -#define SPELL_BERSERK 27680 - -#define SAY_AGGRO "Alert, you are marked for extermination!" -#define SAY_SLAY1 "Extermination, successful." -#define SAY_SLAY2 "Imbecile life form, no longer functional." -#define SAY_SLAY3 "Threat neutralized." -#define SAY_DEATH "Systems... shutting... down..." -#define SAY_POUNDING1 "Alternative measure commencing..." -#define SAY_POUNDING2 "Calculating force parameters..." - -#define SOUND_AGGRO 11213 -#define SOUND_SLAY1 11215 -#define SOUND_SLAY2 11216 -#define SOUND_SLAY3 11217 -#define SOUND_DEATH 11214 -#define SOUND_POUNDING1 11218 -#define SOUND_POUNDING2 11219 - -#define CREATURE_ORB_TARGET 19577 - -struct MANGOS_DLL_DECL boss_void_reaverAI : public ScriptedAI -{ - boss_void_reaverAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance* pInstance; - - uint32 Pounding_Timer; - uint32 ArcaneOrb_Timer; - uint32 KnockAway_Timer; - uint32 Berserk_Timer; - - void Reset() - { - Pounding_Timer = 12000; - ArcaneOrb_Timer = 3000; - KnockAway_Timer = 30000; - Berserk_Timer = 600000; - - if(pInstance) - pInstance->SetData(DATA_VOIDREAVEREVENT, NOT_STARTED); - } - - void KilledUnit(Unit *victim) - { - switch(rand()%3) - { - case 0: - DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - case 2: - DoYell(SAY_SLAY3, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_SLAY3); - break; - } - } - - void JustDied(Unit *victim) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - - if(pInstance) - pInstance->SetData(DATA_VOIDREAVEREVENT, NOT_STARTED); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_AGGRO); - - if(pInstance) - pInstance->SetData(DATA_VOIDREAVEREVENT, IN_PROGRESS); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - // Pounding - if(Pounding_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POUNDING); - - switch(rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_POUNDING1); - DoYell(SAY_POUNDING1, LANG_UNIVERSAL, NULL); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_POUNDING2); - DoYell(SAY_POUNDING2, LANG_UNIVERSAL, NULL); - break; - } - Pounding_Timer = 12000; - }else Pounding_Timer -= diff; - - // Arcane Orb - if(ArcaneOrb_Timer < diff) - { - Unit *target; - std::list t_list = m_creature->getThreatManager().getThreatList(); - std::vector target_list; - for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - //15 yard radius minimum - if(target && target->GetDistance2d(m_creature) > 15) - target_list.push_back(target); - target = NULL; - } - if(target_list.size()) - target = *(target_list.begin()+rand()%target_list.size()); - - if (target) - { - Unit* Spawn = NULL; - Spawn = m_creature->SummonCreature(CREATURE_ORB_TARGET, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); - if (Spawn) - m_creature->CastSpell(Spawn, SPELL_ARCANE_ORB_TRIGGER, true); - } - - ArcaneOrb_Timer = 3000; - }else ArcaneOrb_Timer -= diff; - - // Single Target knock back, reduces aggro - if(KnockAway_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCK_AWAY); - - //Drop 25% aggro - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-25); - - KnockAway_Timer = 30000; - }else KnockAway_Timer -= diff; - - //Berserk - if(Berserk_Timer < diff) - { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCast(m_creature,SPELL_BERSERK); - Berserk_Timer = 600000; - }else Berserk_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_void_reaver(Creature *_Creature) -{ - return new boss_void_reaverAI (_Creature); -} - -void AddSC_boss_void_reaver() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_void_reaver"; - newscript->GetAI = GetAI_boss_void_reaver; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Void_Reaver +SD%Complete: 100 +SDComment: +SDCategory: Tempest Keep, The Eye +EndScriptData */ + +#include "precompiled.h" +#include "def_the_eye.h" + +#define SPELL_POUNDING 34162 +#define SPELL_ARCANE_ORB_TRIGGER 34172 +#define SPELL_KNOCK_AWAY 11130 +#define SPELL_BERSERK 27680 + +#define SAY_AGGRO "Alert, you are marked for extermination!" +#define SAY_SLAY1 "Extermination, successful." +#define SAY_SLAY2 "Imbecile life form, no longer functional." +#define SAY_SLAY3 "Threat neutralized." +#define SAY_DEATH "Systems... shutting... down..." +#define SAY_POUNDING1 "Alternative measure commencing..." +#define SAY_POUNDING2 "Calculating force parameters..." + +#define SOUND_AGGRO 11213 +#define SOUND_SLAY1 11215 +#define SOUND_SLAY2 11216 +#define SOUND_SLAY3 11217 +#define SOUND_DEATH 11214 +#define SOUND_POUNDING1 11218 +#define SOUND_POUNDING2 11219 + +#define CREATURE_ORB_TARGET 19577 + +struct MANGOS_DLL_DECL boss_void_reaverAI : public ScriptedAI +{ + boss_void_reaverAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance* pInstance; + + uint32 Pounding_Timer; + uint32 ArcaneOrb_Timer; + uint32 KnockAway_Timer; + uint32 Berserk_Timer; + + void Reset() + { + Pounding_Timer = 12000; + ArcaneOrb_Timer = 3000; + KnockAway_Timer = 30000; + Berserk_Timer = 600000; + + if(pInstance) + pInstance->SetData(DATA_VOIDREAVEREVENT, NOT_STARTED); + } + + void KilledUnit(Unit *victim) + { + switch(rand()%3) + { + case 0: + DoYell(SAY_SLAY1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY1); + break; + case 1: + DoYell(SAY_SLAY2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY2); + break; + case 2: + DoYell(SAY_SLAY3, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SLAY3); + break; + } + } + + void JustDied(Unit *victim) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if(pInstance) + pInstance->SetData(DATA_VOIDREAVEREVENT, NOT_STARTED); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + + if(pInstance) + pInstance->SetData(DATA_VOIDREAVEREVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + // Pounding + if(Pounding_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POUNDING); + + switch(rand()%2) + { + case 0: + DoPlaySoundToSet(m_creature, SOUND_POUNDING1); + DoYell(SAY_POUNDING1, LANG_UNIVERSAL, NULL); + break; + case 1: + DoPlaySoundToSet(m_creature, SOUND_POUNDING2); + DoYell(SAY_POUNDING2, LANG_UNIVERSAL, NULL); + break; + } + Pounding_Timer = 12000; + }else Pounding_Timer -= diff; + + // Arcane Orb + if(ArcaneOrb_Timer < diff) + { + Unit *target; + std::list t_list = m_creature->getThreatManager().getThreatList(); + std::vector target_list; + for(std::list::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + { + target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); + //15 yard radius minimum + if(target && target->GetDistance2d(m_creature) > 15) + target_list.push_back(target); + target = NULL; + } + if(target_list.size()) + target = *(target_list.begin()+rand()%target_list.size()); + + if (target) + { + Unit* Spawn = NULL; + Spawn = m_creature->SummonCreature(CREATURE_ORB_TARGET, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); + if (Spawn) + m_creature->CastSpell(Spawn, SPELL_ARCANE_ORB_TRIGGER, true); + } + + ArcaneOrb_Timer = 3000; + }else ArcaneOrb_Timer -= diff; + + // Single Target knock back, reduces aggro + if(KnockAway_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCK_AWAY); + + //Drop 25% aggro + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-25); + + KnockAway_Timer = 30000; + }else KnockAway_Timer -= diff; + + //Berserk + if(Berserk_Timer < diff) + { + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + + DoCast(m_creature,SPELL_BERSERK); + Berserk_Timer = 600000; + }else Berserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_void_reaver(Creature *_Creature) +{ + return new boss_void_reaverAI (_Creature); +} + +void AddSC_boss_void_reaver() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_void_reaver"; + newscript->GetAI = GetAI_boss_void_reaver; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/def_the_eye.h b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/def_the_eye.h index eb7a9ecedf1..3478ae88970 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/def_the_eye.h +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/def_the_eye.h @@ -1,20 +1,20 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_THE_EYE_H -#define DEF_THE_EYE_H - -#define DATA_ALAREVENT 1 -#define DATA_ASTROMANCER 2 -#define DATA_GRANDASTROMANCERCAPERNIAN 3 -#define DATA_HIGHASTROMANCERSOLARIANEVENT 4 -#define DATA_FATHOMLORDKARATHRESSEVENT 5 -#define DATA_KAELTHAS 6 -#define DATA_KAELTHASEVENT 7 -#define DATA_LORDSANGUINAR 8 -#define DATA_MASTERENGINEERTELONICUS 9 -#define DATA_SOLARIANEVENT 10 -#define DATA_THALADREDTHEDARKENER 11 -#define DATA_VOIDREAVEREVENT 12 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_THE_EYE_H +#define DEF_THE_EYE_H + +#define DATA_ALAREVENT 1 +#define DATA_ASTROMANCER 2 +#define DATA_GRANDASTROMANCERCAPERNIAN 3 +#define DATA_HIGHASTROMANCERSOLARIANEVENT 4 +#define DATA_FATHOMLORDKARATHRESSEVENT 5 +#define DATA_KAELTHAS 6 +#define DATA_KAELTHASEVENT 7 +#define DATA_LORDSANGUINAR 8 +#define DATA_MASTERENGINEERTELONICUS 9 +#define DATA_SOLARIANEVENT 10 +#define DATA_THALADREDTHEDARKENER 11 +#define DATA_VOIDREAVEREVENT 12 +#endif diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/instance_the_eye.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/instance_the_eye.cpp index b2bd2920a82..8091216efe3 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/instance_the_eye.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/instance_the_eye.cpp @@ -1,178 +1,178 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_The_Eye -SD%Complete: 100 -SDComment: -SDCategory: Tempest Keep, The Eye -EndScriptData */ - -#include "precompiled.h" -#include "def_the_eye.h" - -#define ENCOUNTERS 5 - -/* 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(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint64 ThaladredTheDarkener; - uint64 LordSanguinar; - uint64 GrandAstromancerCapernian; - uint64 MasterEngineerTelonicus; - uint64 Kaelthas; - uint64 Astromancer; - - uint8 KaelthasEventPhase; - - bool Encounters[ENCOUNTERS]; - - void Initialize() - { - ThaladredTheDarkener = 0; - LordSanguinar = 0; - GrandAstromancerCapernian = 0; - MasterEngineerTelonicus = 0; - Kaelthas = 0; - Astromancer = 0; - - KaelthasEventPhase = 0; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounters[i] = false; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; i++) - if(Encounters[i]) return true; - - return false; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case 20064: ThaladredTheDarkener = creature->GetGUID(); break; - case 20063: MasterEngineerTelonicus = creature->GetGUID(); break; - case 20062: GrandAstromancerCapernian = creature->GetGUID(); break; - case 20060: LordSanguinar = creature->GetGUID(); break; - case 19622: Kaelthas = creature->GetGUID(); break; - case 18805: Astromancer = creature->GetGUID(); break; - } - } - - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_THALADREDTHEDARKENER: - return ThaladredTheDarkener; - - case DATA_LORDSANGUINAR: - return LordSanguinar; - - case DATA_GRANDASTROMANCERCAPERNIAN: - return GrandAstromancerCapernian; - - case DATA_MASTERENGINEERTELONICUS: - return MasterEngineerTelonicus; - - case DATA_KAELTHAS: - return Kaelthas; - - case DATA_ASTROMANCER: - return Astromancer; - } - - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_ALAREVENT: - Encounters[0] = (data) ? true : false; - break; - - case DATA_SOLARIANEVENT: - Encounters[1] = (data) ? true : false; - break; - - case DATA_VOIDREAVEREVENT: - Encounters[2] = (data) ? true : false; - break; - - //Kael'thas - case DATA_KAELTHASEVENT: - KaelthasEventPhase = data; - Encounters[3] = (data) ? true : false; - break; - - case DATA_HIGHASTROMANCERSOLARIANEVENT: - Encounters[4] = (data) ? true : false; - break; - } - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_ALAREVENT: - return Encounters[0]; - - case DATA_SOLARIANEVENT: - return Encounters[1]; - - case DATA_VOIDREAVEREVENT: - return Encounters[2]; - - case DATA_HIGHASTROMANCERSOLARIANEVENT: - return Encounters[4]; - - //Kael'thas - case DATA_KAELTHASEVENT: - return KaelthasEventPhase; - } - - return 0; - } -}; - -InstanceData* GetInstanceData_instance_the_eye(Map* map) -{ - return new instance_the_eye(map); -} - -void AddSC_instance_the_eye() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_the_eye"; - newscript->GetInstanceData = GetInstanceData_instance_the_eye; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_The_Eye +SD%Complete: 100 +SDComment: +SDCategory: Tempest Keep, The Eye +EndScriptData */ + +#include "precompiled.h" +#include "def_the_eye.h" + +#define ENCOUNTERS 5 + +/* 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(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint64 ThaladredTheDarkener; + uint64 LordSanguinar; + uint64 GrandAstromancerCapernian; + uint64 MasterEngineerTelonicus; + uint64 Kaelthas; + uint64 Astromancer; + + uint8 KaelthasEventPhase; + + bool Encounters[ENCOUNTERS]; + + void Initialize() + { + ThaladredTheDarkener = 0; + LordSanguinar = 0; + GrandAstromancerCapernian = 0; + MasterEngineerTelonicus = 0; + Kaelthas = 0; + Astromancer = 0; + + KaelthasEventPhase = 0; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounters[i] = false; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounters[i]) return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case 20064: ThaladredTheDarkener = creature->GetGUID(); break; + case 20063: MasterEngineerTelonicus = creature->GetGUID(); break; + case 20062: GrandAstromancerCapernian = creature->GetGUID(); break; + case 20060: LordSanguinar = creature->GetGUID(); break; + case 19622: Kaelthas = creature->GetGUID(); break; + case 18805: Astromancer = creature->GetGUID(); break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_THALADREDTHEDARKENER: + return ThaladredTheDarkener; + + case DATA_LORDSANGUINAR: + return LordSanguinar; + + case DATA_GRANDASTROMANCERCAPERNIAN: + return GrandAstromancerCapernian; + + case DATA_MASTERENGINEERTELONICUS: + return MasterEngineerTelonicus; + + case DATA_KAELTHAS: + return Kaelthas; + + case DATA_ASTROMANCER: + return Astromancer; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_ALAREVENT: + Encounters[0] = (data) ? true : false; + break; + + case DATA_SOLARIANEVENT: + Encounters[1] = (data) ? true : false; + break; + + case DATA_VOIDREAVEREVENT: + Encounters[2] = (data) ? true : false; + break; + + //Kael'thas + case DATA_KAELTHASEVENT: + KaelthasEventPhase = data; + Encounters[3] = (data) ? true : false; + break; + + case DATA_HIGHASTROMANCERSOLARIANEVENT: + Encounters[4] = (data) ? true : false; + break; + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_ALAREVENT: + return Encounters[0]; + + case DATA_SOLARIANEVENT: + return Encounters[1]; + + case DATA_VOIDREAVEREVENT: + return Encounters[2]; + + case DATA_HIGHASTROMANCERSOLARIANEVENT: + return Encounters[4]; + + //Kael'thas + case DATA_KAELTHASEVENT: + return KaelthasEventPhase; + } + + return 0; + } +}; + +InstanceData* GetInstanceData_instance_the_eye(Map* map) +{ + return new instance_the_eye(map); +} + +void AddSC_instance_the_eye() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_the_eye"; + newscript->GetInstanceData = GetInstanceData_instance_the_eye; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/the_eye.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/the_eye.cpp index 055a7ad3095..1effc9a2412 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/the_eye.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/the_eye.cpp @@ -1,98 +1,98 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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 "def_the_eye.h" - -#define SPELL_COUNTERCHARGE 35035 -#define SPELL_KNOCKAWAY 22893 - -struct MANGOS_DLL_DECL mob_crystalcore_devastatorAI : public ScriptedAI -{ - mob_crystalcore_devastatorAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Knockaway_Timer; - uint32 Countercharge_Timer; - - void Reset() - { - Countercharge_Timer = 9000; - Knockaway_Timer = 25000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !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 = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); - - if (!Target || Target == m_creature->getVictim()) - Target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); - - if (Target) - m_creature->TauntApply(Target); - - Knockaway_Timer = 23000; - } - else Knockaway_Timer -= diff; - - //Countercharge_Timer - if (Countercharge_Timer < diff) - { - DoCast(this->m_creature,SPELL_COUNTERCHARGE); - Countercharge_Timer = 45000; - }else Countercharge_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_crystalcore_devastator(Creature *_Creature) -{ - return new mob_crystalcore_devastatorAI (_Creature); -} - -void AddSC_the_eye() -{ - Script *newscript; - newscript = new Script; - newscript->Name="mob_crystalcore_devastator"; - newscript->GetAI = GetAI_mob_crystalcore_devastator; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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 "def_the_eye.h" + +#define SPELL_COUNTERCHARGE 35035 +#define SPELL_KNOCKAWAY 22893 + +struct MANGOS_DLL_DECL mob_crystalcore_devastatorAI : public ScriptedAI +{ + mob_crystalcore_devastatorAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Knockaway_Timer; + uint32 Countercharge_Timer; + + void Reset() + { + Countercharge_Timer = 9000; + Knockaway_Timer = 25000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !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 = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); + + if (!Target || Target == m_creature->getVictim()) + Target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); + + if (Target) + m_creature->TauntApply(Target); + + Knockaway_Timer = 23000; + } + else Knockaway_Timer -= diff; + + //Countercharge_Timer + if (Countercharge_Timer < diff) + { + DoCast(this->m_creature,SPELL_COUNTERCHARGE); + Countercharge_Timer = 45000; + }else Countercharge_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_crystalcore_devastator(Creature *_Creature) +{ + return new mob_crystalcore_devastatorAI (_Creature); +} + +void AddSC_the_eye() +{ + Script *newscript; + newscript = new Script; + newscript->Name="mob_crystalcore_devastator"; + newscript->GetAI = GetAI_mob_crystalcore_devastator; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp index f7aab61b6bb..cf9f26b7c37 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp @@ -1,24 +1,24 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 Gyrokill -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Tempest Keep, The Mechanar -EndScriptData */ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 Gyrokill +SD%Complete: 0 +SDComment: Place Holder +SDCategory: Tempest Keep, The Mechanar +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp index 77d57ff9b4c..7716782f682 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp @@ -1,147 +1,147 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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: 100 -SDComment: -SDCategory: Tempest Keep, The Mechanar -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOW_POWER 35322 -#define SPELL_JACKHAMMER 35326 -#define SPELL_STREAM_OF_MACHINE_FLUID 35311 - -#define SAY_SPELL_JACKHAMMER_1 "With the precise angle and velocity... " -#define SOUND_SPELL_JACKHAMMER_1 11112 -#define SAY_SPELL_JACKHAMMER_2 "Low tech yet quiet effective!" -#define SOUND_SPELL_JACKHAMMER_2 11113 - -#define SAY_AGGRO_1 "You have approximately five seconds to live." -#define SOUND_SAY_AGGRO_1 11109 - -#define SAY_SLAY_1 "A foregone conclusion." -#define SOUND_SLAY_1 11110 -#define SAY_SLAY_2 "The processing will continue a schedule!" -#define SOUND_SLAY_2 11111 - -#define SAY_DEATH_1 "My calculations did not... " -#define SOUND_DEATH_1 11114 - - -struct MANGOS_DLL_DECL boss_gatewatcher_iron_handAI : public ScriptedAI -{ - boss_gatewatcher_iron_handAI(Creature *c) : ScriptedAI(c) { Reset(); } - - 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) - { - } - - void KilledUnit(Unit* victim) - { - if (rand()%2) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_2); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH_1,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH_1); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Shadow Power - if(Shadow_Power_Timer < diff) - { - DoCast(m_creature,SPELL_SHADOW_POWER); - Shadow_Power_Timer = 25000; - }else Shadow_Power_Timer -= diff; - - //Jack Hammer - if(Jackhammer_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_JACKHAMMER); - - if (rand()%2) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_SPELL_JACKHAMMER_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SPELL_JACKHAMMER_1); - break; - case 1: - DoYell(SAY_SPELL_JACKHAMMER_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SPELL_JACKHAMMER_2); - break; - } - - Jackhammer_Timer = 45000; - }else Jackhammer_Timer -= diff; - - //Stream of Machine Fluid - if(Stream_of_Machine_Fluid_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_STREAM_OF_MACHINE_FLUID); - Stream_of_Machine_Fluid_Timer = 55000; - }else Stream_of_Machine_Fluid_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gatewatcher_iron_hand(Creature *_Creature) -{ - return new boss_gatewatcher_iron_handAI (_Creature); -} - -void AddSC_boss_gatewatcher_iron_hand() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gatewatcher_iron_hand"; - newscript->GetAI = GetAI_boss_gatewatcher_iron_hand; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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: 100 +SDComment: +SDCategory: Tempest Keep, The Mechanar +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SHADOW_POWER 35322 +#define SPELL_JACKHAMMER 35326 +#define SPELL_STREAM_OF_MACHINE_FLUID 35311 + +#define SAY_SPELL_JACKHAMMER_1 "With the precise angle and velocity... " +#define SOUND_SPELL_JACKHAMMER_1 11112 +#define SAY_SPELL_JACKHAMMER_2 "Low tech yet quiet effective!" +#define SOUND_SPELL_JACKHAMMER_2 11113 + +#define SAY_AGGRO_1 "You have approximately five seconds to live." +#define SOUND_SAY_AGGRO_1 11109 + +#define SAY_SLAY_1 "A foregone conclusion." +#define SOUND_SLAY_1 11110 +#define SAY_SLAY_2 "The processing will continue a schedule!" +#define SOUND_SLAY_2 11111 + +#define SAY_DEATH_1 "My calculations did not... " +#define SOUND_DEATH_1 11114 + + +struct MANGOS_DLL_DECL boss_gatewatcher_iron_handAI : public ScriptedAI +{ + boss_gatewatcher_iron_handAI(Creature *c) : ScriptedAI(c) { Reset(); } + + 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) + { + } + + void KilledUnit(Unit* victim) + { + if (rand()%2) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_2); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH_1,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH_1); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Shadow Power + if(Shadow_Power_Timer < diff) + { + DoCast(m_creature,SPELL_SHADOW_POWER); + Shadow_Power_Timer = 25000; + }else Shadow_Power_Timer -= diff; + + //Jack Hammer + if(Jackhammer_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_JACKHAMMER); + + if (rand()%2) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_SPELL_JACKHAMMER_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SPELL_JACKHAMMER_1); + break; + case 1: + DoYell(SAY_SPELL_JACKHAMMER_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SPELL_JACKHAMMER_2); + break; + } + + Jackhammer_Timer = 45000; + }else Jackhammer_Timer -= diff; + + //Stream of Machine Fluid + if(Stream_of_Machine_Fluid_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_STREAM_OF_MACHINE_FLUID); + Stream_of_Machine_Fluid_Timer = 55000; + }else Stream_of_Machine_Fluid_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_gatewatcher_iron_hand(Creature *_Creature) +{ + return new boss_gatewatcher_iron_handAI (_Creature); +} + +void AddSC_boss_gatewatcher_iron_hand() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gatewatcher_iron_hand"; + newscript->GetAI = GetAI_boss_gatewatcher_iron_hand; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp index e5012885d93..0d8b1a2486f 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp @@ -1,223 +1,223 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss Nethermancer Sepethrea -SD%Complete: 100 -SDComment: -SDCategory: Tempest Keep, The Mechanar -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SUMMON_RAGIN_FLAMES 35275 -#define SPELL_INFERNO 19695 -#define SPELL_FIRE_TAIL 35278 - -#define SPELL_FROST_ATTACK 35263 -#define SPELL_ARCANE_BLAST 35314 -#define SPELL_DRAGONS_BREATH 35250 -#define SPELL_KNOCKBACK 37317 -#define SPELL_SOLARBURN 35267 - -#define SAY_SPELL_DRAGONS_BREATH_1 "Think you can take the heat?" -#define SOUND_SPELL_DRAGONS_BREATH_1 11189 -#define SAY_SPELL_DRAGONS_BREATH_2 "Anar'endal dracon!" -#define SOUND_SPELL_DRAGONS_BREATH_2 11190 - -#define SAY_AGGRO "Don't value your life very much, do you?" -#define SOUND_SAY_AGGRO 11186 - -#define SAY_SLAY "And don't come back!" -#define SOUND_SLAY 11187 - -#define SAY_DEATH "Anu... bala belore...alon." -#define SOUND_DEATH 11192 - -struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI -{ - boss_nethermancer_sepethreaAI(Creature *c) : ScriptedAI(c) { Reset(); } - - uint32 frost_attack_Timer; - uint32 arcane_blast_Timer; - uint32 dragons_breath_Timer; - uint32 knockback_Timer; - uint32 solarburn_Timer; - - void Reset() - { - frost_attack_Timer = 10000; - arcane_blast_Timer = 15000; - dragons_breath_Timer = 20000; - knockback_Timer = 25000; - solarburn_Timer = 30000; - } - - void Aggro(Unit *who) - { - } - - void KilledUnit(Unit* victim) - { - DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_DEATH); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Frost Attack - if(frost_attack_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROST_ATTACK); - frost_attack_Timer = 10000; - }else frost_attack_Timer -= diff; - - //Arcane Blast - if(arcane_blast_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ARCANE_BLAST); - arcane_blast_Timer = 15000; - }else arcane_blast_Timer -= diff; - - //Dragons Breath - if(dragons_breath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DRAGONS_BREATH); - dragons_breath_Timer = 20000; - - if (rand()%2) - return; - - switch(rand()%2) - { - case 0: - DoYell(SAY_SPELL_DRAGONS_BREATH_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SPELL_DRAGONS_BREATH_1); - break; - case 1: - DoYell(SAY_SPELL_DRAGONS_BREATH_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SPELL_DRAGONS_BREATH_2); - break; - } - }else dragons_breath_Timer -= diff; - - //Knockback - if(knockback_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKBACK); - knockback_Timer = 25000; - }else knockback_Timer -= diff; - - //Solarburn - if(solarburn_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SOLARBURN); - solarburn_Timer = 30000; - }else solarburn_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_nethermancer_sepethrea(Creature *_Creature) -{ - return new boss_nethermancer_sepethreaAI (_Creature); -} - -struct MANGOS_DLL_DECL mob_ragin_flamesAI : public ScriptedAI -{ - mob_ragin_flamesAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 inferno_Timer; - uint32 flame_timer; - - bool onlyonce; - - void Reset() - { - inferno_Timer = 10000; - flame_timer = 200; - onlyonce = false; - } - - void Aggro(Unit* who) - { - } - - void UpdateAI(const uint32 diff) - { - Unit* target = NULL; - - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (!onlyonce) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - m_creature->GetMotionMaster()->MoveChase(target); - onlyonce = true; - } - - if(inferno_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_INFERNO); - inferno_Timer = 10000; - - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - m_creature->GetMotionMaster()->MoveChase(target); - }else inferno_Timer -= diff; - - if(flame_timer < diff) - { - DoCast(m_creature,SPELL_FIRE_TAIL); - flame_timer = 200; - }else flame_timer -=diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_mob_ragin_flames(Creature *_Creature) -{ - return new mob_ragin_flamesAI (_Creature); -} - -void AddSC_boss_nethermancer_sepethrea() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_nethermancer_sepethrea"; - newscript->GetAI = GetAI_boss_nethermancer_sepethrea; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_ragin_flames"; - newscript->GetAI = GetAI_mob_ragin_flames; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss Nethermancer Sepethrea +SD%Complete: 100 +SDComment: +SDCategory: Tempest Keep, The Mechanar +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_SUMMON_RAGIN_FLAMES 35275 +#define SPELL_INFERNO 19695 +#define SPELL_FIRE_TAIL 35278 + +#define SPELL_FROST_ATTACK 35263 +#define SPELL_ARCANE_BLAST 35314 +#define SPELL_DRAGONS_BREATH 35250 +#define SPELL_KNOCKBACK 37317 +#define SPELL_SOLARBURN 35267 + +#define SAY_SPELL_DRAGONS_BREATH_1 "Think you can take the heat?" +#define SOUND_SPELL_DRAGONS_BREATH_1 11189 +#define SAY_SPELL_DRAGONS_BREATH_2 "Anar'endal dracon!" +#define SOUND_SPELL_DRAGONS_BREATH_2 11190 + +#define SAY_AGGRO "Don't value your life very much, do you?" +#define SOUND_SAY_AGGRO 11186 + +#define SAY_SLAY "And don't come back!" +#define SOUND_SLAY 11187 + +#define SAY_DEATH "Anu... bala belore...alon." +#define SOUND_DEATH 11192 + +struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI +{ + boss_nethermancer_sepethreaAI(Creature *c) : ScriptedAI(c) { Reset(); } + + uint32 frost_attack_Timer; + uint32 arcane_blast_Timer; + uint32 dragons_breath_Timer; + uint32 knockback_Timer; + uint32 solarburn_Timer; + + void Reset() + { + frost_attack_Timer = 10000; + arcane_blast_Timer = 15000; + dragons_breath_Timer = 20000; + knockback_Timer = 25000; + solarburn_Timer = 30000; + } + + void Aggro(Unit *who) + { + } + + void KilledUnit(Unit* victim) + { + DoYell(SAY_SLAY, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_DEATH); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Frost Attack + if(frost_attack_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROST_ATTACK); + frost_attack_Timer = 10000; + }else frost_attack_Timer -= diff; + + //Arcane Blast + if(arcane_blast_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ARCANE_BLAST); + arcane_blast_Timer = 15000; + }else arcane_blast_Timer -= diff; + + //Dragons Breath + if(dragons_breath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DRAGONS_BREATH); + dragons_breath_Timer = 20000; + + if (rand()%2) + return; + + switch(rand()%2) + { + case 0: + DoYell(SAY_SPELL_DRAGONS_BREATH_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SPELL_DRAGONS_BREATH_1); + break; + case 1: + DoYell(SAY_SPELL_DRAGONS_BREATH_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SPELL_DRAGONS_BREATH_2); + break; + } + }else dragons_breath_Timer -= diff; + + //Knockback + if(knockback_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKBACK); + knockback_Timer = 25000; + }else knockback_Timer -= diff; + + //Solarburn + if(solarburn_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SOLARBURN); + solarburn_Timer = 30000; + }else solarburn_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_nethermancer_sepethrea(Creature *_Creature) +{ + return new boss_nethermancer_sepethreaAI (_Creature); +} + +struct MANGOS_DLL_DECL mob_ragin_flamesAI : public ScriptedAI +{ + mob_ragin_flamesAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 inferno_Timer; + uint32 flame_timer; + + bool onlyonce; + + void Reset() + { + inferno_Timer = 10000; + flame_timer = 200; + onlyonce = false; + } + + void Aggro(Unit* who) + { + } + + void UpdateAI(const uint32 diff) + { + Unit* target = NULL; + + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (!onlyonce) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + m_creature->GetMotionMaster()->MoveChase(target); + onlyonce = true; + } + + if(inferno_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_INFERNO); + inferno_Timer = 10000; + + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + m_creature->GetMotionMaster()->MoveChase(target); + }else inferno_Timer -= diff; + + if(flame_timer < diff) + { + DoCast(m_creature,SPELL_FIRE_TAIL); + flame_timer = 200; + }else flame_timer -=diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_mob_ragin_flames(Creature *_Creature) +{ + return new mob_ragin_flamesAI (_Creature); +} + +void AddSC_boss_nethermancer_sepethrea() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_nethermancer_sepethrea"; + newscript->GetAI = GetAI_boss_nethermancer_sepethrea; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_ragin_flames"; + newscript->GetAI = GetAI_mob_ragin_flames; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_bug_trio.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_bug_trio.cpp index 2592d8e8297..c507fe03898 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_bug_trio.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_bug_trio.cpp @@ -1,384 +1,348 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: boss_kri, boss_yauj, boss_vem : The Bug Trio -SD%Complete: 100 -SDComment: -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" -#include "def_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. - -#define SPELL_CHARGE 26561 -#define SPELL_KNOCKBACK 26027 - -#define SPELL_HEAL 25807 -#define SPELL_FEAR 19408 - -struct MANGOS_DLL_DECL boss_kriAI : public ScriptedAI -{ - boss_kriAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Cleave_Timer; - uint32 ToxicVolley_Timer; - uint32 Check_Timer; - - bool VemDead; - bool Death; - - void Reset() - { - Cleave_Timer = 4000 + rand()%4000; - ToxicVolley_Timer = 6000 + rand()%6000; - Check_Timer = 2000; - - VemDead = false; - Death = false; - } - - void Aggro(Unit *who) - { - } - - void JustDied(Unit* killer) - { - if(pInstance) - { - if(pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) - // Unlootable if death - m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - - pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); - } - } - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 5000 + rand()%7000; - }else Cleave_Timer -= diff; - - //ToxicVolley_Timer - if (ToxicVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_TOXIC_VOLLEY); - ToxicVolley_Timer = 10000 + rand()%5000; - }else ToxicVolley_Timer -= diff; - - if (m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.05 && !Death) - { - DoCast(m_creature->getVictim(),SPELL_POISON_CLOUD); - Death = true; - } - - if(!VemDead) - { - //Checking if Vem is dead. If yes we will enrage. - if(Check_Timer < diff) - { - if(pInstance && pInstance->GetData(DATA_VEMISDEAD)) - { - DoCast(m_creature, SPELL_ENRAGE); - VemDead = true; - } - Check_Timer = 2000; - }else Check_Timer -=diff; - } - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_vemAI : public ScriptedAI -{ - boss_vemAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Charge_Timer; - uint32 KnockBack_Timer; - uint32 Enrage_Timer; - - bool Enraged; - - void Reset() - { - Charge_Timer = 15000 + rand()%12000; - KnockBack_Timer = 8000 + rand()%12000; - Enrage_Timer = 120000; - - Enraged = false; - } - - void JustDied(Unit* Killer) - { - if(pInstance) - { - pInstance->SetData(DATA_VEM_DEATH, 0); - if(pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) - // Unlootable if death - m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); - } - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || m_creature->getVictim()) - return; - - if (who->isTargetableForAttack() && IsVisible(who) && 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - //Begin melee attack if we are within range - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Charge_Timer - if (Charge_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if(target) - { - DoCast(target, SPELL_CHARGE); - m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); - DoStartAttackAndMovement(target); - } - - Charge_Timer = 8000 + rand()%8000; - }else Charge_Timer -= diff; - - //KnockBack_Timer - if (KnockBack_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KNOCKBACK); - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); - KnockBack_Timer = 15000 + rand()%10000; - }else KnockBack_Timer -= diff; - - //Enrage_Timer - if (!Enraged && Enrage_Timer < diff) - { - DoCast(m_creature,SPELL_ENRAGE); - Enraged = true; - }else Charge_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_yaujAI : public ScriptedAI -{ - boss_yaujAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Heal_Timer; - uint32 Fear_Timer; - uint32 Check_Timer; - - bool VemDead; - - void Reset() - { - Heal_Timer = 25000 + rand()%15000; - Fear_Timer = 12000 + rand()%12000; - Check_Timer = 2000; - - VemDead = false; - } - - void JustDied(Unit* Killer) - { - if(pInstance) - { - if(pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) - // Unlootable if death - m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); - } - - for(int i = 0; i < 10;i++) - { - Unit* target = SelectUnit(SELECT_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) - ((CreatureAI*)Summoned->AI())->AttackStart(target); - } - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || m_creature->getVictim()) - return; - - if (who->isTargetableForAttack() && IsVisible(who) && 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - //Begin melee attack if we are within range - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Fear_Timer - if (Fear_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FEAR); - DoResetThreat(); - Fear_Timer = 20000; - }else Fear_Timer -= diff; - - //Casting Heal to other twins or herself. - if(Heal_Timer < diff) - { - if(pInstance) - { - Unit *pKri = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KRI)); - Unit *pVem = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_VEM)); - - switch(rand()%3) - { - case 0: - if(pKri) - DoCast(pKri, SPELL_HEAL); - break; - case 1: - if(pVem) - DoCast(pVem, SPELL_HEAL); - break; - case 2: - DoCast(m_creature, SPELL_HEAL); - break; - } - } - - Heal_Timer = 15000+rand()%15000; - }else Heal_Timer -= diff; - - //Checking if Vem is dead. If yes we will enrage. - if(Check_Timer < diff) - { - if (!VemDead) - { - if(pInstance) - { - if(pInstance->GetData(DATA_VEMISDEAD)) - { - DoCast(m_creature, SPELL_ENRAGE); - VemDead = true; - } - } - } - Check_Timer = 2000; - }else Check_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_yauj(Creature *_Creature) -{ - return new boss_yaujAI (_Creature); -} - -CreatureAI* GetAI_boss_vem(Creature *_Creature) -{ - return new boss_vemAI (_Creature); -} - -CreatureAI* GetAI_boss_kri(Creature *_Creature) -{ - return new boss_kriAI (_Creature); -} - -void AddSC_bug_trio() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_kri"; - newscript->GetAI = GetAI_boss_kri; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_vem"; - newscript->GetAI = GetAI_boss_vem; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_yauj"; - newscript->GetAI = GetAI_boss_yauj; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: boss_kri, boss_yauj, boss_vem : The Bug Trio +SD%Complete: 100 +SDComment: +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" +#include "def_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. + +#define SPELL_CHARGE 26561 +#define SPELL_KNOCKBACK 26027 + +#define SPELL_HEAL 25807 +#define SPELL_FEAR 19408 + +struct MANGOS_DLL_DECL boss_kriAI : public ScriptedAI +{ + boss_kriAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Cleave_Timer; + uint32 ToxicVolley_Timer; + uint32 Check_Timer; + + bool VemDead; + bool Death; + + void Reset() + { + Cleave_Timer = 4000 + rand()%4000; + ToxicVolley_Timer = 6000 + rand()%6000; + Check_Timer = 2000; + + VemDead = false; + Death = false; + } + + void Aggro(Unit *who) + { + } + + void JustDied(Unit* killer) + { + if(pInstance) + { + if(pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) + // Unlootable if death + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); + } + } + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Cleave_Timer + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 5000 + rand()%7000; + }else Cleave_Timer -= diff; + + //ToxicVolley_Timer + if (ToxicVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_TOXIC_VOLLEY); + ToxicVolley_Timer = 10000 + rand()%5000; + }else ToxicVolley_Timer -= diff; + + if (m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.05 && !Death) + { + DoCast(m_creature->getVictim(),SPELL_POISON_CLOUD); + Death = true; + } + + if(!VemDead) + { + //Checking if Vem is dead. If yes we will enrage. + if(Check_Timer < diff) + { + if(pInstance && pInstance->GetData(DATA_VEMISDEAD)) + { + DoCast(m_creature, SPELL_ENRAGE); + VemDead = true; + } + Check_Timer = 2000; + }else Check_Timer -=diff; + } + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_vemAI : public ScriptedAI +{ + boss_vemAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Charge_Timer; + uint32 KnockBack_Timer; + uint32 Enrage_Timer; + + bool Enraged; + + void Reset() + { + Charge_Timer = 15000 + rand()%12000; + KnockBack_Timer = 8000 + rand()%12000; + Enrage_Timer = 120000; + + Enraged = false; + } + + void JustDied(Unit* Killer) + { + if(pInstance) + { + pInstance->SetData(DATA_VEM_DEATH, 0); + if(pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) + // Unlootable if death + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Charge_Timer + if (Charge_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if(target) + { + DoCast(target, SPELL_CHARGE); + m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); + DoStartAttackAndMovement(target); + } + + Charge_Timer = 8000 + rand()%8000; + }else Charge_Timer -= diff; + + //KnockBack_Timer + if (KnockBack_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KNOCKBACK); + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); + KnockBack_Timer = 15000 + rand()%10000; + }else KnockBack_Timer -= diff; + + //Enrage_Timer + if (!Enraged && Enrage_Timer < diff) + { + DoCast(m_creature,SPELL_ENRAGE); + Enraged = true; + }else Charge_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL boss_yaujAI : public ScriptedAI +{ + boss_yaujAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Heal_Timer; + uint32 Fear_Timer; + uint32 Check_Timer; + + bool VemDead; + + void Reset() + { + Heal_Timer = 25000 + rand()%15000; + Fear_Timer = 12000 + rand()%12000; + Check_Timer = 2000; + + VemDead = false; + } + + void JustDied(Unit* Killer) + { + if(pInstance) + { + if(pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) + // Unlootable if death + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); + } + + for(int i = 0; i < 10;i++) + { + Unit* target = SelectUnit(SELECT_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) + ((CreatureAI*)Summoned->AI())->AttackStart(target); + } + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Fear_Timer + if (Fear_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FEAR); + DoResetThreat(); + Fear_Timer = 20000; + }else Fear_Timer -= diff; + + //Casting Heal to other twins or herself. + if(Heal_Timer < diff) + { + if(pInstance) + { + Unit *pKri = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_KRI)); + Unit *pVem = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_VEM)); + + switch(rand()%3) + { + case 0: + if(pKri) + DoCast(pKri, SPELL_HEAL); + break; + case 1: + if(pVem) + DoCast(pVem, SPELL_HEAL); + break; + case 2: + DoCast(m_creature, SPELL_HEAL); + break; + } + } + + Heal_Timer = 15000+rand()%15000; + }else Heal_Timer -= diff; + + //Checking if Vem is dead. If yes we will enrage. + if(Check_Timer < diff) + { + if (!VemDead) + { + if(pInstance) + { + if(pInstance->GetData(DATA_VEMISDEAD)) + { + DoCast(m_creature, SPELL_ENRAGE); + VemDead = true; + } + } + } + Check_Timer = 2000; + }else Check_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_yauj(Creature *_Creature) +{ + return new boss_yaujAI (_Creature); +} + +CreatureAI* GetAI_boss_vem(Creature *_Creature) +{ + return new boss_vemAI (_Creature); +} + +CreatureAI* GetAI_boss_kri(Creature *_Creature) +{ + return new boss_kriAI (_Creature); +} + +void AddSC_bug_trio() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_kri"; + newscript->GetAI = GetAI_boss_kri; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_vem"; + newscript->GetAI = GetAI_boss_vem; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_yauj"; + newscript->GetAI = GetAI_boss_yauj; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp index a01de84604b..17d159451f4 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp @@ -1,1360 +1,1360 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Cthun -SD%Complete: 95 -SDComment: Darkglare tracking issue -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" -#include "def_temple_of_ahnqiraj.h" - -#define PI 3.14 - -//****** Out of Combat ****** -//Random Wispers - No txt only sound -#define RND_WISPER_1 8580 //Death is close -#define RND_WISPER_2 8581 //You are already dead -#define RND_WISPER_3 8582 //Your courage will fail -#define RND_WISPER_4 8583 //Your friends will abandon you -#define RND_WISPER_5 8584 //You will betray your friends -#define RND_WISPER_6 8585 //You will die -#define RND_WISPER_7 8586 //You are weak -#define RND_WISPER_8 8587 //Your heart will explode - -//***** 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 - -//Text emote -#define EMOTE_WEAKENED "is weakened!" - -//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 Scripted_NoMovementAI -{ - flesh_tentacleAI(Creature *c) : Scripted_NoMovementAI(c), Parent(0) {Reset();} - - uint64 Parent; - uint32 CheckTimer; - - void SpawnedByCthun(uint64 p) - { - Parent = p; - } - - void Reset() - { - CheckTimer = 1000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff); - - void JustDied(Unit* killer); -}; - -struct MANGOS_DLL_DECL eye_of_cthunAI : public Scripted_NoMovementAI -{ - eye_of_cthunAI(Creature *c) : Scripted_NoMovementAI(c) - { - pInst = (ScriptedInstance*)c->GetInstanceData(); - if (!pInst) - error_log("SD2: No Instance eye_of_cthunAI"); - - Reset(); - } - - ScriptedInstance* pInst; - - //Global variables - uint32 PhaseTimer; - - //Eye beam phase - uint32 BeamTimer; - uint32 EyeTentacleTimer; - uint32 ClawTentacleTimer; - - //Dark Glare phase - uint32 DarkGlareTick; - uint32 DarkGlareTickTimer; - float DarkGlareAngle; - bool ClockWise; - - 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) - - //Dark Beam phase 35 seconds (each tick = 1 second, 35 ticks) - DarkGlareTick = 0; - DarkGlareTickTimer = 1000; - DarkGlareAngle = 0; - ClockWise = false; - - //Reset flags - m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - //Reset Phase - if (pInst) - pInst->SetData(DATA_CTHUN_PHASE, 0); - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - } - - void SpawnEyeTentacle(float x, float y) - { - 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) - { - Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - if (target) - Spawned->AI()->AttackStart(target); - } - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //No instance - if (!pInst) - return; - - switch (pInst->GetData(DATA_CTHUN_PHASE)) - { - case 0: - { - //BeamTimer - if (BeamTimer < diff) - { - //SPELL_GREEN_BEAM - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(target,SPELL_GREEN_BEAM); - - //Correctly update our target - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); - } - - //Beam every 3 seconds - BeamTimer = 3000; - }else BeamTimer -= diff; - - //ClawTentacleTimer - if (ClawTentacleTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - { - Creature* Spawned = NULL; - - //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 (Spawned) - Spawned->AI()->AttackStart(target); - } - - //One claw tentacle every 12.5 seconds - ClawTentacleTimer = 12500; - }else ClawTentacleTimer -= diff; - - //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 - pInst->SetData(DATA_CTHUN_PHASE, 1); - - m_creature->InterruptNonMeleeSpells(false); - - //Select random target for dark beam to start on - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - if (target) - { - //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 = rand()%2; - } - - //Add red coloration to C'thun - DoCast(m_creature,SPELL_RED_COLORATION); - - //Freeze animation - m_creature->setEmoteState(53); - - //Darkbeam for 35 seconds - PhaseTimer = 35000; - }else PhaseTimer -= diff; - - } - break; - case 1: - { - //EyeTentacleTimer - if (DarkGlareTick < 35) - if (DarkGlareTickTimer < diff) - { - //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); - - //Increase tick - DarkGlareTick++; - - //1 second per tick - DarkGlareTickTimer = 1000; - }else DarkGlareTickTimer -= diff; - - //PhaseTimer - if (PhaseTimer < diff) - { - //Switch to Eye Beam - pInst->SetData(DATA_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->setEmoteState(0); - m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, 0); - - //Eye Beam for 50 seconds - PhaseTimer = 50000; - }else PhaseTimer -= diff; - }break; - - //Transition phase - case 2: - { - //Remove any target - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); - m_creature->SetHealth(0); - } - - //Dead phase - case 5: - { - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } - } - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - //No instance - if (!pInst) - return; - - switch (pInst->GetData(DATA_CTHUN_PHASE)) - { - 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->setEmoteState(0); - 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; - pInst->SetData(DATA_CTHUN_PHASE, 2); - - m_creature->SetHealth(0); - damage = 0; - - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); - } - break; - - case 5: - { - //Allow death here - return; - } - - default: - { - //Prevent death in this phase - damage = 0; - return; - } - break; - } - } -}; - -struct MANGOS_DLL_DECL cthunAI : public Scripted_NoMovementAI -{ - cthunAI(Creature *c) : Scripted_NoMovementAI(c) - { - pInst = (ScriptedInstance*)c->GetInstanceData(); - if (!pInst) - error_log("SD2: No Instance eye_of_cthunAI"); - - Reset(); - } - - ScriptedInstance* pInst; - - //Out of combat whisper timer - uint32 WisperTimer; - - //Global variables - uint32 PhaseTimer; - - //------------------- - - //Phase transition - uint64 HoldPlayer; - - //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 - HM_NAMESPACE::hash_map Stomach_Map; - - 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; - - //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 - - //Clear players in stomach and outside - Stomach_Map.clear(); - - //Reset flags - m_creature->RemoveAurasDueToSpell(SPELL_TRANSFORM); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - if (pInst) - pInst->SetData(DATA_CTHUN_PHASE, 0); - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - } - - void SpawnEyeTentacle(float x, float y) - { - 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) - { - Unit* target; - - target = SelectRandomNotStomach(); - - if (target) - Spawned->AI()->AttackStart(target); - } - } - - Unit* SelectRandomNotStomach() - { - if (Stomach_Map.empty()) - return NULL; - - HM_NAMESPACE::hash_map::iterator i = Stomach_Map.begin(); - - std::list temp; - std::list::iterator j; - - //Get all players in map - while (i != Stomach_Map.end()) - { - //Check for valid player - Unit* pUnit = Unit::GetUnit(*m_creature, i->first); - - //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 ( i , rand() % (temp.size() - 1) ); - - return (*j); - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - { - //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; - - InstanceMap::PlayerList const &PlayerList = ((InstanceMap*)map)->GetPlayers(); - for (InstanceMap::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - //Play random sound to the zone - switch (rand()%8) - { - case 0: (*i)->PlaySound(RND_WISPER_1, true); break; - case 1: (*i)->PlaySound(RND_WISPER_2, true); break; - case 2: (*i)->PlaySound(RND_WISPER_3, true); break; - case 3: (*i)->PlaySound(RND_WISPER_4, true); break; - case 4: (*i)->PlaySound(RND_WISPER_5, true); break; - case 5: (*i)->PlaySound(RND_WISPER_6, true); break; - case 6: (*i)->PlaySound(RND_WISPER_7, true); break; - case 7: (*i)->PlaySound(RND_WISPER_8, true); break; - } - } - - //One random wisper every 90 - 300 seconds - WisperTimer = 90000 + (rand()% 210000); - }else WisperTimer -= diff; - - return; - } - - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); - - //No instance - if (!pInst) - return; - - switch (pInst->GetData(DATA_CTHUN_PHASE)) - { - //Transition phase - case 2: - { - //PhaseTimer - if (PhaseTimer < diff) - { - //Switch - pInst->SetData(DATA_CTHUN_PHASE, 3); - - //Switch to c'thun model - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature, SPELL_TRANSFORM, false); - m_creature->SetHealth(m_creature->GetMaxHealth()); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - //Emerging phase - //AttackStart(Unit::GetUnit(*m_creature, HoldPlayer)); - DoZoneInCombat(); - - //Place all units in threat list on outside of stomach - Stomach_Map.clear(); - - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - //Outside stomach - Stomach_Map[(*i)->getUnitGuid()] = false; - } - - //Spawn 2 flesh tentacles - FleshTentaclesKilled = 0; - - Creature* Spawned; - - //Spawn flesh tentacle - Spawned = (Creature*)m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS1_X, TENTACLE_POS1_Y, TENTACLE_POS1_Z, TENTACLE_POS1_O, TEMPSUMMON_CORPSE_DESPAWN, 0); - - if (!Spawned) - FleshTentaclesKilled++; - else - ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(m_creature->GetGUID()); - - //Spawn flesh tentacle - Spawned = (Creature*)m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS2_X, TENTACLE_POS2_Y, TENTACLE_POS2_Z, TENTACLE_POS2_O, TEMPSUMMON_CORPSE_DESPAWN, 0); - - if (!Spawned) - FleshTentaclesKilled++; - else - ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(m_creature->GetGUID()); - - PhaseTimer = 0; - }else PhaseTimer -= diff; - - }break; - - //Body Phase - case 3: - { - //Remove Target field - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); - - //Weaken - if (FleshTentaclesKilled > 1) - { - pInst->SetData(DATA_CTHUN_PHASE, 4); - - DoTextEmote(EMOTE_WEAKENED, NULL); - PhaseTimer = 45000; - - DoCast(m_creature, SPELL_RED_COLORATION, true); - - HM_NAMESPACE::hash_map::iterator i = Stomach_Map.begin(); - - //Kick all players out of stomach - while (i != Stomach_Map.end()) - { - //Check for valid player - Unit* pUnit = Unit::GetUnit(*m_creature, 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); - - //Cast knockback on them - DoCast(pUnit, SPELL_EXIT_STOMACH_KNOCKBACK, true); - - //Remove the acid debuff - pUnit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); - - i->second = false; - } - ++i; - } - - return; - } - - //Stomach acid - if (StomachAcidTimer < diff) - { - //Apply aura to all players in stomach - HM_NAMESPACE::hash_map::iterator i = Stomach_Map.begin(); - - while (i != Stomach_Map.end()) - { - //Check for valid player - Unit* pUnit = Unit::GetUnit(*m_creature, i->first); - - //Only apply to units in stomach - if (pUnit && i->second == true) - { - //Cast digestive acid on them - DoCast(pUnit, SPELL_DIGESTIVE_ACID, true); - - //Check if player should be kicked from stomach - if (pUnit->GetDistance(KICK_X, KICK_Y, KICK_Z) < 15) - { - //Teleport each player out - DoTeleportPlayer(pUnit, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+10, rand()%6); - - //Cast knockback on them - DoCast(pUnit, SPELL_EXIT_STOMACH_KNOCKBACK, true); - - //Remove the acid debuff - pUnit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); - - i->second = false; - } - } - ++i; - } - - StomachAcidTimer = 4000; - }else StomachAcidTimer -= diff; - - //Stomach Enter Timer - if (StomachEnterTimer < diff) - { - Unit* target = NULL; - target = SelectRandomNotStomach(); - - if (target) - { - //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; - - if (StomachEnterVisTimer && StomachEnterTarget) - if (StomachEnterVisTimer <= diff) - { - //Check for valid player - Unit* pUnit = Unit::GetUnit(*m_creature, StomachEnterTarget); - - if (pUnit) - { - DoTeleportPlayer(pUnit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O); - } - - StomachEnterTarget = 0; - StomachEnterVisTimer = 0; - }else StomachEnterVisTimer -= diff; - - //GientClawTentacleTimer - if (GiantClawTentacleTimer < diff) - { - Unit* target = NULL; - target = SelectRandomNotStomach(); - if (target) - { - 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); - - if (Spawned) - Spawned->AI()->AttackStart(target); - } - - //One giant claw tentacle every minute - GiantClawTentacleTimer = 60000; - }else GiantClawTentacleTimer -= diff; - - //GiantEyeTentacleTimer - if (GiantEyeTentacleTimer < diff) - { - Unit* target = NULL; - target = SelectRandomNotStomach(); - if (target) - { - - Creature* Spawned = NULL; - - //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); - - if (Spawned) - Spawned->AI()->AttackStart(target); - } - - //One giant eye tentacle every minute - GiantEyeTentacleTimer = 60000; - }else GiantEyeTentacleTimer -= diff; - - //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 - - SpawnEyeTentacle(0, -25); //north - SpawnEyeTentacle(-12, -12); //north east - SpawnEyeTentacle(-25, 0); // east - SpawnEyeTentacle(-12, 12); // south east - - //These spawn at every 30 seconds - EyeTentacleTimer = 30000; - }else EyeTentacleTimer -= diff; - - }break; - - //Weakened state - case 4: - { - //PhaseTimer - if (PhaseTimer < diff) - { - //Switch - pInst->SetData(DATA_CTHUN_PHASE, 3); - - //Remove red coloration - m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - - //Spawn 2 flesh tentacles - FleshTentaclesKilled = 0; - - Creature* Spawned; - - //Spawn flesh tentacle - Spawned = (Creature*)m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS1_X, TENTACLE_POS1_Y, TENTACLE_POS1_Z, TENTACLE_POS1_O, TEMPSUMMON_CORPSE_DESPAWN, 0); - - if (!Spawned) - FleshTentaclesKilled++; - else - ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(m_creature->GetGUID()); - - //Spawn flesh tentacle - Spawned = (Creature*)m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS2_X, TENTACLE_POS2_Y, TENTACLE_POS2_Z, TENTACLE_POS2_O, TEMPSUMMON_CORPSE_DESPAWN, 0); - - if (!Spawned) - FleshTentaclesKilled++; - else - ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(m_creature->GetGUID()); - - PhaseTimer = 0; - }else PhaseTimer -= diff; - } - } - } - - void JustDied(Unit* pKiller) - { - //Switch - if( pInst ) - pInst->SetData(DATA_CTHUN_PHASE, 5); - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - //No instance - if (!pInst) - return; - - switch (pInst->GetData(DATA_CTHUN_PHASE)) - { - case 3: - { - //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; - } - break; - - case 4: - { - //Weakened - takes normal damage - return; - } - - default: - damage = 0; - break; - } - } - - void FleshTentcleKilled() - { - FleshTentaclesKilled++; - } -}; - -struct MANGOS_DLL_DECL eye_tentacleAI : public Scripted_NoMovementAI -{ - eye_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) - { - Reset(); - Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); - if (p) - Portal = p->GetGUID(); - } - - uint32 MindflayTimer; - uint32 KillSelfTimer; - uint64 Portal; - - void JustDied(Unit*) - { - Unit* p = Unit::GetUnit(*m_creature, Portal); - if (p) - p->DealDamage(p, p->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 *who) - { - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostilTarget() || !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 = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target && !target->HasAura(SPELL_DIGESTIVE_ACID, 0)) - DoCast(target,SPELL_MIND_FLAY); - - //Mindflay every 10 seconds - MindflayTimer = 10100; - }else MindflayTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL claw_tentacleAI : public Scripted_NoMovementAI -{ - claw_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) - { - Reset(); - Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); - if (p) - Portal = p->GetGUID(); - } - - uint32 GroundRuptureTimer; - uint32 HamstringTimer; - uint32 EvadeTimer; - uint64 Portal; - - void JustDied(Unit*) - { - Unit* p = Unit::GetUnit(*m_creature, Portal); - if (p) - p->DealDamage(p, p->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } - - void Reset() - { - //First rupture should happen half a second after we spawn - GroundRuptureTimer = 500; - HamstringTimer = 2000; - EvadeTimer = 5000; - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //EvadeTimer - if (m_creature->GetDistance(m_creature->getVictim()) > ATTACK_DISTANCE) - if (EvadeTimer < diff) - { - Unit* p = Unit::GetUnit(*m_creature, Portal); - if (p) - p->DealDamage(p, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - - //Dissapear and reappear at new position - m_creature->SetVisibility(VISIBILITY_OFF); - - Unit* target = NULL; - target = SelectUnit(SELECT_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, 0)) - { - m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); - if (p) - Portal = p->GetGUID(); - - GroundRuptureTimer = 500; - HamstringTimer = 2000; - EvadeTimer = 5000; - AttackStart(target); - } - - m_creature->SetVisibility(VISIBILITY_ON); - - }else EvadeTimer -= diff; - - //GroundRuptureTimer - if (GroundRuptureTimer < diff) - { - DoCast(m_creature->getVictim(),SPELL_GROUND_RUPTURE); - GroundRuptureTimer = 30000; - }else GroundRuptureTimer -= diff; - - //HamstringTimer - if (HamstringTimer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMSTRING); - HamstringTimer = 5000; - }else HamstringTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL giant_claw_tentacleAI : public Scripted_NoMovementAI -{ - giant_claw_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) - { - Reset(); - Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); - if (p) - Portal = p->GetGUID(); - } - - uint32 GroundRuptureTimer; - uint32 ThrashTimer; - uint32 HamstringTimer; - uint32 EvadeTimer; - uint64 Portal; - - void JustDied(Unit*) - { - Unit* p = Unit::GetUnit(*m_creature, Portal); - if (p) - p->DealDamage(p, p->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } - - void Reset() - { - //First rupture should happen half a second after we spawn - GroundRuptureTimer = 500; - HamstringTimer = 2000; - ThrashTimer = 5000; - EvadeTimer = 5000; - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //EvadeTimer - if (m_creature->GetDistance(m_creature->getVictim()) > ATTACK_DISTANCE) - if (EvadeTimer < diff) - { - Unit* p = Unit::GetUnit(*m_creature, Portal); - if (p) - p->DealDamage(p, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - - //Dissapear and reappear at new position - m_creature->SetVisibility(VISIBILITY_OFF); - - Unit* target = NULL; - target = SelectUnit(SELECT_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, 0)) - { - m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); - if (p) - Portal = p->GetGUID(); - - GroundRuptureTimer = 500; - HamstringTimer = 2000; - ThrashTimer = 5000; - EvadeTimer = 5000; - AttackStart(target); - } - - m_creature->SetVisibility(VISIBILITY_ON); - - }else EvadeTimer -= diff; - - //GroundRuptureTimer - if (GroundRuptureTimer < diff) - { - DoCast(m_creature->getVictim(),SPELL_GROUND_RUPTURE); - GroundRuptureTimer = 30000; - }else GroundRuptureTimer -= diff; - - //ThrashTimer - if (ThrashTimer < diff) - { - DoCast(m_creature->getVictim(),SPELL_THRASH); - ThrashTimer = 10000; - }else ThrashTimer -= diff; - - //HamstringTimer - if (HamstringTimer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMSTRING); - HamstringTimer = 10000; - }else HamstringTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL giant_eye_tentacleAI : public Scripted_NoMovementAI -{ - giant_eye_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) - { - Reset(); - Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); - if (p) - Portal = p->GetGUID(); - } - - uint32 BeamTimer; - uint64 Portal; - - void JustDied(Unit*) - { - Unit* p = Unit::GetUnit(*m_creature, Portal); - if (p) - p->DealDamage(p, p->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 *who) - { - DoZoneInCombat(); - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //BeamTimer - if (BeamTimer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target && !target->HasAura(SPELL_DIGESTIVE_ACID, 0)) - DoCast(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->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (Parent) - if (CheckTimer < diff) - { - Unit* pUnit = Unit::GetUnit(*m_creature, Parent); - - if (!pUnit || !pUnit->isAlive() || !pUnit->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) - { - DoYell("Error: No Parent variable", LANG_UNIVERSAL, NULL); - return; - } - - Creature* Cthun = (Creature*)Unit::GetUnit(*m_creature, Parent); - - if (Cthun) - ((cthunAI*)(Cthun->AI()))->FleshTentcleKilled(); - else DoYell("Error: No Cthun", LANG_UNIVERSAL, NULL); -} - -//GetAIs -CreatureAI* GetAI_eye_of_cthun(Creature *_Creature) -{ - return new eye_of_cthunAI (_Creature); -} - -CreatureAI* GetAI_cthun(Creature *_Creature) -{ - return new cthunAI (_Creature); -} - -CreatureAI* GetAI_eye_tentacle(Creature *_Creature) -{ - return new eye_tentacleAI (_Creature); -} - -CreatureAI* GetAI_claw_tentacle(Creature *_Creature) -{ - return new claw_tentacleAI (_Creature); -} - -CreatureAI* GetAI_giant_claw_tentacle(Creature *_Creature) -{ - return new giant_claw_tentacleAI (_Creature); -} - -CreatureAI* GetAI_giant_eye_tentacle(Creature *_Creature) -{ - return new giant_eye_tentacleAI (_Creature); -} - -CreatureAI* GetAI_flesh_tentacle(Creature *_Creature) -{ - return new flesh_tentacleAI (_Creature); -} - -void AddSC_boss_cthun() -{ - Script *newscript; - - //Eye - newscript = new Script; - newscript->Name="boss_eye_of_cthun"; - newscript->GetAI = GetAI_eye_of_cthun; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_cthun"; - newscript->GetAI = GetAI_cthun; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_eye_tentacle"; - newscript->GetAI = GetAI_eye_tentacle; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_claw_tentacle"; - newscript->GetAI = GetAI_claw_tentacle; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_giant_claw_tentacle"; - newscript->GetAI = GetAI_giant_claw_tentacle; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_giant_eye_tentacle"; - newscript->GetAI = GetAI_giant_eye_tentacle; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_giant_flesh_tentacle"; - newscript->GetAI = GetAI_flesh_tentacle; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Cthun +SD%Complete: 95 +SDComment: Darkglare tracking issue +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" +#include "def_temple_of_ahnqiraj.h" + +#define PI 3.14 + +//****** Out of Combat ****** +//Random Wispers - No txt only sound +#define RND_WISPER_1 8580 //Death is close +#define RND_WISPER_2 8581 //You are already dead +#define RND_WISPER_3 8582 //Your courage will fail +#define RND_WISPER_4 8583 //Your friends will abandon you +#define RND_WISPER_5 8584 //You will betray your friends +#define RND_WISPER_6 8585 //You will die +#define RND_WISPER_7 8586 //You are weak +#define RND_WISPER_8 8587 //Your heart will explode + +//***** 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 + +//Text emote +#define EMOTE_WEAKENED "is weakened!" + +//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 Scripted_NoMovementAI +{ + flesh_tentacleAI(Creature *c) : Scripted_NoMovementAI(c), Parent(0) {Reset();} + + uint64 Parent; + uint32 CheckTimer; + + void SpawnedByCthun(uint64 p) + { + Parent = p; + } + + void Reset() + { + CheckTimer = 1000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff); + + void JustDied(Unit* killer); +}; + +struct MANGOS_DLL_DECL eye_of_cthunAI : public Scripted_NoMovementAI +{ + eye_of_cthunAI(Creature *c) : Scripted_NoMovementAI(c) + { + pInst = (ScriptedInstance*)c->GetInstanceData(); + if (!pInst) + error_log("SD2: No Instance eye_of_cthunAI"); + + Reset(); + } + + ScriptedInstance* pInst; + + //Global variables + uint32 PhaseTimer; + + //Eye beam phase + uint32 BeamTimer; + uint32 EyeTentacleTimer; + uint32 ClawTentacleTimer; + + //Dark Glare phase + uint32 DarkGlareTick; + uint32 DarkGlareTickTimer; + float DarkGlareAngle; + bool ClockWise; + + 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) + + //Dark Beam phase 35 seconds (each tick = 1 second, 35 ticks) + DarkGlareTick = 0; + DarkGlareTickTimer = 1000; + DarkGlareAngle = 0; + ClockWise = false; + + //Reset flags + m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + + //Reset Phase + if (pInst) + pInst->SetData(DATA_CTHUN_PHASE, 0); + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + } + + void SpawnEyeTentacle(float x, float y) + { + 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) + { + Unit* target; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + if (target) + Spawned->AI()->AttackStart(target); + } + } + + void UpdateAI(const uint32 diff) + { + //Check if we have a target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //No instance + if (!pInst) + return; + + switch (pInst->GetData(DATA_CTHUN_PHASE)) + { + case 0: + { + //BeamTimer + if (BeamTimer < diff) + { + //SPELL_GREEN_BEAM + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(target,SPELL_GREEN_BEAM); + + //Correctly update our target + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); + } + + //Beam every 3 seconds + BeamTimer = 3000; + }else BeamTimer -= diff; + + //ClawTentacleTimer + if (ClawTentacleTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + { + Creature* Spawned = NULL; + + //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 (Spawned) + Spawned->AI()->AttackStart(target); + } + + //One claw tentacle every 12.5 seconds + ClawTentacleTimer = 12500; + }else ClawTentacleTimer -= diff; + + //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 + pInst->SetData(DATA_CTHUN_PHASE, 1); + + m_creature->InterruptNonMeleeSpells(false); + + //Select random target for dark beam to start on + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + if (target) + { + //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 = rand()%2; + } + + //Add red coloration to C'thun + DoCast(m_creature,SPELL_RED_COLORATION); + + //Freeze animation + m_creature->setEmoteState(53); + + //Darkbeam for 35 seconds + PhaseTimer = 35000; + }else PhaseTimer -= diff; + + } + break; + case 1: + { + //EyeTentacleTimer + if (DarkGlareTick < 35) + if (DarkGlareTickTimer < diff) + { + //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); + + //Increase tick + DarkGlareTick++; + + //1 second per tick + DarkGlareTickTimer = 1000; + }else DarkGlareTickTimer -= diff; + + //PhaseTimer + if (PhaseTimer < diff) + { + //Switch to Eye Beam + pInst->SetData(DATA_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->setEmoteState(0); + m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, 0); + + //Eye Beam for 50 seconds + PhaseTimer = 50000; + }else PhaseTimer -= diff; + }break; + + //Transition phase + case 2: + { + //Remove any target + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); + m_creature->SetHealth(0); + } + + //Dead phase + case 5: + { + m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + //No instance + if (!pInst) + return; + + switch (pInst->GetData(DATA_CTHUN_PHASE)) + { + 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->setEmoteState(0); + 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; + pInst->SetData(DATA_CTHUN_PHASE, 2); + + m_creature->SetHealth(0); + damage = 0; + + m_creature->InterruptNonMeleeSpells(true); + m_creature->RemoveAllAuras(); + } + break; + + case 5: + { + //Allow death here + return; + } + + default: + { + //Prevent death in this phase + damage = 0; + return; + } + break; + } + } +}; + +struct MANGOS_DLL_DECL cthunAI : public Scripted_NoMovementAI +{ + cthunAI(Creature *c) : Scripted_NoMovementAI(c) + { + pInst = (ScriptedInstance*)c->GetInstanceData(); + if (!pInst) + error_log("SD2: No Instance eye_of_cthunAI"); + + Reset(); + } + + ScriptedInstance* pInst; + + //Out of combat whisper timer + uint32 WisperTimer; + + //Global variables + uint32 PhaseTimer; + + //------------------- + + //Phase transition + uint64 HoldPlayer; + + //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 + HM_NAMESPACE::hash_map Stomach_Map; + + 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; + + //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 + + //Clear players in stomach and outside + Stomach_Map.clear(); + + //Reset flags + m_creature->RemoveAurasDueToSpell(SPELL_TRANSFORM); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + + if (pInst) + pInst->SetData(DATA_CTHUN_PHASE, 0); + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + } + + void SpawnEyeTentacle(float x, float y) + { + 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) + { + Unit* target; + + target = SelectRandomNotStomach(); + + if (target) + Spawned->AI()->AttackStart(target); + } + } + + Unit* SelectRandomNotStomach() + { + if (Stomach_Map.empty()) + return NULL; + + HM_NAMESPACE::hash_map::iterator i = Stomach_Map.begin(); + + std::list temp; + std::list::iterator j; + + //Get all players in map + while (i != Stomach_Map.end()) + { + //Check for valid player + Unit* pUnit = Unit::GetUnit(*m_creature, i->first); + + //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 ( i , rand() % (temp.size() - 1) ); + + return (*j); + } + + void UpdateAI(const uint32 diff) + { + //Check if we have a target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + { + //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; + + InstanceMap::PlayerList const &PlayerList = ((InstanceMap*)map)->GetPlayers(); + for (InstanceMap::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + //Play random sound to the zone + switch (rand()%8) + { + case 0: (*i)->PlaySound(RND_WISPER_1, true); break; + case 1: (*i)->PlaySound(RND_WISPER_2, true); break; + case 2: (*i)->PlaySound(RND_WISPER_3, true); break; + case 3: (*i)->PlaySound(RND_WISPER_4, true); break; + case 4: (*i)->PlaySound(RND_WISPER_5, true); break; + case 5: (*i)->PlaySound(RND_WISPER_6, true); break; + case 6: (*i)->PlaySound(RND_WISPER_7, true); break; + case 7: (*i)->PlaySound(RND_WISPER_8, true); break; + } + } + + //One random wisper every 90 - 300 seconds + WisperTimer = 90000 + (rand()% 210000); + }else WisperTimer -= diff; + + return; + } + + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); + + //No instance + if (!pInst) + return; + + switch (pInst->GetData(DATA_CTHUN_PHASE)) + { + //Transition phase + case 2: + { + //PhaseTimer + if (PhaseTimer < diff) + { + //Switch + pInst->SetData(DATA_CTHUN_PHASE, 3); + + //Switch to c'thun model + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_TRANSFORM, false); + m_creature->SetHealth(m_creature->GetMaxHealth()); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + + //Emerging phase + //AttackStart(Unit::GetUnit(*m_creature, HoldPlayer)); + DoZoneInCombat(); + + //Place all units in threat list on outside of stomach + Stomach_Map.clear(); + + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + //Outside stomach + Stomach_Map[(*i)->getUnitGuid()] = false; + } + + //Spawn 2 flesh tentacles + FleshTentaclesKilled = 0; + + Creature* Spawned; + + //Spawn flesh tentacle + Spawned = (Creature*)m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS1_X, TENTACLE_POS1_Y, TENTACLE_POS1_Z, TENTACLE_POS1_O, TEMPSUMMON_CORPSE_DESPAWN, 0); + + if (!Spawned) + FleshTentaclesKilled++; + else + ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(m_creature->GetGUID()); + + //Spawn flesh tentacle + Spawned = (Creature*)m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS2_X, TENTACLE_POS2_Y, TENTACLE_POS2_Z, TENTACLE_POS2_O, TEMPSUMMON_CORPSE_DESPAWN, 0); + + if (!Spawned) + FleshTentaclesKilled++; + else + ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(m_creature->GetGUID()); + + PhaseTimer = 0; + }else PhaseTimer -= diff; + + }break; + + //Body Phase + case 3: + { + //Remove Target field + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); + + //Weaken + if (FleshTentaclesKilled > 1) + { + pInst->SetData(DATA_CTHUN_PHASE, 4); + + DoTextEmote(EMOTE_WEAKENED, NULL); + PhaseTimer = 45000; + + DoCast(m_creature, SPELL_RED_COLORATION, true); + + HM_NAMESPACE::hash_map::iterator i = Stomach_Map.begin(); + + //Kick all players out of stomach + while (i != Stomach_Map.end()) + { + //Check for valid player + Unit* pUnit = Unit::GetUnit(*m_creature, 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); + + //Cast knockback on them + DoCast(pUnit, SPELL_EXIT_STOMACH_KNOCKBACK, true); + + //Remove the acid debuff + pUnit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); + + i->second = false; + } + ++i; + } + + return; + } + + //Stomach acid + if (StomachAcidTimer < diff) + { + //Apply aura to all players in stomach + HM_NAMESPACE::hash_map::iterator i = Stomach_Map.begin(); + + while (i != Stomach_Map.end()) + { + //Check for valid player + Unit* pUnit = Unit::GetUnit(*m_creature, i->first); + + //Only apply to units in stomach + if (pUnit && i->second == true) + { + //Cast digestive acid on them + DoCast(pUnit, SPELL_DIGESTIVE_ACID, true); + + //Check if player should be kicked from stomach + if (pUnit->GetDistance(KICK_X, KICK_Y, KICK_Z) < 15) + { + //Teleport each player out + DoTeleportPlayer(pUnit, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+10, rand()%6); + + //Cast knockback on them + DoCast(pUnit, SPELL_EXIT_STOMACH_KNOCKBACK, true); + + //Remove the acid debuff + pUnit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); + + i->second = false; + } + } + ++i; + } + + StomachAcidTimer = 4000; + }else StomachAcidTimer -= diff; + + //Stomach Enter Timer + if (StomachEnterTimer < diff) + { + Unit* target = NULL; + target = SelectRandomNotStomach(); + + if (target) + { + //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; + + if (StomachEnterVisTimer && StomachEnterTarget) + if (StomachEnterVisTimer <= diff) + { + //Check for valid player + Unit* pUnit = Unit::GetUnit(*m_creature, StomachEnterTarget); + + if (pUnit) + { + DoTeleportPlayer(pUnit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O); + } + + StomachEnterTarget = 0; + StomachEnterVisTimer = 0; + }else StomachEnterVisTimer -= diff; + + //GientClawTentacleTimer + if (GiantClawTentacleTimer < diff) + { + Unit* target = NULL; + target = SelectRandomNotStomach(); + if (target) + { + 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); + + if (Spawned) + Spawned->AI()->AttackStart(target); + } + + //One giant claw tentacle every minute + GiantClawTentacleTimer = 60000; + }else GiantClawTentacleTimer -= diff; + + //GiantEyeTentacleTimer + if (GiantEyeTentacleTimer < diff) + { + Unit* target = NULL; + target = SelectRandomNotStomach(); + if (target) + { + + Creature* Spawned = NULL; + + //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); + + if (Spawned) + Spawned->AI()->AttackStart(target); + } + + //One giant eye tentacle every minute + GiantEyeTentacleTimer = 60000; + }else GiantEyeTentacleTimer -= diff; + + //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 + + SpawnEyeTentacle(0, -25); //north + SpawnEyeTentacle(-12, -12); //north east + SpawnEyeTentacle(-25, 0); // east + SpawnEyeTentacle(-12, 12); // south east + + //These spawn at every 30 seconds + EyeTentacleTimer = 30000; + }else EyeTentacleTimer -= diff; + + }break; + + //Weakened state + case 4: + { + //PhaseTimer + if (PhaseTimer < diff) + { + //Switch + pInst->SetData(DATA_CTHUN_PHASE, 3); + + //Remove red coloration + m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); + + //Spawn 2 flesh tentacles + FleshTentaclesKilled = 0; + + Creature* Spawned; + + //Spawn flesh tentacle + Spawned = (Creature*)m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS1_X, TENTACLE_POS1_Y, TENTACLE_POS1_Z, TENTACLE_POS1_O, TEMPSUMMON_CORPSE_DESPAWN, 0); + + if (!Spawned) + FleshTentaclesKilled++; + else + ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(m_creature->GetGUID()); + + //Spawn flesh tentacle + Spawned = (Creature*)m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS2_X, TENTACLE_POS2_Y, TENTACLE_POS2_Z, TENTACLE_POS2_O, TEMPSUMMON_CORPSE_DESPAWN, 0); + + if (!Spawned) + FleshTentaclesKilled++; + else + ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(m_creature->GetGUID()); + + PhaseTimer = 0; + }else PhaseTimer -= diff; + } + } + } + + void JustDied(Unit* pKiller) + { + //Switch + if( pInst ) + pInst->SetData(DATA_CTHUN_PHASE, 5); + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + //No instance + if (!pInst) + return; + + switch (pInst->GetData(DATA_CTHUN_PHASE)) + { + case 3: + { + //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; + } + break; + + case 4: + { + //Weakened - takes normal damage + return; + } + + default: + damage = 0; + break; + } + } + + void FleshTentcleKilled() + { + FleshTentaclesKilled++; + } +}; + +struct MANGOS_DLL_DECL eye_tentacleAI : public Scripted_NoMovementAI +{ + eye_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) + { + Reset(); + Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); + if (p) + Portal = p->GetGUID(); + } + + uint32 MindflayTimer; + uint32 KillSelfTimer; + uint64 Portal; + + void JustDied(Unit*) + { + Unit* p = Unit::GetUnit(*m_creature, Portal); + if (p) + p->DealDamage(p, p->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 *who) + { + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + //Check if we have a target + if (!m_creature->SelectHostilTarget() || !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 = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target && !target->HasAura(SPELL_DIGESTIVE_ACID, 0)) + DoCast(target,SPELL_MIND_FLAY); + + //Mindflay every 10 seconds + MindflayTimer = 10100; + }else MindflayTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL claw_tentacleAI : public Scripted_NoMovementAI +{ + claw_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) + { + Reset(); + Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); + if (p) + Portal = p->GetGUID(); + } + + uint32 GroundRuptureTimer; + uint32 HamstringTimer; + uint32 EvadeTimer; + uint64 Portal; + + void JustDied(Unit*) + { + Unit* p = Unit::GetUnit(*m_creature, Portal); + if (p) + p->DealDamage(p, p->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + + void Reset() + { + //First rupture should happen half a second after we spawn + GroundRuptureTimer = 500; + HamstringTimer = 2000; + EvadeTimer = 5000; + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + //Check if we have a target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //EvadeTimer + if (m_creature->GetDistance(m_creature->getVictim()) > ATTACK_DISTANCE) + if (EvadeTimer < diff) + { + Unit* p = Unit::GetUnit(*m_creature, Portal); + if (p) + p->DealDamage(p, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + + //Dissapear and reappear at new position + m_creature->SetVisibility(VISIBILITY_OFF); + + Unit* target = NULL; + target = SelectUnit(SELECT_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, 0)) + { + m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); + if (p) + Portal = p->GetGUID(); + + GroundRuptureTimer = 500; + HamstringTimer = 2000; + EvadeTimer = 5000; + AttackStart(target); + } + + m_creature->SetVisibility(VISIBILITY_ON); + + }else EvadeTimer -= diff; + + //GroundRuptureTimer + if (GroundRuptureTimer < diff) + { + DoCast(m_creature->getVictim(),SPELL_GROUND_RUPTURE); + GroundRuptureTimer = 30000; + }else GroundRuptureTimer -= diff; + + //HamstringTimer + if (HamstringTimer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HAMSTRING); + HamstringTimer = 5000; + }else HamstringTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL giant_claw_tentacleAI : public Scripted_NoMovementAI +{ + giant_claw_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) + { + Reset(); + Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); + if (p) + Portal = p->GetGUID(); + } + + uint32 GroundRuptureTimer; + uint32 ThrashTimer; + uint32 HamstringTimer; + uint32 EvadeTimer; + uint64 Portal; + + void JustDied(Unit*) + { + Unit* p = Unit::GetUnit(*m_creature, Portal); + if (p) + p->DealDamage(p, p->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + + void Reset() + { + //First rupture should happen half a second after we spawn + GroundRuptureTimer = 500; + HamstringTimer = 2000; + ThrashTimer = 5000; + EvadeTimer = 5000; + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + //Check if we have a target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //EvadeTimer + if (m_creature->GetDistance(m_creature->getVictim()) > ATTACK_DISTANCE) + if (EvadeTimer < diff) + { + Unit* p = Unit::GetUnit(*m_creature, Portal); + if (p) + p->DealDamage(p, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + + //Dissapear and reappear at new position + m_creature->SetVisibility(VISIBILITY_OFF); + + Unit* target = NULL; + target = SelectUnit(SELECT_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, 0)) + { + m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); + if (p) + Portal = p->GetGUID(); + + GroundRuptureTimer = 500; + HamstringTimer = 2000; + ThrashTimer = 5000; + EvadeTimer = 5000; + AttackStart(target); + } + + m_creature->SetVisibility(VISIBILITY_ON); + + }else EvadeTimer -= diff; + + //GroundRuptureTimer + if (GroundRuptureTimer < diff) + { + DoCast(m_creature->getVictim(),SPELL_GROUND_RUPTURE); + GroundRuptureTimer = 30000; + }else GroundRuptureTimer -= diff; + + //ThrashTimer + if (ThrashTimer < diff) + { + DoCast(m_creature->getVictim(),SPELL_THRASH); + ThrashTimer = 10000; + }else ThrashTimer -= diff; + + //HamstringTimer + if (HamstringTimer < diff) + { + DoCast(m_creature->getVictim(),SPELL_HAMSTRING); + HamstringTimer = 10000; + }else HamstringTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL giant_eye_tentacleAI : public Scripted_NoMovementAI +{ + giant_eye_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) + { + Reset(); + Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0); + if (p) + Portal = p->GetGUID(); + } + + uint32 BeamTimer; + uint64 Portal; + + void JustDied(Unit*) + { + Unit* p = Unit::GetUnit(*m_creature, Portal); + if (p) + p->DealDamage(p, p->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 *who) + { + DoZoneInCombat(); + } + + void UpdateAI(const uint32 diff) + { + //Check if we have a target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //BeamTimer + if (BeamTimer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target && !target->HasAura(SPELL_DIGESTIVE_ACID, 0)) + DoCast(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->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (Parent) + if (CheckTimer < diff) + { + Unit* pUnit = Unit::GetUnit(*m_creature, Parent); + + if (!pUnit || !pUnit->isAlive() || !pUnit->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) + { + DoYell("Error: No Parent variable", LANG_UNIVERSAL, NULL); + return; + } + + Creature* Cthun = (Creature*)Unit::GetUnit(*m_creature, Parent); + + if (Cthun) + ((cthunAI*)(Cthun->AI()))->FleshTentcleKilled(); + else DoYell("Error: No Cthun", LANG_UNIVERSAL, NULL); +} + +//GetAIs +CreatureAI* GetAI_eye_of_cthun(Creature *_Creature) +{ + return new eye_of_cthunAI (_Creature); +} + +CreatureAI* GetAI_cthun(Creature *_Creature) +{ + return new cthunAI (_Creature); +} + +CreatureAI* GetAI_eye_tentacle(Creature *_Creature) +{ + return new eye_tentacleAI (_Creature); +} + +CreatureAI* GetAI_claw_tentacle(Creature *_Creature) +{ + return new claw_tentacleAI (_Creature); +} + +CreatureAI* GetAI_giant_claw_tentacle(Creature *_Creature) +{ + return new giant_claw_tentacleAI (_Creature); +} + +CreatureAI* GetAI_giant_eye_tentacle(Creature *_Creature) +{ + return new giant_eye_tentacleAI (_Creature); +} + +CreatureAI* GetAI_flesh_tentacle(Creature *_Creature) +{ + return new flesh_tentacleAI (_Creature); +} + +void AddSC_boss_cthun() +{ + Script *newscript; + + //Eye + newscript = new Script; + newscript->Name="boss_eye_of_cthun"; + newscript->GetAI = GetAI_eye_of_cthun; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_cthun"; + newscript->GetAI = GetAI_cthun; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_eye_tentacle"; + newscript->GetAI = GetAI_eye_tentacle; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_claw_tentacle"; + newscript->GetAI = GetAI_claw_tentacle; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_giant_claw_tentacle"; + newscript->GetAI = GetAI_giant_claw_tentacle; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_giant_eye_tentacle"; + newscript->GetAI = GetAI_giant_eye_tentacle; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_giant_flesh_tentacle"; + newscript->GetAI = GetAI_flesh_tentacle; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_fankriss.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_fankriss.cpp index da03cc2aad5..9e903593df4 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_fankriss.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_fankriss.cpp @@ -1,190 +1,190 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Fankriss -SD%Complete: 100 -SDComment: sound not implemented -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.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 - -// Enrage for his spawns -#define SPELL_ENRAGE 28798 - -struct MANGOS_DLL_DECL boss_fankrissAI : public ScriptedAI -{ - boss_fankrissAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 MortalWound_Timer; - uint32 SpawnHatchlings_Timer; - uint32 SpawnSpawns_Timer; - int Rand; - int RandX; - int RandY; - - Creature* Hatchling; - Creature* Spawn; - - void Reset() - { - MortalWound_Timer = 10000 + rand()%5000; - SpawnHatchlings_Timer = 6000 + rand()%6000; - SpawnSpawns_Timer = 15000 + rand()%30000; - } - - void SummonSpawn(Unit* victim) - { - Rand = 10 + (rand()%10); - switch (rand()%2) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = 10 + (rand()%10); - switch (rand()%2) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - Spawn = DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - if(Spawn) - ((CreatureAI*)Spawn->AI())->AttackStart(victim); - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //MortalWound_Timer - if (MortalWound_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTAL_WOUND); - MortalWound_Timer = 10000 + rand()%10000; - }else MortalWound_Timer -= diff; - - //Summon 1-3 Spawns of Fankriss at random time. - if (SpawnSpawns_Timer < diff) - { - switch(rand()%3) - { - case 0: - SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); - break; - case 1: - SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); - SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); - break; - case 2: - SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); - SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); - SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); - break; - } - SpawnSpawns_Timer = 30000 + rand()%30000; - }else SpawnSpawns_Timer -= diff; - - // 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->GetHealth()*100 / m_creature->GetMaxHealth() > 3 ) - { - if(SpawnHatchlings_Timer< diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target && target->GetTypeId() == TYPEID_PLAYER) - { - DoCast(target, SPELL_ROOT); - - if(m_creature->getThreatManager().getThreat(target)) - m_creature->getThreatManager().modifyThreatPercent(target, -100); - - switch(rand()%3) - { - case 0: - DoTeleportPlayer(target, -8106.0142,1289.2900,-74.419533,5.112); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - break; - case 1: - DoTeleportPlayer(target, -7990.135354,1155.1907,-78.849319,2.608); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - break; - case 2: - DoTeleportPlayer(target,-8159.7753,1127.9064,-76.868660,0.675); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - ((CreatureAI*)Hatchling->AI())->AttackStart(target); - break; - } - } - SpawnHatchlings_Timer = 45000 + rand()%15000; - }else SpawnHatchlings_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_fankriss(Creature *_Creature) -{ - return new boss_fankrissAI (_Creature); -} - -void AddSC_boss_fankriss() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_fankriss"; - newscript->GetAI = GetAI_boss_fankriss; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Fankriss +SD%Complete: 100 +SDComment: sound not implemented +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.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 + +// Enrage for his spawns +#define SPELL_ENRAGE 28798 + +struct MANGOS_DLL_DECL boss_fankrissAI : public ScriptedAI +{ + boss_fankrissAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 MortalWound_Timer; + uint32 SpawnHatchlings_Timer; + uint32 SpawnSpawns_Timer; + int Rand; + int RandX; + int RandY; + + Creature* Hatchling; + Creature* Spawn; + + void Reset() + { + MortalWound_Timer = 10000 + rand()%5000; + SpawnHatchlings_Timer = 6000 + rand()%6000; + SpawnSpawns_Timer = 15000 + rand()%30000; + } + + void SummonSpawn(Unit* victim) + { + Rand = 10 + (rand()%10); + switch (rand()%2) + { + case 0: RandX = 0 - Rand; break; + case 1: RandX = 0 + Rand; break; + } + Rand = 0; + Rand = 10 + (rand()%10); + switch (rand()%2) + { + case 0: RandY = 0 - Rand; break; + case 1: RandY = 0 + Rand; break; + } + Rand = 0; + Spawn = DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + if(Spawn) + ((CreatureAI*)Spawn->AI())->AttackStart(victim); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //MortalWound_Timer + if (MortalWound_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTAL_WOUND); + MortalWound_Timer = 10000 + rand()%10000; + }else MortalWound_Timer -= diff; + + //Summon 1-3 Spawns of Fankriss at random time. + if (SpawnSpawns_Timer < diff) + { + switch(rand()%3) + { + case 0: + SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); + break; + case 1: + SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); + SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); + break; + case 2: + SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); + SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); + SummonSpawn(SelectUnit(SELECT_TARGET_RANDOM,0)); + break; + } + SpawnSpawns_Timer = 30000 + rand()%30000; + }else SpawnSpawns_Timer -= diff; + + // 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->GetHealth()*100 / m_creature->GetMaxHealth() > 3 ) + { + if(SpawnHatchlings_Timer< diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target && target->GetTypeId() == TYPEID_PLAYER) + { + DoCast(target, SPELL_ROOT); + + if(m_creature->getThreatManager().getThreat(target)) + m_creature->getThreatManager().modifyThreatPercent(target, -100); + + switch(rand()%3) + { + case 0: + DoTeleportPlayer(target, -8106.0142,1289.2900,-74.419533,5.112); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + break; + case 1: + DoTeleportPlayer(target, -7990.135354,1155.1907,-78.849319,2.608); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + break; + case 2: + DoTeleportPlayer(target,-8159.7753,1127.9064,-76.868660,0.675); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + ((CreatureAI*)Hatchling->AI())->AttackStart(target); + break; + } + } + SpawnHatchlings_Timer = 45000 + rand()%15000; + }else SpawnHatchlings_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_fankriss(Creature *_Creature) +{ + return new boss_fankrissAI (_Creature); +} + +void AddSC_boss_fankriss() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_fankriss"; + newscript->GetAI = GetAI_boss_fankriss; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_huhuran.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_huhuran.cpp index 65e1da14955..2f960307663 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_huhuran.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_huhuran.cpp @@ -1,143 +1,143 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Huhuran -SD%Complete: 100 -SDComment: -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FRENZY 26051 -#define SPELL_BERSERK 26068 -#define SPELL_POISONBOLT 26052 -#define SPELL_NOXIOUSPOISON 26053 -#define SPELL_WYVERNSTING 26180 -#define SPELL_ACIDSPIT 26050 - -struct MANGOS_DLL_DECL boss_huhuranAI : public ScriptedAI -{ - boss_huhuranAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Frenzy_Timer; - uint32 Wyvern_Timer; - uint32 Spit_Timer; - uint32 PoisonBolt_Timer; - uint32 NoxiousPoison_Timer; - uint32 FrenzyBack_Timer; - - bool Frenzy; - bool Berserk; - - void Reset() - { - Frenzy_Timer = 25000 + rand()%10000; - Wyvern_Timer = 18000 + rand()%10000; - Spit_Timer = 8000; - PoisonBolt_Timer = 4000; - NoxiousPoison_Timer = 10000 + rand()%10000; - FrenzyBack_Timer = 15000; - - Frenzy = false; - Berserk = false; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Frenzy_Timer - if (!Frenzy && Frenzy_Timer < diff) - { - DoCast(m_creature, SPELL_FRENZY); - Frenzy = true; - PoisonBolt_Timer = 3000; - Frenzy_Timer = 25000 + rand()%10000; - }else Frenzy_Timer -= diff; - - // Wyvern Timer - if (Wyvern_Timer < diff) - { - if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) - DoCast(target,SPELL_WYVERNSTING); - Wyvern_Timer = 15000 + rand()%17000; - }else Wyvern_Timer -= diff; - - //Spit Timer - if (Spit_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ACIDSPIT); - Spit_Timer = 5000 + rand()%5000; - }else Spit_Timer -= diff; - - //NoxiousPoison_Timer - if (NoxiousPoison_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_NOXIOUSPOISON); - NoxiousPoison_Timer = 12000 + rand()%12000; - }else NoxiousPoison_Timer -= diff; - - //PoisonBolt only if frenzy or berserk - if (Frenzy || Berserk) - { - if (PoisonBolt_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POISONBOLT); - PoisonBolt_Timer = 3000; - }else PoisonBolt_Timer -= diff; - } - - //FrenzyBack_Timer - if (Frenzy && FrenzyBack_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - Frenzy = false; - FrenzyBack_Timer = 15000; - }else FrenzyBack_Timer -= diff; - - if ( !Berserk && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 31 ) - { - m_creature->InterruptNonMeleeSpells(false); - DoTextEmote("is going berserk", NULL); - DoCast(m_creature, SPELL_BERSERK); - Berserk = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_huhuran(Creature *_Creature) -{ - return new boss_huhuranAI (_Creature); -} - -void AddSC_boss_huhuran() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_huhuran"; - newscript->GetAI = GetAI_boss_huhuran; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Huhuran +SD%Complete: 100 +SDComment: +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_FRENZY 26051 +#define SPELL_BERSERK 26068 +#define SPELL_POISONBOLT 26052 +#define SPELL_NOXIOUSPOISON 26053 +#define SPELL_WYVERNSTING 26180 +#define SPELL_ACIDSPIT 26050 + +struct MANGOS_DLL_DECL boss_huhuranAI : public ScriptedAI +{ + boss_huhuranAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Frenzy_Timer; + uint32 Wyvern_Timer; + uint32 Spit_Timer; + uint32 PoisonBolt_Timer; + uint32 NoxiousPoison_Timer; + uint32 FrenzyBack_Timer; + + bool Frenzy; + bool Berserk; + + void Reset() + { + Frenzy_Timer = 25000 + rand()%10000; + Wyvern_Timer = 18000 + rand()%10000; + Spit_Timer = 8000; + PoisonBolt_Timer = 4000; + NoxiousPoison_Timer = 10000 + rand()%10000; + FrenzyBack_Timer = 15000; + + Frenzy = false; + Berserk = false; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Frenzy_Timer + if (!Frenzy && Frenzy_Timer < diff) + { + DoCast(m_creature, SPELL_FRENZY); + Frenzy = true; + PoisonBolt_Timer = 3000; + Frenzy_Timer = 25000 + rand()%10000; + }else Frenzy_Timer -= diff; + + // Wyvern Timer + if (Wyvern_Timer < diff) + { + if( Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0) ) + DoCast(target,SPELL_WYVERNSTING); + Wyvern_Timer = 15000 + rand()%17000; + }else Wyvern_Timer -= diff; + + //Spit Timer + if (Spit_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ACIDSPIT); + Spit_Timer = 5000 + rand()%5000; + }else Spit_Timer -= diff; + + //NoxiousPoison_Timer + if (NoxiousPoison_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_NOXIOUSPOISON); + NoxiousPoison_Timer = 12000 + rand()%12000; + }else NoxiousPoison_Timer -= diff; + + //PoisonBolt only if frenzy or berserk + if (Frenzy || Berserk) + { + if (PoisonBolt_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POISONBOLT); + PoisonBolt_Timer = 3000; + }else PoisonBolt_Timer -= diff; + } + + //FrenzyBack_Timer + if (Frenzy && FrenzyBack_Timer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + Frenzy = false; + FrenzyBack_Timer = 15000; + }else FrenzyBack_Timer -= diff; + + if ( !Berserk && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 31 ) + { + m_creature->InterruptNonMeleeSpells(false); + DoTextEmote("is going berserk", NULL); + DoCast(m_creature, SPELL_BERSERK); + Berserk = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_huhuran(Creature *_Creature) +{ + return new boss_huhuranAI (_Creature); +} + +void AddSC_boss_huhuran() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_huhuran"; + newscript->GetAI = GetAI_boss_huhuran; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_ouro.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_ouro.cpp index 97853c6cf87..6c018321fc1 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_ouro.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_ouro.cpp @@ -1,140 +1,140 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Ouro -SD%Complete: 85 -SDComment: No model for submerging. Currently just invisible. -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" -#include "def_temple_of_ahnqiraj.h" - -#define SPELL_SWEEP 26103 -#define SPELL_SANDBLAST 26102 -#define SPELL_GROUND_RUPTURE 26100 -#define SPELL_BIRTH 26262 //The Birth Animation - -#define SPELL_DIRTMOUND_PASSIVE 26092 - -struct MANGOS_DLL_DECL boss_ouroAI : public ScriptedAI -{ - boss_ouroAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Sweep_Timer; - uint32 SandBlast_Timer; - uint32 Submerge_Timer; - uint32 Back_Timer; - uint32 ChangeTarget_Timer; - uint32 Spawn_Timer; - - bool Enrage; - bool Submerged; - bool InCombat; - - void Reset() - { - Sweep_Timer = 5000 + rand()%5000; - SandBlast_Timer = 20000 + rand()%15000; - Submerge_Timer = 90000 + rand()%60000; - Back_Timer = 30000 + rand()%15000; - ChangeTarget_Timer = 5000 + rand()%3000; - Spawn_Timer = 10000 + rand()%10000; - - Enrage = false; - Submerged = false; - } - - void Aggro(Unit *who) - { - DoCast(m_creature->getVictim(), SPELL_BIRTH); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Sweep_Timer - if (!Submerged && Sweep_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SWEEP); - Sweep_Timer = 15000 + rand()%15000; - }else Sweep_Timer -= diff; - - //SandBlast_Timer - if (!Submerged && SandBlast_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SANDBLAST); - SandBlast_Timer = 20000 + rand()%15000; - }else SandBlast_Timer -= diff; - - //Submerge_Timer - if (!Submerged && Submerge_Timer < diff) - { - //Cast - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(35); - DoCast(m_creature, SPELL_DIRTMOUND_PASSIVE); - - Submerged = true; - Back_Timer = 30000 + rand()%15000; - }else Submerge_Timer -= diff; - - //ChangeTarget_Timer - if (Submerged && ChangeTarget_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); - - ChangeTarget_Timer = 10000 + rand()%10000; - }else ChangeTarget_Timer -= diff; - - //Back_Timer - if (Submerged && Back_Timer < diff) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(14); - - DoCast(m_creature->getVictim(), SPELL_GROUND_RUPTURE); - - Submerged = false; - Submerge_Timer = 60000 + rand()%60000; - }else Back_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_ouro(Creature *_Creature) -{ - return new boss_ouroAI (_Creature); -} - -void AddSC_boss_ouro() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ouro"; - newscript->GetAI = GetAI_boss_ouro; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Ouro +SD%Complete: 85 +SDComment: No model for submerging. Currently just invisible. +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" +#include "def_temple_of_ahnqiraj.h" + +#define SPELL_SWEEP 26103 +#define SPELL_SANDBLAST 26102 +#define SPELL_GROUND_RUPTURE 26100 +#define SPELL_BIRTH 26262 //The Birth Animation + +#define SPELL_DIRTMOUND_PASSIVE 26092 + +struct MANGOS_DLL_DECL boss_ouroAI : public ScriptedAI +{ + boss_ouroAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Sweep_Timer; + uint32 SandBlast_Timer; + uint32 Submerge_Timer; + uint32 Back_Timer; + uint32 ChangeTarget_Timer; + uint32 Spawn_Timer; + + bool Enrage; + bool Submerged; + bool InCombat; + + void Reset() + { + Sweep_Timer = 5000 + rand()%5000; + SandBlast_Timer = 20000 + rand()%15000; + Submerge_Timer = 90000 + rand()%60000; + Back_Timer = 30000 + rand()%15000; + ChangeTarget_Timer = 5000 + rand()%3000; + Spawn_Timer = 10000 + rand()%10000; + + Enrage = false; + Submerged = false; + } + + void Aggro(Unit *who) + { + DoCast(m_creature->getVictim(), SPELL_BIRTH); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Sweep_Timer + if (!Submerged && Sweep_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SWEEP); + Sweep_Timer = 15000 + rand()%15000; + }else Sweep_Timer -= diff; + + //SandBlast_Timer + if (!Submerged && SandBlast_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SANDBLAST); + SandBlast_Timer = 20000 + rand()%15000; + }else SandBlast_Timer -= diff; + + //Submerge_Timer + if (!Submerged && Submerge_Timer < diff) + { + //Cast + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->setFaction(35); + DoCast(m_creature, SPELL_DIRTMOUND_PASSIVE); + + Submerged = true; + Back_Timer = 30000 + rand()%15000; + }else Submerge_Timer -= diff; + + //ChangeTarget_Timer + if (Submerged && ChangeTarget_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); + + ChangeTarget_Timer = 10000 + rand()%10000; + }else ChangeTarget_Timer -= diff; + + //Back_Timer + if (Submerged && Back_Timer < diff) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->setFaction(14); + + DoCast(m_creature->getVictim(), SPELL_GROUND_RUPTURE); + + Submerged = false; + Submerge_Timer = 60000 + rand()%60000; + }else Back_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ouro(Creature *_Creature) +{ + return new boss_ouroAI (_Creature); +} + +void AddSC_boss_ouro() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ouro"; + newscript->GetAI = GetAI_boss_ouro; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_sartura.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_sartura.cpp index d9a9d27dffc..9a6e04982fd 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_sartura.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_sartura.cpp @@ -1,271 +1,271 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Sartura -SD%Complete: 99 -SDComment: -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_WHIRLWIND 26083 -#define SPELL_ENRAGE 28747 //Not sure if right ID. -#define SPELL_ENRAGEHARD 28798 - -//Guard Spell -#define SPELL_WHIRLWINDADD 26038 -#define SPELL_KNOCKBACK 26027 - -struct MANGOS_DLL_DECL boss_sarturaAI : public ScriptedAI -{ - boss_sarturaAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 WhirlWind_Timer; - uint32 WhirlWindRandom_Timer; - uint32 WhirlWindEnd_Timer; - uint32 AggroReset_Timer; - uint32 AggroResetEnd_Timer; - uint32 EnrageHard_Timer; - - bool Enraged; - bool EnragedHard; - bool WhirlWind; - bool AggroReset; - - void Reset() - { - WhirlWind_Timer = 30000; - WhirlWindRandom_Timer = 3000 + rand()%4000; - WhirlWindEnd_Timer = 15000; - AggroReset_Timer = 45000 + rand()%10000; - AggroResetEnd_Timer = 5000; - EnrageHard_Timer = 10*60000; - - WhirlWind = false; - AggroReset = false; - Enraged = false; - EnragedHard = false; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (WhirlWind) - { - if (WhirlWindRandom_Timer < diff) - { - //Attack random Gamers - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,1); - if (target) - DoStartAttackAndMovement(target); - - WhirlWindRandom_Timer = 3000 + rand()%4000; - }else WhirlWindRandom_Timer -= diff; - - if (WhirlWindEnd_Timer < diff) - { - WhirlWind = false; - WhirlWind_Timer = 25000 + rand()%15000; - }else WhirlWindEnd_Timer -= diff; - } - - if (!WhirlWind) - { - if (WhirlWind_Timer < diff) - { - DoCast(m_creature, SPELL_WHIRLWIND); - WhirlWind = true; - WhirlWindEnd_Timer = 15000; - }else WhirlWind_Timer -= diff; - - if (AggroReset_Timer < diff) - { - //Attack random Gamers - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,1); - if (target) - m_creature->TauntApply(target); - - AggroReset = true; - AggroReset_Timer = 2000 + rand()%3000; - }else AggroReset_Timer -= diff; - - if (AggroReset) - { - if (AggroResetEnd_Timer GetHealth()*100 / m_creature->GetMaxHealth() <= 20 && !m_creature->IsNonMeleeSpellCasted(false)) - { - DoCast(m_creature, SPELL_ENRAGE); - Enraged = true; - } - } - - //After 10 minutes hard enrage - if (!EnragedHard) - { - if (EnrageHard_Timer < diff) - { - DoCast(m_creature, SPELL_ENRAGEHARD); - EnragedHard = true; - }EnrageHard_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } - } -}; - -struct MANGOS_DLL_DECL mob_sartura_royal_guardAI : public ScriptedAI -{ - mob_sartura_royal_guardAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 WhirlWind_Timer; - uint32 WhirlWindRandom_Timer; - uint32 WhirlWindEnd_Timer; - uint32 AggroReset_Timer; - uint32 AggroResetEnd_Timer; - uint32 KnockBack_Timer; - - bool WhirlWind; - bool AggroReset; - - void Reset() - { - WhirlWind_Timer = 30000; - WhirlWindRandom_Timer = 3000 + rand()%4000; - WhirlWindEnd_Timer = 15000; - AggroReset_Timer = 45000 + rand()%10000; - AggroResetEnd_Timer = 5000; - KnockBack_Timer = 10000; - - WhirlWind = false; - AggroReset = false; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (!WhirlWind && WhirlWind_Timer < diff) - { - DoCast(m_creature, SPELL_WHIRLWINDADD); - WhirlWind = true; - WhirlWind_Timer = 25000 + rand()%15000; - WhirlWindEnd_Timer = 15000; - }else WhirlWind_Timer -= diff; - - if (WhirlWind) - { - if (WhirlWindRandom_Timer < diff) - { - //Attack random Gamers - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,1); - if (target) - m_creature->TauntApply(target); - - WhirlWindRandom_Timer = 3000 + rand()%4000; - }else WhirlWindRandom_Timer -= diff; - - if (WhirlWindEnd_Timer < diff) - { - WhirlWind = false; - }else WhirlWindEnd_Timer -= diff; - } - - if (!WhirlWind) - { - if(AggroReset_Timer < diff) - { - //Attack random Gamers - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,1); - if (target) - DoStartAttackAndMovement(target); - - AggroReset = true; - AggroReset_Timer = 2000 + rand()%3000; - }else AggroReset_Timer -= diff; - - if (KnockBack_Timer < diff) - { - DoCast(m_creature, SPELL_WHIRLWINDADD); - KnockBack_Timer = 10000 + rand()%10000; - }else KnockBack_Timer -= diff; - } - - if (AggroReset) - { - if (AggroResetEnd_Timer Name="boss_sartura"; - newscript->GetAI = GetAI_boss_sartura; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_sartura_royal_guard"; - newscript->GetAI = GetAI_mob_sartura_royal_guard; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Sartura +SD%Complete: 99 +SDComment: +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_WHIRLWIND 26083 +#define SPELL_ENRAGE 28747 //Not sure if right ID. +#define SPELL_ENRAGEHARD 28798 + +//Guard Spell +#define SPELL_WHIRLWINDADD 26038 +#define SPELL_KNOCKBACK 26027 + +struct MANGOS_DLL_DECL boss_sarturaAI : public ScriptedAI +{ + boss_sarturaAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 WhirlWind_Timer; + uint32 WhirlWindRandom_Timer; + uint32 WhirlWindEnd_Timer; + uint32 AggroReset_Timer; + uint32 AggroResetEnd_Timer; + uint32 EnrageHard_Timer; + + bool Enraged; + bool EnragedHard; + bool WhirlWind; + bool AggroReset; + + void Reset() + { + WhirlWind_Timer = 30000; + WhirlWindRandom_Timer = 3000 + rand()%4000; + WhirlWindEnd_Timer = 15000; + AggroReset_Timer = 45000 + rand()%10000; + AggroResetEnd_Timer = 5000; + EnrageHard_Timer = 10*60000; + + WhirlWind = false; + AggroReset = false; + Enraged = false; + EnragedHard = false; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (WhirlWind) + { + if (WhirlWindRandom_Timer < diff) + { + //Attack random Gamers + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,1); + if (target) + DoStartAttackAndMovement(target); + + WhirlWindRandom_Timer = 3000 + rand()%4000; + }else WhirlWindRandom_Timer -= diff; + + if (WhirlWindEnd_Timer < diff) + { + WhirlWind = false; + WhirlWind_Timer = 25000 + rand()%15000; + }else WhirlWindEnd_Timer -= diff; + } + + if (!WhirlWind) + { + if (WhirlWind_Timer < diff) + { + DoCast(m_creature, SPELL_WHIRLWIND); + WhirlWind = true; + WhirlWindEnd_Timer = 15000; + }else WhirlWind_Timer -= diff; + + if (AggroReset_Timer < diff) + { + //Attack random Gamers + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,1); + if (target) + m_creature->TauntApply(target); + + AggroReset = true; + AggroReset_Timer = 2000 + rand()%3000; + }else AggroReset_Timer -= diff; + + if (AggroReset) + { + if (AggroResetEnd_Timer GetHealth()*100 / m_creature->GetMaxHealth() <= 20 && !m_creature->IsNonMeleeSpellCasted(false)) + { + DoCast(m_creature, SPELL_ENRAGE); + Enraged = true; + } + } + + //After 10 minutes hard enrage + if (!EnragedHard) + { + if (EnrageHard_Timer < diff) + { + DoCast(m_creature, SPELL_ENRAGEHARD); + EnragedHard = true; + }EnrageHard_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } + } +}; + +struct MANGOS_DLL_DECL mob_sartura_royal_guardAI : public ScriptedAI +{ + mob_sartura_royal_guardAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 WhirlWind_Timer; + uint32 WhirlWindRandom_Timer; + uint32 WhirlWindEnd_Timer; + uint32 AggroReset_Timer; + uint32 AggroResetEnd_Timer; + uint32 KnockBack_Timer; + + bool WhirlWind; + bool AggroReset; + + void Reset() + { + WhirlWind_Timer = 30000; + WhirlWindRandom_Timer = 3000 + rand()%4000; + WhirlWindEnd_Timer = 15000; + AggroReset_Timer = 45000 + rand()%10000; + AggroResetEnd_Timer = 5000; + KnockBack_Timer = 10000; + + WhirlWind = false; + AggroReset = false; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (!WhirlWind && WhirlWind_Timer < diff) + { + DoCast(m_creature, SPELL_WHIRLWINDADD); + WhirlWind = true; + WhirlWind_Timer = 25000 + rand()%15000; + WhirlWindEnd_Timer = 15000; + }else WhirlWind_Timer -= diff; + + if (WhirlWind) + { + if (WhirlWindRandom_Timer < diff) + { + //Attack random Gamers + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,1); + if (target) + m_creature->TauntApply(target); + + WhirlWindRandom_Timer = 3000 + rand()%4000; + }else WhirlWindRandom_Timer -= diff; + + if (WhirlWindEnd_Timer < diff) + { + WhirlWind = false; + }else WhirlWindEnd_Timer -= diff; + } + + if (!WhirlWind) + { + if(AggroReset_Timer < diff) + { + //Attack random Gamers + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,1); + if (target) + DoStartAttackAndMovement(target); + + AggroReset = true; + AggroReset_Timer = 2000 + rand()%3000; + }else AggroReset_Timer -= diff; + + if (KnockBack_Timer < diff) + { + DoCast(m_creature, SPELL_WHIRLWINDADD); + KnockBack_Timer = 10000 + rand()%10000; + }else KnockBack_Timer -= diff; + } + + if (AggroReset) + { + if (AggroResetEnd_Timer Name="boss_sartura"; + newscript->GetAI = GetAI_boss_sartura; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_sartura_royal_guard"; + newscript->GetAI = GetAI_mob_sartura_royal_guard; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_skeram.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_skeram.cpp index a2123c21da0..ada2f7a1dd7 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_skeram.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_skeram.cpp @@ -1,314 +1,314 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Skeram -SD%Complete: 75 -SDComment: Mind Control buggy. -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" -#include "def_temple_of_ahnqiraj.h" -#include "Group.h" - -#define SPELL_ARCANE_EXPLOSION 25679 -#define SPELL_EARTH_SHOCK 26194 -#define SPELL_TRUE_FULFILLMENT4 26526 -#define SPELL_BLINK 28391 - -#define SOUND_AGGRO1 8615 //8615 Are you so eager to die? I would be happy to accomodate you. -#define SOUND_AGGRO2 8616 //8616 Cower mortals! The age of darkness is at hand. -#define SOUND_AGGRO3 8621 //8621 Tremble! The end is upon you. -#define SOUND_SLAY1 8617 //8617 Let your death serve as an example! -#define SOUND_SLAY2 8619 //8619 Spineless wretchers you will drown in rivers of blood! -#define SOUND_SLAY3 8620 //8620 The screams of the dying will fill the air. A symphony of terror is about to begin! -#define SOUND_SPLIT 8618 //8618 Prepare for the return of the ancient ones! -#define SOUND_DEATH 8622 //8622 You only delay... the inevetable - -class ov_mycoordinates -{ - public: - float x,y,z,r; - ov_mycoordinates(float cx, float cy, float cz, float cr) - { - x = cx; y = cy; z = cz; r = cr; - } -}; - -struct MANGOS_DLL_DECL boss_skeramAI : public ScriptedAI -{ - boss_skeramAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - IsImage = false; - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 ArcaneExplosion_Timer; - uint32 EarthShock_Timer; - uint32 FullFillment_Timer; - uint32 Blink_Timer; - uint32 Invisible_Timer; - - Creature *Image1, *Image2; - - bool Images75; - bool Images50; - bool Images25; - bool IsImage; - bool Invisible; - - void Reset() - { - ArcaneExplosion_Timer = 6000 + rand()%6000; - EarthShock_Timer = 2000; - FullFillment_Timer = 15000; - Blink_Timer = 8000 + rand()%12000; - 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); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%3) - { - case 0: - DoPlaySoundToSet(m_creature,SOUND_SLAY1); - break; - case 1: - DoPlaySoundToSet(m_creature,SOUND_SLAY2); - break; - case 2: - DoPlaySoundToSet(m_creature,SOUND_SLAY3); - break; - } - } - - void JustDied(Unit* Killer) - { - if (!IsImage) - DoPlaySoundToSet(m_creature,SOUND_DEATH); - } - - void Aggro(Unit *who) - { - if (IsImage || Images75) - return; - switch(rand()%3) - { - case 0: - DoPlaySoundToSet(m_creature,SOUND_AGGRO1); - break; - case 1: - DoPlaySoundToSet(m_creature,SOUND_AGGRO2); - break; - case 2: - DoPlaySoundToSet(m_creature,SOUND_AGGRO3); - break; - } - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //ArcaneExplosion_Timer - if (ArcaneExplosion_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); - ArcaneExplosion_Timer = 8000 + rand()%10000; - }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) - { - DoCast(m_creature->getVictim(),SPELL_EARTH_SHOCK); - EarthShock_Timer = 1000; - }else EarthShock_Timer -= diff; - } - - //Blink_Timer - if (Blink_Timer < diff) - { - //DoCast(m_creature, SPELL_BLINK); - switch(rand()%3) - { - case 0: - m_creature->Relocate(-8340.782227,2083.814453,125.648788,0); - DoResetThreat(); - break; - case 1: - m_creature->Relocate(-8341.546875,2118.504639,133.058151,0); - DoResetThreat(); - break; - case 2: - m_creature->Relocate(-8318.822266,2058.231201,133.058151,0); - DoResetThreat(); - break; - } - DoStopAttack(); - - Blink_Timer= 20000 + rand()%20000; - }else Blink_Timer -= diff; - - int procent = (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5); - - //Summoning 2 Images and teleporting to a random position on 75% health - if ( (!Images75 && !IsImage) && - (procent <= 75 && procent > 70) ) - DoSplit(75); - - //Summoning 2 Images and teleporting to a random position on 50% health - if ( (!Images50 && !IsImage) && - (procent <= 50 && procent > 45) ) - DoSplit(50); - - //Summoning 2 Images and teleporting to a random position on 25% health - if ( (!Images25 && !IsImage) && - (procent <= 25 && procent > 20) ) - DoSplit(25); - - //Invisible_Timer - if (Invisible) - { - 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; - } - - DoMeleeAttackIfReady(); - } - - void DoSplit(int atPercent /* 75 50 25 */) - { - DoPlaySoundToSet(m_creature,SOUND_SPLIT); - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - ov_mycoordinates *place1 = new ov_mycoordinates(-8340.782227,2083.814453,125.648788,0); - ov_mycoordinates *place2 = new ov_mycoordinates(-8341.546875,2118.504639,133.058151,0); - ov_mycoordinates *place3 = new ov_mycoordinates(-8318.822266,2058.231201,133.058151,0); - - ov_mycoordinates *bossc=place1, *i1=place2, *i2=place3; - - switch(rand()%3) - { - 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; - } - - for (int tryi = 0; tryi < 41; tryi ++) - { - Unit *targetpl = SelectUnit(SELECT_TARGET_RANDOM, 0); - if (targetpl->isType(TYPEMASK_PLAYER)) - { - Group *grp = ((Player *)targetpl)->GetGroup(); - if (grp) - { - for (int ici = 0; ici < TARGETICONCOUNT; ici++) - { - //if (grp ->m_targetIcons[ici] == m_creature->GetGUID()) -- private member:( - grp->SetTargetIcon(ici, 0); - } - } - break; - } - } - - m_creature->RemoveAllAuras(); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->Relocate(bossc->x, bossc->y, bossc->z, bossc->r); - Invisible = true; - DoResetThreat(); - DoStopAttack(); - - switch (atPercent) - { - case 75: Images75 = true; break; - case 50: Images50 = true; break; - case 25: Images25 = true; break; - } - - Image1 = m_creature->SummonCreature(15263, i1->x, i1->y, i1->z, i1->r, TEMPSUMMON_CORPSE_DESPAWN, 30000); - Image1->SetMaxHealth(m_creature->GetMaxHealth() / 5); - Image1->SetHealth(m_creature->GetHealth() / 5); - Image1->AI()->AttackStart(target); - - Image2 = m_creature->SummonCreature(15263,i2->x, i2->y, i2->z, i2->r, TEMPSUMMON_CORPSE_DESPAWN, 30000); - Image2->SetMaxHealth(m_creature->GetMaxHealth() / 5); - Image2->SetHealth(m_creature->GetHealth() / 5); - Image2->AI()->AttackStart(target); - - ((boss_skeramAI*)Image1->AI())->IsImage = true; - ((boss_skeramAI*)Image2->AI())->IsImage = true; - - Invisible = true; - } -}; - -CreatureAI* GetAI_boss_skeram(Creature *_Creature) -{ - return new boss_skeramAI (_Creature); -} - -void AddSC_boss_skeram() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_skeram"; - newscript->GetAI = GetAI_boss_skeram; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Skeram +SD%Complete: 75 +SDComment: Mind Control buggy. +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" +#include "def_temple_of_ahnqiraj.h" +#include "Group.h" + +#define SPELL_ARCANE_EXPLOSION 25679 +#define SPELL_EARTH_SHOCK 26194 +#define SPELL_TRUE_FULFILLMENT4 26526 +#define SPELL_BLINK 28391 + +#define SOUND_AGGRO1 8615 //8615 Are you so eager to die? I would be happy to accomodate you. +#define SOUND_AGGRO2 8616 //8616 Cower mortals! The age of darkness is at hand. +#define SOUND_AGGRO3 8621 //8621 Tremble! The end is upon you. +#define SOUND_SLAY1 8617 //8617 Let your death serve as an example! +#define SOUND_SLAY2 8619 //8619 Spineless wretchers you will drown in rivers of blood! +#define SOUND_SLAY3 8620 //8620 The screams of the dying will fill the air. A symphony of terror is about to begin! +#define SOUND_SPLIT 8618 //8618 Prepare for the return of the ancient ones! +#define SOUND_DEATH 8622 //8622 You only delay... the inevetable + +class ov_mycoordinates +{ + public: + float x,y,z,r; + ov_mycoordinates(float cx, float cy, float cz, float cr) + { + x = cx; y = cy; z = cz; r = cr; + } +}; + +struct MANGOS_DLL_DECL boss_skeramAI : public ScriptedAI +{ + boss_skeramAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + IsImage = false; + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 ArcaneExplosion_Timer; + uint32 EarthShock_Timer; + uint32 FullFillment_Timer; + uint32 Blink_Timer; + uint32 Invisible_Timer; + + Creature *Image1, *Image2; + + bool Images75; + bool Images50; + bool Images25; + bool IsImage; + bool Invisible; + + void Reset() + { + ArcaneExplosion_Timer = 6000 + rand()%6000; + EarthShock_Timer = 2000; + FullFillment_Timer = 15000; + Blink_Timer = 8000 + rand()%12000; + 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); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%3) + { + case 0: + DoPlaySoundToSet(m_creature,SOUND_SLAY1); + break; + case 1: + DoPlaySoundToSet(m_creature,SOUND_SLAY2); + break; + case 2: + DoPlaySoundToSet(m_creature,SOUND_SLAY3); + break; + } + } + + void JustDied(Unit* Killer) + { + if (!IsImage) + DoPlaySoundToSet(m_creature,SOUND_DEATH); + } + + void Aggro(Unit *who) + { + if (IsImage || Images75) + return; + switch(rand()%3) + { + case 0: + DoPlaySoundToSet(m_creature,SOUND_AGGRO1); + break; + case 1: + DoPlaySoundToSet(m_creature,SOUND_AGGRO2); + break; + case 2: + DoPlaySoundToSet(m_creature,SOUND_AGGRO3); + break; + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //ArcaneExplosion_Timer + if (ArcaneExplosion_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); + ArcaneExplosion_Timer = 8000 + rand()%10000; + }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) + { + DoCast(m_creature->getVictim(),SPELL_EARTH_SHOCK); + EarthShock_Timer = 1000; + }else EarthShock_Timer -= diff; + } + + //Blink_Timer + if (Blink_Timer < diff) + { + //DoCast(m_creature, SPELL_BLINK); + switch(rand()%3) + { + case 0: + m_creature->Relocate(-8340.782227,2083.814453,125.648788,0); + DoResetThreat(); + break; + case 1: + m_creature->Relocate(-8341.546875,2118.504639,133.058151,0); + DoResetThreat(); + break; + case 2: + m_creature->Relocate(-8318.822266,2058.231201,133.058151,0); + DoResetThreat(); + break; + } + DoStopAttack(); + + Blink_Timer= 20000 + rand()%20000; + }else Blink_Timer -= diff; + + int procent = (int) (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() +0.5); + + //Summoning 2 Images and teleporting to a random position on 75% health + if ( (!Images75 && !IsImage) && + (procent <= 75 && procent > 70) ) + DoSplit(75); + + //Summoning 2 Images and teleporting to a random position on 50% health + if ( (!Images50 && !IsImage) && + (procent <= 50 && procent > 45) ) + DoSplit(50); + + //Summoning 2 Images and teleporting to a random position on 25% health + if ( (!Images25 && !IsImage) && + (procent <= 25 && procent > 20) ) + DoSplit(25); + + //Invisible_Timer + if (Invisible) + { + 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; + } + + DoMeleeAttackIfReady(); + } + + void DoSplit(int atPercent /* 75 50 25 */) + { + DoPlaySoundToSet(m_creature,SOUND_SPLIT); + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + ov_mycoordinates *place1 = new ov_mycoordinates(-8340.782227,2083.814453,125.648788,0); + ov_mycoordinates *place2 = new ov_mycoordinates(-8341.546875,2118.504639,133.058151,0); + ov_mycoordinates *place3 = new ov_mycoordinates(-8318.822266,2058.231201,133.058151,0); + + ov_mycoordinates *bossc=place1, *i1=place2, *i2=place3; + + switch(rand()%3) + { + 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; + } + + for (int tryi = 0; tryi < 41; tryi ++) + { + Unit *targetpl = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (targetpl->isType(TYPEMASK_PLAYER)) + { + Group *grp = ((Player *)targetpl)->GetGroup(); + if (grp) + { + for (int ici = 0; ici < TARGETICONCOUNT; ici++) + { + //if (grp ->m_targetIcons[ici] == m_creature->GetGUID()) -- private member:( + grp->SetTargetIcon(ici, 0); + } + } + break; + } + } + + m_creature->RemoveAllAuras(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->Relocate(bossc->x, bossc->y, bossc->z, bossc->r); + Invisible = true; + DoResetThreat(); + DoStopAttack(); + + switch (atPercent) + { + case 75: Images75 = true; break; + case 50: Images50 = true; break; + case 25: Images25 = true; break; + } + + Image1 = m_creature->SummonCreature(15263, i1->x, i1->y, i1->z, i1->r, TEMPSUMMON_CORPSE_DESPAWN, 30000); + Image1->SetMaxHealth(m_creature->GetMaxHealth() / 5); + Image1->SetHealth(m_creature->GetHealth() / 5); + Image1->AI()->AttackStart(target); + + Image2 = m_creature->SummonCreature(15263,i2->x, i2->y, i2->z, i2->r, TEMPSUMMON_CORPSE_DESPAWN, 30000); + Image2->SetMaxHealth(m_creature->GetMaxHealth() / 5); + Image2->SetHealth(m_creature->GetHealth() / 5); + Image2->AI()->AttackStart(target); + + ((boss_skeramAI*)Image1->AI())->IsImage = true; + ((boss_skeramAI*)Image2->AI())->IsImage = true; + + Invisible = true; + } +}; + +CreatureAI* GetAI_boss_skeram(Creature *_Creature) +{ + return new boss_skeramAI (_Creature); +} + +void AddSC_boss_skeram() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_skeram"; + newscript->GetAI = GetAI_boss_skeram; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp index dacb55c4055..16528b6c595 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp @@ -1,698 +1,698 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Twinemperors -SD%Complete: 95 -SDComment: -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" -#include "def_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 - -struct MANGOS_DLL_DECL boss_twinemperorsAI : public ScriptedAI -{ - ScriptedInstance *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 *c): ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - } - - 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 = 10000 + rand()%7000; - BugsTimer = 2000; - m_creature->clearUnitState(UNIT_STAT_STUNDED); - DontYellWhenDead = false; - EnrageTimer = 15*60000; - } - - Creature *GetOtherBoss() - { - if(pInstance) - { - return (Creature *)Unit::GetUnit((*m_creature), pInstance->GetData64(IAmVeklor() ? DATA_VEKNILASH : DATA_VEKLOR)); - } - else - { - return (Creature *)0; - } - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - Unit *pOtherBoss = GetOtherBoss(); - if (pOtherBoss) - { - 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) - { - pOtherBoss->setDeathState(JUST_DIED); - pOtherBoss->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - } - } - } - - void JustDied(Unit* Killer) - { - Creature *pOtherBoss = GetOtherBoss(); - if (pOtherBoss) - { - pOtherBoss->SetHealth(0); - pOtherBoss->setDeathState(JUST_DIED); - pOtherBoss->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - ((boss_twinemperorsAI *)pOtherBoss->AI())->DontYellWhenDead = true; - } - if (!DontYellWhenDead) // I hope AI is not threaded - DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_DEATH : SOUND_VN_DEATH); - } - - void KilledUnit(Unit* victim) - { - DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_KILL : SOUND_VN_KILL); - } - - void Aggro(Unit *who) - { - DoZoneInCombat(); - InCombat = true; - Creature *pOtherBoss = GetOtherBoss(); - if (pOtherBoss) - { - // 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 - ScriptedAI *otherAI = (ScriptedAI*)pOtherBoss->AI(); - if (!otherAI->InCombat) - { - DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_AGGRO : SOUND_VN_AGGRO); - otherAI->AttackStart(who); - otherAI->DoZoneInCombat(); - } - } - } - - void SpellHit(Unit *caster, const SpellEntry *entry) - { - if (caster == m_creature) - return; - - Creature *pOtherBoss = GetOtherBoss(); - if (entry->Id != SPELL_HEAL_BROTHER || !pOtherBoss) - 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) - { - uint32 h = m_creature->GetHealth()+largerAmount; - m_creature->SetHealth(std::min(mytotal, h)); - } - else - { - uint32 h = pOtherBoss->GetHealth()+largerAmount; - pOtherBoss->SetHealth(std::min(histotal, h)); - } - } - - void TryHealBrother(uint32 diff) - { - if (IAmVeklor()) // this spell heals caster and the other brother so let VN cast it - return; - - if (Heal_Timer < diff) - { - Unit *pOtherBoss = GetOtherBoss(); - if (pOtherBoss && (pOtherBoss->GetDistance((const Creature *)m_creature) <= 60)) - { - DoCast(pOtherBoss, SPELL_HEAL_BROTHER); - Heal_Timer = 1000; - } - } else Heal_Timer -= diff; - } - - Unit *GetAnyoneCloseEnough(float dist, bool totallyRandom) - { - int cnt = 0; - std::list::iterator i; - std::list candidates; - - for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - 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(); - - i = candidates.begin(); - Unit *ret = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - candidates.clear(); - return ret; - } - - Unit *PickNearestPlayer() - { - Unit *nearp = NULL; - float neardist = 0.0f; - std::list::iterator i; - for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - Unit* pUnit = NULL; - pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if (!pUnit) - continue; - float pudist = pUnit->GetDistance((const Creature *)m_creature); - if (!nearp || (neardist > pudist)) - { - nearp = pUnit; - neardist = pudist; - } - } - return nearp; - } - - void TeleportToMyBrother() - { - if (!pInstance) - return; - - Teleport_Timer = TELEPORTTIME; - - if(IAmVeklor()) - return; // mechanics handled by veknilash so they teleport exactly at the same time and to correct coordinates - - Creature *pOtherBoss = GetOtherBoss(); - if (pOtherBoss) - { - //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(); - ((boss_twinemperorsAI*) pOtherBoss->AI())->SetAfterTeleport(); - } - } - - void SetAfterTeleport() - { - m_creature->InterruptNonMeleeSpells(false); - DoStopAttack(); - DoResetThreat(); - DoCast(m_creature, SPELL_TWIN_TELEPORT_VISUAL); - m_creature->addUnitState(UNIT_STAT_STUNDED); - AfterTeleport = true; - AfterTeleportTimer = 2000; - tspellcasted = false; - } - - bool TryActivateAfterTTelep(uint32 diff) - { - if (AfterTeleport) - { - if (!tspellcasted) - { - m_creature->clearUnitState(UNIT_STAT_STUNDED); - DoCast(m_creature, SPELL_TWIN_TELEPORT); - m_creature->addUnitState(UNIT_STAT_STUNDED); - } - - tspellcasted = true; - - if (AfterTeleportTimer < diff) - { - AfterTeleport = false; - m_creature->clearUnitState(UNIT_STAT_STUNDED); - 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; - } - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || m_creature->getVictim()) - return; - - 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); - } - } - } - - class AnyBugCheck - { - public: - AnyBugCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(Unit* u) - { - Creature *c = (Creature *)u; - if (!i_obj->IsWithinDistInMap(c, i_range)) - return false; - return (c->GetEntry() == 15316 || c->GetEntry() == 15317); - } - private: - WorldObject const* i_obj; - float i_range; - }; - - Creature *RespawnNearbyBugsAndGetOne() - { - CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list unitList; - - AnyBugCheck u_check(m_creature, 150); - MaNGOS::CreatureListSearcher searcher(unitList, u_check); - TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap())); - - Creature *nearb = NULL; - - for(std::list::iterator iter = unitList.begin(); iter != unitList.end(); ++iter) - { - Creature *c = (Creature *)(*iter); - if (c->isDead()) - { - c->Respawn(); - c->setFaction(7); - c->RemoveAllAuras(); - } - if (c->IsWithinDistInMap(m_creature, ABUSE_BUG_RANGE)) - { - if (!nearb || (rand()%4)==0) - nearb = c; - } - } - return nearb; - } - - void HandleBugs(uint32 diff) - { - if (BugsTimer < diff || Abuse_Bug_Timer < diff) - { - Creature *c = RespawnNearbyBugsAndGetOne(); - if (Abuse_Bug_Timer < diff) - { - if (c) - { - CastSpellOnBug(c); - Abuse_Bug_Timer = 10000 + rand()%7000; - } - else - { - Abuse_Bug_Timer = 1000; - } - } - else - { - Abuse_Bug_Timer -= diff; - } - BugsTimer = 2000; - } - else - { - BugsTimer -= diff; - Abuse_Bug_Timer -= diff; - } - } - - void CheckEnrage(uint32 diff) - { - if (EnrageTimer < diff) - { - if (!m_creature->IsNonMeleeSpellCasted(true)) - { - DoCast(m_creature, SPELL_BERSERK); - EnrageTimer = 60*60000; - } else EnrageTimer = 0; - } else EnrageTimer-=diff; - } -}; - -class MANGOS_DLL_DECL BugAura : public Aura -{ - public: - BugAura(SpellEntry *spell, uint32 eff, int32 *bp, Unit *target, Unit *caster) : Aura(spell, eff, bp, target, caster, NULL) - {} -}; - -struct MANGOS_DLL_DECL boss_veknilashAI : public boss_twinemperorsAI -{ - bool IAmVeklor() {return false;} - boss_veknilashAI(Creature *c) : boss_twinemperorsAI(c) - { - Reset(); - } - - uint32 UpperCut_Timer; - uint32 UnbalancingStrike_Timer; - uint32 Scarabs_Timer; - int Rand; - int RandX; - int RandY; - - Creature* Summoned; - - void Reset() - { - TwinReset(); - UpperCut_Timer = 14000 + rand()%15000; - UnbalancingStrike_Timer = 8000 + rand()%10000; - Scarabs_Timer = 7000 + rand()%7000; - - //Added. Can be removed if its included in DB. - m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); - } - - void CastSpellOnBug(Creature *target) - { - target->setFaction(14); - ((CreatureAI*)target->AI())->AttackStart(m_creature->getThreatManager().getHostilTarget()); - SpellEntry *spell = (SpellEntry *)GetSpellStore()->LookupEntry(SPELL_MUTATE_BUG); - for (int i=0; i<3; i++) - { - if (!spell->Effect[i]) - continue; - target->AddAura(new BugAura(spell, i, NULL, target, target)); - } - target->SetHealth(target->GetMaxHealth()); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (!TryActivateAfterTTelep(diff)) - return; - - //UnbalancingStrike_Timer - if (UnbalancingStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_UNBALANCING_STRIKE); - UnbalancingStrike_Timer = 8000+rand()%12000; - }else UnbalancingStrike_Timer -= diff; - - if (UpperCut_Timer < diff) - { - Unit* randomMelee = GetAnyoneCloseEnough(ATTACK_DISTANCE, true); - if (randomMelee) - DoCast(randomMelee,SPELL_UPPERCUT); - UpperCut_Timer = 15000+rand()%15000; - }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(); - } -}; - -struct MANGOS_DLL_DECL boss_veklorAI : public boss_twinemperorsAI -{ - bool IAmVeklor() {return true;} - boss_veklorAI(Creature *c) : boss_twinemperorsAI(c) - { - Reset(); - } - - uint32 ShadowBolt_Timer; - uint32 Blizzard_Timer; - uint32 ArcaneBurst_Timer; - uint32 Scorpions_Timer; - int Rand; - int RandX; - int RandY; - - Creature* Summoned; - - void Reset() - { - TwinReset(); - ShadowBolt_Timer = 0; - Blizzard_Timer = 15000 + rand()%5000;; - ArcaneBurst_Timer = 1000; - Scorpions_Timer = 7000 + rand()%7000; - - //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); - } - - void CastSpellOnBug(Creature *target) - { - target->setFaction(14); - SpellEntry *spell = (SpellEntry *)GetSpellStore()->LookupEntry(SPELL_EXPLODEBUG); - for (int i=0; i<3; i++) - { - if (!spell->Effect[i]) - continue; - target->AddAura(new BugAura(spell, i, NULL, target, target)); - } - target->SetHealth(target->GetMaxHealth()); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - // 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; - - //ShadowBolt_Timer - if (ShadowBolt_Timer < diff) - { - if (m_creature->GetDistance(m_creature->getVictim()) > 45) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), VEKLOR_DIST, 0); - else - DoCast(m_creature->getVictim(),SPELL_SHADOWBOLT); - ShadowBolt_Timer = 2000; - }else ShadowBolt_Timer -= diff; - - //Blizzard_Timer - if (Blizzard_Timer < diff) - { - Unit* target = NULL; - target = GetAnyoneCloseEnough(45, true); - if (target) - DoCast(target,SPELL_BLIZZARD); - Blizzard_Timer = 15000+rand()%15000; - }else Blizzard_Timer -= diff; - - if (ArcaneBurst_Timer < diff) - { - Unit *mvic; - if ((mvic=GetAnyoneCloseEnough(ATTACK_DISTANCE, false))!=NULL) - { - DoCast(mvic,SPELL_ARCANEBURST); - ArcaneBurst_Timer = 5000; - } - }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; - - if (who->isTargetableForAttack()) - { - // VL doesn't melee - if ( m_creature->Attack(who, false) ) - { - m_creature->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0); - m_creature->AddThreat(who, 0.0f); - } - - if (!InCombat) - { - Aggro(who); - InCombat = true; - } - } - } -}; - -CreatureAI* GetAI_boss_veknilash(Creature *_Creature) -{ - return new boss_veknilashAI (_Creature); -} - -CreatureAI* GetAI_boss_veklor(Creature *_Creature) -{ - return new boss_veklorAI (_Creature); -} - -void AddSC_boss_twinemperors() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_veknilash"; - newscript->GetAI = GetAI_boss_veknilash; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="boss_veklor"; - newscript->GetAI = GetAI_boss_veklor; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Twinemperors +SD%Complete: 95 +SDComment: +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" +#include "def_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 + +struct MANGOS_DLL_DECL boss_twinemperorsAI : public ScriptedAI +{ + ScriptedInstance *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 *c): ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + } + + 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 = 10000 + rand()%7000; + BugsTimer = 2000; + m_creature->clearUnitState(UNIT_STAT_STUNDED); + DontYellWhenDead = false; + EnrageTimer = 15*60000; + } + + Creature *GetOtherBoss() + { + if(pInstance) + { + return (Creature *)Unit::GetUnit((*m_creature), pInstance->GetData64(IAmVeklor() ? DATA_VEKNILASH : DATA_VEKLOR)); + } + else + { + return (Creature *)0; + } + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + Unit *pOtherBoss = GetOtherBoss(); + if (pOtherBoss) + { + 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) + { + pOtherBoss->setDeathState(JUST_DIED); + pOtherBoss->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + } + } + + void JustDied(Unit* Killer) + { + Creature *pOtherBoss = GetOtherBoss(); + if (pOtherBoss) + { + pOtherBoss->SetHealth(0); + pOtherBoss->setDeathState(JUST_DIED); + pOtherBoss->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + ((boss_twinemperorsAI *)pOtherBoss->AI())->DontYellWhenDead = true; + } + if (!DontYellWhenDead) // I hope AI is not threaded + DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_DEATH : SOUND_VN_DEATH); + } + + void KilledUnit(Unit* victim) + { + DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_KILL : SOUND_VN_KILL); + } + + void Aggro(Unit *who) + { + DoZoneInCombat(); + InCombat = true; + Creature *pOtherBoss = GetOtherBoss(); + if (pOtherBoss) + { + // 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 + ScriptedAI *otherAI = (ScriptedAI*)pOtherBoss->AI(); + if (!otherAI->InCombat) + { + DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_AGGRO : SOUND_VN_AGGRO); + otherAI->AttackStart(who); + otherAI->DoZoneInCombat(); + } + } + } + + void SpellHit(Unit *caster, const SpellEntry *entry) + { + if (caster == m_creature) + return; + + Creature *pOtherBoss = GetOtherBoss(); + if (entry->Id != SPELL_HEAL_BROTHER || !pOtherBoss) + 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) + { + uint32 h = m_creature->GetHealth()+largerAmount; + m_creature->SetHealth(std::min(mytotal, h)); + } + else + { + uint32 h = pOtherBoss->GetHealth()+largerAmount; + pOtherBoss->SetHealth(std::min(histotal, h)); + } + } + + void TryHealBrother(uint32 diff) + { + if (IAmVeklor()) // this spell heals caster and the other brother so let VN cast it + return; + + if (Heal_Timer < diff) + { + Unit *pOtherBoss = GetOtherBoss(); + if (pOtherBoss && (pOtherBoss->GetDistance((const Creature *)m_creature) <= 60)) + { + DoCast(pOtherBoss, SPELL_HEAL_BROTHER); + Heal_Timer = 1000; + } + } else Heal_Timer -= diff; + } + + Unit *GetAnyoneCloseEnough(float dist, bool totallyRandom) + { + int cnt = 0; + std::list::iterator i; + std::list candidates; + + for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + 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(); + + i = candidates.begin(); + Unit *ret = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + candidates.clear(); + return ret; + } + + Unit *PickNearestPlayer() + { + Unit *nearp = NULL; + float neardist = 0.0f; + std::list::iterator i; + for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Unit* pUnit = NULL; + pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if (!pUnit) + continue; + float pudist = pUnit->GetDistance((const Creature *)m_creature); + if (!nearp || (neardist > pudist)) + { + nearp = pUnit; + neardist = pudist; + } + } + return nearp; + } + + void TeleportToMyBrother() + { + if (!pInstance) + return; + + Teleport_Timer = TELEPORTTIME; + + if(IAmVeklor()) + return; // mechanics handled by veknilash so they teleport exactly at the same time and to correct coordinates + + Creature *pOtherBoss = GetOtherBoss(); + if (pOtherBoss) + { + //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(); + ((boss_twinemperorsAI*) pOtherBoss->AI())->SetAfterTeleport(); + } + } + + void SetAfterTeleport() + { + m_creature->InterruptNonMeleeSpells(false); + DoStopAttack(); + DoResetThreat(); + DoCast(m_creature, SPELL_TWIN_TELEPORT_VISUAL); + m_creature->addUnitState(UNIT_STAT_STUNDED); + AfterTeleport = true; + AfterTeleportTimer = 2000; + tspellcasted = false; + } + + bool TryActivateAfterTTelep(uint32 diff) + { + if (AfterTeleport) + { + if (!tspellcasted) + { + m_creature->clearUnitState(UNIT_STAT_STUNDED); + DoCast(m_creature, SPELL_TWIN_TELEPORT); + m_creature->addUnitState(UNIT_STAT_STUNDED); + } + + tspellcasted = true; + + if (AfterTeleportTimer < diff) + { + AfterTeleport = false; + m_creature->clearUnitState(UNIT_STAT_STUNDED); + 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; + } + } + + void MoveInLineOfSight(Unit *who) + { + if (!who || m_creature->getVictim()) + return; + + 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); + } + } + } + + class AnyBugCheck + { + public: + AnyBugCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(Unit* u) + { + Creature *c = (Creature *)u; + if (!i_obj->IsWithinDistInMap(c, i_range)) + return false; + return (c->GetEntry() == 15316 || c->GetEntry() == 15317); + } + private: + WorldObject const* i_obj; + float i_range; + }; + + Creature *RespawnNearbyBugsAndGetOne() + { + CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + std::list unitList; + + AnyBugCheck u_check(m_creature, 150); + MaNGOS::CreatureListSearcher searcher(unitList, u_check); + TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap())); + + Creature *nearb = NULL; + + for(std::list::iterator iter = unitList.begin(); iter != unitList.end(); ++iter) + { + Creature *c = (Creature *)(*iter); + if (c->isDead()) + { + c->Respawn(); + c->setFaction(7); + c->RemoveAllAuras(); + } + if (c->IsWithinDistInMap(m_creature, ABUSE_BUG_RANGE)) + { + if (!nearb || (rand()%4)==0) + nearb = c; + } + } + return nearb; + } + + void HandleBugs(uint32 diff) + { + if (BugsTimer < diff || Abuse_Bug_Timer < diff) + { + Creature *c = RespawnNearbyBugsAndGetOne(); + if (Abuse_Bug_Timer < diff) + { + if (c) + { + CastSpellOnBug(c); + Abuse_Bug_Timer = 10000 + rand()%7000; + } + else + { + Abuse_Bug_Timer = 1000; + } + } + else + { + Abuse_Bug_Timer -= diff; + } + BugsTimer = 2000; + } + else + { + BugsTimer -= diff; + Abuse_Bug_Timer -= diff; + } + } + + void CheckEnrage(uint32 diff) + { + if (EnrageTimer < diff) + { + if (!m_creature->IsNonMeleeSpellCasted(true)) + { + DoCast(m_creature, SPELL_BERSERK); + EnrageTimer = 60*60000; + } else EnrageTimer = 0; + } else EnrageTimer-=diff; + } +}; + +class MANGOS_DLL_DECL BugAura : public Aura +{ + public: + BugAura(SpellEntry *spell, uint32 eff, int32 *bp, Unit *target, Unit *caster) : Aura(spell, eff, bp, target, caster, NULL) + {} +}; + +struct MANGOS_DLL_DECL boss_veknilashAI : public boss_twinemperorsAI +{ + bool IAmVeklor() {return false;} + boss_veknilashAI(Creature *c) : boss_twinemperorsAI(c) + { + Reset(); + } + + uint32 UpperCut_Timer; + uint32 UnbalancingStrike_Timer; + uint32 Scarabs_Timer; + int Rand; + int RandX; + int RandY; + + Creature* Summoned; + + void Reset() + { + TwinReset(); + UpperCut_Timer = 14000 + rand()%15000; + UnbalancingStrike_Timer = 8000 + rand()%10000; + Scarabs_Timer = 7000 + rand()%7000; + + //Added. Can be removed if its included in DB. + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + } + + void CastSpellOnBug(Creature *target) + { + target->setFaction(14); + ((CreatureAI*)target->AI())->AttackStart(m_creature->getThreatManager().getHostilTarget()); + SpellEntry *spell = (SpellEntry *)GetSpellStore()->LookupEntry(SPELL_MUTATE_BUG); + for (int i=0; i<3; i++) + { + if (!spell->Effect[i]) + continue; + target->AddAura(new BugAura(spell, i, NULL, target, target)); + } + target->SetHealth(target->GetMaxHealth()); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (!TryActivateAfterTTelep(diff)) + return; + + //UnbalancingStrike_Timer + if (UnbalancingStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_UNBALANCING_STRIKE); + UnbalancingStrike_Timer = 8000+rand()%12000; + }else UnbalancingStrike_Timer -= diff; + + if (UpperCut_Timer < diff) + { + Unit* randomMelee = GetAnyoneCloseEnough(ATTACK_DISTANCE, true); + if (randomMelee) + DoCast(randomMelee,SPELL_UPPERCUT); + UpperCut_Timer = 15000+rand()%15000; + }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(); + } +}; + +struct MANGOS_DLL_DECL boss_veklorAI : public boss_twinemperorsAI +{ + bool IAmVeklor() {return true;} + boss_veklorAI(Creature *c) : boss_twinemperorsAI(c) + { + Reset(); + } + + uint32 ShadowBolt_Timer; + uint32 Blizzard_Timer; + uint32 ArcaneBurst_Timer; + uint32 Scorpions_Timer; + int Rand; + int RandX; + int RandY; + + Creature* Summoned; + + void Reset() + { + TwinReset(); + ShadowBolt_Timer = 0; + Blizzard_Timer = 15000 + rand()%5000;; + ArcaneBurst_Timer = 1000; + Scorpions_Timer = 7000 + rand()%7000; + + //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); + } + + void CastSpellOnBug(Creature *target) + { + target->setFaction(14); + SpellEntry *spell = (SpellEntry *)GetSpellStore()->LookupEntry(SPELL_EXPLODEBUG); + for (int i=0; i<3; i++) + { + if (!spell->Effect[i]) + continue; + target->AddAura(new BugAura(spell, i, NULL, target, target)); + } + target->SetHealth(target->GetMaxHealth()); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + // 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; + + //ShadowBolt_Timer + if (ShadowBolt_Timer < diff) + { + if (m_creature->GetDistance(m_creature->getVictim()) > 45) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), VEKLOR_DIST, 0); + else + DoCast(m_creature->getVictim(),SPELL_SHADOWBOLT); + ShadowBolt_Timer = 2000; + }else ShadowBolt_Timer -= diff; + + //Blizzard_Timer + if (Blizzard_Timer < diff) + { + Unit* target = NULL; + target = GetAnyoneCloseEnough(45, true); + if (target) + DoCast(target,SPELL_BLIZZARD); + Blizzard_Timer = 15000+rand()%15000; + }else Blizzard_Timer -= diff; + + if (ArcaneBurst_Timer < diff) + { + Unit *mvic; + if ((mvic=GetAnyoneCloseEnough(ATTACK_DISTANCE, false))!=NULL) + { + DoCast(mvic,SPELL_ARCANEBURST); + ArcaneBurst_Timer = 5000; + } + }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; + + if (who->isTargetableForAttack()) + { + // VL doesn't melee + if ( m_creature->Attack(who, false) ) + { + m_creature->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0); + m_creature->AddThreat(who, 0.0f); + } + + if (!InCombat) + { + Aggro(who); + InCombat = true; + } + } + } +}; + +CreatureAI* GetAI_boss_veknilash(Creature *_Creature) +{ + return new boss_veknilashAI (_Creature); +} + +CreatureAI* GetAI_boss_veklor(Creature *_Creature) +{ + return new boss_veklorAI (_Creature); +} + +void AddSC_boss_twinemperors() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_veknilash"; + newscript->GetAI = GetAI_boss_veknilash; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="boss_veklor"; + newscript->GetAI = GetAI_boss_veklor; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_viscidus.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_viscidus.cpp index 36a8bfea1c1..28d1d7ba963 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_viscidus.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_viscidus.cpp @@ -1,29 +1,29 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Viscidus -SD%Complete: 0 -SDComment: place holder -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_POISON_SHOCK 25993 -#define SPELL_POISONBOLT_VOLLEY 25991 - -#define SPELL_TOXIN_CLOUD 25989 +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Viscidus +SD%Complete: 0 +SDComment: place holder +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_POISON_SHOCK 25993 +#define SPELL_POISONBOLT_VOLLEY 25991 + +#define SPELL_TOXIN_CLOUD 25989 diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/def_temple_of_ahnqiraj.h b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/def_temple_of_ahnqiraj.h index fdc6d30a0cb..935a1587c2a 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/def_temple_of_ahnqiraj.h +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/def_temple_of_ahnqiraj.h @@ -1,22 +1,22 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_TEMPLE_OF_AHNQIRAJ_H -#define DEF_TEMPLE_OF_AHNQIRAJ_H - -#define DATA_SKERAM 1 -#define DATA_KRI 2 -#define DATA_VEM 3 -#define DATA_VEMISDEAD 4 -#define DATA_VEM_DEATH 5 -#define DATA_VEKLOR 6 -#define DATA_VEKLORISDEAD 7 -#define DATA_VEKLOR_DEATH 8 -#define DATA_VEKNILASH 9 -#define DATA_VEKNILASHISDEAD 10 -#define DATA_VEKNILASH_DEATH 11 -#define DATA_BUG_TRIO_DEATH 14 - -#define DATA_CTHUN_PHASE 20 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_TEMPLE_OF_AHNQIRAJ_H +#define DEF_TEMPLE_OF_AHNQIRAJ_H + +#define DATA_SKERAM 1 +#define DATA_KRI 2 +#define DATA_VEM 3 +#define DATA_VEMISDEAD 4 +#define DATA_VEM_DEATH 5 +#define DATA_VEKLOR 6 +#define DATA_VEKLORISDEAD 7 +#define DATA_VEKLOR_DEATH 8 +#define DATA_VEKNILASH 9 +#define DATA_VEKNILASHISDEAD 10 +#define DATA_VEKNILASH_DEATH 11 +#define DATA_BUG_TRIO_DEATH 14 + +#define DATA_CTHUN_PHASE 20 +#endif diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp index 724a64e2baa..933550b07c3 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp @@ -1,165 +1,165 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Ahnqiraj -SD%Complete: 80 -SDComment: -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" -#include "def_temple_of_ahnqiraj.h" - -struct MANGOS_DLL_DECL instance_temple_of_ahnqiraj : public ScriptedInstance -{ - instance_temple_of_ahnqiraj(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - //If Vem is dead... - bool IsBossDied[3]; - - //Storing Skeram, Vem and Kri. - uint64 SkeramGUID; - uint64 VemGUID; - uint64 KriGUID; - uint64 VeklorGUID; - uint64 VeknilashGUID; - - uint32 BugTrioDeathCount; - - uint32 CthunPhase; - - void Initialize() - { - IsBossDied[0] = false; - IsBossDied[1] = false; - IsBossDied[2] = false; - - SkeramGUID = 0; - VemGUID = 0; - KriGUID = 0; - VeklorGUID = 0; - VeknilashGUID = 0; - - BugTrioDeathCount = 0; - - CthunPhase = 0; - } - - void OnCreatureCreate (Creature *creature, uint32 creature_entry) - { - switch (creature_entry) - { - case 15263: SkeramGUID = creature->GetGUID(); break; - case 15544: VemGUID = creature->GetGUID(); break; - case 15511: KriGUID = creature->GetGUID(); break; - case 15276: VeklorGUID = creature->GetGUID(); break; - case 15275: VeknilashGUID = creature->GetGUID(); break; - } - } - - bool IsEncounterInProgress() const - { - //not active in AQ40 - return false; - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_VEMISDEAD: - if(IsBossDied[0]) - return 1; - break; - - case DATA_VEKLORISDEAD: - if(IsBossDied[1]) - return 1; - break; - - case DATA_VEKNILASHISDEAD: - if(IsBossDied[2]) - return 1; - break; - - case DATA_BUG_TRIO_DEATH: - return BugTrioDeathCount; - - case DATA_CTHUN_PHASE: - return CthunPhase; - } - return 0; - } - - uint64 GetData64 (uint32 identifier) - { - switch(identifier) - { - case DATA_SKERAM: - return SkeramGUID; - case DATA_VEM: - return VemGUID; - case DATA_KRI: - return KriGUID; - case DATA_VEKLOR: - return VeklorGUID; - case DATA_VEKNILASH: - return VeknilashGUID; - } - return 0; - } // end GetData64 - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_VEM_DEATH: - IsBossDied[0] = true; - break; - - case DATA_BUG_TRIO_DEATH: - BugTrioDeathCount++; - break; - - case DATA_VEKLOR_DEATH: - IsBossDied[1] = true; - break; - - case DATA_VEKNILASH_DEATH: - IsBossDied[2] = true; - break; - - case DATA_CTHUN_PHASE: - CthunPhase = data; - break; - } - } -}; - -InstanceData* GetInstanceData_instance_temple_of_ahnqiraj(Map* map) -{ - return new instance_temple_of_ahnqiraj(map); -} - -void AddSC_instance_temple_of_ahnqiraj() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_temple_of_ahnqiraj"; - newscript->GetInstanceData = GetInstanceData_instance_temple_of_ahnqiraj; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Ahnqiraj +SD%Complete: 80 +SDComment: +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" +#include "def_temple_of_ahnqiraj.h" + +struct MANGOS_DLL_DECL instance_temple_of_ahnqiraj : public ScriptedInstance +{ + instance_temple_of_ahnqiraj(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + //If Vem is dead... + bool IsBossDied[3]; + + //Storing Skeram, Vem and Kri. + uint64 SkeramGUID; + uint64 VemGUID; + uint64 KriGUID; + uint64 VeklorGUID; + uint64 VeknilashGUID; + + uint32 BugTrioDeathCount; + + uint32 CthunPhase; + + void Initialize() + { + IsBossDied[0] = false; + IsBossDied[1] = false; + IsBossDied[2] = false; + + SkeramGUID = 0; + VemGUID = 0; + KriGUID = 0; + VeklorGUID = 0; + VeknilashGUID = 0; + + BugTrioDeathCount = 0; + + CthunPhase = 0; + } + + void OnCreatureCreate (Creature *creature, uint32 creature_entry) + { + switch (creature_entry) + { + case 15263: SkeramGUID = creature->GetGUID(); break; + case 15544: VemGUID = creature->GetGUID(); break; + case 15511: KriGUID = creature->GetGUID(); break; + case 15276: VeklorGUID = creature->GetGUID(); break; + case 15275: VeknilashGUID = creature->GetGUID(); break; + } + } + + bool IsEncounterInProgress() const + { + //not active in AQ40 + return false; + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_VEMISDEAD: + if(IsBossDied[0]) + return 1; + break; + + case DATA_VEKLORISDEAD: + if(IsBossDied[1]) + return 1; + break; + + case DATA_VEKNILASHISDEAD: + if(IsBossDied[2]) + return 1; + break; + + case DATA_BUG_TRIO_DEATH: + return BugTrioDeathCount; + + case DATA_CTHUN_PHASE: + return CthunPhase; + } + return 0; + } + + uint64 GetData64 (uint32 identifier) + { + switch(identifier) + { + case DATA_SKERAM: + return SkeramGUID; + case DATA_VEM: + return VemGUID; + case DATA_KRI: + return KriGUID; + case DATA_VEKLOR: + return VeklorGUID; + case DATA_VEKNILASH: + return VeknilashGUID; + } + return 0; + } // end GetData64 + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_VEM_DEATH: + IsBossDied[0] = true; + break; + + case DATA_BUG_TRIO_DEATH: + BugTrioDeathCount++; + break; + + case DATA_VEKLOR_DEATH: + IsBossDied[1] = true; + break; + + case DATA_VEKNILASH_DEATH: + IsBossDied[2] = true; + break; + + case DATA_CTHUN_PHASE: + CthunPhase = data; + break; + } + } +}; + +InstanceData* GetInstanceData_instance_temple_of_ahnqiraj(Map* map) +{ + return new instance_temple_of_ahnqiraj(map); +} + +void AddSC_instance_temple_of_ahnqiraj() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_temple_of_ahnqiraj"; + newscript->GetInstanceData = GetInstanceData_instance_temple_of_ahnqiraj; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp index 62c21978adf..5f6e4f0ef44 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp @@ -1,344 +1,344 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: mob_anubisath_sentinel -SD%Complete: 95 -SDComment: Shadow storm is not properly implemented in core it should only target ppl outside of melee range. -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - -#include "precompiled.h" -#include "WorldPacket.h" - -#include "Item.h" -#include "Player.h" -#include "Spell.h" - -#include "Cell.h" -#include "CellImpl.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" - -#define SPELL_MENDING_BUFF 2147 - -#define SPELL_KNOCK_BUFF 21737 -#define SPELL_KNOCK 25778 -#define SPELL_MANAB_BUFF 812 -#define SPELL_MANAB 25779 - -#define SPELL_REFLECTAF_BUFF 13022 -#define SPELL_REFLECTSFr_BUFF 19595 -#define SPELL_THORNS_BUFF 25777 - -#define SPELL_THUNDER_BUFF 2834 -#define SPELL_THUNDER 8732 - -#define SPELL_MSTRIKE_BUFF 9347 -#define SPELL_MSTRIKE 24573 - -#define SPELL_STORM_BUFF 2148 -#define SPELL_STORM 26546 - -class NearbyAQSentinel -{ - public: - NearbyAQSentinel(Unit const* obj) : i_obj(obj) {} - bool operator()(Unit* u) - { - if (u->GetEntry() == 15264 && i_obj->IsWithinDistInMap(u, 70) && !u->isDead()) - return true; - else - return false; - } - private: - Unit const* i_obj; -}; - -struct MANGOS_DLL_DECL aqsentinelAI; -class MANGOS_DLL_DECL SentinelAbilityAura : public Aura -{ - public: - ~SentinelAbilityAura(); - Unit* GetTriggerTarget() const; - SentinelAbilityAura(aqsentinelAI *abilityOwner, SpellEntry *spell, uint32 ability, uint32 eff); - protected: - aqsentinelAI *aOwner; - int32 currentBasePoints; - uint32 abilityId; -}; - -struct MANGOS_DLL_DECL aqsentinelAI : public ScriptedAI -{ - uint32 ability; - int abselected; - - void selectAbility(int asel) - { - switch (asel) - { - case 0: ability = SPELL_MENDING_BUFF;break; - case 1: ability = SPELL_KNOCK_BUFF;break; - case 2: ability = SPELL_MANAB_BUFF;break; - case 3: ability = SPELL_REFLECTAF_BUFF;break; - case 4: ability = SPELL_REFLECTSFr_BUFF;break; - case 5: ability = SPELL_THORNS_BUFF;break; - case 6: ability = SPELL_THUNDER_BUFF;break; - case 7: ability = SPELL_MSTRIKE_BUFF;break; - case 8: ability = SPELL_STORM_BUFF;break; - } - } - - aqsentinelAI(Creature *c) : ScriptedAI(c) - { - ClearBudyList(); - abselected = 0; // just initialization of variable - Reset(); - } - - Creature *nearby[3]; - - void ClearBudyList() - { - nearby[0] = nearby[1] = nearby[2] = NULL; - } - - void AddBuddyToList(Creature *c) - { - if (c==m_creature) - return; - for (int i=0; i<3; i++) - { - if (nearby[i] == c) - return; - if (!nearby[i]) - { - nearby[i] = c; - return; - } - } - } - - void GiveBuddyMyList(Creature *c) - { - aqsentinelAI *cai = (aqsentinelAI *)(c->AI()); - for (int i=0; i<3; i++) - if (nearby[i] && nearby[i]!=c) - cai->AddBuddyToList(nearby[i]); - cai->AddBuddyToList(m_creature); - } - - void SendMyListToBuddies() - { - for (int i=0; i<3; i++) - if (nearby[i]) - GiveBuddyMyList(nearby[i]); - } - - void CallBuddiesToAttack(Unit *who) - { - for (int i=0; i<3; i++) - { - Creature *c = nearby[i]; - if (c) - { - if (!c->isInCombat()) - { - c->SetNoCallAssistence(true); - if(c->AI()) - c->AI()->AttackStart(who); - } - } - } - } - - void AddSentinelsNear(Unit *nears) - { - CellPair p(MaNGOS::ComputeCellPair(nears->GetPositionX(), nears->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list assistList; - - NearbyAQSentinel u_check(nears); - MaNGOS::CreatureListSearcher searcher(assistList, u_check); - TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *(nears->GetMap())); - - for(std::list::iterator iter = assistList.begin(); iter != assistList.end(); ++iter) - AddBuddyToList((*iter)); - } - - int pickAbilityRandom(bool *chosenAbilities) - { - for (int t = 0; t < 2; t++) - { - for (int i = !t ? (rand()%9) : 0; i < 9; i++) - { - if (!chosenAbilities[i]) - { - chosenAbilities[i] = true; - return i; - } - } - } - return 0; // should never happen - } - - void GetOtherSentinels(Unit *who) - { - bool *chosenAbilities = new bool[9]; - memset(chosenAbilities, 0, 9*sizeof(bool)); - selectAbility(pickAbilityRandom(chosenAbilities)); - - ClearBudyList(); - AddSentinelsNear(m_creature); - int bli; - for (bli = 0; bli < 3;bli++) - { - if (!nearby[bli]) - break; - AddSentinelsNear(nearby[bli]); - ((aqsentinelAI *)nearby[bli]->AI())->gatherOthersWhenAggro = false; - ((aqsentinelAI *)nearby[bli]->AI())->selectAbility(pickAbilityRandom(chosenAbilities)); - } - /*if (bli < 3) - DoYell("I dont have enough buddies.", LANG_NEUTRAL, 0);*/ - SendMyListToBuddies(); - CallBuddiesToAttack(who); - } - - bool gatherOthersWhenAggro; - - void Reset() - { - if (!m_creature->isDead()) - { - for (int i=0; i<3; i++) - { - if (!nearby[i]) - continue; - if (nearby[i]->isDead()) - nearby[i]->Respawn(); - } - } - ClearBudyList(); - gatherOthersWhenAggro = true; - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); - } - - void GainSentinelAbility(uint32 id) - { - const SpellEntry *spell = GetSpellStore()->LookupEntry(id); - for (int i=0; i<3; i++) - { - if (!spell->Effect[i]) - continue; - SentinelAbilityAura *a = new SentinelAbilityAura(this, (SpellEntry *)spell, id, i); - m_creature->AddAura(a); - } - if (id == SPELL_KNOCK_BUFF) - { - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); - } - } - - void Aggro(Unit *who) - { - if (gatherOthersWhenAggro) - GetOtherSentinels(who); - - GainSentinelAbility(ability); - DoZoneInCombat(); - } - - void JustDied(Unit*) - { - for (int ni=0; ni<3; ni++) - { - Creature *sent = nearby[ni]; - if (!sent) - continue; - if (sent->isDead()) - continue; - int h = sent->GetHealth() + (sent->GetMaxHealth() / 2); - if (h > sent->GetMaxHealth()) - h = sent->GetMaxHealth(); - sent->SetHealth(h); - ((aqsentinelAI *)sent->AI())->GainSentinelAbility(ability); - } - } - - Unit *GetHatedManaUser() - { - std::list::iterator i; - for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - if (pUnit->getPowerType()==POWER_MANA) - return pUnit; - } - return NULL; - } -}; -CreatureAI* GetAI_mob_anubisath_sentinelAI(Creature *_Creature) -{ - return new aqsentinelAI (_Creature); -} - -void AddSC_mob_anubisath_sentinel() -{ - Script *newscript; - newscript = new Script; - newscript->Name="mob_anubisath_sentinel"; - newscript->GetAI = GetAI_mob_anubisath_sentinelAI; - m_scripts[nrscripts++] = newscript; -} - -SentinelAbilityAura::~SentinelAbilityAura() {} -Unit* SentinelAbilityAura::GetTriggerTarget() const -{ - switch (abilityId) - { - case SPELL_KNOCK_BUFF: - case SPELL_THUNDER_BUFF: - case SPELL_MSTRIKE_BUFF: - case SPELL_STORM_BUFF: - return aOwner->m_creature->getVictim(); - - case SPELL_MANAB_BUFF: - return aOwner->GetHatedManaUser(); - - case SPELL_MENDING_BUFF: - case SPELL_REFLECTAF_BUFF: - case SPELL_REFLECTSFr_BUFF: - case SPELL_THORNS_BUFF: - default: - return aOwner->m_creature; - } -} - -SentinelAbilityAura::SentinelAbilityAura(aqsentinelAI *abilityOwner, SpellEntry *spell, uint32 ability, uint32 eff) -: Aura(spell, eff, NULL, abilityOwner->m_creature, abilityOwner->m_creature, NULL) -{ - aOwner = abilityOwner; - abilityId = ability; - currentBasePoints = 0; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: mob_anubisath_sentinel +SD%Complete: 95 +SDComment: Shadow storm is not properly implemented in core it should only target ppl outside of melee range. +SDCategory: Temple of Ahn'Qiraj +EndScriptData */ + +#include "precompiled.h" +#include "WorldPacket.h" + +#include "Item.h" +#include "Player.h" +#include "Spell.h" + +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" + +#define SPELL_MENDING_BUFF 2147 + +#define SPELL_KNOCK_BUFF 21737 +#define SPELL_KNOCK 25778 +#define SPELL_MANAB_BUFF 812 +#define SPELL_MANAB 25779 + +#define SPELL_REFLECTAF_BUFF 13022 +#define SPELL_REFLECTSFr_BUFF 19595 +#define SPELL_THORNS_BUFF 25777 + +#define SPELL_THUNDER_BUFF 2834 +#define SPELL_THUNDER 8732 + +#define SPELL_MSTRIKE_BUFF 9347 +#define SPELL_MSTRIKE 24573 + +#define SPELL_STORM_BUFF 2148 +#define SPELL_STORM 26546 + +class NearbyAQSentinel +{ + public: + NearbyAQSentinel(Unit const* obj) : i_obj(obj) {} + bool operator()(Unit* u) + { + if (u->GetEntry() == 15264 && i_obj->IsWithinDistInMap(u, 70) && !u->isDead()) + return true; + else + return false; + } + private: + Unit const* i_obj; +}; + +struct MANGOS_DLL_DECL aqsentinelAI; +class MANGOS_DLL_DECL SentinelAbilityAura : public Aura +{ + public: + ~SentinelAbilityAura(); + Unit* GetTriggerTarget() const; + SentinelAbilityAura(aqsentinelAI *abilityOwner, SpellEntry *spell, uint32 ability, uint32 eff); + protected: + aqsentinelAI *aOwner; + int32 currentBasePoints; + uint32 abilityId; +}; + +struct MANGOS_DLL_DECL aqsentinelAI : public ScriptedAI +{ + uint32 ability; + int abselected; + + void selectAbility(int asel) + { + switch (asel) + { + case 0: ability = SPELL_MENDING_BUFF;break; + case 1: ability = SPELL_KNOCK_BUFF;break; + case 2: ability = SPELL_MANAB_BUFF;break; + case 3: ability = SPELL_REFLECTAF_BUFF;break; + case 4: ability = SPELL_REFLECTSFr_BUFF;break; + case 5: ability = SPELL_THORNS_BUFF;break; + case 6: ability = SPELL_THUNDER_BUFF;break; + case 7: ability = SPELL_MSTRIKE_BUFF;break; + case 8: ability = SPELL_STORM_BUFF;break; + } + } + + aqsentinelAI(Creature *c) : ScriptedAI(c) + { + ClearBudyList(); + abselected = 0; // just initialization of variable + Reset(); + } + + Creature *nearby[3]; + + void ClearBudyList() + { + nearby[0] = nearby[1] = nearby[2] = NULL; + } + + void AddBuddyToList(Creature *c) + { + if (c==m_creature) + return; + for (int i=0; i<3; i++) + { + if (nearby[i] == c) + return; + if (!nearby[i]) + { + nearby[i] = c; + return; + } + } + } + + void GiveBuddyMyList(Creature *c) + { + aqsentinelAI *cai = (aqsentinelAI *)(c->AI()); + for (int i=0; i<3; i++) + if (nearby[i] && nearby[i]!=c) + cai->AddBuddyToList(nearby[i]); + cai->AddBuddyToList(m_creature); + } + + void SendMyListToBuddies() + { + for (int i=0; i<3; i++) + if (nearby[i]) + GiveBuddyMyList(nearby[i]); + } + + void CallBuddiesToAttack(Unit *who) + { + for (int i=0; i<3; i++) + { + Creature *c = nearby[i]; + if (c) + { + if (!c->isInCombat()) + { + c->SetNoCallAssistence(true); + if(c->AI()) + c->AI()->AttackStart(who); + } + } + } + } + + void AddSentinelsNear(Unit *nears) + { + CellPair p(MaNGOS::ComputeCellPair(nears->GetPositionX(), nears->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + std::list assistList; + + NearbyAQSentinel u_check(nears); + MaNGOS::CreatureListSearcher searcher(assistList, u_check); + TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *(nears->GetMap())); + + for(std::list::iterator iter = assistList.begin(); iter != assistList.end(); ++iter) + AddBuddyToList((*iter)); + } + + int pickAbilityRandom(bool *chosenAbilities) + { + for (int t = 0; t < 2; t++) + { + for (int i = !t ? (rand()%9) : 0; i < 9; i++) + { + if (!chosenAbilities[i]) + { + chosenAbilities[i] = true; + return i; + } + } + } + return 0; // should never happen + } + + void GetOtherSentinels(Unit *who) + { + bool *chosenAbilities = new bool[9]; + memset(chosenAbilities, 0, 9*sizeof(bool)); + selectAbility(pickAbilityRandom(chosenAbilities)); + + ClearBudyList(); + AddSentinelsNear(m_creature); + int bli; + for (bli = 0; bli < 3;bli++) + { + if (!nearby[bli]) + break; + AddSentinelsNear(nearby[bli]); + ((aqsentinelAI *)nearby[bli]->AI())->gatherOthersWhenAggro = false; + ((aqsentinelAI *)nearby[bli]->AI())->selectAbility(pickAbilityRandom(chosenAbilities)); + } + /*if (bli < 3) + DoYell("I dont have enough buddies.", LANG_NEUTRAL, 0);*/ + SendMyListToBuddies(); + CallBuddiesToAttack(who); + } + + bool gatherOthersWhenAggro; + + void Reset() + { + if (!m_creature->isDead()) + { + for (int i=0; i<3; i++) + { + if (!nearby[i]) + continue; + if (nearby[i]->isDead()) + nearby[i]->Respawn(); + } + } + ClearBudyList(); + gatherOthersWhenAggro = true; + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); + } + + void GainSentinelAbility(uint32 id) + { + const SpellEntry *spell = GetSpellStore()->LookupEntry(id); + for (int i=0; i<3; i++) + { + if (!spell->Effect[i]) + continue; + SentinelAbilityAura *a = new SentinelAbilityAura(this, (SpellEntry *)spell, id, i); + m_creature->AddAura(a); + } + if (id == SPELL_KNOCK_BUFF) + { + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); + } + } + + void Aggro(Unit *who) + { + if (gatherOthersWhenAggro) + GetOtherSentinels(who); + + GainSentinelAbility(ability); + DoZoneInCombat(); + } + + void JustDied(Unit*) + { + for (int ni=0; ni<3; ni++) + { + Creature *sent = nearby[ni]; + if (!sent) + continue; + if (sent->isDead()) + continue; + int h = sent->GetHealth() + (sent->GetMaxHealth() / 2); + if (h > sent->GetMaxHealth()) + h = sent->GetMaxHealth(); + sent->SetHealth(h); + ((aqsentinelAI *)sent->AI())->GainSentinelAbility(ability); + } + } + + Unit *GetHatedManaUser() + { + std::list::iterator i; + for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); + if (pUnit->getPowerType()==POWER_MANA) + return pUnit; + } + return NULL; + } +}; +CreatureAI* GetAI_mob_anubisath_sentinelAI(Creature *_Creature) +{ + return new aqsentinelAI (_Creature); +} + +void AddSC_mob_anubisath_sentinel() +{ + Script *newscript; + newscript = new Script; + newscript->Name="mob_anubisath_sentinel"; + newscript->GetAI = GetAI_mob_anubisath_sentinelAI; + m_scripts[nrscripts++] = newscript; +} + +SentinelAbilityAura::~SentinelAbilityAura() {} +Unit* SentinelAbilityAura::GetTriggerTarget() const +{ + switch (abilityId) + { + case SPELL_KNOCK_BUFF: + case SPELL_THUNDER_BUFF: + case SPELL_MSTRIKE_BUFF: + case SPELL_STORM_BUFF: + return aOwner->m_creature->getVictim(); + + case SPELL_MANAB_BUFF: + return aOwner->GetHatedManaUser(); + + case SPELL_MENDING_BUFF: + case SPELL_REFLECTAF_BUFF: + case SPELL_REFLECTSFr_BUFF: + case SPELL_THORNS_BUFF: + default: + return aOwner->m_creature; + } +} + +SentinelAbilityAura::SentinelAbilityAura(aqsentinelAI *abilityOwner, SpellEntry *spell, uint32 ability, uint32 eff) +: Aura(spell, eff, NULL, abilityOwner->m_creature, abilityOwner->m_creature, NULL) +{ + aOwner = abilityOwner; + abilityId = ability; + currentBasePoints = 0; +} diff --git a/src/bindings/scripts/scripts/zone/terokkar_forest/terokkar_forest.cpp b/src/bindings/scripts/scripts/zone/terokkar_forest/terokkar_forest.cpp index 2dc7e54297b..0dead7e7646 100644 --- a/src/bindings/scripts/scripts/zone/terokkar_forest/terokkar_forest.cpp +++ b/src/bindings/scripts/scripts/zone/terokkar_forest/terokkar_forest.cpp @@ -1,399 +1,399 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Terokkar_Forest -SD%Complete: 80 -SDComment: Quest support: 9889(test script only, sql inside script), 10009, 10873, 10896, 11096. Skettis->Ogri'la Flight -SDCategory: Terokkar Forest -EndScriptData */ - -/* ContentData -mob_unkor_the_ruthless -mob_infested_root_walker -mob_rotting_forest_rager -mob_netherweb_victim -npc_floon -npc_skyguard_handler_deesak -EndContentData */ - -#include "precompiled.h" - -/*###### -## mob_unkor_the_ruthless -######*/ - -/* -UPDATE `creature_template` SET `ScriptName`='mob_unkor_the_ruthless' WHERE `entry`=18262; -*/ - -#define SAY_SUBMIT "I give up! Please don't kill me!" - -#define FACTION_HOSTILE 45 -#define FACTION_FRIENDLY 35 -#define QUEST_DONTKILLTHEFATONE 9889 - -#define SPELL_PULVERIZE 2676 -//#define SPELL_QUID9889 32174 - -struct MANGOS_DLL_DECL mob_unkor_the_ruthlessAI : public ScriptedAI -{ - mob_unkor_the_ruthlessAI(Creature* c) : ScriptedAI(c) { Reset(); } - - bool CanDoQuest; - uint32 UnkorUnfriendly_Timer; - uint32 Pulverize_Timer; - - void Reset() - { - CanDoQuest = false; - UnkorUnfriendly_Timer = 0; - Pulverize_Timer = 3000; - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE); - m_creature->setFaction(FACTION_HOSTILE); - } - - void Aggro(Unit *who) {} - - void DoNice() - { - DoSay(SAY_SUBMIT,LANG_UNIVERSAL,NULL); - m_creature->setFaction(FACTION_FRIENDLY); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_SIT); - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - UnkorUnfriendly_Timer = 60000; - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if( done_by->GetTypeId() == TYPEID_PLAYER ) - if( (m_creature->GetHealth()-damage)*100 / m_creature->GetMaxHealth() < 30 ) - { - 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; - } - } - } - - void UpdateAI(const uint32 diff) - { - if( CanDoQuest ) - { - if( !UnkorUnfriendly_Timer ) - { - //DoCast(m_creature,SPELL_QUID9889); //not using spell for now - DoNice(); - } - else - { - if( UnkorUnfriendly_Timer < diff ) - { - EnterEvadeMode(); - }else UnkorUnfriendly_Timer -= diff; - } - } - - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( Pulverize_Timer < diff ) - { - DoCast(m_creature,SPELL_PULVERIZE); - Pulverize_Timer = 9000; - }else Pulverize_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_unkor_the_ruthless(Creature *_Creature) -{ - return new mob_unkor_the_ruthlessAI (_Creature); -} - -/*###### -## mob_infested_root_walker -######*/ - -struct MANGOS_DLL_DECL mob_infested_root_walkerAI : public ScriptedAI -{ - mob_infested_root_walkerAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() { } - void Aggro(Unit *who) { } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (done_by && done_by->GetTypeId() == TYPEID_PLAYER) - if (m_creature->GetHealth() <= damage) - if (rand()%100 < 75) - //Summon Wood Mites - m_creature->CastSpell(m_creature,39130,true); - } -}; -CreatureAI* GetAI_mob_infested_root_walker(Creature *_Creature) -{ - return new mob_infested_root_walkerAI (_Creature); -} - -/*###### -## mob_rotting_forest_rager -######*/ - -struct MANGOS_DLL_DECL mob_rotting_forest_ragerAI : public ScriptedAI -{ - mob_rotting_forest_ragerAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() { } - void Aggro(Unit *who) { } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (done_by->GetTypeId() == TYPEID_PLAYER) - if (m_creature->GetHealth() <= damage) - if (rand()%100 < 75) - //Summon Lots of Wood Mights - m_creature->CastSpell(m_creature,39134,true); - } -}; -CreatureAI* GetAI_mob_rotting_forest_rager(Creature *_Creature) -{ - return new mob_rotting_forest_ragerAI (_Creature); -} - -/*###### -## mob_netherweb_victim -######*/ - -#define QUEST_TARGET 22459 -//#define 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 *c) : ScriptedAI(c) {Reset();} - - void Reset() { } - void Aggro(Unit *who) { } - void MoveInLineOfSight(Unit *who) { } - - void JustDied(Unit* Killer) - { - if( Killer->GetTypeId() == TYPEID_PLAYER ) - { - if( ((Player*)Killer)->GetQuestStatus(10873) == QUEST_STATUS_INCOMPLETE ) - { - if( rand()%100 < 25 ) - { - DoSpawnCreature(QUEST_TARGET,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); - ((Player*)Killer)->KilledMonster(QUEST_TARGET, m_creature->GetGUID()); - }else - DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); - - if( rand()%100 < 75 ) - DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); - DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); - } - } - } -}; -CreatureAI* GetAI_mob_netherweb_victim(Creature *_Creature) -{ - return new mob_netherweb_victimAI (_Creature); -} - -/*###### -## npc_floon -######*/ - -#define GOSSIP_FLOON1 "You owe Sim'salabim money. Hand them over or die!" -#define GOSSIP_FLOON2 "Hand over the money or die...again!" -#define SAY_FLOON_ATTACK "I choose the third option: KILLING YOU!" - -#define FACTION_HOSTILE_FL 1738 -#define FACTION_FRIENDLY_FL 35 - -#define SPELL_SILENCE 6726 -#define SPELL_FROSTBOLT 9672 -#define SPELL_FROST_NOVA 11831 - -struct MANGOS_DLL_DECL npc_floonAI : public ScriptedAI -{ - npc_floonAI(Creature* c) : ScriptedAI(c) { Reset(); } - - uint32 Silence_Timer; - uint32 Frostbolt_Timer; - uint32 FrostNova_Timer; - - void Reset() - { - Silence_Timer = 2000; - Frostbolt_Timer = 4000; - FrostNova_Timer = 9000; - m_creature->setFaction(FACTION_FRIENDLY_FL); - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( Silence_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_SILENCE); - Silence_Timer = 30000; - }else Silence_Timer -= diff; - - if( FrostNova_Timer < diff ) - { - DoCast(m_creature,SPELL_FROST_NOVA); - FrostNova_Timer = 20000; - }else FrostNova_Timer -= diff; - - if( Frostbolt_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_FROSTBOLT); - Frostbolt_Timer = 5000; - }else Frostbolt_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_floon(Creature *_Creature) -{ - return new npc_floonAI (_Creature); -} - -bool GossipHello_npc_floon(Player *player, Creature *_Creature ) -{ - if( player->GetQuestStatus(10009) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM(1, GOSSIP_FLOON1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(9442, _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_floon(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_INFO_DEF ) - { - player->ADD_GOSSIP_ITEM(1, GOSSIP_FLOON2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(9443, _Creature->GetGUID()); - } - if( action == GOSSIP_ACTION_INFO_DEF+1 ) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->setFaction(FACTION_HOSTILE_FL); - ((npc_floonAI*)_Creature->AI())->DoSay(SAY_FLOON_ATTACK,LANG_UNIVERSAL,player); - ((npc_floonAI*)_Creature->AI())->AttackStart(player); - } - return true; -} - -/*###### -## npc_skyguard_handler_deesak -######*/ - -#define GOSSIP_SKYGUARD "Fly me to Ogri'la please" - -bool GossipHello_npc_skyguard_handler_deesak(Player *player, Creature *_Creature ) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetReputationRank(1031) >= REP_HONORED) - player->ADD_GOSSIP_ITEM( 2, GOSSIP_SKYGUARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_skyguard_handler_deesak(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player,41279,true); //TaxiPath 705 (Taxi - Skettis to Skyguard Outpost) - } - return true; -} - -/*###### -## AddSC -######*/ - -void AddSC_terokkar_forest() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_unkor_the_ruthless"; - newscript->GetAI = GetAI_mob_unkor_the_ruthless; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_infested_root_walker"; - newscript->GetAI = GetAI_mob_infested_root_walker; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_rotting_forest_rager"; - newscript->GetAI = GetAI_mob_rotting_forest_rager; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_netherweb_victim"; - newscript->GetAI = GetAI_mob_netherweb_victim; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_floon"; - newscript->pGossipHello = &GossipHello_npc_floon; - newscript->pGossipSelect = &GossipSelect_npc_floon; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_skyguard_handler_deesak"; - newscript->pGossipHello = &GossipHello_npc_skyguard_handler_deesak; - newscript->pGossipSelect = &GossipSelect_npc_skyguard_handler_deesak; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Terokkar_Forest +SD%Complete: 80 +SDComment: Quest support: 9889(test script only, sql inside script), 10009, 10873, 10896, 11096. Skettis->Ogri'la Flight +SDCategory: Terokkar Forest +EndScriptData */ + +/* ContentData +mob_unkor_the_ruthless +mob_infested_root_walker +mob_rotting_forest_rager +mob_netherweb_victim +npc_floon +npc_skyguard_handler_deesak +EndContentData */ + +#include "precompiled.h" + +/*###### +## mob_unkor_the_ruthless +######*/ + +/* +UPDATE `creature_template` SET `ScriptName`='mob_unkor_the_ruthless' WHERE `entry`=18262; +*/ + +#define SAY_SUBMIT "I give up! Please don't kill me!" + +#define FACTION_HOSTILE 45 +#define FACTION_FRIENDLY 35 +#define QUEST_DONTKILLTHEFATONE 9889 + +#define SPELL_PULVERIZE 2676 +//#define SPELL_QUID9889 32174 + +struct MANGOS_DLL_DECL mob_unkor_the_ruthlessAI : public ScriptedAI +{ + mob_unkor_the_ruthlessAI(Creature* c) : ScriptedAI(c) { Reset(); } + + bool CanDoQuest; + uint32 UnkorUnfriendly_Timer; + uint32 Pulverize_Timer; + + void Reset() + { + CanDoQuest = false; + UnkorUnfriendly_Timer = 0; + Pulverize_Timer = 3000; + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE); + m_creature->setFaction(FACTION_HOSTILE); + } + + void Aggro(Unit *who) {} + + void DoNice() + { + DoSay(SAY_SUBMIT,LANG_UNIVERSAL,NULL); + m_creature->setFaction(FACTION_FRIENDLY); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_SIT); + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + UnkorUnfriendly_Timer = 60000; + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if( done_by->GetTypeId() == TYPEID_PLAYER ) + if( (m_creature->GetHealth()-damage)*100 / m_creature->GetMaxHealth() < 30 ) + { + 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; + } + } + } + + void UpdateAI(const uint32 diff) + { + if( CanDoQuest ) + { + if( !UnkorUnfriendly_Timer ) + { + //DoCast(m_creature,SPELL_QUID9889); //not using spell for now + DoNice(); + } + else + { + if( UnkorUnfriendly_Timer < diff ) + { + EnterEvadeMode(); + }else UnkorUnfriendly_Timer -= diff; + } + } + + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( Pulverize_Timer < diff ) + { + DoCast(m_creature,SPELL_PULVERIZE); + Pulverize_Timer = 9000; + }else Pulverize_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_unkor_the_ruthless(Creature *_Creature) +{ + return new mob_unkor_the_ruthlessAI (_Creature); +} + +/*###### +## mob_infested_root_walker +######*/ + +struct MANGOS_DLL_DECL mob_infested_root_walkerAI : public ScriptedAI +{ + mob_infested_root_walkerAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() { } + void Aggro(Unit *who) { } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if (done_by && done_by->GetTypeId() == TYPEID_PLAYER) + if (m_creature->GetHealth() <= damage) + if (rand()%100 < 75) + //Summon Wood Mites + m_creature->CastSpell(m_creature,39130,true); + } +}; +CreatureAI* GetAI_mob_infested_root_walker(Creature *_Creature) +{ + return new mob_infested_root_walkerAI (_Creature); +} + +/*###### +## mob_rotting_forest_rager +######*/ + +struct MANGOS_DLL_DECL mob_rotting_forest_ragerAI : public ScriptedAI +{ + mob_rotting_forest_ragerAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() { } + void Aggro(Unit *who) { } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if (done_by->GetTypeId() == TYPEID_PLAYER) + if (m_creature->GetHealth() <= damage) + if (rand()%100 < 75) + //Summon Lots of Wood Mights + m_creature->CastSpell(m_creature,39134,true); + } +}; +CreatureAI* GetAI_mob_rotting_forest_rager(Creature *_Creature) +{ + return new mob_rotting_forest_ragerAI (_Creature); +} + +/*###### +## mob_netherweb_victim +######*/ + +#define QUEST_TARGET 22459 +//#define 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 *c) : ScriptedAI(c) {Reset();} + + void Reset() { } + void Aggro(Unit *who) { } + void MoveInLineOfSight(Unit *who) { } + + void JustDied(Unit* Killer) + { + if( Killer->GetTypeId() == TYPEID_PLAYER ) + { + if( ((Player*)Killer)->GetQuestStatus(10873) == QUEST_STATUS_INCOMPLETE ) + { + if( rand()%100 < 25 ) + { + DoSpawnCreature(QUEST_TARGET,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); + ((Player*)Killer)->KilledMonster(QUEST_TARGET, m_creature->GetGUID()); + }else + DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); + + if( rand()%100 < 75 ) + DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); + DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); + } + } + } +}; +CreatureAI* GetAI_mob_netherweb_victim(Creature *_Creature) +{ + return new mob_netherweb_victimAI (_Creature); +} + +/*###### +## npc_floon +######*/ + +#define GOSSIP_FLOON1 "You owe Sim'salabim money. Hand them over or die!" +#define GOSSIP_FLOON2 "Hand over the money or die...again!" +#define SAY_FLOON_ATTACK "I choose the third option: KILLING YOU!" + +#define FACTION_HOSTILE_FL 1738 +#define FACTION_FRIENDLY_FL 35 + +#define SPELL_SILENCE 6726 +#define SPELL_FROSTBOLT 9672 +#define SPELL_FROST_NOVA 11831 + +struct MANGOS_DLL_DECL npc_floonAI : public ScriptedAI +{ + npc_floonAI(Creature* c) : ScriptedAI(c) { Reset(); } + + uint32 Silence_Timer; + uint32 Frostbolt_Timer; + uint32 FrostNova_Timer; + + void Reset() + { + Silence_Timer = 2000; + Frostbolt_Timer = 4000; + FrostNova_Timer = 9000; + m_creature->setFaction(FACTION_FRIENDLY_FL); + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( Silence_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_SILENCE); + Silence_Timer = 30000; + }else Silence_Timer -= diff; + + if( FrostNova_Timer < diff ) + { + DoCast(m_creature,SPELL_FROST_NOVA); + FrostNova_Timer = 20000; + }else FrostNova_Timer -= diff; + + if( Frostbolt_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_FROSTBOLT); + Frostbolt_Timer = 5000; + }else Frostbolt_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_floon(Creature *_Creature) +{ + return new npc_floonAI (_Creature); +} + +bool GossipHello_npc_floon(Player *player, Creature *_Creature ) +{ + if( player->GetQuestStatus(10009) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM(1, GOSSIP_FLOON1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(9442, _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_floon(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF ) + { + player->ADD_GOSSIP_ITEM(1, GOSSIP_FLOON2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(9443, _Creature->GetGUID()); + } + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->setFaction(FACTION_HOSTILE_FL); + ((npc_floonAI*)_Creature->AI())->DoSay(SAY_FLOON_ATTACK,LANG_UNIVERSAL,player); + ((npc_floonAI*)_Creature->AI())->AttackStart(player); + } + return true; +} + +/*###### +## npc_skyguard_handler_deesak +######*/ + +#define GOSSIP_SKYGUARD "Fly me to Ogri'la please" + +bool GossipHello_npc_skyguard_handler_deesak(Player *player, Creature *_Creature ) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetReputationRank(1031) >= REP_HONORED) + player->ADD_GOSSIP_ITEM( 2, GOSSIP_SKYGUARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_skyguard_handler_deesak(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player,41279,true); //TaxiPath 705 (Taxi - Skettis to Skyguard Outpost) + } + return true; +} + +/*###### +## AddSC +######*/ + +void AddSC_terokkar_forest() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_unkor_the_ruthless"; + newscript->GetAI = GetAI_mob_unkor_the_ruthless; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_infested_root_walker"; + newscript->GetAI = GetAI_mob_infested_root_walker; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_rotting_forest_rager"; + newscript->GetAI = GetAI_mob_rotting_forest_rager; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_netherweb_victim"; + newscript->GetAI = GetAI_mob_netherweb_victim; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_floon"; + newscript->pGossipHello = &GossipHello_npc_floon; + newscript->pGossipSelect = &GossipSelect_npc_floon; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_skyguard_handler_deesak"; + newscript->pGossipHello = &GossipHello_npc_skyguard_handler_deesak; + newscript->pGossipSelect = &GossipSelect_npc_skyguard_handler_deesak; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/thunder_bluff/thunder_bluff.cpp b/src/bindings/scripts/scripts/zone/thunder_bluff/thunder_bluff.cpp index b526325f5c9..8462cc68a2f 100644 --- a/src/bindings/scripts/scripts/zone/thunder_bluff/thunder_bluff.cpp +++ b/src/bindings/scripts/scripts/zone/thunder_bluff/thunder_bluff.cpp @@ -1,136 +1,136 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Thunder_Bluff -SD%Complete: 100 -SDComment: Quest support: 925 -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* c) : ScriptedAI(c) { 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 Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( BerserkerCharge_Timer < diff ) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0); - if( target ) - DoCast(target,SPELL_BERSERKER_CHARGE); - BerserkerCharge_Timer = 25000; - }else BerserkerCharge_Timer -= diff; - - if( Uppercut_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_UPPERCUT); - Uppercut_Timer = 20000; - }else Uppercut_Timer -= diff; - - if( Thunderclap_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); - Thunderclap_Timer = 15000; - }else Thunderclap_Timer -= diff; - - if( MortalStrike_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_MORTAL_STRIKE); - MortalStrike_Timer = 15000; - }else MortalStrike_Timer -= diff; - - if( Cleave_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_cairne_bloodhoof(Creature *_Creature) -{ - return new npc_cairne_bloodhoofAI (_Creature); -} - -bool GossipHello_npc_cairne_bloodhoof(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if( player->GetQuestStatus(925) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM( 0, "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 ); - - player->SEND_GOSSIP_MENU(7013, _Creature->GetGUID() ); - - return true; -} - -bool GossipSelect_npc_cairne_bloodhoof(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_SENDER_INFO ) - { - player->CastSpell(player, 23123, false); - player->SEND_GOSSIP_MENU(7014, _Creature->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; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Thunder_Bluff +SD%Complete: 100 +SDComment: Quest support: 925 +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* c) : ScriptedAI(c) { 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 Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( BerserkerCharge_Timer < diff ) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0); + if( target ) + DoCast(target,SPELL_BERSERKER_CHARGE); + BerserkerCharge_Timer = 25000; + }else BerserkerCharge_Timer -= diff; + + if( Uppercut_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_UPPERCUT); + Uppercut_Timer = 20000; + }else Uppercut_Timer -= diff; + + if( Thunderclap_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_THUNDERCLAP); + Thunderclap_Timer = 15000; + }else Thunderclap_Timer -= diff; + + if( MortalStrike_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_MORTAL_STRIKE); + MortalStrike_Timer = 15000; + }else MortalStrike_Timer -= diff; + + if( Cleave_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 7000; + }else Cleave_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_cairne_bloodhoof(Creature *_Creature) +{ + return new npc_cairne_bloodhoofAI (_Creature); +} + +bool GossipHello_npc_cairne_bloodhoof(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->GetQuestStatus(925) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM( 0, "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 ); + + player->SEND_GOSSIP_MENU(7013, _Creature->GetGUID() ); + + return true; +} + +bool GossipSelect_npc_cairne_bloodhoof(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_SENDER_INFO ) + { + player->CastSpell(player, 23123, false); + player->SEND_GOSSIP_MENU(7014, _Creature->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; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/tirisfal_glades/tirisfal_glades.cpp b/src/bindings/scripts/scripts/zone/tirisfal_glades/tirisfal_glades.cpp index 8a02147eb41..2e9691852c2 100644 --- a/src/bindings/scripts/scripts/zone/tirisfal_glades/tirisfal_glades.cpp +++ b/src/bindings/scripts/scripts/zone/tirisfal_glades/tirisfal_glades.cpp @@ -1,88 +1,88 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Tirisfal_Glades -SD%Complete: 100 -SDComment: Quest support: 590 -SDCategory: Tirisfal Glades -EndScriptData */ - -/* ContentData -npc_calvin_montague -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_calvin_montague -######*/ - -#define QUEST_590 590 -#define FACTION_FRIENDLY 68 -#define FACTION_HOSTILE 16 - -struct MANGOS_DLL_DECL npc_calvin_montagueAI : public ScriptedAI -{ - npc_calvin_montagueAI(Creature* c) : ScriptedAI(c) { Reset(); } - - void Reset() - { - m_creature->setFaction(FACTION_FRIENDLY); - } - - void Aggro(Unit* who) { } - - void JustDied(Unit* Killer) - { - if( Killer->GetTypeId() == TYPEID_PLAYER ) - if( ((Player*)Killer)->GetQuestStatus(QUEST_590) == QUEST_STATUS_INCOMPLETE ) - ((Player*)Killer)->AreaExploredOrEventHappens(QUEST_590); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_calvin_montague(Creature *_Creature) -{ - return new npc_calvin_montagueAI (_Creature); -} - -bool QuestAccept_npc_calvin_montague(Player* player, Creature* creature, Quest const* quest) -{ - if( quest->GetQuestId() == QUEST_590 ) - { - creature->setFaction(FACTION_HOSTILE); - ((npc_calvin_montagueAI*)creature->AI())->AttackStart(player); - } - return true; -} - -void AddSC_tirisfal_glades() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_calvin_montague"; - newscript->GetAI = GetAI_npc_calvin_montague; - newscript->pQuestAccept = &QuestAccept_npc_calvin_montague; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Tirisfal_Glades +SD%Complete: 100 +SDComment: Quest support: 590 +SDCategory: Tirisfal Glades +EndScriptData */ + +/* ContentData +npc_calvin_montague +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_calvin_montague +######*/ + +#define QUEST_590 590 +#define FACTION_FRIENDLY 68 +#define FACTION_HOSTILE 16 + +struct MANGOS_DLL_DECL npc_calvin_montagueAI : public ScriptedAI +{ + npc_calvin_montagueAI(Creature* c) : ScriptedAI(c) { Reset(); } + + void Reset() + { + m_creature->setFaction(FACTION_FRIENDLY); + } + + void Aggro(Unit* who) { } + + void JustDied(Unit* Killer) + { + if( Killer->GetTypeId() == TYPEID_PLAYER ) + if( ((Player*)Killer)->GetQuestStatus(QUEST_590) == QUEST_STATUS_INCOMPLETE ) + ((Player*)Killer)->AreaExploredOrEventHappens(QUEST_590); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_calvin_montague(Creature *_Creature) +{ + return new npc_calvin_montagueAI (_Creature); +} + +bool QuestAccept_npc_calvin_montague(Player* player, Creature* creature, Quest const* quest) +{ + if( quest->GetQuestId() == QUEST_590 ) + { + creature->setFaction(FACTION_HOSTILE); + ((npc_calvin_montagueAI*)creature->AI())->AttackStart(player); + } + return true; +} + +void AddSC_tirisfal_glades() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_calvin_montague"; + newscript->GetAI = GetAI_npc_calvin_montague; + newscript->pQuestAccept = &QuestAccept_npc_calvin_montague; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/uldaman/boss_ironaya.cpp b/src/bindings/scripts/scripts/zone/uldaman/boss_ironaya.cpp index 57871381f9d..fce9a9f29af 100644 --- a/src/bindings/scripts/scripts/zone/uldaman/boss_ironaya.cpp +++ b/src/bindings/scripts/scripts/zone/uldaman/boss_ironaya.cpp @@ -1,107 +1,107 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Ironaya -SD%Complete: 100 -SDComment: -SDCategory: Uldaman -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_ARCINGSMASH 39144 -#define SPELL_KNOCKAWAY 22893 -#define SPELL_WSTOMP 16727 - -#define SAY_AGGRO "None may steal the secrets of the makers!" -#define SOUND_AGGRO 5851 - -struct MANGOS_DLL_DECL boss_ironayaAI : public ScriptedAI -{ - boss_ironayaAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Arcing_Timer; - bool hasCastedWstomp; - bool hasCastedKnockaway; - - void Reset() - { - Arcing_Timer = 3000; - hasCastedKnockaway = false; - hasCastedWstomp = false; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //If we are <50% hp do knockaway ONCE - if (!hasCastedKnockaway && m_creature->GetHealth()*2 < m_creature->GetMaxHealth()) - { - m_creature->CastSpell(m_creature->getVictim(),SPELL_KNOCKAWAY, true); - - // current aggro target is knocked away pick new target - Unit* Target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); - - if (!Target || Target == m_creature->getVictim()) - Target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); - - if (Target) - m_creature->TauntApply(Target); - - //Shouldn't cast this agian - hasCastedKnockaway = true; - } - - //Arcing_Timer - if (Arcing_Timer < diff) - { - DoCast(m_creature,SPELL_ARCINGSMASH); - Arcing_Timer = 13000; - }else Arcing_Timer -= diff; - - if (!hasCastedWstomp && m_creature->GetHealth()*4 < m_creature->GetMaxHealth()) - { - DoCast(m_creature,SPELL_WSTOMP); - hasCastedWstomp = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_ironaya(Creature *_Creature) -{ - return new boss_ironayaAI (_Creature); -} - -void AddSC_boss_ironaya() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_ironaya"; - newscript->GetAI = GetAI_boss_ironaya; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Ironaya +SD%Complete: 100 +SDComment: +SDCategory: Uldaman +EndScriptData */ + +#include "precompiled.h" + +#define SPELL_ARCINGSMASH 39144 +#define SPELL_KNOCKAWAY 22893 +#define SPELL_WSTOMP 16727 + +#define SAY_AGGRO "None may steal the secrets of the makers!" +#define SOUND_AGGRO 5851 + +struct MANGOS_DLL_DECL boss_ironayaAI : public ScriptedAI +{ + boss_ironayaAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Arcing_Timer; + bool hasCastedWstomp; + bool hasCastedKnockaway; + + void Reset() + { + Arcing_Timer = 3000; + hasCastedKnockaway = false; + hasCastedWstomp = false; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //If we are <50% hp do knockaway ONCE + if (!hasCastedKnockaway && m_creature->GetHealth()*2 < m_creature->GetMaxHealth()) + { + m_creature->CastSpell(m_creature->getVictim(),SPELL_KNOCKAWAY, true); + + // current aggro target is knocked away pick new target + Unit* Target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); + + if (!Target || Target == m_creature->getVictim()) + Target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1); + + if (Target) + m_creature->TauntApply(Target); + + //Shouldn't cast this agian + hasCastedKnockaway = true; + } + + //Arcing_Timer + if (Arcing_Timer < diff) + { + DoCast(m_creature,SPELL_ARCINGSMASH); + Arcing_Timer = 13000; + }else Arcing_Timer -= diff; + + if (!hasCastedWstomp && m_creature->GetHealth()*4 < m_creature->GetMaxHealth()) + { + DoCast(m_creature,SPELL_WSTOMP); + hasCastedWstomp = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ironaya(Creature *_Creature) +{ + return new boss_ironayaAI (_Creature); +} + +void AddSC_boss_ironaya() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_ironaya"; + newscript->GetAI = GetAI_boss_ironaya; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/uldaman/uldaman.cpp b/src/bindings/scripts/scripts/zone/uldaman/uldaman.cpp index 59bad6854fb..16e0c8bee7b 100644 --- a/src/bindings/scripts/scripts/zone/uldaman/uldaman.cpp +++ b/src/bindings/scripts/scripts/zone/uldaman/uldaman.cpp @@ -1,187 +1,187 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Uldaman -SD%Complete: 100 -SDComment: Quest support: 2278 + 1 trash mob. -SDCategory: Uldaman -EndScriptData */ - -/* ContentData -mob_jadespine_basilisk -npc_lore_keeper_of_norgannon -EndContentData */ - -#include "precompiled.h" - -/*###### -## mob_jadespine_basilisk -######*/ - -#define SPELL_CSLUMBER 3636 - -struct MANGOS_DLL_DECL mob_jadespine_basiliskAI : public ScriptedAI -{ - mob_jadespine_basiliskAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Cslumber_Timer; - - void Reset() - { - Cslumber_Timer = 2000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Cslumber_Timer - if (Cslumber_Timer < diff) - { - //Cast - // DoCast(m_creature->getVictim(),SPELL_CSLUMBER); - m_creature->CastSpell(m_creature->getVictim(),SPELL_CSLUMBER, true); - - //Stop attacking target thast asleep and pick new target - Cslumber_Timer = 28000; - - Unit* Target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); - - if (!Target || Target == m_creature->getVictim()) - Target = SelectUnit(SELECT_TARGET_RANDOM, 0); - - if (Target) - m_creature->TauntApply(Target); - - }else Cslumber_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_jadespine_basilisk(Creature *_Creature) -{ - return new mob_jadespine_basiliskAI (_Creature); -} - -/*###### -## npc_lore_keeper_of_norgannon -######*/ - -bool GossipHello_npc_lore_keeper_of_norgannon(Player *player, Creature *_Creature) -{ - if (player->GetQuestStatus(2278) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Who are the Earthen?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(1079, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lore_keeper_of_norgannon(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "What is a \"subterranean being matrix\"?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(1080, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "What are the anomalies you speak of?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(1081, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "What is a resilient foundation of construction?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(1082, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM( 0, "So... the Earthen were made out of stone?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(1083, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM( 0, "Anything else I should know about the Earthen?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - player->SEND_GOSSIP_MENU(1084, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(1085, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - player->ADD_GOSSIP_ITEM( 0, "What high-stress environments would cause the Earthen to destabilize?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+8); - player->SEND_GOSSIP_MENU(1086, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+8: - player->ADD_GOSSIP_ITEM( 0, "What happens when the Earthen destabilize?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); - player->SEND_GOSSIP_MENU(1087, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+9: - player->ADD_GOSSIP_ITEM( 0, "Troggs?! Are the troggs you mention the same as the ones in the world today?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+10); - player->SEND_GOSSIP_MENU(1088, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+10: - player->ADD_GOSSIP_ITEM( 0, "You mentioned two results when the Earthen destabilize. What is the second?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+11); - player->SEND_GOSSIP_MENU(1089, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - player->ADD_GOSSIP_ITEM( 0, "Dwarves!!! Now you're telling me that dwarves originally came from the Earthen?!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+12); - player->SEND_GOSSIP_MENU(1090, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+12: - player->ADD_GOSSIP_ITEM( 0, "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); - player->SEND_GOSSIP_MENU(1091, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+13: - player->ADD_GOSSIP_ITEM( 0, "Who are the Creators?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+14); - player->SEND_GOSSIP_MENU(1092, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+14: - player->ADD_GOSSIP_ITEM( 0, "This is a lot to think about.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+15); - player->SEND_GOSSIP_MENU(1093, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+15: - player->ADD_GOSSIP_ITEM( 0, "I will access the discs now.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+16); - player->SEND_GOSSIP_MENU(1094, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+16: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(2278); - break; - } - return true; -} - -void AddSC_uldaman() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="mob_jadespine_basilisk"; - newscript->GetAI = GetAI_mob_jadespine_basilisk; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_lore_keeper_of_norgannon"; - newscript->pGossipHello = &GossipHello_npc_lore_keeper_of_norgannon; - newscript->pGossipSelect = &GossipSelect_npc_lore_keeper_of_norgannon; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Uldaman +SD%Complete: 100 +SDComment: Quest support: 2278 + 1 trash mob. +SDCategory: Uldaman +EndScriptData */ + +/* ContentData +mob_jadespine_basilisk +npc_lore_keeper_of_norgannon +EndContentData */ + +#include "precompiled.h" + +/*###### +## mob_jadespine_basilisk +######*/ + +#define SPELL_CSLUMBER 3636 + +struct MANGOS_DLL_DECL mob_jadespine_basiliskAI : public ScriptedAI +{ + mob_jadespine_basiliskAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Cslumber_Timer; + + void Reset() + { + Cslumber_Timer = 2000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Cslumber_Timer + if (Cslumber_Timer < diff) + { + //Cast + // DoCast(m_creature->getVictim(),SPELL_CSLUMBER); + m_creature->CastSpell(m_creature->getVictim(),SPELL_CSLUMBER, true); + + //Stop attacking target thast asleep and pick new target + Cslumber_Timer = 28000; + + Unit* Target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); + + if (!Target || Target == m_creature->getVictim()) + Target = SelectUnit(SELECT_TARGET_RANDOM, 0); + + if (Target) + m_creature->TauntApply(Target); + + }else Cslumber_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_jadespine_basilisk(Creature *_Creature) +{ + return new mob_jadespine_basiliskAI (_Creature); +} + +/*###### +## npc_lore_keeper_of_norgannon +######*/ + +bool GossipHello_npc_lore_keeper_of_norgannon(Player *player, Creature *_Creature) +{ + if (player->GetQuestStatus(2278) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Who are the Earthen?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(1079, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_lore_keeper_of_norgannon(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "What is a \"subterranean being matrix\"?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(1080, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "What are the anomalies you speak of?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(1081, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "What is a resilient foundation of construction?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(1082, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM( 0, "So... the Earthen were made out of stone?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(1083, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->ADD_GOSSIP_ITEM( 0, "Anything else I should know about the Earthen?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + player->SEND_GOSSIP_MENU(1084, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+6: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(1085, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+7: + player->ADD_GOSSIP_ITEM( 0, "What high-stress environments would cause the Earthen to destabilize?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+8); + player->SEND_GOSSIP_MENU(1086, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+8: + player->ADD_GOSSIP_ITEM( 0, "What happens when the Earthen destabilize?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); + player->SEND_GOSSIP_MENU(1087, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+9: + player->ADD_GOSSIP_ITEM( 0, "Troggs?! Are the troggs you mention the same as the ones in the world today?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+10); + player->SEND_GOSSIP_MENU(1088, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+10: + player->ADD_GOSSIP_ITEM( 0, "You mentioned two results when the Earthen destabilize. What is the second?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+11); + player->SEND_GOSSIP_MENU(1089, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+11: + player->ADD_GOSSIP_ITEM( 0, "Dwarves!!! Now you're telling me that dwarves originally came from the Earthen?!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+12); + player->SEND_GOSSIP_MENU(1090, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+12: + player->ADD_GOSSIP_ITEM( 0, "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); + player->SEND_GOSSIP_MENU(1091, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+13: + player->ADD_GOSSIP_ITEM( 0, "Who are the Creators?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+14); + player->SEND_GOSSIP_MENU(1092, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+14: + player->ADD_GOSSIP_ITEM( 0, "This is a lot to think about.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+15); + player->SEND_GOSSIP_MENU(1093, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+15: + player->ADD_GOSSIP_ITEM( 0, "I will access the discs now.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+16); + player->SEND_GOSSIP_MENU(1094, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+16: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(2278); + break; + } + return true; +} + +void AddSC_uldaman() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="mob_jadespine_basilisk"; + newscript->GetAI = GetAI_mob_jadespine_basilisk; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_lore_keeper_of_norgannon"; + newscript->pGossipHello = &GossipHello_npc_lore_keeper_of_norgannon; + newscript->pGossipSelect = &GossipSelect_npc_lore_keeper_of_norgannon; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/undercity/undercity.cpp b/src/bindings/scripts/scripts/zone/undercity/undercity.cpp index b4845317612..93ef0584c99 100644 --- a/src/bindings/scripts/scripts/zone/undercity/undercity.cpp +++ b/src/bindings/scripts/scripts/zone/undercity/undercity.cpp @@ -1,260 +1,260 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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). -SDCategory: Undercity -EndScriptData */ - -/* ContentData -npc_lady_sylvanas_windrunner -npc_highborne_lamenter -npc_parqual_fintallas -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_lady_sylvanas_windrunner -######*/ - -#define SAY_LAMENT_END "Belore..." -#define EMOTE_LAMENT_END "kneels down and pick up the amulet." - -#define SOUND_CREDIT 10896 -#define ENTRY_HIGHBORNE_LAMENTER 21628 -#define ENTRY_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 - -float HighborneLoc[4][3]= -{ - {1285.41, 312.47, 0.51}, - {1286.96, 310.40, 1.00}, - {1289.66, 309.66, 1.52}, - {1292.51, 310.50, 1.99}, -}; -#define HIGHBORNE_LOC_Y -61.00 -#define HIGHBORNE_LOC_Y_NEW -55.50 - -struct MANGOS_DLL_DECL npc_lady_sylvanas_windrunnerAI : public ScriptedAI -{ - npc_lady_sylvanas_windrunnerAI(Creature *c) : ScriptedAI(c) { Reset(); } - - uint32 LamentEvent_Timer; - bool LamentEvent; - uint64 targetGUID; - - float myX; - float myY; - float myZ; - - void Reset() - { - myX = m_creature->GetPositionX(); - myY = m_creature->GetPositionY(); - myZ = m_creature->GetPositionZ(); - - LamentEvent_Timer = 5000; - LamentEvent = false; - targetGUID = 0; - } - - void Aggro(Unit *who) {} - - void JustSummoned(Creature *summoned) - { - if( summoned->GetEntry() == ENTRY_HIGHBORNE_BUNNY ) - { - if( Unit* target = Unit::GetUnit(*summoned,targetGUID) ) - { - target->SendMonsterMove(target->GetPositionX(),target->GetPositionY(),myZ+15.0,0,0,0); - target->Relocate(target->GetPositionX(),target->GetPositionY(),myZ+15.0); - summoned->CastSpell(target,SPELL_RIBBON_OF_SOULS,false); - } - - summoned->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - targetGUID = summoned->GetGUID(); - } - } - - void UpdateAI(const uint32 diff) - { - if( LamentEvent ) - { - if( LamentEvent_Timer < diff ) - { - float raX = myX; - float raY = myY; - float raZ = myZ; - - 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); - - LamentEvent_Timer = 2000; - if( !m_creature->HasAura(SPELL_SYLVANAS_CAST,0) ) - { - DoSay(SAY_LAMENT_END,LANG_UNIVERSAL,NULL); - DoTextEmote(EMOTE_LAMENT_END,NULL); - LamentEvent = false; - } - }else LamentEvent_Timer -= diff; - } - - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_lady_sylvanas_windrunner(Creature *_Creature) -{ - return new npc_lady_sylvanas_windrunnerAI (_Creature); -} - -bool ChooseReward_npc_lady_sylvanas_windrunner(Player *player, Creature *_Creature, const Quest *_Quest, uint32 slot) -{ - if( _Quest->GetQuestId() == 9180 ) - { - ((npc_lady_sylvanas_windrunnerAI*)_Creature->AI())->LamentEvent = true; - ((npc_lady_sylvanas_windrunnerAI*)_Creature->AI())->DoPlaySoundToSet(_Creature,SOUND_CREDIT); - _Creature->CastSpell(_Creature,SPELL_SYLVANAS_CAST,false); - - for( uint8 i = 0; i < 4; i++ ) - _Creature->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 *c) : ScriptedAI(c) { Reset(); } - - uint32 EventMove_Timer; - uint32 EventCast_Timer; - bool EventMove; - bool EventCast; - - void Reset() - { - EventMove_Timer = 10000; - EventCast_Timer = 17500; - EventMove = true; - EventCast = true; - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if( EventMove ) - { - if( EventMove_Timer < diff ) - { - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT | MOVEMENTFLAG_LEVITATING); - m_creature->SendMonsterMoveWithSpeed(m_creature->GetPositionX(),m_creature->GetPositionY(),HIGHBORNE_LOC_Y_NEW,MOVEMENTFLAG_ONTRANSPORT,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( EventCast ) - { - if( EventCast_Timer < diff ) - { - DoCast(m_creature,SPELL_HIGHBORNE_AURA); - EventCast = false; - }else EventCast_Timer -= diff; - } - } -}; -CreatureAI* GetAI_npc_highborne_lamenter(Creature *_Creature) -{ - return new npc_highborne_lamenterAI (_Creature); -} - -/*###### -## npc_parqual_fintallas -######*/ - -#define SPELL_MARK_OF_SHAME 6767 - -bool GossipHello_npc_parqual_fintallas(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(6628) == QUEST_STATUS_INCOMPLETE && !player->HasAura(SPELL_MARK_OF_SHAME,0) ) - { - player->ADD_GOSSIP_ITEM( 0, "Gul'dan", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM( 0, "Kel'Thuzad", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM( 0, "Ner'zhul", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(5822, _Creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(5821, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_parqual_fintallas(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player,SPELL_MARK_OF_SHAME,false); - } - if (action == GOSSIP_ACTION_INFO_DEF+2) - { - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(6628); - } - 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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_highborne_lamenter"; - newscript->GetAI = GetAI_npc_highborne_lamenter; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_parqual_fintallas"; - newscript->pGossipHello = &GossipHello_npc_parqual_fintallas; - newscript->pGossipSelect = &GossipSelect_npc_parqual_fintallas; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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). +SDCategory: Undercity +EndScriptData */ + +/* ContentData +npc_lady_sylvanas_windrunner +npc_highborne_lamenter +npc_parqual_fintallas +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_lady_sylvanas_windrunner +######*/ + +#define SAY_LAMENT_END "Belore..." +#define EMOTE_LAMENT_END "kneels down and pick up the amulet." + +#define SOUND_CREDIT 10896 +#define ENTRY_HIGHBORNE_LAMENTER 21628 +#define ENTRY_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 + +float HighborneLoc[4][3]= +{ + {1285.41, 312.47, 0.51}, + {1286.96, 310.40, 1.00}, + {1289.66, 309.66, 1.52}, + {1292.51, 310.50, 1.99}, +}; +#define HIGHBORNE_LOC_Y -61.00 +#define HIGHBORNE_LOC_Y_NEW -55.50 + +struct MANGOS_DLL_DECL npc_lady_sylvanas_windrunnerAI : public ScriptedAI +{ + npc_lady_sylvanas_windrunnerAI(Creature *c) : ScriptedAI(c) { Reset(); } + + uint32 LamentEvent_Timer; + bool LamentEvent; + uint64 targetGUID; + + float myX; + float myY; + float myZ; + + void Reset() + { + myX = m_creature->GetPositionX(); + myY = m_creature->GetPositionY(); + myZ = m_creature->GetPositionZ(); + + LamentEvent_Timer = 5000; + LamentEvent = false; + targetGUID = 0; + } + + void Aggro(Unit *who) {} + + void JustSummoned(Creature *summoned) + { + if( summoned->GetEntry() == ENTRY_HIGHBORNE_BUNNY ) + { + if( Unit* target = Unit::GetUnit(*summoned,targetGUID) ) + { + target->SendMonsterMove(target->GetPositionX(),target->GetPositionY(),myZ+15.0,0,0,0); + target->Relocate(target->GetPositionX(),target->GetPositionY(),myZ+15.0); + summoned->CastSpell(target,SPELL_RIBBON_OF_SOULS,false); + } + + summoned->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + targetGUID = summoned->GetGUID(); + } + } + + void UpdateAI(const uint32 diff) + { + if( LamentEvent ) + { + if( LamentEvent_Timer < diff ) + { + float raX = myX; + float raY = myY; + float raZ = myZ; + + 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); + + LamentEvent_Timer = 2000; + if( !m_creature->HasAura(SPELL_SYLVANAS_CAST,0) ) + { + DoSay(SAY_LAMENT_END,LANG_UNIVERSAL,NULL); + DoTextEmote(EMOTE_LAMENT_END,NULL); + LamentEvent = false; + } + }else LamentEvent_Timer -= diff; + } + + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_lady_sylvanas_windrunner(Creature *_Creature) +{ + return new npc_lady_sylvanas_windrunnerAI (_Creature); +} + +bool ChooseReward_npc_lady_sylvanas_windrunner(Player *player, Creature *_Creature, const Quest *_Quest, uint32 slot) +{ + if( _Quest->GetQuestId() == 9180 ) + { + ((npc_lady_sylvanas_windrunnerAI*)_Creature->AI())->LamentEvent = true; + ((npc_lady_sylvanas_windrunnerAI*)_Creature->AI())->DoPlaySoundToSet(_Creature,SOUND_CREDIT); + _Creature->CastSpell(_Creature,SPELL_SYLVANAS_CAST,false); + + for( uint8 i = 0; i < 4; i++ ) + _Creature->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 *c) : ScriptedAI(c) { Reset(); } + + uint32 EventMove_Timer; + uint32 EventCast_Timer; + bool EventMove; + bool EventCast; + + void Reset() + { + EventMove_Timer = 10000; + EventCast_Timer = 17500; + EventMove = true; + EventCast = true; + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if( EventMove ) + { + if( EventMove_Timer < diff ) + { + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT | MOVEMENTFLAG_LEVITATING); + m_creature->SendMonsterMoveWithSpeed(m_creature->GetPositionX(),m_creature->GetPositionY(),HIGHBORNE_LOC_Y_NEW,MOVEMENTFLAG_ONTRANSPORT,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( EventCast ) + { + if( EventCast_Timer < diff ) + { + DoCast(m_creature,SPELL_HIGHBORNE_AURA); + EventCast = false; + }else EventCast_Timer -= diff; + } + } +}; +CreatureAI* GetAI_npc_highborne_lamenter(Creature *_Creature) +{ + return new npc_highborne_lamenterAI (_Creature); +} + +/*###### +## npc_parqual_fintallas +######*/ + +#define SPELL_MARK_OF_SHAME 6767 + +bool GossipHello_npc_parqual_fintallas(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(6628) == QUEST_STATUS_INCOMPLETE && !player->HasAura(SPELL_MARK_OF_SHAME,0) ) + { + player->ADD_GOSSIP_ITEM( 0, "Gul'dan", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM( 0, "Kel'Thuzad", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM( 0, "Ner'zhul", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(5822, _Creature->GetGUID()); + } + else + player->SEND_GOSSIP_MENU(5821, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_parqual_fintallas(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player,SPELL_MARK_OF_SHAME,false); + } + if (action == GOSSIP_ACTION_INFO_DEF+2) + { + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(6628); + } + 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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_highborne_lamenter"; + newscript->GetAI = GetAI_npc_highborne_lamenter; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_parqual_fintallas"; + newscript->pGossipHello = &GossipHello_npc_parqual_fintallas; + newscript->pGossipSelect = &GossipSelect_npc_parqual_fintallas; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/wailing_caverns/instance_wailing_caverns.cpp b/src/bindings/scripts/scripts/zone/wailing_caverns/instance_wailing_caverns.cpp index a67db38d4ed..963accb14a8 100644 --- a/src/bindings/scripts/scripts/zone/wailing_caverns/instance_wailing_caverns.cpp +++ b/src/bindings/scripts/scripts/zone/wailing_caverns/instance_wailing_caverns.cpp @@ -1,24 +1,24 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Wailing_Caverns -SD%Complete: 0 -SDComment: Placeholder -SDCategory: Wailing Caverns -EndScriptData */ - -#include "precompiled.h" +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Wailing_Caverns +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Wailing Caverns +EndScriptData */ + +#include "precompiled.h" diff --git a/src/bindings/scripts/scripts/zone/western_plaguelands/western_plaguelands.cpp b/src/bindings/scripts/scripts/zone/western_plaguelands/western_plaguelands.cpp index d6a20fb5cca..e0eede13e5d 100644 --- a/src/bindings/scripts/scripts/zone/western_plaguelands/western_plaguelands.cpp +++ b/src/bindings/scripts/scripts/zone/western_plaguelands/western_plaguelands.cpp @@ -1,176 +1,176 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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) -SDCategory: Western Plaguelands -EndScriptData */ - -/* ContentData -npcs_dithers_and_arbington -npc_the_scourge_cauldron -EndContentData */ - -#include "precompiled.h" - -/*###### -## npcs_dithers_and_arbington -######*/ - -bool GossipHello_npcs_dithers_and_arbington(Player *player, Creature *_Creature) -{ - if(_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - if (_Creature->isVendor()) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - if(player->GetQuestRewardStatus(5237) || player->GetQuestRewardStatus(5238)) - { - player->ADD_GOSSIP_ITEM(0, "What does the Felstone Field Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM(0, "What does the Dalson's Tears Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->ADD_GOSSIP_ITEM(0, "What does the Writhing Haunt Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->ADD_GOSSIP_ITEM(0, "What does the Gahrron's Withering Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(3985, _Creature->GetGUID()); - }else - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npcs_dithers_and_arbington(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch(action) - { - case GOSSIP_ACTION_TRADE: - player->SEND_VENDORLIST( _Creature->GetGUID() ); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(0, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(3980, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(0, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(3981, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(0, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(3982, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(0, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(3983, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player, 17529, false); - break; - } - return true; -} - -/*###### -## npc_the_scourge_cauldron -######*/ - -struct MANGOS_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI -{ - npc_the_scourge_cauldronAI(Creature *c) : ScriptedAI(c) {Reset();} - - void Reset() {} - - void Aggro(Unit* who) {} - - void DoDie() - { - //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); - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || who->GetTypeId() != TYPEID_PLAYER) - return; - - 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 ) - { - DoSpawnCreature(11075,0,0,0,m_creature->GetOrientation(),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 ) - { - DoSpawnCreature(11077,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - DoDie(); - } - break; - case 201: //gahrron - if( ((Player*)who)->GetQuestStatus(5225) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5235) == QUEST_STATUS_INCOMPLETE ) - { - DoSpawnCreature(11078,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - DoDie(); - } - break; - case 202: //writhing - if( ((Player*)who)->GetQuestStatus(5222) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5233) == QUEST_STATUS_INCOMPLETE ) - { - DoSpawnCreature(11076,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - DoDie(); - } - break; - } - } - } -}; -CreatureAI* GetAI_npc_the_scourge_cauldron(Creature *_Creature) -{ - return new npc_the_scourge_cauldronAI (_Creature); -} - -/*###### -## -######*/ - -void AddSC_western_plaguelands() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npcs_dithers_and_arbington"; - newscript->pGossipHello = &GossipHello_npcs_dithers_and_arbington; - newscript->pGossipSelect = &GossipSelect_npcs_dithers_and_arbington; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_the_scourge_cauldron"; - newscript->GetAI = GetAI_npc_the_scourge_cauldron; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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) +SDCategory: Western Plaguelands +EndScriptData */ + +/* ContentData +npcs_dithers_and_arbington +npc_the_scourge_cauldron +EndContentData */ + +#include "precompiled.h" + +/*###### +## npcs_dithers_and_arbington +######*/ + +bool GossipHello_npcs_dithers_and_arbington(Player *player, Creature *_Creature) +{ + if(_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + if (_Creature->isVendor()) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + + if(player->GetQuestRewardStatus(5237) || player->GetQuestRewardStatus(5238)) + { + player->ADD_GOSSIP_ITEM(0, "What does the Felstone Field Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM(0, "What does the Dalson's Tears Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->ADD_GOSSIP_ITEM(0, "What does the Writhing Haunt Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->ADD_GOSSIP_ITEM(0, "What does the Gahrron's Withering Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(3985, _Creature->GetGUID()); + }else + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npcs_dithers_and_arbington(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch(action) + { + case GOSSIP_ACTION_TRADE: + player->SEND_VENDORLIST( _Creature->GetGUID() ); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM(0, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(3980, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM(0, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(3981, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM(0, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(3982, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM(0, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(3983, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player, 17529, false); + break; + } + return true; +} + +/*###### +## npc_the_scourge_cauldron +######*/ + +struct MANGOS_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI +{ + npc_the_scourge_cauldronAI(Creature *c) : ScriptedAI(c) {Reset();} + + void Reset() {} + + void Aggro(Unit* who) {} + + void DoDie() + { + //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); + } + + void MoveInLineOfSight(Unit *who) + { + if (!who || who->GetTypeId() != TYPEID_PLAYER) + return; + + 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 ) + { + DoSpawnCreature(11075,0,0,0,m_creature->GetOrientation(),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 ) + { + DoSpawnCreature(11077,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + DoDie(); + } + break; + case 201: //gahrron + if( ((Player*)who)->GetQuestStatus(5225) == QUEST_STATUS_INCOMPLETE || + ((Player*)who)->GetQuestStatus(5235) == QUEST_STATUS_INCOMPLETE ) + { + DoSpawnCreature(11078,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + DoDie(); + } + break; + case 202: //writhing + if( ((Player*)who)->GetQuestStatus(5222) == QUEST_STATUS_INCOMPLETE || + ((Player*)who)->GetQuestStatus(5233) == QUEST_STATUS_INCOMPLETE ) + { + DoSpawnCreature(11076,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + DoDie(); + } + break; + } + } + } +}; +CreatureAI* GetAI_npc_the_scourge_cauldron(Creature *_Creature) +{ + return new npc_the_scourge_cauldronAI (_Creature); +} + +/*###### +## +######*/ + +void AddSC_western_plaguelands() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npcs_dithers_and_arbington"; + newscript->pGossipHello = &GossipHello_npcs_dithers_and_arbington; + newscript->pGossipSelect = &GossipSelect_npcs_dithers_and_arbington; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_the_scourge_cauldron"; + newscript->GetAI = GetAI_npc_the_scourge_cauldron; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/winterspring/winterspring.cpp b/src/bindings/scripts/scripts/zone/winterspring/winterspring.cpp index fa3ef8dd027..e430f497104 100644 --- a/src/bindings/scripts/scripts/zone/winterspring/winterspring.cpp +++ b/src/bindings/scripts/scripts/zone/winterspring/winterspring.cpp @@ -1,157 +1,157 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* 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 -SDCategory: Winterspring -EndScriptData */ - -/* ContentData -npc_lorax -npc_rivern_frostwind -npc_witch_doctor_mauari -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_lorax -######*/ - -bool GossipHello_npc_lorax(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (player->GetQuestStatus(5126) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM( 0, "Talk to me", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lorax(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, "What do you do here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(3759, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM( 0, "I can help you", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(3760, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM( 0, "What deal?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(3761, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM( 0, "Then what happened?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(3762, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM( 0, "He is not safe, i'll make sure of that.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(3763, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(5126); - break; - } - return true; -} - -/*###### -## npc_rivern_frostwind -######*/ - -bool GossipHello_npc_rivern_frostwind(Player *player, Creature *_Creature) -{ - if (_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if (_Creature->isVendor() && player->GetReputationRank(589) == REP_EXALTED) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_rivern_frostwind(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_TRADE) - player->SEND_VENDORLIST( _Creature->GetGUID() ); - - return true; -} - -/*###### -## npc_witch_doctor_mauari -######*/ - -bool GossipHello_npc_witch_doctor_mauari(Player *player, Creature *_Creature) -{ - if(_Creature->isQuestGiver()) - player->PrepareQuestMenu( _Creature->GetGUID() ); - - if(player->GetQuestRewardStatus(975)) - { - player->ADD_GOSSIP_ITEM(0, "I'd like you to make me a new Cache of Mau'ari please.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(3377, _Creature->GetGUID()); - }else - player->SEND_GOSSIP_MENU(3375, _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_witch_doctor_mauari(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action==GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->CastSpell(player, 16351, false); - } - - return true; -} - -void AddSC_winterspring() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_lorax"; - newscript->pGossipHello = &GossipHello_npc_lorax; - newscript->pGossipSelect = &GossipSelect_npc_lorax; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_rivern_frostwind"; - newscript->pGossipHello = &GossipHello_npc_rivern_frostwind; - newscript->pGossipSelect = &GossipSelect_npc_rivern_frostwind; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_witch_doctor_mauari"; - newscript->pGossipHello = &GossipHello_npc_witch_doctor_mauari; - newscript->pGossipSelect = &GossipSelect_npc_witch_doctor_mauari; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 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 +SDCategory: Winterspring +EndScriptData */ + +/* ContentData +npc_lorax +npc_rivern_frostwind +npc_witch_doctor_mauari +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_lorax +######*/ + +bool GossipHello_npc_lorax(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (player->GetQuestStatus(5126) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM( 0, "Talk to me", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_lorax(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, "What do you do here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(3759, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + player->ADD_GOSSIP_ITEM( 0, "I can help you", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(3760, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + player->ADD_GOSSIP_ITEM( 0, "What deal?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(3761, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + player->ADD_GOSSIP_ITEM( 0, "Then what happened?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->SEND_GOSSIP_MENU(3762, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + player->ADD_GOSSIP_ITEM( 0, "He is not safe, i'll make sure of that.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->SEND_GOSSIP_MENU(3763, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + player->CLOSE_GOSSIP_MENU(); + player->AreaExploredOrEventHappens(5126); + break; + } + return true; +} + +/*###### +## npc_rivern_frostwind +######*/ + +bool GossipHello_npc_rivern_frostwind(Player *player, Creature *_Creature) +{ + if (_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if (_Creature->isVendor() && player->GetReputationRank(589) == REP_EXALTED) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_rivern_frostwind(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_TRADE) + player->SEND_VENDORLIST( _Creature->GetGUID() ); + + return true; +} + +/*###### +## npc_witch_doctor_mauari +######*/ + +bool GossipHello_npc_witch_doctor_mauari(Player *player, Creature *_Creature) +{ + if(_Creature->isQuestGiver()) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if(player->GetQuestRewardStatus(975)) + { + player->ADD_GOSSIP_ITEM(0, "I'd like you to make me a new Cache of Mau'ari please.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(3377, _Creature->GetGUID()); + }else + player->SEND_GOSSIP_MENU(3375, _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_witch_doctor_mauari(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action==GOSSIP_ACTION_INFO_DEF+1) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->CastSpell(player, 16351, false); + } + + return true; +} + +void AddSC_winterspring() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_lorax"; + newscript->pGossipHello = &GossipHello_npc_lorax; + newscript->pGossipSelect = &GossipSelect_npc_lorax; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_rivern_frostwind"; + newscript->pGossipHello = &GossipHello_npc_rivern_frostwind; + newscript->pGossipSelect = &GossipSelect_npc_rivern_frostwind; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_witch_doctor_mauari"; + newscript->pGossipHello = &GossipHello_npc_witch_doctor_mauari; + newscript->pGossipSelect = &GossipSelect_npc_witch_doctor_mauari; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zangarmarsh/zangarmarsh.cpp b/src/bindings/scripts/scripts/zone/zangarmarsh/zangarmarsh.cpp index e5917dd25ee..41c201b3450 100644 --- a/src/bindings/scripts/scripts/zone/zangarmarsh/zangarmarsh.cpp +++ b/src/bindings/scripts/scripts/zone/zangarmarsh/zangarmarsh.cpp @@ -1,283 +1,283 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Zangarmarsh -SD%Complete: 100 -SDComment: Quest support: 9785, 9803, 10009. Mark Of ... buffs. -SDCategory: Zangarmarsh -EndScriptData */ - -/* ContentData -npcs_ashyen_and_keleth -npc_cooshcoosh -npc_elder_kuruti -npc_mortog_steamhead -EndContentData */ - -#include "precompiled.h" - -/*###### -## npcs_ashyen_and_keleth -######*/ - -#define GOSSIP_ITEM_BLESS_ASH "Grant me your mark, wise ancient." -#define GOSSIP_ITEM_BLESS_KEL "Grant me your mark, mighty ancient." -#define GOSSIP_REWARD_BLESS "You have my blessing" -//#define TEXT_BLESSINGS "" - -bool GossipHello_npcs_ashyen_and_keleth(Player *player, Creature *_Creature ) -{ - if (player->GetReputationRank(942) > REP_NEUTRAL) - { - if ( _Creature->GetEntry() == 17900) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_BLESS_ASH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - if ( _Creature->GetEntry() == 17901) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_BLESS_KEL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - } - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npcs_ashyen_and_keleth(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - _Creature->setPowerType(POWER_MANA); - _Creature->SetMaxPower(POWER_MANA,200); //set a "fake" mana value, we can't depend on database doing it in this case - _Creature->SetPower(POWER_MANA,200); - - if ( _Creature->GetEntry() == 17900) //check which creature we are dealing with - { - switch (player->GetReputationRank(942)) - { //mark of lore - case REP_FRIENDLY: - _Creature->CastSpell(player, 31808, true); - _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); - break; - case REP_HONORED: - _Creature->CastSpell(player, 31810, true); - _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); - break; - case REP_REVERED: - _Creature->CastSpell(player, 31811, true); - _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); - break; - case REP_EXALTED: - _Creature->CastSpell(player, 31815, true); - _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); - break; - } - } - - if ( _Creature->GetEntry() == 17901) - { - switch (player->GetReputationRank(942)) //mark of war - { - case REP_FRIENDLY: - _Creature->CastSpell(player, 31807, true); - _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); - break; - case REP_HONORED: - _Creature->CastSpell(player, 31812, true); - _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); - break; - case REP_REVERED: - _Creature->CastSpell(player, 31813, true); - _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); - break; - case REP_EXALTED: - _Creature->CastSpell(player, 31814, true); - _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); - break; - } - } - player->CLOSE_GOSSIP_MENU(); - player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); - } - return true; -} - -/*###### -## npc_cooshcoosh -######*/ - -#define GOSSIP_COOSH "You owe Sim'salabim money. Hand them over or die!" - -#define FACTION_HOSTILE_CO 45 -#define FACTION_FRIENDLY_CO 35 - -#define SPELL_LIGHTNING_BOLT 9532 - -struct MANGOS_DLL_DECL npc_cooshcooshAI : public ScriptedAI -{ - npc_cooshcooshAI(Creature* c) : ScriptedAI(c) { Reset(); } - - uint32 LightningBolt_Timer; - - void Reset() - { - LightningBolt_Timer = 2000; - m_creature->setFaction(FACTION_FRIENDLY_CO); - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if( LightningBolt_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_LIGHTNING_BOLT); - LightningBolt_Timer = 5000; - }else LightningBolt_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_cooshcoosh(Creature *_Creature) -{ - return new npc_cooshcooshAI (_Creature); -} - -bool GossipHello_npc_cooshcoosh(Player *player, Creature *_Creature ) -{ - if( player->GetQuestStatus(10009) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM(1, GOSSIP_COOSH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(9441, _Creature->GetGUID()); - return true; -} - -bool GossipSelect_npc_cooshcoosh(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_INFO_DEF ) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->setFaction(FACTION_HOSTILE_CO); - ((npc_cooshcooshAI*)_Creature->AI())->AttackStart(player); - } - 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 *player, Creature *_Creature ) -{ - if( player->GetQuestStatus(9803) == QUEST_STATUS_INCOMPLETE ) - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KUR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(9226,_Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_elder_kuruti(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KUR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(9227, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 1: - player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KUR3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(9229, _Creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - { - if( !player->HasItemCount(24573,1) ) - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 24573, 1, false); - if( msg == EQUIP_ERR_OK ) - { - player->StoreNewItem( dest, 24573, true); - } - else - player->SendEquipError( msg,NULL,NULL ); - } - player->SEND_GOSSIP_MENU(9231, _Creature->GetGUID()); - break; - } - } - return true; -} - -/*###### -## npc_mortog_steamhead -######*/ - -bool GossipHello_npc_mortog_steamhead(Player *player, Creature *_Creature) -{ - if (_Creature->isVendor() && player->GetReputationRank(942) == REP_EXALTED) - player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_mortog_steamhead(Player *player, Creature *_Creature, uint32 sender, uint32 action) -{ - if (action == GOSSIP_ACTION_TRADE) - { - player->SEND_VENDORLIST( _Creature->GetGUID() ); - } - return true; -} - -/*###### -## AddSC -######*/ - -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; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_cooshcoosh"; - newscript->pGossipHello = &GossipHello_npc_cooshcoosh; - newscript->pGossipSelect = &GossipSelect_npc_cooshcoosh; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_elder_kuruti"; - newscript->pGossipHello = &GossipHello_npc_elder_kuruti; - newscript->pGossipSelect = &GossipSelect_npc_elder_kuruti; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_mortog_steamhead"; - newscript->pGossipHello = &GossipHello_npc_mortog_steamhead; - newscript->pGossipSelect = &GossipSelect_npc_mortog_steamhead; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Zangarmarsh +SD%Complete: 100 +SDComment: Quest support: 9785, 9803, 10009. Mark Of ... buffs. +SDCategory: Zangarmarsh +EndScriptData */ + +/* ContentData +npcs_ashyen_and_keleth +npc_cooshcoosh +npc_elder_kuruti +npc_mortog_steamhead +EndContentData */ + +#include "precompiled.h" + +/*###### +## npcs_ashyen_and_keleth +######*/ + +#define GOSSIP_ITEM_BLESS_ASH "Grant me your mark, wise ancient." +#define GOSSIP_ITEM_BLESS_KEL "Grant me your mark, mighty ancient." +#define GOSSIP_REWARD_BLESS "You have my blessing" +//#define TEXT_BLESSINGS "" + +bool GossipHello_npcs_ashyen_and_keleth(Player *player, Creature *_Creature ) +{ + if (player->GetReputationRank(942) > REP_NEUTRAL) + { + if ( _Creature->GetEntry() == 17900) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_BLESS_ASH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + if ( _Creature->GetEntry() == 17901) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_BLESS_KEL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + } + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npcs_ashyen_and_keleth(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_INFO_DEF+1) + { + _Creature->setPowerType(POWER_MANA); + _Creature->SetMaxPower(POWER_MANA,200); //set a "fake" mana value, we can't depend on database doing it in this case + _Creature->SetPower(POWER_MANA,200); + + if ( _Creature->GetEntry() == 17900) //check which creature we are dealing with + { + switch (player->GetReputationRank(942)) + { //mark of lore + case REP_FRIENDLY: + _Creature->CastSpell(player, 31808, true); + _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); + break; + case REP_HONORED: + _Creature->CastSpell(player, 31810, true); + _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); + break; + case REP_REVERED: + _Creature->CastSpell(player, 31811, true); + _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); + break; + case REP_EXALTED: + _Creature->CastSpell(player, 31815, true); + _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); + break; + } + } + + if ( _Creature->GetEntry() == 17901) + { + switch (player->GetReputationRank(942)) //mark of war + { + case REP_FRIENDLY: + _Creature->CastSpell(player, 31807, true); + _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); + break; + case REP_HONORED: + _Creature->CastSpell(player, 31812, true); + _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); + break; + case REP_REVERED: + _Creature->CastSpell(player, 31813, true); + _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); + break; + case REP_EXALTED: + _Creature->CastSpell(player, 31814, true); + _Creature->Say(GOSSIP_REWARD_BLESS, LANG_UNIVERSAL, 0); + break; + } + } + player->CLOSE_GOSSIP_MENU(); + player->TalkedToCreature(_Creature->GetEntry(), _Creature->GetGUID()); + } + return true; +} + +/*###### +## npc_cooshcoosh +######*/ + +#define GOSSIP_COOSH "You owe Sim'salabim money. Hand them over or die!" + +#define FACTION_HOSTILE_CO 45 +#define FACTION_FRIENDLY_CO 35 + +#define SPELL_LIGHTNING_BOLT 9532 + +struct MANGOS_DLL_DECL npc_cooshcooshAI : public ScriptedAI +{ + npc_cooshcooshAI(Creature* c) : ScriptedAI(c) { Reset(); } + + uint32 LightningBolt_Timer; + + void Reset() + { + LightningBolt_Timer = 2000; + m_creature->setFaction(FACTION_FRIENDLY_CO); + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if( LightningBolt_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_LIGHTNING_BOLT); + LightningBolt_Timer = 5000; + }else LightningBolt_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_cooshcoosh(Creature *_Creature) +{ + return new npc_cooshcooshAI (_Creature); +} + +bool GossipHello_npc_cooshcoosh(Player *player, Creature *_Creature ) +{ + if( player->GetQuestStatus(10009) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM(1, GOSSIP_COOSH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(9441, _Creature->GetGUID()); + return true; +} + +bool GossipSelect_npc_cooshcoosh(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF ) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->setFaction(FACTION_HOSTILE_CO); + ((npc_cooshcooshAI*)_Creature->AI())->AttackStart(player); + } + 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 *player, Creature *_Creature ) +{ + if( player->GetQuestStatus(9803) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KUR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + player->SEND_GOSSIP_MENU(9226,_Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_elder_kuruti(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + switch (action) + { + case GOSSIP_ACTION_INFO_DEF: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KUR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(9227, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 1: + player->ADD_GOSSIP_ITEM( 0, GOSSIP_ITEM_KUR3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(9229, _Creature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + { + if( !player->HasItemCount(24573,1) ) + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 24573, 1, false); + if( msg == EQUIP_ERR_OK ) + { + player->StoreNewItem( dest, 24573, true); + } + else + player->SendEquipError( msg,NULL,NULL ); + } + player->SEND_GOSSIP_MENU(9231, _Creature->GetGUID()); + break; + } + } + return true; +} + +/*###### +## npc_mortog_steamhead +######*/ + +bool GossipHello_npc_mortog_steamhead(Player *player, Creature *_Creature) +{ + if (_Creature->isVendor() && player->GetReputationRank(942) == REP_EXALTED) + player->ADD_GOSSIP_ITEM(1, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_mortog_steamhead(Player *player, Creature *_Creature, uint32 sender, uint32 action) +{ + if (action == GOSSIP_ACTION_TRADE) + { + player->SEND_VENDORLIST( _Creature->GetGUID() ); + } + return true; +} + +/*###### +## AddSC +######*/ + +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; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_cooshcoosh"; + newscript->pGossipHello = &GossipHello_npc_cooshcoosh; + newscript->pGossipSelect = &GossipSelect_npc_cooshcoosh; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_elder_kuruti"; + newscript->pGossipHello = &GossipHello_npc_elder_kuruti; + newscript->pGossipSelect = &GossipSelect_npc_elder_kuruti; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_mortog_steamhead"; + newscript->pGossipHello = &GossipHello_npc_mortog_steamhead; + newscript->pGossipSelect = &GossipSelect_npc_mortog_steamhead; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp index 0f3de44cd10..7ec0eeacfc3 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp @@ -1,777 +1,760 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Janalai -SD%Complete: 100 -SDComment: -SDCategory: Zul'Aman -EndScriptData */ - -#include "precompiled.h" -#include "def_zulaman.h" - -// Jan'alai -// --Spell -#define SPELL_FLAME_BREATH 43140 -#define SPELL_FIRE_WALL 43113 -#define SPELL_ENRAGE 44779 -#define SPELL_TELETOCENTER 43098 -#define SPELL_SUMMONALL 43097 -#define SPELL_BERSERK 47008 -// -- Fire Bob Spells -#define MOB_FIRE_BOMB 23920 -#define SPELL_FIRE_BOMB_CHANNEL 42621 -#define SPELL_FIRE_BOMB_THROW 42628 -#define SPELL_FIRE_BOMB_DUMMY 42629 -#define SPELL_FIRE_BOMB_DAMAGE 42630 - -// -- SAYs -#define SOUND_AGGRO 12031 -#define SAY_AGGRO "Spirits of da wind be your doom!" -#define SOUND_FIRE_BOMBS 12032 -#define SAY_FIRE_BOMBS "I burn ya now!" -#define SOUND_SUMMON_HATCHER 12033 -#define SAY_SUMMON_HATCHER "Where ma hatcha? Get to work on dem eggs!" -#define SOUND_ALL_EGGS 12034 -#define SAY_ALL_EGGS "I show you strength... in numbers." -#define SOUND_BERSERK 12035 -#define SAY_BERSERK "You done run outta time!" - -#define SOUND_SLAY_1 12036 -#define SAY_SLAY_1 "It all be over now, mon!" -#define SOUND_SLAY_2 12037 -#define SAY_SLAY_2 "Tazaga-choo!" - -#define SOUND_DEATH 12038 -#define SAY_DEATH "Zul'jin... got a surprise for you..." - -#define SOUND_AGGRO_1 12039 //NOT USED need more information - //NOT USED need more information (random say before aggro?) -#define SAY_AGGRO_1 "Come, strangers. The spirit of the dragonhawk hot be hungry for worthy souls." -#define SOUND_AGGRO_2 12040 //NOT USED need more information - //NOT USED need more information (random say before aggro?) -#define SAY_AGGRO_2 "Come, friends. Your bodies gonna feed ma hatchlings, and your souls are going to feed me with power!" - -// --Summons -#define MOB_AMANI_HATCHER 23818 -#define MOB_HATCHLING 23598 - -// -- Hatcher Spells -#define SPELL_HATCH_EGG 43734 - -// -- Hatchling Spells -#define SPELL_FLAMEBUFFED 43299 - -const int area_dx = 44; -const int area_dy = 51; - -float JanalainPos[1][3] = -{ - {-33.93, 1149.27, 19} -}; - -float FireWallCoords[4][4] = -{ - {-10.13, 1149.27, 19, 3.1415}, - {-33.93, 1123.90, 19, 0.5*3.1415}, - {-54.80, 1150.08, 19, 0}, - {-33.93, 1175.68, 19, 1.5*3.1415} -}; - -float hatcherway_l[5][3] = -{ - {-87.46,1170.09,6}, - {-74.41,1154.75,6}, - {-52.74,1153.32,19}, - {-33.37,1172.46,19}, - {-33.09,1203.87,19} -}; - -float hatcherway_r[5][3] = -{ - {-86.57,1132.85,6}, - {-73.94,1146.00,6}, - {-52.29,1146.51,19}, - {-33.57,1125.72,19}, - {-34.29,1095.22,19} -}; - -struct MANGOS_DLL_DECL boss_janalaiAI : public ScriptedAI -{ - boss_janalaiAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 fire_breath_timer; - uint32 bomb_timer; - uint32 throw_timer; - uint32 enrage_timer; - uint32 finishedbomb_timer; - uint32 bombcounter; - uint32 hatchertime; - uint32 eggs; - uint32 wipetimer; - uint32 reset_timer; - bool noeggs; - bool enraged; - bool enragetime; - - uint64 FireBombGUIDs[40]; - uint64 ThrowControllerGUID; - - bool bombing; - - void Reset() - { - if(pInstance) - pInstance->SetData(DATA_JANALAIEVENT, NOT_STARTED); - - fire_breath_timer = 8000; - bomb_timer = 30000; - enrage_timer = 300000; // 5 minutes - finishedbomb_timer = 6000; - throw_timer = 1000; - bombcounter = 0; - noeggs = false; - hatchertime = 10000; - wipetimer = 600000; // 10 mins - bombing =false; - reset_timer = 5000; - enraged = false; - enragetime = false; - - ThrowControllerGUID = 0; - - for(uint8 i = 0; i < 40; i++) - FireBombGUIDs[i] = 0; - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - - if(pInstance) - pInstance->SetData(DATA_JANALAIEVENT, DONE); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - case 1: - DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SLAY_1); - break; - } - } - - void Aggro(Unit *who) - { - if(pInstance) - pInstance->SetData(DATA_JANALAIEVENT, IN_PROGRESS); - - DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void FireWall() // Create Firewall - { - Creature* wall = NULL; - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1],FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1]+5,FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1]-5,FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[1][0]-2,FireWallCoords[1][1]-2,FireWallCoords[1][2],FireWallCoords[1][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[1][0]+2,FireWallCoords[1][1]+2,FireWallCoords[1][2],FireWallCoords[1][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1],FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1]-5,FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1]+5,FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[3][0]-2,FireWallCoords[3][1],FireWallCoords[3][2],FireWallCoords[3][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - - wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[3][0]+2,FireWallCoords[3][1],FireWallCoords[3][2],FireWallCoords[3][3],TEMPSUMMON_TIMED_DESPAWN,11500); - if(wall) - wall->CastSpell(wall,SPELL_FIRE_WALL,false); - } - - void throwBombs() // create Bombs - { - float dx; - float dy; - for ( int i(0); i < 40; i++) - { - dx = (rand()%(area_dx))-(area_dx/2); - dy = (rand()%(area_dy))-(area_dy/2); - - Creature* bomb = DoSpawnCreature(MOB_FIRE_BOMB, dx, dy, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 13000); - if(bomb) - FireBombGUIDs[i] = bomb->GetGUID(); - } - - Creature* ThrowController = DoSpawnCreature(MOB_FIRE_BOMB,0,0,1,0,TEMPSUMMON_TIMED_DESPAWN,10000); - if(ThrowController) - ThrowControllerGUID = ThrowController->GetGUID(); - - bombcounter = 0; - } - - void throw5Bombs() //throwanimation - { - for ( int i(0); i < 5; i++) - { - Unit* ThrowController = NULL; - Unit* FireBomb = NULL; - if(ThrowControllerGUID) - ThrowController = Unit::GetUnit((*m_creature), ThrowControllerGUID); - - if(FireBombGUIDs[bombcounter]) - FireBomb = Unit::GetUnit((*m_creature), FireBombGUIDs[bombcounter]); - - if(ThrowController && FireBomb) - { - ThrowController->CastSpell(FireBomb,SPELL_FIRE_BOMB_THROW,true); - FireBomb->CastSpell(FireBomb,SPELL_FIRE_BOMB_DUMMY,false); - bombcounter ++; - } - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if(!bombing) // every Spell if NOT Bombing - { - //FIRE BREATH several videos says every 8Secounds - if(fire_breath_timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if(target) - DoCast(target,SPELL_FLAME_BREATH); - fire_breath_timer = 8000; - }else fire_breath_timer -=diff; - - if(bomb_timer < diff) - { - FireWall(); - bomb_timer = 20000+rand()%20000; - m_creature->Relocate(JanalainPos[0][0],JanalainPos[0][1],JanalainPos[0][2],0); - m_creature->SendMonsterMove(JanalainPos[0][0], JanalainPos[0][1],JanalainPos[0][2],0,0,100); - DoYell(SAY_FIRE_BOMBS, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_FIRE_BOMBS); - throwBombs(); - bombing = true; - - //Teleport every Player into the middle - Unit* Temp = NULL; - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - Temp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); - if (Temp && m_creature->GetDistance(Temp) > 30.0) - DoTeleportPlayer(Temp, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0); - } - DoCast(m_creature,SPELL_TELETOCENTER,true); // only Effect Spell - DoCast(m_creature,SPELL_FIRE_BOMB_CHANNEL,false); - finishedbomb_timer = 11000; - }else bomb_timer -=diff; - - //enrage if under 25% hp before 5 min. - if (((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) && !enraged) - { - enragetime = true; - enrage_timer = 600000; - } - - //Enrage but only if not bombing - if(enragetime && !enraged) - { - DoYell(SAY_BERSERK, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_BERSERK); - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature,SPELL_ENRAGE); - enraged = true; - } - } - - //Enrage after 5 minutes - if(enrage_timer < diff) - { - enragetime = true; - enrage_timer = 600000; - }else enrage_timer -=diff; - - if(bombing) // every Spell if Bombing - { - if(bombcounter < 40) - { - if(throw_timer < diff) - { - throw5Bombs(); - throw_timer = 1000; - }else throw_timer -=diff; - } - - if(finishedbomb_timer < diff) - { - bombing = false; - finishedbomb_timer = 6000; - m_creature->RemoveAura(SPELL_FIRE_BOMB_CHANNEL,0); - m_creature->RemoveAura(SPELL_FIRE_BOMB_CHANNEL,1); - }else finishedbomb_timer -=diff; - } - - //Call Hatcher - if(!noeggs) - { - if(hatchertime < diff) - { - if(pInstance->GetData(DATA_J_EGGSLEFT)>0 || pInstance->GetData(DATA_J_EGGSRIGHT) > 0) - { - Unit* hatcher = NULL; - DoYell(SAY_SUMMON_HATCHER, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_SUMMON_HATCHER); - hatcher = m_creature->SummonCreature(MOB_AMANI_HATCHER,hatcherway_l[0][0],hatcherway_l[0][1],hatcherway_l[0][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000); - if(hatcher) - hatcher->GetMotionMaster()->MovePoint(0, hatcherway_l[0][0], hatcherway_l[0][1], hatcherway_l[0][2]); - - hatcher = m_creature->SummonCreature(MOB_AMANI_HATCHER,hatcherway_r[0][0],hatcherway_r[0][1],hatcherway_r[0][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000); - if(hatcher) - hatcher->GetMotionMaster()->MovePoint(0, hatcherway_r[0][0],hatcherway_r[0][1],hatcherway_r[0][2]); - hatchertime = 45000; - } - else - { - noeggs = true; - } - }else hatchertime -=diff; - } - - //WIPE after 10 minutes - if(wipetimer < diff) - { - DoYell(SAY_BERSERK, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_BERSERK); - DoCast(m_creature,SPELL_ENRAGE); - - wipetimer = 30000; - }else wipetimer -=diff; - - //Hatch All - if(!noeggs && (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 35) - { - DoYell(SAY_ALL_EGGS , LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature,SOUND_BERSERK); - - if(pInstance) - eggs = pInstance->GetData(DATA_J_EGGSLEFT); - - int i; - for(i=1;i<=eggs;i=i+1) - { - int r = (rand()%20 - 10); - int s = (rand()%20 - 10); - m_creature->SummonCreature(MOB_HATCHLING,JanalainPos[0][0]+s,JanalainPos[0][1]+r,JanalainPos[0][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,15000); - - if(pInstance) - pInstance->SetData(DATA_J_HATCHLEFT,1); - } - - if(pInstance) - eggs = pInstance->GetData(DATA_J_EGGSRIGHT); - - for(i=1;i<=eggs;i=i+1) - { - int r = (rand()%20 - 10); - int s = (rand()%20 - 10); - m_creature->SummonCreature(MOB_HATCHLING,JanalainPos[0][0]+s,JanalainPos[0][1]+r,JanalainPos[0][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,15000); - if(pInstance) - pInstance->SetData(DATA_J_HATCHRIGHT,1); - } - - noeggs = true; - } - - //check for reset ... exploit preventing ... pulled from his podest - if(reset_timer < diff) - { - if(m_creature->GetPositionX() < -70 || m_creature->GetPositionX() > 0) - { - EnterEvadeMode(); - reset_timer = 5000; //every 5 Seca - } - }else reset_timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_janalaiAI(Creature *_Creature) -{ - return new boss_janalaiAI (_Creature); -} - -struct MANGOS_DLL_DECL mob_jandalai_firebombAI : public ScriptedAI -{ - mob_jandalai_firebombAI(Creature *c) : ScriptedAI(c){Reset();} - - uint32 bomb_timer; - - void Reset() - { - bomb_timer = 12000; - } - - void Aggro(Unit* who) {} - - void AttackStart(Unit* who) {} - - void MoveInLineOfSight(Unit* who) {} - - void UpdateAI(const uint32 diff) - { - if(bomb_timer < diff) //Boom - { - m_creature->CastSpell(m_creature,SPELL_FIRE_BOMB_DAMAGE,false); - bomb_timer = 1800000; - }else bomb_timer -=diff; - } -}; - -CreatureAI* GetAI_mob_jandalai_firebombAI(Creature *_Creature) -{ - return new mob_jandalai_firebombAI (_Creature); -} - -struct MANGOS_DLL_DECL mob_amanishi_hatcherAI : public ScriptedAI -{ - mob_amanishi_hatcherAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 waypoint; - bool waytype; - bool start; - bool hatch; - bool wait; - uint32 hatchlings; - uint32 waittimer; - uint32 eggs; - uint32 delete_timer; - - void Reset() - { - waypoint = 0; - waytype = 0; - hatch = false; - start = false; - wait = false; - waittimer = 4000; - hatchlings = 0; - eggs = 0; - delete_timer = 10000; - - //m_creature->RemoveAllAuras(); - //m_creature->DeleteThreatList(); - //m_creature->CombatStop(); - //DoGoHome(); - } - - void Aggro(Unit* who) - { - } - - void UpdateAI(const uint32 diff) - { - if(pInstance && (pInstance->GetData(DATA_JANALAIEVENT) == 1)) - { - if(!start && !hatch) - { - waytype = ( m_creature->GetPositionY() > 1150); - waypoint = 1; - start = true; - } - - if(start && !hatch) - { - if(wait) - { - if(waittimer < diff) - { - wait = false; - waittimer = 4000; - waypoint++; - - if (waypoint == 5) - { - hatch = true; - waittimer = 0; - hatchlings = 1; - } - } - else - { - waittimer -=diff; - } - } - else - { - m_creature->GetMotionMaster()->Clear(); - if(waytype) - m_creature->GetMotionMaster()->MovePoint(0,hatcherway_l[waypoint][0],hatcherway_l[waypoint][1],hatcherway_l[waypoint][2]); - else - m_creature->GetMotionMaster()->MovePoint(0,hatcherway_r[waypoint][0],hatcherway_r[waypoint][1],hatcherway_r[waypoint][2]); - wait= true; - } - } - - if(start && hatch) - { - if(waittimer < diff) - { - if(!pInstance) - return; - - waittimer = 4000; - Unit* hatchling; - - if(waytype) - { - eggs = pInstance->GetData(DATA_J_EGGSLEFT); - - if(eggs > 0) - DoCast(m_creature,SPELL_HATCH_EGG); - - int i; - for(i=1;i<=hatchlings;i=i+1) - { - eggs = pInstance->GetData(DATA_J_EGGSLEFT); - if(eggs <= 0) - { - if (waytype) waytype = false; else waytype = true; - waittimer = 15000; - hatch = false; - waypoint = 4; - wait = true; - i = hatchlings; - } - else - { - hatchling = DoSpawnCreature(MOB_HATCHLING,rand()%4-2,rand()%4-2,0,0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,15000); - pInstance->SetData(DATA_J_HATCHLEFT,1); - } - } - - DoCast(m_creature,SPELL_HATCH_EGG); - - if(hatchlings < 5) - hatchlings++; - } - else - { - eggs = pInstance->GetData(DATA_J_EGGSRIGHT); - - if(eggs > 0) - DoCast(m_creature,SPELL_HATCH_EGG); - - int i; - for(i=1;i<=hatchlings;i=i+1) - { - eggs = pInstance->GetData(DATA_J_EGGSRIGHT); - if(eggs <= 0) - { - if (waytype) waytype = false; else waytype = true; - waittimer = 15000; - hatch = false; - waypoint = 4; - wait = true; - i = hatchlings; - } - else - { - hatchling = DoSpawnCreature(MOB_HATCHLING,rand()%4-2,rand()%4-2,0,0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,15000); - pInstance->SetData(DATA_J_HATCHRIGHT,1); - } - } - - DoCast(m_creature,SPELL_HATCH_EGG); - hatchlings++; - } - }else waittimer -=diff; - } - } - else - { - if(delete_timer < diff) - { - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - delete_timer = 10000; - }else delete_timer -=diff; - } - } -}; - -CreatureAI* GetAI_mob_amanishi_hatcherAI(Creature *_Creature) -{ - return new mob_amanishi_hatcherAI (_Creature); -} - -struct MANGOS_DLL_DECL mob_hatchlingAI : public ScriptedAI -{ - mob_hatchlingAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 buffer_timer; - uint32 delete_timer; - bool start; - - void Reset() - { - buffer_timer = 7000; - delete_timer = 10000; - start = false; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - DoStartAttackAndMovement(who); - } - } - } - - 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; - } - - if(delete_timer < diff && (pInstance && !(pInstance->GetData(DATA_JANALAIEVENT) == 1))) - { - if(!(m_creature->getVictim())) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - delete_timer = 10000; - }else delete_timer -=diff; - - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - if (buffer_timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if(target) - DoCast(target,SPELL_FLAMEBUFFED); - - buffer_timer = 7000; - }else buffer_timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_hatchlingAI(Creature *_Creature) -{ - return new mob_hatchlingAI (_Creature); -} - -void AddSC_boss_janalai() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_janalai"; - newscript->GetAI = GetAI_boss_janalaiAI; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_jandalai_firebomb"; - newscript->GetAI = GetAI_mob_jandalai_firebombAI; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_amanishi_hatcher"; - newscript->GetAI = GetAI_mob_amanishi_hatcherAI; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_hatchling"; - newscript->GetAI = GetAI_mob_hatchlingAI; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Janalai +SD%Complete: 100 +SDComment: +SDCategory: Zul'Aman +EndScriptData */ + +#include "precompiled.h" +#include "def_zulaman.h" + +// Jan'alai +// --Spell +#define SPELL_FLAME_BREATH 43140 +#define SPELL_FIRE_WALL 43113 +#define SPELL_ENRAGE 44779 +#define SPELL_TELETOCENTER 43098 +#define SPELL_SUMMONALL 43097 +#define SPELL_BERSERK 47008 +// -- Fire Bob Spells +#define MOB_FIRE_BOMB 23920 +#define SPELL_FIRE_BOMB_CHANNEL 42621 +#define SPELL_FIRE_BOMB_THROW 42628 +#define SPELL_FIRE_BOMB_DUMMY 42629 +#define SPELL_FIRE_BOMB_DAMAGE 42630 + +// -- SAYs +#define SOUND_AGGRO 12031 +#define SAY_AGGRO "Spirits of da wind be your doom!" +#define SOUND_FIRE_BOMBS 12032 +#define SAY_FIRE_BOMBS "I burn ya now!" +#define SOUND_SUMMON_HATCHER 12033 +#define SAY_SUMMON_HATCHER "Where ma hatcha? Get to work on dem eggs!" +#define SOUND_ALL_EGGS 12034 +#define SAY_ALL_EGGS "I show you strength... in numbers." +#define SOUND_BERSERK 12035 +#define SAY_BERSERK "You done run outta time!" + +#define SOUND_SLAY_1 12036 +#define SAY_SLAY_1 "It all be over now, mon!" +#define SOUND_SLAY_2 12037 +#define SAY_SLAY_2 "Tazaga-choo!" + +#define SOUND_DEATH 12038 +#define SAY_DEATH "Zul'jin... got a surprise for you..." + +#define SOUND_AGGRO_1 12039 //NOT USED need more information + //NOT USED need more information (random say before aggro?) +#define SAY_AGGRO_1 "Come, strangers. The spirit of the dragonhawk hot be hungry for worthy souls." +#define SOUND_AGGRO_2 12040 //NOT USED need more information + //NOT USED need more information (random say before aggro?) +#define SAY_AGGRO_2 "Come, friends. Your bodies gonna feed ma hatchlings, and your souls are going to feed me with power!" + +// --Summons +#define MOB_AMANI_HATCHER 23818 +#define MOB_HATCHLING 23598 + +// -- Hatcher Spells +#define SPELL_HATCH_EGG 43734 + +// -- Hatchling Spells +#define SPELL_FLAMEBUFFED 43299 + +const int area_dx = 44; +const int area_dy = 51; + +float JanalainPos[1][3] = +{ + {-33.93, 1149.27, 19} +}; + +float FireWallCoords[4][4] = +{ + {-10.13, 1149.27, 19, 3.1415}, + {-33.93, 1123.90, 19, 0.5*3.1415}, + {-54.80, 1150.08, 19, 0}, + {-33.93, 1175.68, 19, 1.5*3.1415} +}; + +float hatcherway_l[5][3] = +{ + {-87.46,1170.09,6}, + {-74.41,1154.75,6}, + {-52.74,1153.32,19}, + {-33.37,1172.46,19}, + {-33.09,1203.87,19} +}; + +float hatcherway_r[5][3] = +{ + {-86.57,1132.85,6}, + {-73.94,1146.00,6}, + {-52.29,1146.51,19}, + {-33.57,1125.72,19}, + {-34.29,1095.22,19} +}; + +struct MANGOS_DLL_DECL boss_janalaiAI : public ScriptedAI +{ + boss_janalaiAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 fire_breath_timer; + uint32 bomb_timer; + uint32 throw_timer; + uint32 enrage_timer; + uint32 finishedbomb_timer; + uint32 bombcounter; + uint32 hatchertime; + uint32 eggs; + uint32 wipetimer; + uint32 reset_timer; + bool noeggs; + bool enraged; + bool enragetime; + + uint64 FireBombGUIDs[40]; + uint64 ThrowControllerGUID; + + bool bombing; + + void Reset() + { + if(pInstance) + pInstance->SetData(DATA_JANALAIEVENT, NOT_STARTED); + + fire_breath_timer = 8000; + bomb_timer = 30000; + enrage_timer = 300000; // 5 minutes + finishedbomb_timer = 6000; + throw_timer = 1000; + bombcounter = 0; + noeggs = false; + hatchertime = 10000; + wipetimer = 600000; // 10 mins + bombing =false; + reset_timer = 5000; + enraged = false; + enragetime = false; + + ThrowControllerGUID = 0; + + for(uint8 i = 0; i < 40; i++) + FireBombGUIDs[i] = 0; + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + + if(pInstance) + pInstance->SetData(DATA_JANALAIEVENT, DONE); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + case 1: + DoYell(SAY_SLAY_2, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SLAY_1); + break; + } + } + + void Aggro(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_JANALAIEVENT, IN_PROGRESS); + + DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void FireWall() // Create Firewall + { + Creature* wall = NULL; + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1],FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1]+5,FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1]-5,FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[1][0]-2,FireWallCoords[1][1]-2,FireWallCoords[1][2],FireWallCoords[1][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[1][0]+2,FireWallCoords[1][1]+2,FireWallCoords[1][2],FireWallCoords[1][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1],FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1]-5,FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1]+5,FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[3][0]-2,FireWallCoords[3][1],FireWallCoords[3][2],FireWallCoords[3][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + + wall = m_creature->SummonCreature(MOB_FIRE_BOMB,FireWallCoords[3][0]+2,FireWallCoords[3][1],FireWallCoords[3][2],FireWallCoords[3][3],TEMPSUMMON_TIMED_DESPAWN,11500); + if(wall) + wall->CastSpell(wall,SPELL_FIRE_WALL,false); + } + + void throwBombs() // create Bombs + { + float dx; + float dy; + for ( int i(0); i < 40; i++) + { + dx = (rand()%(area_dx))-(area_dx/2); + dy = (rand()%(area_dy))-(area_dy/2); + + Creature* bomb = DoSpawnCreature(MOB_FIRE_BOMB, dx, dy, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 13000); + if(bomb) + FireBombGUIDs[i] = bomb->GetGUID(); + } + + Creature* ThrowController = DoSpawnCreature(MOB_FIRE_BOMB,0,0,1,0,TEMPSUMMON_TIMED_DESPAWN,10000); + if(ThrowController) + ThrowControllerGUID = ThrowController->GetGUID(); + + bombcounter = 0; + } + + void throw5Bombs() //throwanimation + { + for ( int i(0); i < 5; i++) + { + Unit* ThrowController = NULL; + Unit* FireBomb = NULL; + if(ThrowControllerGUID) + ThrowController = Unit::GetUnit((*m_creature), ThrowControllerGUID); + + if(FireBombGUIDs[bombcounter]) + FireBomb = Unit::GetUnit((*m_creature), FireBombGUIDs[bombcounter]); + + if(ThrowController && FireBomb) + { + ThrowController->CastSpell(FireBomb,SPELL_FIRE_BOMB_THROW,true); + FireBomb->CastSpell(FireBomb,SPELL_FIRE_BOMB_DUMMY,false); + bombcounter ++; + } + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if(!bombing) // every Spell if NOT Bombing + { + //FIRE BREATH several videos says every 8Secounds + if(fire_breath_timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if(target) + DoCast(target,SPELL_FLAME_BREATH); + fire_breath_timer = 8000; + }else fire_breath_timer -=diff; + + if(bomb_timer < diff) + { + FireWall(); + bomb_timer = 20000+rand()%20000; + m_creature->Relocate(JanalainPos[0][0],JanalainPos[0][1],JanalainPos[0][2],0); + m_creature->SendMonsterMove(JanalainPos[0][0], JanalainPos[0][1],JanalainPos[0][2],0,0,100); + DoYell(SAY_FIRE_BOMBS, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_FIRE_BOMBS); + throwBombs(); + bombing = true; + + //Teleport every Player into the middle + Unit* Temp = NULL; + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Temp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); + if (Temp && m_creature->GetDistance(Temp) > 30.0) + DoTeleportPlayer(Temp, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0); + } + DoCast(m_creature,SPELL_TELETOCENTER,true); // only Effect Spell + DoCast(m_creature,SPELL_FIRE_BOMB_CHANNEL,false); + finishedbomb_timer = 11000; + }else bomb_timer -=diff; + + //enrage if under 25% hp before 5 min. + if (((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) && !enraged) + { + enragetime = true; + enrage_timer = 600000; + } + + //Enrage but only if not bombing + if(enragetime && !enraged) + { + DoYell(SAY_BERSERK, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_BERSERK); + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature,SPELL_ENRAGE); + enraged = true; + } + } + + //Enrage after 5 minutes + if(enrage_timer < diff) + { + enragetime = true; + enrage_timer = 600000; + }else enrage_timer -=diff; + + if(bombing) // every Spell if Bombing + { + if(bombcounter < 40) + { + if(throw_timer < diff) + { + throw5Bombs(); + throw_timer = 1000; + }else throw_timer -=diff; + } + + if(finishedbomb_timer < diff) + { + bombing = false; + finishedbomb_timer = 6000; + m_creature->RemoveAura(SPELL_FIRE_BOMB_CHANNEL,0); + m_creature->RemoveAura(SPELL_FIRE_BOMB_CHANNEL,1); + }else finishedbomb_timer -=diff; + } + + //Call Hatcher + if(!noeggs) + { + if(hatchertime < diff) + { + if(pInstance->GetData(DATA_J_EGGSLEFT)>0 || pInstance->GetData(DATA_J_EGGSRIGHT) > 0) + { + Unit* hatcher = NULL; + DoYell(SAY_SUMMON_HATCHER, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_SUMMON_HATCHER); + hatcher = m_creature->SummonCreature(MOB_AMANI_HATCHER,hatcherway_l[0][0],hatcherway_l[0][1],hatcherway_l[0][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000); + if(hatcher) + hatcher->GetMotionMaster()->MovePoint(0, hatcherway_l[0][0], hatcherway_l[0][1], hatcherway_l[0][2]); + + hatcher = m_creature->SummonCreature(MOB_AMANI_HATCHER,hatcherway_r[0][0],hatcherway_r[0][1],hatcherway_r[0][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000); + if(hatcher) + hatcher->GetMotionMaster()->MovePoint(0, hatcherway_r[0][0],hatcherway_r[0][1],hatcherway_r[0][2]); + hatchertime = 45000; + } + else + { + noeggs = true; + } + }else hatchertime -=diff; + } + + //WIPE after 10 minutes + if(wipetimer < diff) + { + DoYell(SAY_BERSERK, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_BERSERK); + DoCast(m_creature,SPELL_ENRAGE); + + wipetimer = 30000; + }else wipetimer -=diff; + + //Hatch All + if(!noeggs && (m_creature->GetHealth()*100) / m_creature->GetMaxHealth() < 35) + { + DoYell(SAY_ALL_EGGS , LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature,SOUND_BERSERK); + + if(pInstance) + eggs = pInstance->GetData(DATA_J_EGGSLEFT); + + int i; + for(i=1;i<=eggs;i=i+1) + { + int r = (rand()%20 - 10); + int s = (rand()%20 - 10); + m_creature->SummonCreature(MOB_HATCHLING,JanalainPos[0][0]+s,JanalainPos[0][1]+r,JanalainPos[0][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,15000); + + if(pInstance) + pInstance->SetData(DATA_J_HATCHLEFT,1); + } + + if(pInstance) + eggs = pInstance->GetData(DATA_J_EGGSRIGHT); + + for(i=1;i<=eggs;i=i+1) + { + int r = (rand()%20 - 10); + int s = (rand()%20 - 10); + m_creature->SummonCreature(MOB_HATCHLING,JanalainPos[0][0]+s,JanalainPos[0][1]+r,JanalainPos[0][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,15000); + if(pInstance) + pInstance->SetData(DATA_J_HATCHRIGHT,1); + } + + noeggs = true; + } + + //check for reset ... exploit preventing ... pulled from his podest + if(reset_timer < diff) + { + if(m_creature->GetPositionX() < -70 || m_creature->GetPositionX() > 0) + { + EnterEvadeMode(); + reset_timer = 5000; //every 5 Seca + } + }else reset_timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_janalaiAI(Creature *_Creature) +{ + return new boss_janalaiAI (_Creature); +} + +struct MANGOS_DLL_DECL mob_jandalai_firebombAI : public ScriptedAI +{ + mob_jandalai_firebombAI(Creature *c) : ScriptedAI(c){Reset();} + + uint32 bomb_timer; + + void Reset() + { + bomb_timer = 12000; + } + + void Aggro(Unit* who) {} + + void AttackStart(Unit* who) {} + + void MoveInLineOfSight(Unit* who) {} + + void UpdateAI(const uint32 diff) + { + if(bomb_timer < diff) //Boom + { + m_creature->CastSpell(m_creature,SPELL_FIRE_BOMB_DAMAGE,false); + bomb_timer = 1800000; + }else bomb_timer -=diff; + } +}; + +CreatureAI* GetAI_mob_jandalai_firebombAI(Creature *_Creature) +{ + return new mob_jandalai_firebombAI (_Creature); +} + +struct MANGOS_DLL_DECL mob_amanishi_hatcherAI : public ScriptedAI +{ + mob_amanishi_hatcherAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 waypoint; + bool waytype; + bool start; + bool hatch; + bool wait; + uint32 hatchlings; + uint32 waittimer; + uint32 eggs; + uint32 delete_timer; + + void Reset() + { + waypoint = 0; + waytype = 0; + hatch = false; + start = false; + wait = false; + waittimer = 4000; + hatchlings = 0; + eggs = 0; + delete_timer = 10000; + + //m_creature->RemoveAllAuras(); + //m_creature->DeleteThreatList(); + //m_creature->CombatStop(); + //DoGoHome(); + } + + void Aggro(Unit* who) + { + } + + void UpdateAI(const uint32 diff) + { + if(pInstance && (pInstance->GetData(DATA_JANALAIEVENT) == 1)) + { + if(!start && !hatch) + { + waytype = ( m_creature->GetPositionY() > 1150); + waypoint = 1; + start = true; + } + + if(start && !hatch) + { + if(wait) + { + if(waittimer < diff) + { + wait = false; + waittimer = 4000; + waypoint++; + + if (waypoint == 5) + { + hatch = true; + waittimer = 0; + hatchlings = 1; + } + } + else + { + waittimer -=diff; + } + } + else + { + m_creature->GetMotionMaster()->Clear(); + if(waytype) + m_creature->GetMotionMaster()->MovePoint(0,hatcherway_l[waypoint][0],hatcherway_l[waypoint][1],hatcherway_l[waypoint][2]); + else + m_creature->GetMotionMaster()->MovePoint(0,hatcherway_r[waypoint][0],hatcherway_r[waypoint][1],hatcherway_r[waypoint][2]); + wait= true; + } + } + + if(start && hatch) + { + if(waittimer < diff) + { + if(!pInstance) + return; + + waittimer = 4000; + Unit* hatchling; + + if(waytype) + { + eggs = pInstance->GetData(DATA_J_EGGSLEFT); + + if(eggs > 0) + DoCast(m_creature,SPELL_HATCH_EGG); + + int i; + for(i=1;i<=hatchlings;i=i+1) + { + eggs = pInstance->GetData(DATA_J_EGGSLEFT); + if(eggs <= 0) + { + if (waytype) waytype = false; else waytype = true; + waittimer = 15000; + hatch = false; + waypoint = 4; + wait = true; + i = hatchlings; + } + else + { + hatchling = DoSpawnCreature(MOB_HATCHLING,rand()%4-2,rand()%4-2,0,0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,15000); + pInstance->SetData(DATA_J_HATCHLEFT,1); + } + } + + DoCast(m_creature,SPELL_HATCH_EGG); + + if(hatchlings < 5) + hatchlings++; + } + else + { + eggs = pInstance->GetData(DATA_J_EGGSRIGHT); + + if(eggs > 0) + DoCast(m_creature,SPELL_HATCH_EGG); + + int i; + for(i=1;i<=hatchlings;i=i+1) + { + eggs = pInstance->GetData(DATA_J_EGGSRIGHT); + if(eggs <= 0) + { + if (waytype) waytype = false; else waytype = true; + waittimer = 15000; + hatch = false; + waypoint = 4; + wait = true; + i = hatchlings; + } + else + { + hatchling = DoSpawnCreature(MOB_HATCHLING,rand()%4-2,rand()%4-2,0,0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,15000); + pInstance->SetData(DATA_J_HATCHRIGHT,1); + } + } + + DoCast(m_creature,SPELL_HATCH_EGG); + hatchlings++; + } + }else waittimer -=diff; + } + } + else + { + if(delete_timer < diff) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + delete_timer = 10000; + }else delete_timer -=diff; + } + } +}; + +CreatureAI* GetAI_mob_amanishi_hatcherAI(Creature *_Creature) +{ + return new mob_amanishi_hatcherAI (_Creature); +} + +struct MANGOS_DLL_DECL mob_hatchlingAI : public ScriptedAI +{ + mob_hatchlingAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 buffer_timer; + uint32 delete_timer; + bool start; + + void Reset() + { + buffer_timer = 7000; + delete_timer = 10000; + start = false; + } + + void Aggro(Unit *who) + { + } + + 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; + } + + if(delete_timer < diff && (pInstance && !(pInstance->GetData(DATA_JANALAIEVENT) == 1))) + { + if(!(m_creature->getVictim())) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + delete_timer = 10000; + }else delete_timer -=diff; + + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + if (buffer_timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if(target) + DoCast(target,SPELL_FLAMEBUFFED); + + buffer_timer = 7000; + }else buffer_timer -=diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_hatchlingAI(Creature *_Creature) +{ + return new mob_hatchlingAI (_Creature); +} + +void AddSC_boss_janalai() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_janalai"; + newscript->GetAI = GetAI_boss_janalaiAI; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_jandalai_firebomb"; + newscript->GetAI = GetAI_mob_jandalai_firebombAI; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_amanishi_hatcher"; + newscript->GetAI = GetAI_mob_amanishi_hatcherAI; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_hatchling"; + newscript->GetAI = GetAI_mob_hatchlingAI; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp index 01dae191217..0a207eae946 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp @@ -1,272 +1,272 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Nalorakk -SD%Complete: 80 -SDComment: Todo: Trash Waves -SDCategory: Zul'Aman -EndScriptData */ - -#include "precompiled.h" - -//TODO: Trash Waves - -//Unimplemented SoundIDs -/* -#define SOUND_NALORAKK_WAVE1 12066 -#define SOUND_NALORAKK_WAVE2 12067 -#define SOUND_NALORAKK_WAVE3 12068 -#define SOUND_NALORAKK_WAVE4 12069 - -#define SOUND_NALORAKK_EVENT1 12078 -#define SOUND_NALORAKK_EVENT2 12079 -*/ - -//General defines -#define YELL_AGGRO "You be dead soon enough!" -#define SOUND_YELL_AGGRO 12070 -#define YELL_KILL_ONE "Mua-ha-ha! Now whatchoo got to say?" -#define SOUND_YELL_KILL_ONE 12075 -#define YELL_KILL_TWO "Da Amani gonna rule again!" -#define SOUND_YELL_KILL_TWO 12076 -#define YELL_DEATH "I... be waitin' on da udda side...." -#define SOUND_YELL_DEATH 12077 - //Never seen this being used, so just guessing from what I hear. -#define YELL_BERSERK "You had your chance, now it be too late!" -#define SOUND_YELL_BERSERK 12074 - -#define SPELL_BERSERK 45078 //unsure, this increases damage, size and speed - -//Defines for Troll form -#define SPELL_BRUTALSWIPE 42384 -//#define SPELL_MANGLE 42389 This doesn't seem to apply the mangle debuff after all -#define SPELL_MANGLEEFFECT 44955 -#define SPELL_SURGE 42402 -#define SPELL_BEARFORM 42377 - -#define YELL_SURGE "I bring da pain!" -#define SOUND_YELL_SURGE 12071 - -#define YELL_SHIFTEDTOTROLL "Make way for Nalorakk!" -#define SOUND_YELL_TOTROLL 12073 - -//Defines for Bear form -#define SPELL_LACERATINGSLASH 42395 -#define SPELL_RENDFLESH 42397 -#define SPELL_DEAFENINGROAR 42398 - -#define YELL_SHIFTEDTOBEAR "You call on da beast, you gonna get more dan you bargain for!" -#define SOUND_YELL_TOBEAR 12072 - -struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI -{ - boss_nalorakkAI(Creature *c) : ScriptedAI(c) {Reset();} - - 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; - - 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; - } - - void Aggro(Unit *who) - { - DoYell(YELL_AGGRO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_YELL_AGGRO); - } - - void KilledUnit(Unit* victim) - { - switch(rand()%2) - { - case 0: - DoYell(YELL_KILL_ONE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_YELL_KILL_ONE); - break; - case 1: - DoYell(YELL_KILL_TWO, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_YELL_KILL_TWO); - break; - } - } - - void JustDied(Unit* Killer) - { - DoYell(YELL_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature, SOUND_YELL_DEATH); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Berserking - if ((Berserk_Timer < diff) && (!Berserking)) - { - DoCast(m_creature, SPELL_BERSERK); - DoYell(YELL_BERSERK, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_YELL_BERSERK); - Berserking = true; - }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, 0); - ShapeShiftCheck_Timer = 1000; - }else ShapeShiftCheck_Timer -= diff; - - //Spells for Troll Form (only to be casted if we NOT have bear phase aura) - if (!inBearForm) - { - //We just changed to troll form! - if (!ChangedToTroll) - { - DoYell(YELL_SHIFTEDTOTROLL, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_YELL_TOTROLL); - ChangedToTroll = true; - ChangedToBear = false; - //Reset spell timers - LaceratingSlash_Timer = 6000 + rand()%19000; - RendFlesh_Timer = 6000 + rand()%19000; - DeafeningRoar_Timer = 15000 + rand()%10000; - ShapeShiftCheck_Timer = 40000; - } - - //Brutal Swipe (some sources may say otherwise, but I've never seen this in Bear form) - if (BrutalSwipe_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_BRUTALSWIPE); - BrutalSwipe_Timer = 7000 + rand()%13000; - }else BrutalSwipe_Timer -= diff; - - //Mangle - if (Mangle_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_MANGLEEFFECT); - Mangle_Timer = 3000 + rand()%17000; - }else Mangle_Timer -= diff; - - //Surge - if (Surge_Timer < diff) - { - //select a random unit other than the main tank - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 1); - - //if there aren't other units, cast on the tank - if(!target) - target = m_creature->getVictim(); - - DoCast(target, SPELL_SURGE); - - DoYell(YELL_SURGE, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_YELL_SURGE); - - Surge_Timer = 15000 + rand()%17500; - }else Surge_Timer -= diff; - - //Change to Bear Form if we're in Troll Form for 45sec - if (ChangeForm_Timer < diff) - { - DoCast(m_creature, SPELL_BEARFORM); - //And 30sec (bear form) + 45sec (troll form) before we should cast this again - ChangeForm_Timer = 75000; - }else ChangeForm_Timer -= diff; - } - //Spells for Bear Form (only to be casted if we have bear phase aura) - else - { - //We just changed to bear form! - if (!ChangedToBear) - { - DoYell(YELL_SHIFTEDTOBEAR, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, SOUND_YELL_TOBEAR); - ChangedToBear = true; - ChangedToTroll = false; - //Reset spell timers - Surge_Timer = 15000 + rand()%17500; - BrutalSwipe_Timer = 7000 + rand()%13000; - Mangle_Timer = 3000 + rand()%17000; - ShapeShiftCheck_Timer = 25000; - } - - //Lacerating Slash - if (LaceratingSlash_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_LACERATINGSLASH); - LaceratingSlash_Timer = 6000 + rand()%19000; - }else LaceratingSlash_Timer -= diff; - - //Rend Flesh - if (RendFlesh_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_RENDFLESH); - RendFlesh_Timer = 6000 + rand()%19000; - }else RendFlesh_Timer -= diff; - - //Deafening Roar - if (DeafeningRoar_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_DEAFENINGROAR); - DeafeningRoar_Timer = 15000 + rand()%10000; - }else DeafeningRoar_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_nalorakk(Creature *_Creature) -{ - return new boss_nalorakkAI (_Creature); -} - -void AddSC_boss_nalorakk() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_nalorakk"; - newscript->GetAI = GetAI_boss_nalorakk; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Nalorakk +SD%Complete: 80 +SDComment: Todo: Trash Waves +SDCategory: Zul'Aman +EndScriptData */ + +#include "precompiled.h" + +//TODO: Trash Waves + +//Unimplemented SoundIDs +/* +#define SOUND_NALORAKK_WAVE1 12066 +#define SOUND_NALORAKK_WAVE2 12067 +#define SOUND_NALORAKK_WAVE3 12068 +#define SOUND_NALORAKK_WAVE4 12069 + +#define SOUND_NALORAKK_EVENT1 12078 +#define SOUND_NALORAKK_EVENT2 12079 +*/ + +//General defines +#define YELL_AGGRO "You be dead soon enough!" +#define SOUND_YELL_AGGRO 12070 +#define YELL_KILL_ONE "Mua-ha-ha! Now whatchoo got to say?" +#define SOUND_YELL_KILL_ONE 12075 +#define YELL_KILL_TWO "Da Amani gonna rule again!" +#define SOUND_YELL_KILL_TWO 12076 +#define YELL_DEATH "I... be waitin' on da udda side...." +#define SOUND_YELL_DEATH 12077 + //Never seen this being used, so just guessing from what I hear. +#define YELL_BERSERK "You had your chance, now it be too late!" +#define SOUND_YELL_BERSERK 12074 + +#define SPELL_BERSERK 45078 //unsure, this increases damage, size and speed + +//Defines for Troll form +#define SPELL_BRUTALSWIPE 42384 +//#define SPELL_MANGLE 42389 This doesn't seem to apply the mangle debuff after all +#define SPELL_MANGLEEFFECT 44955 +#define SPELL_SURGE 42402 +#define SPELL_BEARFORM 42377 + +#define YELL_SURGE "I bring da pain!" +#define SOUND_YELL_SURGE 12071 + +#define YELL_SHIFTEDTOTROLL "Make way for Nalorakk!" +#define SOUND_YELL_TOTROLL 12073 + +//Defines for Bear form +#define SPELL_LACERATINGSLASH 42395 +#define SPELL_RENDFLESH 42397 +#define SPELL_DEAFENINGROAR 42398 + +#define YELL_SHIFTEDTOBEAR "You call on da beast, you gonna get more dan you bargain for!" +#define SOUND_YELL_TOBEAR 12072 + +struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI +{ + boss_nalorakkAI(Creature *c) : ScriptedAI(c) {Reset();} + + 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; + + 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; + } + + void Aggro(Unit *who) + { + DoYell(YELL_AGGRO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_YELL_AGGRO); + } + + void KilledUnit(Unit* victim) + { + switch(rand()%2) + { + case 0: + DoYell(YELL_KILL_ONE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_YELL_KILL_ONE); + break; + case 1: + DoYell(YELL_KILL_TWO, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_YELL_KILL_TWO); + break; + } + } + + void JustDied(Unit* Killer) + { + DoYell(YELL_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature, SOUND_YELL_DEATH); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Berserking + if ((Berserk_Timer < diff) && (!Berserking)) + { + DoCast(m_creature, SPELL_BERSERK); + DoYell(YELL_BERSERK, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_YELL_BERSERK); + Berserking = true; + }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, 0); + ShapeShiftCheck_Timer = 1000; + }else ShapeShiftCheck_Timer -= diff; + + //Spells for Troll Form (only to be casted if we NOT have bear phase aura) + if (!inBearForm) + { + //We just changed to troll form! + if (!ChangedToTroll) + { + DoYell(YELL_SHIFTEDTOTROLL, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_YELL_TOTROLL); + ChangedToTroll = true; + ChangedToBear = false; + //Reset spell timers + LaceratingSlash_Timer = 6000 + rand()%19000; + RendFlesh_Timer = 6000 + rand()%19000; + DeafeningRoar_Timer = 15000 + rand()%10000; + ShapeShiftCheck_Timer = 40000; + } + + //Brutal Swipe (some sources may say otherwise, but I've never seen this in Bear form) + if (BrutalSwipe_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_BRUTALSWIPE); + BrutalSwipe_Timer = 7000 + rand()%13000; + }else BrutalSwipe_Timer -= diff; + + //Mangle + if (Mangle_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_MANGLEEFFECT); + Mangle_Timer = 3000 + rand()%17000; + }else Mangle_Timer -= diff; + + //Surge + if (Surge_Timer < diff) + { + //select a random unit other than the main tank + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 1); + + //if there aren't other units, cast on the tank + if(!target) + target = m_creature->getVictim(); + + DoCast(target, SPELL_SURGE); + + DoYell(YELL_SURGE, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_YELL_SURGE); + + Surge_Timer = 15000 + rand()%17500; + }else Surge_Timer -= diff; + + //Change to Bear Form if we're in Troll Form for 45sec + if (ChangeForm_Timer < diff) + { + DoCast(m_creature, SPELL_BEARFORM); + //And 30sec (bear form) + 45sec (troll form) before we should cast this again + ChangeForm_Timer = 75000; + }else ChangeForm_Timer -= diff; + } + //Spells for Bear Form (only to be casted if we have bear phase aura) + else + { + //We just changed to bear form! + if (!ChangedToBear) + { + DoYell(YELL_SHIFTEDTOBEAR, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_YELL_TOBEAR); + ChangedToBear = true; + ChangedToTroll = false; + //Reset spell timers + Surge_Timer = 15000 + rand()%17500; + BrutalSwipe_Timer = 7000 + rand()%13000; + Mangle_Timer = 3000 + rand()%17000; + ShapeShiftCheck_Timer = 25000; + } + + //Lacerating Slash + if (LaceratingSlash_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_LACERATINGSLASH); + LaceratingSlash_Timer = 6000 + rand()%19000; + }else LaceratingSlash_Timer -= diff; + + //Rend Flesh + if (RendFlesh_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_RENDFLESH); + RendFlesh_Timer = 6000 + rand()%19000; + }else RendFlesh_Timer -= diff; + + //Deafening Roar + if (DeafeningRoar_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_DEAFENINGROAR); + DeafeningRoar_Timer = 15000 + rand()%10000; + }else DeafeningRoar_Timer -= diff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_nalorakk(Creature *_Creature) +{ + return new boss_nalorakkAI (_Creature); +} + +void AddSC_boss_nalorakk() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_nalorakk"; + newscript->GetAI = GetAI_boss_nalorakk; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulaman/def_zulaman.h b/src/bindings/scripts/scripts/zone/zulaman/def_zulaman.h index 7a57eba2f51..66694fe51b6 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/def_zulaman.h +++ b/src/bindings/scripts/scripts/zone/zulaman/def_zulaman.h @@ -1,17 +1,17 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_ZULAMAN_H -#define DEF_ZULAMAN_H - -#define DATA_JANALAI 1 -#define DATA_JANALAIEVENT 2 -#define DATA_J_EGGSLEFT 3 -#define DATA_J_EGGSRIGHT 4 -#define DATA_J_HATCHLEFT 5 -#define DATA_J_HATCHRIGHT 6 - -#define TYPE_RAND_VENDOR_1 7 -#define TYPE_RAND_VENDOR_2 8 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_ZULAMAN_H +#define DEF_ZULAMAN_H + +#define DATA_JANALAI 1 +#define DATA_JANALAIEVENT 2 +#define DATA_J_EGGSLEFT 3 +#define DATA_J_EGGSRIGHT 4 +#define DATA_J_HATCHLEFT 5 +#define DATA_J_HATCHRIGHT 6 + +#define TYPE_RAND_VENDOR_1 7 +#define TYPE_RAND_VENDOR_2 8 +#endif diff --git a/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp b/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp index 7283a27d3a8..7f05e4e0bfb 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp @@ -1,137 +1,137 @@ -/* Copyright (C) 2006,2007 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_Zulaman -SD%Complete: 80 -SDComment: -SDCategory: Zul'Aman -EndScriptData */ - -#include "precompiled.h" -#include "def_zulaman.h" - -#define ENCOUNTERS 1 -#define RAND_VENDOR 2 - -struct MANGOS_DLL_DECL instance_zulaman : public ScriptedInstance -{ - instance_zulaman(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - uint64 janalai; - uint32 janalai_eggs_l; - uint32 janalai_eggs_r; - - uint32 Encounters[ENCOUNTERS]; - uint32 RandVendor[RAND_VENDOR]; - - void Initialize() - { - janalai = 0; - janalai_eggs_l = 20; - janalai_eggs_r = 20; - - for(uint8 i = 0; i < ENCOUNTERS; i++) - Encounters[i] = NOT_STARTED; - for(uint8 i = 0; i < RAND_VENDOR; i++) - RandVendor[i] = NOT_STARTED; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < ENCOUNTERS; i++) - if(Encounters[i] == IN_PROGRESS) return true; - - return false; - } - - void OnCreatureCreate(Creature *creature, uint32 creature_entry) - { - switch(creature_entry) - { - case 23578: - janalai = creature->GetGUID(); - break; - } - } - - uint64 GetData64(uint32 identifier) - { - if(identifier == DATA_JANALAI && janalai) - return janalai; - - return 0; - } - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_JANALAIEVENT: - if(data == 0) - { - janalai_eggs_l = 20; - janalai_eggs_r = 20; - } - Encounters[0] = data; - break; - case DATA_J_HATCHLEFT: - janalai_eggs_l -= data; - break; - case DATA_J_HATCHRIGHT: - janalai_eggs_r -= data; - break; - case TYPE_RAND_VENDOR_1: - RandVendor[0] = data; - break; - case TYPE_RAND_VENDOR_2: - RandVendor[1] = data; - break; - } - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_JANALAIEVENT: - return Encounters[0]; - case DATA_J_EGGSLEFT: - return janalai_eggs_l; - case DATA_J_EGGSRIGHT: - return janalai_eggs_r; - case TYPE_RAND_VENDOR_1: - return RandVendor[0]; - case TYPE_RAND_VENDOR_2: - return RandVendor[1]; - } - return 0; - } -}; - -InstanceData* GetInstanceData_instance_zulaman(Map* map) -{ - return new instance_zulaman(map); -} - -void AddSC_instance_zulaman() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_zulaman"; - newscript->GetInstanceData = GetInstanceData_instance_zulaman; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006,2007 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_Zulaman +SD%Complete: 80 +SDComment: +SDCategory: Zul'Aman +EndScriptData */ + +#include "precompiled.h" +#include "def_zulaman.h" + +#define ENCOUNTERS 1 +#define RAND_VENDOR 2 + +struct MANGOS_DLL_DECL instance_zulaman : public ScriptedInstance +{ + instance_zulaman(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint64 janalai; + uint32 janalai_eggs_l; + uint32 janalai_eggs_r; + + uint32 Encounters[ENCOUNTERS]; + uint32 RandVendor[RAND_VENDOR]; + + void Initialize() + { + janalai = 0; + janalai_eggs_l = 20; + janalai_eggs_r = 20; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounters[i] = NOT_STARTED; + for(uint8 i = 0; i < RAND_VENDOR; i++) + RandVendor[i] = NOT_STARTED; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounters[i] == IN_PROGRESS) return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, uint32 creature_entry) + { + switch(creature_entry) + { + case 23578: + janalai = creature->GetGUID(); + break; + } + } + + uint64 GetData64(uint32 identifier) + { + if(identifier == DATA_JANALAI && janalai) + return janalai; + + return 0; + } + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_JANALAIEVENT: + if(data == 0) + { + janalai_eggs_l = 20; + janalai_eggs_r = 20; + } + Encounters[0] = data; + break; + case DATA_J_HATCHLEFT: + janalai_eggs_l -= data; + break; + case DATA_J_HATCHRIGHT: + janalai_eggs_r -= data; + break; + case TYPE_RAND_VENDOR_1: + RandVendor[0] = data; + break; + case TYPE_RAND_VENDOR_2: + RandVendor[1] = data; + break; + } + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_JANALAIEVENT: + return Encounters[0]; + case DATA_J_EGGSLEFT: + return janalai_eggs_l; + case DATA_J_EGGSRIGHT: + return janalai_eggs_r; + case TYPE_RAND_VENDOR_1: + return RandVendor[0]; + case TYPE_RAND_VENDOR_2: + return RandVendor[1]; + } + return 0; + } +}; + +InstanceData* GetInstanceData_instance_zulaman(Map* map) +{ + return new instance_zulaman(map); +} + +void AddSC_instance_zulaman() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_zulaman"; + newscript->GetInstanceData = GetInstanceData_instance_zulaman; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp b/src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp index 965fc6cb11b..ebf945da7f9 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp @@ -1,108 +1,108 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Zulaman -SD%Complete: 90 -SDComment: Forest Frog will turn into different NPC's. Workaround to prevent new entry from running this script -SDCategory: Zul'Aman -EndScriptData */ - -/* ContentData -npc_forest_frog -EndContentData */ - -#include "precompiled.h" -#include "def_zulaman.h" - -/*###### -## npc_forest_frog -######*/ - -#define SPELL_REMOVE_AMANI_CURSE 43732 -#define SPELL_PUSH_MOJO 43923 -#define ENTRY_FOREST_FROG 24396 - -struct MANGOS_DLL_DECL npc_forest_frogAI : public ScriptedAI -{ - npc_forest_frogAI(Creature* c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - void Reset() { } - - void Aggro(Unit *who) { } - - void DoSpawnRandom() - { - if( pInstance ) - { - uint32 cEntry = 0; - switch(rand()%11) - { - 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 - } - - if( !pInstance->GetData(TYPE_RAND_VENDOR_1) ) - if(rand()%10 == 1) cEntry = 24408; //Gunter - if( !pInstance->GetData(TYPE_RAND_VENDOR_2) ) - if(rand()%10 == 1) cEntry = 24409; //Kyren - - if( cEntry ) m_creature->UpdateEntry(cEntry); - - if( cEntry == 24408) pInstance->SetData(TYPE_RAND_VENDOR_1,DONE); - if( cEntry == 24409) pInstance->SetData(TYPE_RAND_VENDOR_2,DONE); - } - } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if( spell->Id == SPELL_REMOVE_AMANI_CURSE && caster->GetTypeId() == TYPEID_PLAYER && m_creature->GetEntry() == ENTRY_FOREST_FROG ) - { - //increase or decrease chance of mojo? - if( rand()%99 == 50 ) DoCast(caster,SPELL_PUSH_MOJO,true); - else DoSpawnRandom(); - } - } -}; -CreatureAI* GetAI_npc_forest_frog(Creature *_Creature) -{ - return new npc_forest_frogAI (_Creature); -} - -void AddSC_zulaman() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_forest_frog"; - newscript->GetAI = GetAI_npc_forest_frog; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Zulaman +SD%Complete: 90 +SDComment: Forest Frog will turn into different NPC's. Workaround to prevent new entry from running this script +SDCategory: Zul'Aman +EndScriptData */ + +/* ContentData +npc_forest_frog +EndContentData */ + +#include "precompiled.h" +#include "def_zulaman.h" + +/*###### +## npc_forest_frog +######*/ + +#define SPELL_REMOVE_AMANI_CURSE 43732 +#define SPELL_PUSH_MOJO 43923 +#define ENTRY_FOREST_FROG 24396 + +struct MANGOS_DLL_DECL npc_forest_frogAI : public ScriptedAI +{ + npc_forest_frogAI(Creature* c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + void Reset() { } + + void Aggro(Unit *who) { } + + void DoSpawnRandom() + { + if( pInstance ) + { + uint32 cEntry = 0; + switch(rand()%11) + { + 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 + } + + if( !pInstance->GetData(TYPE_RAND_VENDOR_1) ) + if(rand()%10 == 1) cEntry = 24408; //Gunter + if( !pInstance->GetData(TYPE_RAND_VENDOR_2) ) + if(rand()%10 == 1) cEntry = 24409; //Kyren + + if( cEntry ) m_creature->UpdateEntry(cEntry); + + if( cEntry == 24408) pInstance->SetData(TYPE_RAND_VENDOR_1,DONE); + if( cEntry == 24409) pInstance->SetData(TYPE_RAND_VENDOR_2,DONE); + } + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if( spell->Id == SPELL_REMOVE_AMANI_CURSE && caster->GetTypeId() == TYPEID_PLAYER && m_creature->GetEntry() == ENTRY_FOREST_FROG ) + { + //increase or decrease chance of mojo? + if( rand()%99 == 50 ) DoCast(caster,SPELL_PUSH_MOJO,true); + else DoSpawnRandom(); + } + } +}; +CreatureAI* GetAI_npc_forest_frog(Creature *_Creature) +{ + return new npc_forest_frogAI (_Creature); +} + +void AddSC_zulaman() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_forest_frog"; + newscript->GetAI = GetAI_npc_forest_frog; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulfarrak/zulfarrak.cpp b/src/bindings/scripts/scripts/zone/zulfarrak/zulfarrak.cpp index c526a83ad7e..1834bcf7ff8 100644 --- a/src/bindings/scripts/scripts/zone/zulfarrak/zulfarrak.cpp +++ b/src/bindings/scripts/scripts/zone/zulfarrak/zulfarrak.cpp @@ -1,224 +1,224 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Zulfarrak -SD%Complete: 50 -SDComment: Consider it temporary, no instance script made for this instance yet. -SDCategory: Zul'Farrak -EndScriptData */ - -/* ContentData -npc_sergeant_bly -npc_weegli_blastfuse -EndContentData */ - -#include "precompiled.h" - -/*###### -## npc_sergeant_bly -######*/ - -#define FACTION_HOSTILE 14 -#define FACTION_FRIENDLY 35 - -#define SPELL_SHIELD_BASH 11972 -#define SPELL_REVENGE 12170 - -#define GOSSIP_BLY "[PH] In that case, i will take my reward!" - -struct MANGOS_DLL_DECL npc_sergeant_blyAI : public ScriptedAI -{ - npc_sergeant_blyAI(Creature *c) : ScriptedAI(c) - { - //pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - //ScriptedInstance* pInstance; - - uint32 ShieldBash_Timer; - uint32 Revenge_Timer; //this is wrong, spell should never be used unless m_creature->getVictim() dodge, parry or block attack. Mangos support required. - - void Reset() - { - ShieldBash_Timer = 5000; - Revenge_Timer = 8000; - - m_creature->setFaction(FACTION_FRIENDLY); - - /*if( pInstance ) - pInstance->SetData(0, NOT_STARTED);*/ - } - - void Aggro(Unit *who) - { - /*if( pInstance ) - pInstance->SetData(0, IN_PROGRESS);*/ - } - - void JustDied(Unit *victim) - { - /*if( pInstance ) - pInstance->SetData(0, DONE);*/ - } - - void UpdateAI(const uint32 diff) - { - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - if( ShieldBash_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_SHIELD_BASH); - ShieldBash_Timer = 15000; - }else ShieldBash_Timer -= diff; - - if( Revenge_Timer < diff ) - { - DoCast(m_creature->getVictim(),SPELL_REVENGE); - Revenge_Timer = 10000; - }else Revenge_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_sergeant_bly(Creature *_Creature) -{ - return new npc_sergeant_blyAI (_Creature); -} - -bool GossipHello_npc_sergeant_bly(Player *player, Creature *_Creature ) -{ - /*if( pInstance->GetData(0) == DONE ) - {*/ - player->ADD_GOSSIP_ITEM(1, GOSSIP_BLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(1517, _Creature->GetGUID()); - /*} - else if( pInstance->GetData(0) == IN_PROGRESS ) - player->SEND_GOSSIP_MENU(1516, _Creature->GetGUID()); - else - player->SEND_GOSSIP_MENU(1515, _Creature->GetGUID());*/ - - return true; -} - -bool GossipSelect_npc_sergeant_bly(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_INFO_DEF+1 ) - { - player->CLOSE_GOSSIP_MENU(); - _Creature->setFaction(FACTION_HOSTILE); - ((npc_sergeant_blyAI*)_Creature->AI())->AttackStart(player); - } - return true; -} - -/*###### -## npc_weegli_blastfuse -######*/ - -#define SPELL_BOMB 8858 -#define SPELL_GOBLIN_LAND_MINE 21688 -#define SPELL_SHOOT 6660 -#define 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 *c) : ScriptedAI(c) - { - //pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - //ScriptedInstance* pInstance; - - void Reset() - { - /*if( pInstance ) - pInstance->SetData(0, NOT_STARTED);*/ - } - - void Aggro(Unit *who) - { - /*if( pInstance ) - pInstance->SetData(0, IN_PROGRESS);*/ - } - - void JustDied(Unit *victim) - { - /*if( pInstance ) - pInstance->SetData(0, DONE);*/ - } - - void UpdateAI(const uint32 diff) - { - if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_weegli_blastfuse(Creature *_Creature) -{ - return new npc_weegli_blastfuseAI (_Creature); -} - -bool GossipHello_npc_weegli_blastfuse(Player *player, Creature *_Creature ) -{ - //event not implemented yet, this is only placeholder for future developement - /*if( pInstance->GetData(0) == DONE ) - { - player->ADD_GOSSIP_ITEM(1, GOSSIP_WEEGLI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(1514, _Creature->GetGUID());//if event can proceed to end - } - else if( pInstance->GetData(0) == IN_PROGRESS ) - player->SEND_GOSSIP_MENU(1513, _Creature->GetGUID());//if event are in progress - else*/ - player->SEND_GOSSIP_MENU(1511, _Creature->GetGUID()); //if event not started - return true; -} - -bool GossipSelect_npc_weegli_blastfuse(Player *player, Creature *_Creature, uint32 sender, uint32 action ) -{ - if( action == GOSSIP_ACTION_INFO_DEF+1 ) - { - player->CLOSE_GOSSIP_MENU(); - //here we make him run to door, set the charge and run away off to nowhere - } - return true; -} - -void AddSC_zulfarrak() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="npc_sergeant_bly"; - newscript->GetAI = GetAI_npc_sergeant_bly; - newscript->pGossipHello = &GossipHello_npc_sergeant_bly; - newscript->pGossipSelect = &GossipSelect_npc_sergeant_bly; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="npc_weegli_blastfuse"; - newscript->GetAI = GetAI_npc_weegli_blastfuse; - newscript->pGossipHello = &GossipHello_npc_weegli_blastfuse; - newscript->pGossipSelect = &GossipSelect_npc_weegli_blastfuse; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Zulfarrak +SD%Complete: 50 +SDComment: Consider it temporary, no instance script made for this instance yet. +SDCategory: Zul'Farrak +EndScriptData */ + +/* ContentData +npc_sergeant_bly +npc_weegli_blastfuse +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_sergeant_bly +######*/ + +#define FACTION_HOSTILE 14 +#define FACTION_FRIENDLY 35 + +#define SPELL_SHIELD_BASH 11972 +#define SPELL_REVENGE 12170 + +#define GOSSIP_BLY "[PH] In that case, i will take my reward!" + +struct MANGOS_DLL_DECL npc_sergeant_blyAI : public ScriptedAI +{ + npc_sergeant_blyAI(Creature *c) : ScriptedAI(c) + { + //pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + //ScriptedInstance* pInstance; + + uint32 ShieldBash_Timer; + uint32 Revenge_Timer; //this is wrong, spell should never be used unless m_creature->getVictim() dodge, parry or block attack. Mangos support required. + + void Reset() + { + ShieldBash_Timer = 5000; + Revenge_Timer = 8000; + + m_creature->setFaction(FACTION_FRIENDLY); + + /*if( pInstance ) + pInstance->SetData(0, NOT_STARTED);*/ + } + + void Aggro(Unit *who) + { + /*if( pInstance ) + pInstance->SetData(0, IN_PROGRESS);*/ + } + + void JustDied(Unit *victim) + { + /*if( pInstance ) + pInstance->SetData(0, DONE);*/ + } + + void UpdateAI(const uint32 diff) + { + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + if( ShieldBash_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_SHIELD_BASH); + ShieldBash_Timer = 15000; + }else ShieldBash_Timer -= diff; + + if( Revenge_Timer < diff ) + { + DoCast(m_creature->getVictim(),SPELL_REVENGE); + Revenge_Timer = 10000; + }else Revenge_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_sergeant_bly(Creature *_Creature) +{ + return new npc_sergeant_blyAI (_Creature); +} + +bool GossipHello_npc_sergeant_bly(Player *player, Creature *_Creature ) +{ + /*if( pInstance->GetData(0) == DONE ) + {*/ + player->ADD_GOSSIP_ITEM(1, GOSSIP_BLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(1517, _Creature->GetGUID()); + /*} + else if( pInstance->GetData(0) == IN_PROGRESS ) + player->SEND_GOSSIP_MENU(1516, _Creature->GetGUID()); + else + player->SEND_GOSSIP_MENU(1515, _Creature->GetGUID());*/ + + return true; +} + +bool GossipSelect_npc_sergeant_bly(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->setFaction(FACTION_HOSTILE); + ((npc_sergeant_blyAI*)_Creature->AI())->AttackStart(player); + } + return true; +} + +/*###### +## npc_weegli_blastfuse +######*/ + +#define SPELL_BOMB 8858 +#define SPELL_GOBLIN_LAND_MINE 21688 +#define SPELL_SHOOT 6660 +#define 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 *c) : ScriptedAI(c) + { + //pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + //ScriptedInstance* pInstance; + + void Reset() + { + /*if( pInstance ) + pInstance->SetData(0, NOT_STARTED);*/ + } + + void Aggro(Unit *who) + { + /*if( pInstance ) + pInstance->SetData(0, IN_PROGRESS);*/ + } + + void JustDied(Unit *victim) + { + /*if( pInstance ) + pInstance->SetData(0, DONE);*/ + } + + void UpdateAI(const uint32 diff) + { + if( !m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_npc_weegli_blastfuse(Creature *_Creature) +{ + return new npc_weegli_blastfuseAI (_Creature); +} + +bool GossipHello_npc_weegli_blastfuse(Player *player, Creature *_Creature ) +{ + //event not implemented yet, this is only placeholder for future developement + /*if( pInstance->GetData(0) == DONE ) + { + player->ADD_GOSSIP_ITEM(1, GOSSIP_WEEGLI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(1514, _Creature->GetGUID());//if event can proceed to end + } + else if( pInstance->GetData(0) == IN_PROGRESS ) + player->SEND_GOSSIP_MENU(1513, _Creature->GetGUID());//if event are in progress + else*/ + player->SEND_GOSSIP_MENU(1511, _Creature->GetGUID()); //if event not started + return true; +} + +bool GossipSelect_npc_weegli_blastfuse(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + { + player->CLOSE_GOSSIP_MENU(); + //here we make him run to door, set the charge and run away off to nowhere + } + return true; +} + +void AddSC_zulfarrak() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_sergeant_bly"; + newscript->GetAI = GetAI_npc_sergeant_bly; + newscript->pGossipHello = &GossipHello_npc_sergeant_bly; + newscript->pGossipSelect = &GossipSelect_npc_sergeant_bly; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="npc_weegli_blastfuse"; + newscript->GetAI = GetAI_npc_weegli_blastfuse; + newscript->pGossipHello = &GossipHello_npc_weegli_blastfuse; + newscript->pGossipSelect = &GossipSelect_npc_weegli_blastfuse; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_arlokk.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_arlokk.cpp index 7be65ad73f0..91e89f7490a 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_arlokk.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_arlokk.cpp @@ -1,211 +1,211 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Arlokk -SD%Complete: 95 -SDComment: Wrong cleave and red aura is missing. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#define SPELL_SHADOWWORDPAIN 23952 -#define SPELL_GOUGE 24698 -#define SPELL_MARK 24210 -#define SPELL_CLEAVE 26350 //Perhaps not right. Not a red aura... -#define SPELL_PANTHER_TRANSFORM 24190 - -#define SAY_TRANSFORM "Bethekk, your priestess calls upon your might!" -#define SAY_DEATH "At last I am free of the soul flayer..." - -#define SOUND_TRANSFORM 8416 -#define SOUND_DEATH 8412 - -struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI -{ - boss_arlokkAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ShadowWordPain_Timer; - uint32 Gouge_Timer; - uint32 Mark_Timer; - uint32 Cleave_Timer; - uint32 Vanish_Timer; - uint32 Summon_Timer; - uint32 Visible_Timer; - - Unit* markedTarget; - Creature *Panther; - uint32 Counter; - - bool PhaseTwo; - bool VanishedOnce; - - void Reset() - { - ShadowWordPain_Timer = 8000; - Gouge_Timer = 14000; - Mark_Timer = 35000; - Cleave_Timer = 4000; - Vanish_Timer = 60000; - Summon_Timer = 5000; - Visible_Timer = 6000; - - Counter = 0; - - markedTarget = NULL; - PhaseTwo = false; - VanishedOnce = false; - - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15218); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit *who) - { - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15218); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - - if(pInstance) - pInstance->SetData(DATA_ARLOKK_DEATH, 0); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget()) - return; - - if( m_creature->getVictim() && m_creature->isAlive()) - { - if (!PhaseTwo && ShadowWordPain_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); - ShadowWordPain_Timer = 15000; - }else ShadowWordPain_Timer -= diff; - - if (!PhaseTwo && Mark_Timer < diff) - { - markedTarget = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(markedTarget,SPELL_MARK); - Mark_Timer = 15000; - }else Mark_Timer -= diff; - - if (Summon_Timer < diff && Counter < 31) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - Panther = m_creature->SummonCreature(15101,-11532.79980,-1649.6734,41.4800,0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - - if(markedTarget && Panther ) - { Panther ->AI()->AttackStart(markedTarget); } - else - { Panther ->AI()->AttackStart(target); } - - Panther = m_creature->SummonCreature(15101,-11532.9970,-1606.4840,41.2979,0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - - if(markedTarget && Panther ) - { Panther ->AI()->AttackStart(markedTarget); } - else - { Panther ->AI()->AttackStart(target); } - - Counter++; - Summon_Timer = 5000; - }else Summon_Timer -= diff; - - if (Vanish_Timer < diff) - { - //Invisble Model - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,11686); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //m_creature->CombatStop(); - DoResetThreat(); - VanishedOnce = true; - Vanish_Timer = 45000; - Visible_Timer = 6000; - }else Vanish_Timer -= diff; - - if (VanishedOnce) - { - if(Visible_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - //The Panther Model - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15215); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - if (!PhaseTwo) - { - DoYell(SAY_TRANSFORM,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_TRANSFORM); - } - - 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); - DoStartAttackAndMovement(target); - //The Panther Model - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15215); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - PhaseTwo = true; - }else Visible_Timer -= diff; - } - - //Cleave_Timer - if(PhaseTwo && Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_CLEAVE); - Cleave_Timer = 16000; - }Cleave_Timer -=diff; - - //Gouge_Timer - if(PhaseTwo && Gouge_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_GOUGE); - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); - - Gouge_Timer = 17000+rand()%10000; - }else Gouge_Timer -= diff; - - DoMeleeAttackIfReady(); - } - } -}; -CreatureAI* GetAI_boss_arlokk(Creature *_Creature) -{ - return new boss_arlokkAI (_Creature); -} - -void AddSC_boss_arlokk() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_arlokk"; - newscript->GetAI = GetAI_boss_arlokk; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Arlokk +SD%Complete: 95 +SDComment: Wrong cleave and red aura is missing. +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#define SPELL_SHADOWWORDPAIN 23952 +#define SPELL_GOUGE 24698 +#define SPELL_MARK 24210 +#define SPELL_CLEAVE 26350 //Perhaps not right. Not a red aura... +#define SPELL_PANTHER_TRANSFORM 24190 + +#define SAY_TRANSFORM "Bethekk, your priestess calls upon your might!" +#define SAY_DEATH "At last I am free of the soul flayer..." + +#define SOUND_TRANSFORM 8416 +#define SOUND_DEATH 8412 + +struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI +{ + boss_arlokkAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ShadowWordPain_Timer; + uint32 Gouge_Timer; + uint32 Mark_Timer; + uint32 Cleave_Timer; + uint32 Vanish_Timer; + uint32 Summon_Timer; + uint32 Visible_Timer; + + Unit* markedTarget; + Creature *Panther; + uint32 Counter; + + bool PhaseTwo; + bool VanishedOnce; + + void Reset() + { + ShadowWordPain_Timer = 8000; + Gouge_Timer = 14000; + Mark_Timer = 35000; + Cleave_Timer = 4000; + Vanish_Timer = 60000; + Summon_Timer = 5000; + Visible_Timer = 6000; + + Counter = 0; + + markedTarget = NULL; + PhaseTwo = false; + VanishedOnce = false; + + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15218); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit *who) + { + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15218); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + + if(pInstance) + pInstance->SetData(DATA_ARLOKK_DEATH, 0); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget()) + return; + + if( m_creature->getVictim() && m_creature->isAlive()) + { + if (!PhaseTwo && ShadowWordPain_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); + ShadowWordPain_Timer = 15000; + }else ShadowWordPain_Timer -= diff; + + if (!PhaseTwo && Mark_Timer < diff) + { + markedTarget = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(markedTarget,SPELL_MARK); + Mark_Timer = 15000; + }else Mark_Timer -= diff; + + if (Summon_Timer < diff && Counter < 31) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + Panther = m_creature->SummonCreature(15101,-11532.79980,-1649.6734,41.4800,0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + + if(markedTarget && Panther ) + { Panther ->AI()->AttackStart(markedTarget); } + else + { Panther ->AI()->AttackStart(target); } + + Panther = m_creature->SummonCreature(15101,-11532.9970,-1606.4840,41.2979,0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + + if(markedTarget && Panther ) + { Panther ->AI()->AttackStart(markedTarget); } + else + { Panther ->AI()->AttackStart(target); } + + Counter++; + Summon_Timer = 5000; + }else Summon_Timer -= diff; + + if (Vanish_Timer < diff) + { + //Invisble Model + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,11686); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //m_creature->CombatStop(); + DoResetThreat(); + VanishedOnce = true; + Vanish_Timer = 45000; + Visible_Timer = 6000; + }else Vanish_Timer -= diff; + + if (VanishedOnce) + { + if(Visible_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + //The Panther Model + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15215); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (!PhaseTwo) + { + DoYell(SAY_TRANSFORM,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_TRANSFORM); + } + + 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); + DoStartAttackAndMovement(target); + //The Panther Model + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15215); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + PhaseTwo = true; + }else Visible_Timer -= diff; + } + + //Cleave_Timer + if(PhaseTwo && Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + Cleave_Timer = 16000; + }Cleave_Timer -=diff; + + //Gouge_Timer + if(PhaseTwo && Gouge_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_GOUGE); + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); + + Gouge_Timer = 17000+rand()%10000; + }else Gouge_Timer -= diff; + + DoMeleeAttackIfReady(); + } + } +}; +CreatureAI* GetAI_boss_arlokk(Creature *_Creature) +{ + return new boss_arlokkAI (_Creature); +} + +void AddSC_boss_arlokk() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_arlokk"; + newscript->GetAI = GetAI_boss_arlokk; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_gahzranka.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_gahzranka.cpp index 6fd39159cb5..6b879e58ed6 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_gahzranka.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_gahzranka.cpp @@ -1,92 +1,92 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 21099 -#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 *c) : ScriptedAI(c) {Reset();} - uint32 Frostbreath_Timer; - uint32 MassiveGeyser_Timer; - uint32 Slam_Timer; - - void Reset() - { - Frostbreath_Timer = 8000; - MassiveGeyser_Timer = 25000; - Slam_Timer = 17000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Frostbreath_Timer - if (Frostbreath_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_FROSTBREATH); - Frostbreath_Timer = 7000 + rand()%4000; - }else Frostbreath_Timer -= diff; - - //MassiveGeyser_Timer - if (MassiveGeyser_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MASSIVEGEYSER); - DoResetThreat(); - - MassiveGeyser_Timer = 22000 + rand()%10000; - }else MassiveGeyser_Timer -= diff; - - //Slam_Timer - if (Slam_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SLAM); - Slam_Timer = 12000 + rand()%8000; - }else Slam_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gahzranka(Creature *_Creature) -{ - return new boss_gahzrankaAI (_Creature); -} - -void AddSC_boss_gahzranka() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_gahzranka"; - newscript->GetAI = GetAI_boss_gahzranka; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 21099 +#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 *c) : ScriptedAI(c) {Reset();} + uint32 Frostbreath_Timer; + uint32 MassiveGeyser_Timer; + uint32 Slam_Timer; + + void Reset() + { + Frostbreath_Timer = 8000; + MassiveGeyser_Timer = 25000; + Slam_Timer = 17000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Frostbreath_Timer + if (Frostbreath_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_FROSTBREATH); + Frostbreath_Timer = 7000 + rand()%4000; + }else Frostbreath_Timer -= diff; + + //MassiveGeyser_Timer + if (MassiveGeyser_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MASSIVEGEYSER); + DoResetThreat(); + + MassiveGeyser_Timer = 22000 + rand()%10000; + }else MassiveGeyser_Timer -= diff; + + //Slam_Timer + if (Slam_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SLAM); + Slam_Timer = 12000 + rand()%8000; + }else Slam_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_gahzranka(Creature *_Creature) +{ + return new boss_gahzrankaAI (_Creature); +} + +void AddSC_boss_gahzranka() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gahzranka"; + newscript->GetAI = GetAI_boss_gahzranka; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_grilek.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_grilek.cpp index b25843dbb24..cb0567d0fcc 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_grilek.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_grilek.cpp @@ -1,92 +1,92 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_zulgurub.h" - -#define SPELL_AVARTAR 24646 //The Enrage Spell -#define SPELL_GROUNDTREMOR 6524 - -struct MANGOS_DLL_DECL boss_grilekAI : public ScriptedAI -{ - boss_grilekAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Avartar_Timer; - uint32 GroundTremor_Timer; - - void Reset() - { - Avartar_Timer = 15000 + rand()%10000; - GroundTremor_Timer = 8000 + rand()%8000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Avartar_Timer - if (Avartar_Timer < diff) - { - - DoCast(m_creature, SPELL_AVARTAR); - Unit* target = NULL; - - target = SelectUnit(SELECT_TARGET_RANDOM,1); - - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); - if (target) - DoStartAttackAndMovement(target); - - Avartar_Timer = 25000 + rand()%10000; - }else Avartar_Timer -= diff; - - //GroundTremor_Timer - if (GroundTremor_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_GROUNDTREMOR); - GroundTremor_Timer = 12000 + rand()%4000; - }else GroundTremor_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_grilek(Creature *_Creature) -{ - return new boss_grilekAI (_Creature); -} - -void AddSC_boss_grilek() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_grilek"; - newscript->GetAI = GetAI_boss_grilek; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_zulgurub.h" + +#define SPELL_AVARTAR 24646 //The Enrage Spell +#define SPELL_GROUNDTREMOR 6524 + +struct MANGOS_DLL_DECL boss_grilekAI : public ScriptedAI +{ + boss_grilekAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Avartar_Timer; + uint32 GroundTremor_Timer; + + void Reset() + { + Avartar_Timer = 15000 + rand()%10000; + GroundTremor_Timer = 8000 + rand()%8000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Avartar_Timer + if (Avartar_Timer < diff) + { + + DoCast(m_creature, SPELL_AVARTAR); + Unit* target = NULL; + + target = SelectUnit(SELECT_TARGET_RANDOM,1); + + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); + if (target) + DoStartAttackAndMovement(target); + + Avartar_Timer = 25000 + rand()%10000; + }else Avartar_Timer -= diff; + + //GroundTremor_Timer + if (GroundTremor_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_GROUNDTREMOR); + GroundTremor_Timer = 12000 + rand()%4000; + }else GroundTremor_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_grilek(Creature *_Creature) +{ + return new boss_grilekAI (_Creature); +} + +void AddSC_boss_grilek() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_grilek"; + newscript->GetAI = GetAI_boss_grilek; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_hakkar.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_hakkar.cpp index 719f2d77b87..16056784a18 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_hakkar.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_hakkar.cpp @@ -1,256 +1,256 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Hakkar -SD%Complete: 95 -SDComment: Blood siphon spell buggy cause of Core Issue. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#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 - -#define SAY_AGGRO "PRIDE HERALDS THE END OF YOUR WORLD. COME, MORTALS! FACE THE WRATH OF THE SOULFLAYER!" -#define SOUND_AGGRO 8414 - -#define SAY_SLAY "Fleeing will do you no good, mortals!" - -struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI -{ - boss_hakkarAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - uint32 BloodSiphon_Timer; - uint32 CorruptedBlood_Timer; - uint32 CauseInsanity_Timer; - uint32 WillOfHakkar_Timer; - uint32 Enrage_Timer; - - 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; - - ScriptedInstance *pInstance; - - bool Enraged; - - 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; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //BloodSiphon_Timer - if (BloodSiphon_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_BLOODSIPHON); - BloodSiphon_Timer = 90000; - }else BloodSiphon_Timer -= diff; - - //CorruptedBlood_Timer - if (CorruptedBlood_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CORRUPTEDBLOOD); - CorruptedBlood_Timer = 30000 + rand()%15000; - }else CorruptedBlood_Timer -= diff; - - //CauseInsanity_Timer - // if (CauseInsanity_Timer < diff) - // { - // - // Unit* target = NULL; - // target = SelectUnit(SELECT_TARGET_RANDOM,0); - - // DoCast(target,SPELL_CAUSEINSANITY); - - // CauseInsanity_Timer = 35000 + rand()%8000; - // }else CauseInsanity_Timer -= diff; - - //WillOfHakkar_Timer - if (WillOfHakkar_Timer < diff) - { - - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(target,SPELL_WILLOFHAKKAR); - WillOfHakkar_Timer = 25000 + rand()%10000; - }else WillOfHakkar_Timer -= diff; - - if (!Enraged && Enrage_Timer < diff) - { - DoCast(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(pInstance) - { - if(!pInstance->GetData(DATA_JEKLIKISDEAD)) - { - if (AspectOfJeklik_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ASPECT_OF_JEKLIK); - AspectOfJeklik_Timer = 10000 + rand()%4000; - }else AspectOfJeklik_Timer -= diff; - } - } - CheckJeklik_Timer = 1000; - }else CheckJeklik_Timer -= diff; - - //Checking if Venoxis is dead. If not we cast his Aspect - if(CheckVenoxis_Timer < diff) - { - if(pInstance) - { - if(!pInstance->GetData(DATA_VENOXISISDEAD)) - { - if (AspectOfVenoxis_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ASPECT_OF_VENOXIS); - AspectOfVenoxis_Timer = 8000; - }else AspectOfVenoxis_Timer -= diff; - } - } - CheckVenoxis_Timer = 1000; - }else CheckVenoxis_Timer -= diff; - - //Checking if Marli is dead. If not we cast her Aspect - if(CheckMarli_Timer < diff) - { - if(pInstance) - { - if(!pInstance->GetData(DATA_MARLIISDEAD)) - { - if (AspectOfMarli_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ASPECT_OF_MARLI); - AspectOfMarli_Timer = 10000; - }else AspectOfMarli_Timer -= diff; - - } - } - CheckMarli_Timer = 1000; - }else CheckMarli_Timer -= diff; - - //Checking if Thekal is dead. If not we cast his Aspect - if(CheckThekal_Timer < diff) - { - if(pInstance) - { - if(!pInstance->GetData(DATA_THEKALISDEAD)) - { - if (AspectOfThekal_Timer < diff) - { - DoCast(m_creature,SPELL_ASPECT_OF_THEKAL); - AspectOfThekal_Timer = 15000; - }else AspectOfThekal_Timer -= diff; - } - } - CheckThekal_Timer = 1000; - }else CheckThekal_Timer -= diff; - - //Checking if Arlokk is dead. If yes we cast her Aspect - if(CheckArlokk_Timer < diff) - { - if(pInstance) - { - if(!pInstance->GetData(DATA_ARLOKKISDEAD)) - { - if (AspectOfArlokk_Timer < diff) - { - DoCast(m_creature,SPELL_ASPECT_OF_ARLOKK); - DoResetThreat(); - - AspectOfArlokk_Timer = 10000 + rand()%5000; - }else AspectOfArlokk_Timer -= diff; - } - } - CheckArlokk_Timer = 1000; - }else CheckArlokk_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_hakkar(Creature *_Creature) -{ - return new boss_hakkarAI (_Creature); -} - -void AddSC_boss_hakkar() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_hakkar"; - newscript->GetAI = GetAI_boss_hakkar; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Hakkar +SD%Complete: 95 +SDComment: Blood siphon spell buggy cause of Core Issue. +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#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 + +#define SAY_AGGRO "PRIDE HERALDS THE END OF YOUR WORLD. COME, MORTALS! FACE THE WRATH OF THE SOULFLAYER!" +#define SOUND_AGGRO 8414 + +#define SAY_SLAY "Fleeing will do you no good, mortals!" + +struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI +{ + boss_hakkarAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + uint32 BloodSiphon_Timer; + uint32 CorruptedBlood_Timer; + uint32 CauseInsanity_Timer; + uint32 WillOfHakkar_Timer; + uint32 Enrage_Timer; + + 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; + + ScriptedInstance *pInstance; + + bool Enraged; + + 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; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //BloodSiphon_Timer + if (BloodSiphon_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_BLOODSIPHON); + BloodSiphon_Timer = 90000; + }else BloodSiphon_Timer -= diff; + + //CorruptedBlood_Timer + if (CorruptedBlood_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CORRUPTEDBLOOD); + CorruptedBlood_Timer = 30000 + rand()%15000; + }else CorruptedBlood_Timer -= diff; + + //CauseInsanity_Timer + // if (CauseInsanity_Timer < diff) + // { + // + // Unit* target = NULL; + // target = SelectUnit(SELECT_TARGET_RANDOM,0); + + // DoCast(target,SPELL_CAUSEINSANITY); + + // CauseInsanity_Timer = 35000 + rand()%8000; + // }else CauseInsanity_Timer -= diff; + + //WillOfHakkar_Timer + if (WillOfHakkar_Timer < diff) + { + + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(target,SPELL_WILLOFHAKKAR); + WillOfHakkar_Timer = 25000 + rand()%10000; + }else WillOfHakkar_Timer -= diff; + + if (!Enraged && Enrage_Timer < diff) + { + DoCast(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(pInstance) + { + if(!pInstance->GetData(DATA_JEKLIKISDEAD)) + { + if (AspectOfJeklik_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ASPECT_OF_JEKLIK); + AspectOfJeklik_Timer = 10000 + rand()%4000; + }else AspectOfJeklik_Timer -= diff; + } + } + CheckJeklik_Timer = 1000; + }else CheckJeklik_Timer -= diff; + + //Checking if Venoxis is dead. If not we cast his Aspect + if(CheckVenoxis_Timer < diff) + { + if(pInstance) + { + if(!pInstance->GetData(DATA_VENOXISISDEAD)) + { + if (AspectOfVenoxis_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ASPECT_OF_VENOXIS); + AspectOfVenoxis_Timer = 8000; + }else AspectOfVenoxis_Timer -= diff; + } + } + CheckVenoxis_Timer = 1000; + }else CheckVenoxis_Timer -= diff; + + //Checking if Marli is dead. If not we cast her Aspect + if(CheckMarli_Timer < diff) + { + if(pInstance) + { + if(!pInstance->GetData(DATA_MARLIISDEAD)) + { + if (AspectOfMarli_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ASPECT_OF_MARLI); + AspectOfMarli_Timer = 10000; + }else AspectOfMarli_Timer -= diff; + + } + } + CheckMarli_Timer = 1000; + }else CheckMarli_Timer -= diff; + + //Checking if Thekal is dead. If not we cast his Aspect + if(CheckThekal_Timer < diff) + { + if(pInstance) + { + if(!pInstance->GetData(DATA_THEKALISDEAD)) + { + if (AspectOfThekal_Timer < diff) + { + DoCast(m_creature,SPELL_ASPECT_OF_THEKAL); + AspectOfThekal_Timer = 15000; + }else AspectOfThekal_Timer -= diff; + } + } + CheckThekal_Timer = 1000; + }else CheckThekal_Timer -= diff; + + //Checking if Arlokk is dead. If yes we cast her Aspect + if(CheckArlokk_Timer < diff) + { + if(pInstance) + { + if(!pInstance->GetData(DATA_ARLOKKISDEAD)) + { + if (AspectOfArlokk_Timer < diff) + { + DoCast(m_creature,SPELL_ASPECT_OF_ARLOKK); + DoResetThreat(); + + AspectOfArlokk_Timer = 10000 + rand()%5000; + }else AspectOfArlokk_Timer -= diff; + } + } + CheckArlokk_Timer = 1000; + }else CheckArlokk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_hakkar(Creature *_Creature) +{ + return new boss_hakkarAI (_Creature); +} + +void AddSC_boss_hakkar() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_hakkar"; + newscript->GetAI = GetAI_boss_hakkar; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_hazzarah.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_hazzarah.cpp index adf5a44ec95..f4defb02a17 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_hazzarah.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_hazzarah.cpp @@ -1,100 +1,100 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Hazzarah -SD%Complete: 100 -SDComment: -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#define SPELL_MANABURN 26046 -#define SPELL_SLEEP 24664 - -struct MANGOS_DLL_DECL boss_hazzarahAI : public ScriptedAI -{ - boss_hazzarahAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 ManaBurn_Timer; - uint32 Sleep_Timer; - uint32 Illusions_Timer; - Creature* Illusion; - - void Reset() - { - ManaBurn_Timer = 4000 + rand()%6000; - Sleep_Timer = 10000 + rand()%8000; - Illusions_Timer = 10000 + rand()%8000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //ManaBurn_Timer - if (ManaBurn_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MANABURN); - ManaBurn_Timer = 8000 + rand()%8000; - }else ManaBurn_Timer -= diff; - - //Sleep_Timer - if (Sleep_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SLEEP); - Sleep_Timer = 12000 + rand()%8000; - }else Sleep_Timer -= diff; - - //Illusions_Timer - if (Illusions_Timer < diff) - { - //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 - Unit* target = NULL; - for(int i = 0; i < 3;i++) - { - target = SelectUnit(SELECT_TARGET_RANDOM,0); - Illusion = m_creature->SummonCreature(15163,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,30000); - ((CreatureAI*)Illusion->AI())->AttackStart(target); - } - - Illusions_Timer = 15000 + rand()%10000; - }else Illusions_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_hazzarah(Creature *_Creature) -{ - return new boss_hazzarahAI (_Creature); -} - -void AddSC_boss_hazzarah() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_hazzarah"; - newscript->GetAI = GetAI_boss_hazzarah; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Hazzarah +SD%Complete: 100 +SDComment: +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#define SPELL_MANABURN 26046 +#define SPELL_SLEEP 24664 + +struct MANGOS_DLL_DECL boss_hazzarahAI : public ScriptedAI +{ + boss_hazzarahAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 ManaBurn_Timer; + uint32 Sleep_Timer; + uint32 Illusions_Timer; + Creature* Illusion; + + void Reset() + { + ManaBurn_Timer = 4000 + rand()%6000; + Sleep_Timer = 10000 + rand()%8000; + Illusions_Timer = 10000 + rand()%8000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //ManaBurn_Timer + if (ManaBurn_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MANABURN); + ManaBurn_Timer = 8000 + rand()%8000; + }else ManaBurn_Timer -= diff; + + //Sleep_Timer + if (Sleep_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SLEEP); + Sleep_Timer = 12000 + rand()%8000; + }else Sleep_Timer -= diff; + + //Illusions_Timer + if (Illusions_Timer < diff) + { + //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 + Unit* target = NULL; + for(int i = 0; i < 3;i++) + { + target = SelectUnit(SELECT_TARGET_RANDOM,0); + Illusion = m_creature->SummonCreature(15163,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,30000); + ((CreatureAI*)Illusion->AI())->AttackStart(target); + } + + Illusions_Timer = 15000 + rand()%10000; + }else Illusions_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_hazzarah(Creature *_Creature) +{ + return new boss_hazzarahAI (_Creature); +} + +void AddSC_boss_hazzarah() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_hazzarah"; + newscript->GetAI = GetAI_boss_hazzarah; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_jeklik.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_jeklik.cpp index efe76bbe5ec..014c305a146 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_jeklik.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_jeklik.cpp @@ -1,297 +1,297 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Jeklik -SD%Complete: 85 -SDComment: Problem in finding the right flying batriders for spawning and making them fly. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#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... - -#define SAY_AGGRO "Lord Hireek grant me wings of vengance!" -#define SAY_DEATH "Hireek - Finnaly death. Curse you Hakkar! Curse you!" - -#define SOUND_AGGRO 8417 -#define SOUND_DEATH 8422 - -struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI -{ - boss_jeklikAI(Creature *c) : ScriptedAI(c) {Reset();} - - 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; - - bool PhaseTwo; - - 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; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - DoCast(m_creature,SPELL_BAT_FORM); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - - ScriptedInstance *pInstance = ((ScriptedInstance*)m_creature->GetInstanceData()); - if(pInstance) - pInstance->SetData(DATA_JEKLIK_DEATH, 0); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget()) - return; - - if( m_creature->getVictim() && m_creature->isAlive()) - { - if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > 50)) - { - if (Charge_Timer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0); - if(target) - { - DoCast(target,SPELL_CHARGE); - - m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); - DoStartAttackAndMovement(target); - } - - Charge_Timer = 15000 + rand()%15000; - }else Charge_Timer -= diff; - - if (SonicBurst_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SONICBURST); - SonicBurst_Timer = 8000 + rand()%5000; - }else SonicBurst_Timer -= diff; - - if (Screech_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SCREECH); - Screech_Timer = 18000 + rand()%8000; - }else Screech_Timer -= diff; - - if (SpawnBats_Timer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0); - - Creature* Bat = NULL; - Bat = m_creature->SummonCreature(11368,-12291.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Bat ) { Bat ->AI()->AttackStart(target); } - - Bat = m_creature->SummonCreature(11368,-12289.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Bat ) { Bat ->AI()->AttackStart(target); } - - Bat = m_creature->SummonCreature(11368,-12293.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Bat ) { Bat ->AI()->AttackStart(target); } - - Bat = m_creature->SummonCreature(11368,-12291.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Bat ) { Bat ->AI()->AttackStart(target); } - - Bat = m_creature->SummonCreature(11368,-12289.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Bat ) { Bat ->AI()->AttackStart(target); } - Bat = m_creature->SummonCreature(11368,-12293.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Bat ) { Bat ->AI()->AttackStart(target); } - - SpawnBats_Timer = 60000; - }else SpawnBats_Timer -= diff; - } - else - { - if(PhaseTwo) - { - if(PhaseTwo && ShadowWordPain_Timer < diff) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0); - if(target) - { - DoCast(target, SPELL_SHADOW_WORD_PAIN); - ShadowWordPain_Timer = 12000 + rand()%6000; - } - }ShadowWordPain_Timer -=diff; - - if(MindFlay_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_MIND_FLAY); - MindFlay_Timer = 16000; - }MindFlay_Timer -=diff; - - if(ChainMindFlay_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature->getVictim(), SPELL_CHAIN_MIND_FLAY); - ChainMindFlay_Timer = 15000 + rand()%15000; - }ChainMindFlay_Timer -=diff; - - if(GreaterHeal_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature,SPELL_GREATERHEAL); - GreaterHeal_Timer = 25000 + rand()%10000; - }GreaterHeal_Timer -=diff; - - if(SpawnFlyingBats_Timer < diff) - { - Unit *target = SelectUnit(SELECT_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) - { - if(target) - FlyingBat->AI()->AttackStart(target); - } - - SpawnFlyingBats_Timer = 10000 + rand()%5000; - }SpawnFlyingBats_Timer -=diff; - } - else - { - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15219); - DoResetThreat(); - PhaseTwo = true; - } - } - - DoMeleeAttackIfReady(); - } - } -}; - -//Flying Bat -struct MANGOS_DLL_DECL mob_batriderAI : public ScriptedAI -{ - mob_batriderAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - ScriptedInstance *pInstance; - - uint32 Bomb_Timer; - uint32 Check_Timer; - - void Reset() - { - Bomb_Timer = 2000; - Check_Timer = 1000; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit *who) {} - - void UpdateAI (const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Bomb_Timer - if(Bomb_Timer < diff) - { - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - { - DoCast(target, SPELL_BOMB); - Bomb_Timer = 5000; - } - }else Bomb_Timer -= diff; - - //Check_Timer - if(Check_Timer < diff) - { - if(pInstance) - { - if(pInstance->GetData(DATA_JEKLIKISDEAD)) - { - m_creature->setDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - } - } - - Check_Timer = 1000; - }else Check_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_jeklik(Creature *_Creature) -{ - return new boss_jeklikAI (_Creature); -} - -CreatureAI* GetAI_mob_batrider(Creature *_Creature) -{ - return new mob_batriderAI (_Creature); -} - -void AddSC_boss_jeklik() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_jeklik"; - newscript->GetAI = GetAI_boss_jeklik; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_batrider"; - newscript->GetAI = GetAI_mob_batrider; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Jeklik +SD%Complete: 85 +SDComment: Problem in finding the right flying batriders for spawning and making them fly. +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#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... + +#define SAY_AGGRO "Lord Hireek grant me wings of vengance!" +#define SAY_DEATH "Hireek - Finnaly death. Curse you Hakkar! Curse you!" + +#define SOUND_AGGRO 8417 +#define SOUND_DEATH 8422 + +struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI +{ + boss_jeklikAI(Creature *c) : ScriptedAI(c) {Reset();} + + 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; + + bool PhaseTwo; + + 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; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + DoCast(m_creature,SPELL_BAT_FORM); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + + ScriptedInstance *pInstance = ((ScriptedInstance*)m_creature->GetInstanceData()); + if(pInstance) + pInstance->SetData(DATA_JEKLIK_DEATH, 0); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget()) + return; + + if( m_creature->getVictim() && m_creature->isAlive()) + { + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > 50)) + { + if (Charge_Timer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0); + if(target) + { + DoCast(target,SPELL_CHARGE); + + m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); + DoStartAttackAndMovement(target); + } + + Charge_Timer = 15000 + rand()%15000; + }else Charge_Timer -= diff; + + if (SonicBurst_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SONICBURST); + SonicBurst_Timer = 8000 + rand()%5000; + }else SonicBurst_Timer -= diff; + + if (Screech_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SCREECH); + Screech_Timer = 18000 + rand()%8000; + }else Screech_Timer -= diff; + + if (SpawnBats_Timer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0); + + Creature* Bat = NULL; + Bat = m_creature->SummonCreature(11368,-12291.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Bat ) { Bat ->AI()->AttackStart(target); } + + Bat = m_creature->SummonCreature(11368,-12289.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Bat ) { Bat ->AI()->AttackStart(target); } + + Bat = m_creature->SummonCreature(11368,-12293.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Bat ) { Bat ->AI()->AttackStart(target); } + + Bat = m_creature->SummonCreature(11368,-12291.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Bat ) { Bat ->AI()->AttackStart(target); } + + Bat = m_creature->SummonCreature(11368,-12289.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Bat ) { Bat ->AI()->AttackStart(target); } + Bat = m_creature->SummonCreature(11368,-12293.6220,-1380.2640,144.8304,5.483, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Bat ) { Bat ->AI()->AttackStart(target); } + + SpawnBats_Timer = 60000; + }else SpawnBats_Timer -= diff; + } + else + { + if(PhaseTwo) + { + if(PhaseTwo && ShadowWordPain_Timer < diff) + { + Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0); + if(target) + { + DoCast(target, SPELL_SHADOW_WORD_PAIN); + ShadowWordPain_Timer = 12000 + rand()%6000; + } + }ShadowWordPain_Timer -=diff; + + if(MindFlay_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_MIND_FLAY); + MindFlay_Timer = 16000; + }MindFlay_Timer -=diff; + + if(ChainMindFlay_Timer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature->getVictim(), SPELL_CHAIN_MIND_FLAY); + ChainMindFlay_Timer = 15000 + rand()%15000; + }ChainMindFlay_Timer -=diff; + + if(GreaterHeal_Timer < diff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature,SPELL_GREATERHEAL); + GreaterHeal_Timer = 25000 + rand()%10000; + }GreaterHeal_Timer -=diff; + + if(SpawnFlyingBats_Timer < diff) + { + Unit *target = SelectUnit(SELECT_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) + { + if(target) + FlyingBat->AI()->AttackStart(target); + } + + SpawnFlyingBats_Timer = 10000 + rand()%5000; + }SpawnFlyingBats_Timer -=diff; + } + else + { + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15219); + DoResetThreat(); + PhaseTwo = true; + } + } + + DoMeleeAttackIfReady(); + } + } +}; + +//Flying Bat +struct MANGOS_DLL_DECL mob_batriderAI : public ScriptedAI +{ + mob_batriderAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + uint32 Bomb_Timer; + uint32 Check_Timer; + + void Reset() + { + Bomb_Timer = 2000; + Check_Timer = 1000; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit *who) {} + + void UpdateAI (const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Bomb_Timer + if(Bomb_Timer < diff) + { + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target) + { + DoCast(target, SPELL_BOMB); + Bomb_Timer = 5000; + } + }else Bomb_Timer -= diff; + + //Check_Timer + if(Check_Timer < diff) + { + if(pInstance) + { + if(pInstance->GetData(DATA_JEKLIKISDEAD)) + { + m_creature->setDeathState(JUST_DIED); + m_creature->RemoveCorpse(); + } + } + + Check_Timer = 1000; + }else Check_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_jeklik(Creature *_Creature) +{ + return new boss_jeklikAI (_Creature); +} + +CreatureAI* GetAI_mob_batrider(Creature *_Creature) +{ + return new mob_batriderAI (_Creature); +} + +void AddSC_boss_jeklik() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_jeklik"; + newscript->GetAI = GetAI_boss_jeklik; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_batrider"; + newscript->GetAI = GetAI_mob_batrider; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_jindo.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_jindo.cpp index 8a9a5cb2cc8..79ae84968b8 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_jindo.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_jindo.cpp @@ -1,308 +1,272 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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'do the Hexxer -SD%Complete: 85 -SDComment: Mind Control not working because of core bug. Shades visible for all. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#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. - -//Healing Ward Spell -#define SPELL_HEAL 38588 //Totems are not working right. Right heal spell ID is 24311 but this spell is not casting... - -//Shade of Jindo Spell -#define SPELL_SHADOWSHOCK 19460 -#define SPELL_INVISIBLE 24699 - -#define SAY_AGGRO "Welcome to da great show friends! Step right up to die!" - -#define SOUND_AGGRO 8425 - -struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI -{ - boss_jindoAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 BrainWashTotem_Timer; - uint32 HealingWard_Timer; - uint32 Hex_Timer; - uint32 Delusions_Timer; - uint32 Teleport_Timer; - - Creature *Shade; - Creature *Skeletons; - Creature *HealingWard; - - ScriptedInstance *pInstance; - - void Reset() - { - BrainWashTotem_Timer = 20000; - HealingWard_Timer = 16000; - Hex_Timer = 8000; - Delusions_Timer = 10000; - Teleport_Timer = 5000; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //BrainWashTotem_Timer - if (BrainWashTotem_Timer < diff) - { - DoCast(m_creature, SPELL_BRAINWASHTOTEM); - BrainWashTotem_Timer = 18000 + rand()%8000; - }else BrainWashTotem_Timer -= diff; - - //HealingWard_Timer - if (HealingWard_Timer < diff) - { - //DoCast(m_creature, SPELL_POWERFULLHEALINGWARD); - HealingWard = m_creature->SummonCreature(14987, m_creature->GetPositionX()+3, m_creature->GetPositionY()-2, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,30000); - HealingWard_Timer = 14000 + rand()%6000; - }else HealingWard_Timer -= diff; - - //Hex_Timer - if (Hex_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_HEX); - - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); - - Hex_Timer = 12000 + rand()%8000; - }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) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(target, SPELL_DELUSIONSOFJINDO); - - Shade = m_creature->SummonCreature(14986, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Shade->AI()->AttackStart(target); - - Delusions_Timer = 4000 + rand()%8000; - }else Delusions_Timer -= diff; - - //Teleporting a random gamer and spawning 9 skeletons that will attack this gamer - if (Teleport_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target && target->GetTypeId() == TYPEID_PLAYER) - { - DoTeleportPlayer(target, -11583.7783,-1249.4278,77.5471,4.745); - - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(target,-100); - - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()-2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()-4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()+2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()-2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()+4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()-4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+3, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Skeletons->AI()->AttackStart(target); - } - - Teleport_Timer = 15000 + rand()%8000; - }else Teleport_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Healing Ward -struct MANGOS_DLL_DECL mob_healing_wardAI : public ScriptedAI -{ - mob_healing_wardAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 Heal_Timer; - - ScriptedInstance *pInstance; - - void Reset() - { - Heal_Timer = 2000; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI (const uint32 diff) - { - //Heal_Timer - if(Heal_Timer < diff) - { - if(pInstance) - { - Unit *pJindo = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_JINDO)); - DoCast(pJindo, SPELL_HEAL); - } - Heal_Timer = 3000; - }else Heal_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Shade of Jindo -struct MANGOS_DLL_DECL mob_shade_of_jindoAI : public ScriptedAI -{ - mob_shade_of_jindoAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 ShadowShock_Timer; - - ScriptedInstance *pInstance; - - void Reset() - { - ShadowShock_Timer = 1000; - m_creature->CastSpell(m_creature, SPELL_INVISIBLE,true); - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI (const uint32 diff) - { - - //ShadowShock_Timer - if(ShadowShock_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SHADOWSHOCK); - ShadowShock_Timer = 2000; - }else ShadowShock_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_jindo(Creature *_Creature) -{ - return new boss_jindoAI (_Creature); -} - -CreatureAI* GetAI_mob_healing_ward(Creature *_Creature) -{ - return new mob_healing_wardAI (_Creature); -} - -CreatureAI* GetAI_mob_shade_of_jindo(Creature *_Creature) -{ - return new mob_shade_of_jindoAI (_Creature); -} - -void AddSC_boss_jindo() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_jindo"; - newscript->GetAI = GetAI_boss_jindo; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_healing_ward"; - newscript->GetAI = GetAI_mob_healing_ward; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_shade_of_jindo"; - newscript->GetAI = GetAI_mob_shade_of_jindo; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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'do the Hexxer +SD%Complete: 85 +SDComment: Mind Control not working because of core bug. Shades visible for all. +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#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. + +//Healing Ward Spell +#define SPELL_HEAL 38588 //Totems are not working right. Right heal spell ID is 24311 but this spell is not casting... + +//Shade of Jindo Spell +#define SPELL_SHADOWSHOCK 19460 +#define SPELL_INVISIBLE 24699 + +#define SAY_AGGRO "Welcome to da great show friends! Step right up to die!" + +#define SOUND_AGGRO 8425 + +struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI +{ + boss_jindoAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 BrainWashTotem_Timer; + uint32 HealingWard_Timer; + uint32 Hex_Timer; + uint32 Delusions_Timer; + uint32 Teleport_Timer; + + Creature *Shade; + Creature *Skeletons; + Creature *HealingWard; + + ScriptedInstance *pInstance; + + void Reset() + { + BrainWashTotem_Timer = 20000; + HealingWard_Timer = 16000; + Hex_Timer = 8000; + Delusions_Timer = 10000; + Teleport_Timer = 5000; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //BrainWashTotem_Timer + if (BrainWashTotem_Timer < diff) + { + DoCast(m_creature, SPELL_BRAINWASHTOTEM); + BrainWashTotem_Timer = 18000 + rand()%8000; + }else BrainWashTotem_Timer -= diff; + + //HealingWard_Timer + if (HealingWard_Timer < diff) + { + //DoCast(m_creature, SPELL_POWERFULLHEALINGWARD); + HealingWard = m_creature->SummonCreature(14987, m_creature->GetPositionX()+3, m_creature->GetPositionY()-2, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,30000); + HealingWard_Timer = 14000 + rand()%6000; + }else HealingWard_Timer -= diff; + + //Hex_Timer + if (Hex_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_HEX); + + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); + + Hex_Timer = 12000 + rand()%8000; + }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) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(target, SPELL_DELUSIONSOFJINDO); + + Shade = m_creature->SummonCreature(14986, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Shade->AI()->AttackStart(target); + + Delusions_Timer = 4000 + rand()%8000; + }else Delusions_Timer -= diff; + + //Teleporting a random gamer and spawning 9 skeletons that will attack this gamer + if (Teleport_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target && target->GetTypeId() == TYPEID_PLAYER) + { + DoTeleportPlayer(target, -11583.7783,-1249.4278,77.5471,4.745); + + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(target,-100); + + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()-2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()-4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()+2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()-2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()+4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()-4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+3, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + Skeletons->AI()->AttackStart(target); + } + + Teleport_Timer = 15000 + rand()%8000; + }else Teleport_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Healing Ward +struct MANGOS_DLL_DECL mob_healing_wardAI : public ScriptedAI +{ + mob_healing_wardAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 Heal_Timer; + + ScriptedInstance *pInstance; + + void Reset() + { + Heal_Timer = 2000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI (const uint32 diff) + { + //Heal_Timer + if(Heal_Timer < diff) + { + if(pInstance) + { + Unit *pJindo = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_JINDO)); + DoCast(pJindo, SPELL_HEAL); + } + Heal_Timer = 3000; + }else Heal_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +//Shade of Jindo +struct MANGOS_DLL_DECL mob_shade_of_jindoAI : public ScriptedAI +{ + mob_shade_of_jindoAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 ShadowShock_Timer; + + ScriptedInstance *pInstance; + + void Reset() + { + ShadowShock_Timer = 1000; + m_creature->CastSpell(m_creature, SPELL_INVISIBLE,true); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI (const uint32 diff) + { + + //ShadowShock_Timer + if(ShadowShock_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SHADOWSHOCK); + ShadowShock_Timer = 2000; + }else ShadowShock_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_jindo(Creature *_Creature) +{ + return new boss_jindoAI (_Creature); +} + +CreatureAI* GetAI_mob_healing_ward(Creature *_Creature) +{ + return new mob_healing_wardAI (_Creature); +} + +CreatureAI* GetAI_mob_shade_of_jindo(Creature *_Creature) +{ + return new mob_shade_of_jindoAI (_Creature); +} + +void AddSC_boss_jindo() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_jindo"; + newscript->GetAI = GetAI_boss_jindo; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_healing_ward"; + newscript->GetAI = GetAI_mob_healing_ward; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_shade_of_jindo"; + newscript->GetAI = GetAI_mob_shade_of_jindo; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_mandokir.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_mandokir.cpp index 7d8465b2780..3ffb5a0d32a 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_mandokir.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_mandokir.cpp @@ -1,311 +1,311 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Mandokir -SD%Complete: 90 -SDComment: Ohgan function needs improvements. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#define SPELL_CHARGE 24315 -#define SPELL_CLEAVE 20691 -#define SPELL_FEAR 29321 -#define SPELL_WHIRLWIND 24236 -#define SPELL_MORTAL_STRIKE 24573 -#define SPELL_ENRAGE 23537 -#define SPELL_WATCH 24314 -#define SPELL_LEVEL_UP 24312 - -//Ohgans Spells -#define SPELL_SUNDERARMOR 24317 - -#define SAY_AGGRO "I'll feed your souls to Hakkar himself!" -#define SOUND_AGGRO 8413 - -#define SAY_WATCH "I'm keeping my eye on you, $N!" -#define SAY_KILL "DING!" - -struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI -{ - boss_mandokirAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - uint32 Watch_Timer; - uint32 TargetInRange; - uint32 Cleave_Timer; - uint32 Whirlwind_Timer; - uint32 Fear_Timer; - uint32 MortalStrike_Timer; - uint32 Check_Timer; - float targetX; - float targetY; - float targetZ; - - ScriptedInstance *pInstance; - - bool endWatch; - bool someWatched; - bool RaptorDead; - bool CombatStart; - - uint64 WatchTarget; - - void Reset() - { - Watch_Timer = 33000; - Cleave_Timer = 7000; - Whirlwind_Timer = 20000; - Fear_Timer = 1000; - MortalStrike_Timer = 1000; - Check_Timer = 1000; - - targetX = 0.0; - targetY = 0.0; - targetZ = 0.0; - TargetInRange = 0; - - WatchTarget = 0; - - someWatched = false; - endWatch = false; - RaptorDead = false; - CombatStart = false; - - DoCast(m_creature, 23243); - } - - void KilledUnit(Unit* victim) - { - if(victim->GetTypeId() == TYPEID_PLAYER) - { - DoYell(SAY_KILL, LANG_UNIVERSAL, NULL); - DoCast(m_creature, SPELL_LEVEL_UP, true); - } - } - - void Aggro(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget()) - return; - - if( m_creature->getVictim() && m_creature->isAlive()) - { - if(!CombatStart) - { - //At combat Start Mandokir is mounted so we must unmount it first - m_creature->Unmount(); - - //And summon his raptor - m_creature->SummonCreature(14988, m_creature->getVictim()->GetPositionX(), m_creature->getVictim()->GetPositionY(), m_creature->getVictim()->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); - CombatStart = true; - } - - if (Watch_Timer < diff) //Every 20 Sec Mandokir will check this - { - if(WatchTarget) //If someone is watched and If the Position of the watched target is different from the one stored, or are attacking, mandokir will charge him - { - Unit* pUnit = Unit::GetUnit(*m_creature, WatchTarget); - - if( pUnit && ( - targetX != pUnit->GetPositionX() || - targetY != pUnit->GetPositionY() || - targetZ != pUnit->GetPositionZ() || - pUnit->isInCombat())) - { - if(m_creature->IsWithinDistInMap(pUnit, ATTACK_DISTANCE)) - { - DoCast(pUnit,24316); - } - else - { - DoCast(pUnit,SPELL_CHARGE); - m_creature->SendMonsterMove(pUnit->GetPositionX(), pUnit->GetPositionY(), pUnit->GetPositionZ(), 0, true,1); - DoStartAttackAndMovement(pUnit); - } - } - } - someWatched = false; - Watch_Timer = 20000; - }else Watch_Timer -= diff; - - if ((Watch_Timer < 8000) && !someWatched) //8 sec(cast time + expire time) before the check for the watch effect mandokir will cast watch debuff on a random target - { - Unit* p = SelectUnit(SELECT_TARGET_RANDOM,0); - if(p) - { - DoYell(SAY_WATCH, LANG_UNIVERSAL, p); - DoCast(p, SPELL_WATCH); - WatchTarget = p->GetGUID(); - someWatched = true; - endWatch = true; - } - } - - if ((Watch_Timer < 1000) && endWatch) //1 sec before the debuf expire, store the target position - { - Unit* pUnit = Unit::GetUnit(*m_creature, WatchTarget); - if (pUnit) - { - targetX = pUnit->GetPositionX(); - targetY = pUnit->GetPositionY(); - targetZ = pUnit->GetPositionZ(); - } - endWatch = false; - } - - if(!someWatched) - { - //Cleave - if (Cleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - //Whirlwind - if (Whirlwind_Timer < diff) - { - DoCast(m_creature,SPELL_WHIRLWIND); - Whirlwind_Timer = 18000; - }else Whirlwind_Timer -= diff; - - //If more then 3 targets in melee range mandokir will cast fear - if (Fear_Timer < diff) - { - TargetInRange = 0; - - std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for(; i != m_creature->getThreatManager().getThreatList().end(); ++i) - { - Unit* pUnit = Unit::GetUnit(*m_creature, (*i)->getUnitGuid()); - if(pUnit && m_creature->IsWithinDistInMap(pUnit, ATTACK_DISTANCE)) - TargetInRange++; - } - - if(TargetInRange > 3) - DoCast(m_creature->getVictim(),SPELL_FEAR); - - Fear_Timer = 4000; - }else Fear_Timer -=diff; - - //Mortal Strike if target below 50% hp - if (m_creature->getVictim()->GetHealth() < m_creature->getVictim()->GetMaxHealth()*0.5) - { - if (MortalStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTAL_STRIKE); - MortalStrike_Timer = 15000; - }else MortalStrike_Timer -= diff; - } - } - //Checking if Ohgan is dead. If yes Mandokir will enrage. - if(Check_Timer < diff) - { - if(pInstance) - { - if(pInstance->GetData(DATA_OHGANISDEAD)) - { - if (!RaptorDead) - { - DoCast(m_creature, SPELL_ENRAGE); - RaptorDead = true; - } - } - } - - Check_Timer = 1000; - }else Check_Timer -= diff; - - DoMeleeAttackIfReady(); - } - } -}; - -//Ohgan -struct MANGOS_DLL_DECL mob_ohganAI : public ScriptedAI -{ - mob_ohganAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - Reset(); - } - - uint32 SunderArmor_Timer; - ScriptedInstance *pInstance; - - void Reset() - { - SunderArmor_Timer = 5000; - } - - void Aggro(Unit *who) {} - - void JustDied(Unit* Killer) - { - if(pInstance) - pInstance->SetData(DATA_OHGAN_DEATH, 0); - } - - void UpdateAI (const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //SunderArmor_Timer - if(SunderArmor_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_SUNDERARMOR); - SunderArmor_Timer = 10000 + rand()%5000; - }else SunderArmor_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_mandokir(Creature *_Creature) -{ - return new boss_mandokirAI (_Creature); -} - -CreatureAI* GetAI_mob_ohgan(Creature *_Creature) -{ - return new mob_ohganAI (_Creature); -} - -void AddSC_boss_mandokir() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_mandokir"; - newscript->GetAI = GetAI_boss_mandokir; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_ohgan"; - newscript->GetAI = GetAI_mob_ohgan; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Mandokir +SD%Complete: 90 +SDComment: Ohgan function needs improvements. +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#define SPELL_CHARGE 24315 +#define SPELL_CLEAVE 20691 +#define SPELL_FEAR 29321 +#define SPELL_WHIRLWIND 24236 +#define SPELL_MORTAL_STRIKE 24573 +#define SPELL_ENRAGE 23537 +#define SPELL_WATCH 24314 +#define SPELL_LEVEL_UP 24312 + +//Ohgans Spells +#define SPELL_SUNDERARMOR 24317 + +#define SAY_AGGRO "I'll feed your souls to Hakkar himself!" +#define SOUND_AGGRO 8413 + +#define SAY_WATCH "I'm keeping my eye on you, $N!" +#define SAY_KILL "DING!" + +struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI +{ + boss_mandokirAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + uint32 Watch_Timer; + uint32 TargetInRange; + uint32 Cleave_Timer; + uint32 Whirlwind_Timer; + uint32 Fear_Timer; + uint32 MortalStrike_Timer; + uint32 Check_Timer; + float targetX; + float targetY; + float targetZ; + + ScriptedInstance *pInstance; + + bool endWatch; + bool someWatched; + bool RaptorDead; + bool CombatStart; + + uint64 WatchTarget; + + void Reset() + { + Watch_Timer = 33000; + Cleave_Timer = 7000; + Whirlwind_Timer = 20000; + Fear_Timer = 1000; + MortalStrike_Timer = 1000; + Check_Timer = 1000; + + targetX = 0.0; + targetY = 0.0; + targetZ = 0.0; + TargetInRange = 0; + + WatchTarget = 0; + + someWatched = false; + endWatch = false; + RaptorDead = false; + CombatStart = false; + + DoCast(m_creature, 23243); + } + + void KilledUnit(Unit* victim) + { + if(victim->GetTypeId() == TYPEID_PLAYER) + { + DoYell(SAY_KILL, LANG_UNIVERSAL, NULL); + DoCast(m_creature, SPELL_LEVEL_UP, true); + } + } + + void Aggro(Unit *who) {} + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget()) + return; + + if( m_creature->getVictim() && m_creature->isAlive()) + { + if(!CombatStart) + { + //At combat Start Mandokir is mounted so we must unmount it first + m_creature->Unmount(); + + //And summon his raptor + m_creature->SummonCreature(14988, m_creature->getVictim()->GetPositionX(), m_creature->getVictim()->GetPositionY(), m_creature->getVictim()->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); + CombatStart = true; + } + + if (Watch_Timer < diff) //Every 20 Sec Mandokir will check this + { + if(WatchTarget) //If someone is watched and If the Position of the watched target is different from the one stored, or are attacking, mandokir will charge him + { + Unit* pUnit = Unit::GetUnit(*m_creature, WatchTarget); + + if( pUnit && ( + targetX != pUnit->GetPositionX() || + targetY != pUnit->GetPositionY() || + targetZ != pUnit->GetPositionZ() || + pUnit->isInCombat())) + { + if(m_creature->IsWithinDistInMap(pUnit, ATTACK_DISTANCE)) + { + DoCast(pUnit,24316); + } + else + { + DoCast(pUnit,SPELL_CHARGE); + m_creature->SendMonsterMove(pUnit->GetPositionX(), pUnit->GetPositionY(), pUnit->GetPositionZ(), 0, true,1); + DoStartAttackAndMovement(pUnit); + } + } + } + someWatched = false; + Watch_Timer = 20000; + }else Watch_Timer -= diff; + + if ((Watch_Timer < 8000) && !someWatched) //8 sec(cast time + expire time) before the check for the watch effect mandokir will cast watch debuff on a random target + { + Unit* p = SelectUnit(SELECT_TARGET_RANDOM,0); + if(p) + { + DoYell(SAY_WATCH, LANG_UNIVERSAL, p); + DoCast(p, SPELL_WATCH); + WatchTarget = p->GetGUID(); + someWatched = true; + endWatch = true; + } + } + + if ((Watch_Timer < 1000) && endWatch) //1 sec before the debuf expire, store the target position + { + Unit* pUnit = Unit::GetUnit(*m_creature, WatchTarget); + if (pUnit) + { + targetX = pUnit->GetPositionX(); + targetY = pUnit->GetPositionY(); + targetZ = pUnit->GetPositionZ(); + } + endWatch = false; + } + + if(!someWatched) + { + //Cleave + if (Cleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_CLEAVE); + Cleave_Timer = 7000; + }else Cleave_Timer -= diff; + + //Whirlwind + if (Whirlwind_Timer < diff) + { + DoCast(m_creature,SPELL_WHIRLWIND); + Whirlwind_Timer = 18000; + }else Whirlwind_Timer -= diff; + + //If more then 3 targets in melee range mandokir will cast fear + if (Fear_Timer < diff) + { + TargetInRange = 0; + + std::list::iterator i = m_creature->getThreatManager().getThreatList().begin(); + for(; i != m_creature->getThreatManager().getThreatList().end(); ++i) + { + Unit* pUnit = Unit::GetUnit(*m_creature, (*i)->getUnitGuid()); + if(pUnit && m_creature->IsWithinDistInMap(pUnit, ATTACK_DISTANCE)) + TargetInRange++; + } + + if(TargetInRange > 3) + DoCast(m_creature->getVictim(),SPELL_FEAR); + + Fear_Timer = 4000; + }else Fear_Timer -=diff; + + //Mortal Strike if target below 50% hp + if (m_creature->getVictim()->GetHealth() < m_creature->getVictim()->GetMaxHealth()*0.5) + { + if (MortalStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTAL_STRIKE); + MortalStrike_Timer = 15000; + }else MortalStrike_Timer -= diff; + } + } + //Checking if Ohgan is dead. If yes Mandokir will enrage. + if(Check_Timer < diff) + { + if(pInstance) + { + if(pInstance->GetData(DATA_OHGANISDEAD)) + { + if (!RaptorDead) + { + DoCast(m_creature, SPELL_ENRAGE); + RaptorDead = true; + } + } + } + + Check_Timer = 1000; + }else Check_Timer -= diff; + + DoMeleeAttackIfReady(); + } + } +}; + +//Ohgan +struct MANGOS_DLL_DECL mob_ohganAI : public ScriptedAI +{ + mob_ohganAI(Creature *c) : ScriptedAI(c) + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + Reset(); + } + + uint32 SunderArmor_Timer; + ScriptedInstance *pInstance; + + void Reset() + { + SunderArmor_Timer = 5000; + } + + void Aggro(Unit *who) {} + + void JustDied(Unit* Killer) + { + if(pInstance) + pInstance->SetData(DATA_OHGAN_DEATH, 0); + } + + void UpdateAI (const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //SunderArmor_Timer + if(SunderArmor_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SUNDERARMOR); + SunderArmor_Timer = 10000 + rand()%5000; + }else SunderArmor_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_mandokir(Creature *_Creature) +{ + return new boss_mandokirAI (_Creature); +} + +CreatureAI* GetAI_mob_ohgan(Creature *_Creature) +{ + return new mob_ohganAI (_Creature); +} + +void AddSC_boss_mandokir() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_mandokir"; + newscript->GetAI = GetAI_boss_mandokir; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_ohgan"; + newscript->GetAI = GetAI_mob_ohgan; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_marli.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_marli.cpp index 44bfc0973e8..3849574db97 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_marli.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_marli.cpp @@ -1,269 +1,251 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Marli -SD%Complete: 80 -SDComment: Charging healers and casters not working. Perhaps wrong Spell Timers. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#define SPELL_CHARGE 22911 -#define SPELL_ASPECT_OF_MARLI 24686 // A stun spell -#define SPELL_ENVOLWINGWEB 24110 -#define SPELL_POISONVOLLEY 24099 -#define SPELL_SPIDER_FORM 24084 - -//The Spider Spells -#define SPELL_LEVELUP 24312 //Not right Spell. - -#define SAY_AGGRO "Draw me to your web mistress Shadra. Unleash your venom!" -#define SOUND_AGGRO 8418 - -#define SAY_DEATH "ShadraDeath - Bless you mortal for this release. Hakkar controls me no longer..." -#define SOUND_DEATH 8423 - -struct MANGOS_DLL_DECL boss_marliAI : public ScriptedAI -{ - boss_marliAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 SpawnStartSpiders_Timer; - uint32 PoisonVolley_Timer; - uint32 SpawnSpider_Timer; - uint32 Charge_Timer; - uint32 Aspect_Timer; - uint32 Transform_Timer; - uint32 TransformBack_Timer; - - Creature *Spider; - bool Spawned; - bool PhaseTwo; - - void Reset() - { - SpawnStartSpiders_Timer = 1000; - PoisonVolley_Timer = 15000; - SpawnSpider_Timer = 30000; - Charge_Timer = 1500; - Aspect_Timer = 12000; - Transform_Timer = 45000; - TransformBack_Timer = 25000; - - Spawned = false; - PhaseTwo = false; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - pInstance->SetData(DATA_MARLI_DEATH, 0); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget()) - return; - - if( m_creature->getVictim() && m_creature->isAlive()) - { - if (PoisonVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POISONVOLLEY); - PoisonVolley_Timer = 10000 + rand()%10000; - }else PoisonVolley_Timer -= diff; - - if (!PhaseTwo && Aspect_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_ASPECT_OF_MARLI); - Aspect_Timer = 13000 + rand()%5000; - }else Aspect_Timer -= diff; - - if (!Spawned && SpawnStartSpiders_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Spider ) { Spider ->AI()->AttackStart(target); } - Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Spider ) { Spider ->AI()->AttackStart(target); } - Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Spider ) { Spider ->AI()->AttackStart(target); } - Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Spider ) { Spider ->AI()->AttackStart(target); } - - Spawned = true; - }else SpawnStartSpiders_Timer -= diff; - - if (SpawnSpider_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if(target && Spider ) { Spider ->AI()->AttackStart(target); } - - SpawnSpider_Timer = 12000 + rand()%5000; - }else SpawnSpider_Timer -= diff; - - if(!PhaseTwo && Transform_Timer < diff) - { - DoCast(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); - DoCast(m_creature->getVictim(),SPELL_ENVOLWINGWEB); - - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); - - PhaseTwo = true; - Transform_Timer = 35000 + rand()%25000; - }else Transform_Timer -= diff; - - if (PhaseTwo) - { - if (Charge_Timer < diff) - { - Unit* target = NULL; - int i = 0 ; - while (i < 3) // max 3 tries to get a random target with power_mana - { - ++i; //not aggro leader - target = SelectUnit(SELECT_TARGET_RANDOM,1); - if (target) - if (target->getPowerType() == POWER_MANA) - i=3; - } - if (target) - DoCast(target, SPELL_CHARGE); - // m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - // m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); - DoStartAttackAndMovement(target); - - Charge_Timer = 8000; - }else Charge_Timer -= diff; - - if (TransformBack_Timer < diff) - { - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15220); - 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); - - PhaseTwo = false; - TransformBack_Timer = 25000 + rand()%15000; - }else TransformBack_Timer -= diff; - - } - - DoMeleeAttackIfReady(); - } - } -}; - -//Spawn of Marli -struct MANGOS_DLL_DECL mob_spawn_of_marliAI : public ScriptedAI -{ - mob_spawn_of_marliAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 LevelUp_Timer; - - void Reset() - { - LevelUp_Timer = 3000; - } - - void Aggro(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - 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(who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - DoStartAttackAndMovement(who); - } - } - } - - void UpdateAI (const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //LevelUp_Timer - if(LevelUp_Timer < diff) - { - DoCast(m_creature,SPELL_LEVELUP); - LevelUp_Timer = 3000; - }else LevelUp_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_marli(Creature *_Creature) -{ - return new boss_marliAI (_Creature); -} - -CreatureAI* GetAI_mob_spawn_of_marli(Creature *_Creature) -{ - return new mob_spawn_of_marliAI (_Creature); -} - -void AddSC_boss_marli() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_marli"; - newscript->GetAI = GetAI_boss_marli; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_spawn_of_marli"; - newscript->GetAI = GetAI_mob_spawn_of_marli; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Marli +SD%Complete: 80 +SDComment: Charging healers and casters not working. Perhaps wrong Spell Timers. +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#define SPELL_CHARGE 22911 +#define SPELL_ASPECT_OF_MARLI 24686 // A stun spell +#define SPELL_ENVOLWINGWEB 24110 +#define SPELL_POISONVOLLEY 24099 +#define SPELL_SPIDER_FORM 24084 + +//The Spider Spells +#define SPELL_LEVELUP 24312 //Not right Spell. + +#define SAY_AGGRO "Draw me to your web mistress Shadra. Unleash your venom!" +#define SOUND_AGGRO 8418 + +#define SAY_DEATH "ShadraDeath - Bless you mortal for this release. Hakkar controls me no longer..." +#define SOUND_DEATH 8423 + +struct MANGOS_DLL_DECL boss_marliAI : public ScriptedAI +{ + boss_marliAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 SpawnStartSpiders_Timer; + uint32 PoisonVolley_Timer; + uint32 SpawnSpider_Timer; + uint32 Charge_Timer; + uint32 Aspect_Timer; + uint32 Transform_Timer; + uint32 TransformBack_Timer; + + Creature *Spider; + bool Spawned; + bool PhaseTwo; + + void Reset() + { + SpawnStartSpiders_Timer = 1000; + PoisonVolley_Timer = 15000; + SpawnSpider_Timer = 30000; + Charge_Timer = 1500; + Aspect_Timer = 12000; + Transform_Timer = 45000; + TransformBack_Timer = 25000; + + Spawned = false; + PhaseTwo = false; + + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + pInstance->SetData(DATA_MARLI_DEATH, 0); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget()) + return; + + if( m_creature->getVictim() && m_creature->isAlive()) + { + if (PoisonVolley_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_POISONVOLLEY); + PoisonVolley_Timer = 10000 + rand()%10000; + }else PoisonVolley_Timer -= diff; + + if (!PhaseTwo && Aspect_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_ASPECT_OF_MARLI); + Aspect_Timer = 13000 + rand()%5000; + }else Aspect_Timer -= diff; + + if (!Spawned && SpawnStartSpiders_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Spider ) { Spider ->AI()->AttackStart(target); } + Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Spider ) { Spider ->AI()->AttackStart(target); } + Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Spider ) { Spider ->AI()->AttackStart(target); } + Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Spider ) { Spider ->AI()->AttackStart(target); } + + Spawned = true; + }else SpawnStartSpiders_Timer -= diff; + + if (SpawnSpider_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + Spider = m_creature->SummonCreature(15041,target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if(target && Spider ) { Spider ->AI()->AttackStart(target); } + + SpawnSpider_Timer = 12000 + rand()%5000; + }else SpawnSpider_Timer -= diff; + + if(!PhaseTwo && Transform_Timer < diff) + { + DoCast(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); + DoCast(m_creature->getVictim(),SPELL_ENVOLWINGWEB); + + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); + + PhaseTwo = true; + Transform_Timer = 35000 + rand()%25000; + }else Transform_Timer -= diff; + + if (PhaseTwo) + { + if (Charge_Timer < diff) + { + Unit* target = NULL; + int i = 0 ; + while (i < 3) // max 3 tries to get a random target with power_mana + { + ++i; //not aggro leader + target = SelectUnit(SELECT_TARGET_RANDOM,1); + if (target) + if (target->getPowerType() == POWER_MANA) + i=3; + } + if (target) + DoCast(target, SPELL_CHARGE); + // m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + // m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); + DoStartAttackAndMovement(target); + + Charge_Timer = 8000; + }else Charge_Timer -= diff; + + if (TransformBack_Timer < diff) + { + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15220); + 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); + + PhaseTwo = false; + TransformBack_Timer = 25000 + rand()%15000; + }else TransformBack_Timer -= diff; + + } + + DoMeleeAttackIfReady(); + } + } +}; + +//Spawn of Marli +struct MANGOS_DLL_DECL mob_spawn_of_marliAI : public ScriptedAI +{ + mob_spawn_of_marliAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 LevelUp_Timer; + + void Reset() + { + LevelUp_Timer = 3000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI (const uint32 diff) + { + //Return since we have no target + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //LevelUp_Timer + if(LevelUp_Timer < diff) + { + DoCast(m_creature,SPELL_LEVELUP); + LevelUp_Timer = 3000; + }else LevelUp_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_marli(Creature *_Creature) +{ + return new boss_marliAI (_Creature); +} + +CreatureAI* GetAI_mob_spawn_of_marli(Creature *_Creature) +{ + return new mob_spawn_of_marliAI (_Creature); +} + +void AddSC_boss_marli() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_marli"; + newscript->GetAI = GetAI_boss_marli; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_spawn_of_marli"; + newscript->GetAI = GetAI_mob_spawn_of_marli; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_renataki.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_renataki.cpp index f7e31309b59..b44564825ca 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_renataki.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_renataki.cpp @@ -1,151 +1,151 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Renataki -SD%Complete: 100 -SDComment: -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#define SPELL_AMBUSH 24337 -#define SPELL_THOUSANDBLADES 24649 - -struct MANGOS_DLL_DECL boss_renatakiAI : public ScriptedAI -{ - boss_renatakiAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 Invisible_Timer; - uint32 Ambush_Timer; - uint32 Visible_Timer; - uint32 Aggro_Timer; - uint32 ThousandBlades_Timer; - - bool Invisible; - bool Ambushed; - - void Reset() - { - Invisible_Timer = 8000 + rand()%10000; - Ambush_Timer = 3000; - Visible_Timer = 4000; - Aggro_Timer = 15000 + rand()%10000; - ThousandBlades_Timer = 4000 + rand()%4000; - - Invisible = false; - Ambushed = false; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //Invisible_Timer - if (Invisible_Timer < diff) - { - m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); - m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); - m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO , 218171138); - m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + 1, 3); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,11686); - Invisible = true; - - Invisible_Timer = 15000 + rand()%15000; - }else Invisible_Timer -= diff; - - if (Invisible) - { - if (Ambush_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) - { - m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); - DoCast(target,SPELL_AMBUSH); - } - - Ambushed = true; - Ambush_Timer = 3000; - }else Ambush_Timer -= diff; - } - - if (Ambushed) - { - if (Visible_Timer < diff) - { - m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15268); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 31818); - m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO , 218171138); - m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + 1, 3); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Invisible = false; - - Visible_Timer = 4000; - }else Visible_Timer -= diff; - } - - //Resetting some aggro so he attacks other gamers - if(!Invisible) - if (Aggro_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,1); - - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); - - if (target) - DoStartAttackAndMovement(target); - - Aggro_Timer = 7000 + rand()%13000; - }else Aggro_Timer -= diff; - - if (!Invisible) - if(ThousandBlades_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_THOUSANDBLADES); - ThousandBlades_Timer = 7000 + rand()%5000; - }else ThousandBlades_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_renataki(Creature *_Creature) -{ - return new boss_renatakiAI (_Creature); -} - -void AddSC_boss_renataki() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_renataki"; - newscript->GetAI = GetAI_boss_renataki; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Renataki +SD%Complete: 100 +SDComment: +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#define SPELL_AMBUSH 24337 +#define SPELL_THOUSANDBLADES 24649 + +struct MANGOS_DLL_DECL boss_renatakiAI : public ScriptedAI +{ + boss_renatakiAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 Invisible_Timer; + uint32 Ambush_Timer; + uint32 Visible_Timer; + uint32 Aggro_Timer; + uint32 ThousandBlades_Timer; + + bool Invisible; + bool Ambushed; + + void Reset() + { + Invisible_Timer = 8000 + rand()%10000; + Ambush_Timer = 3000; + Visible_Timer = 4000; + Aggro_Timer = 15000 + rand()%10000; + ThousandBlades_Timer = 4000 + rand()%4000; + + Invisible = false; + Ambushed = false; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //Invisible_Timer + if (Invisible_Timer < diff) + { + m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); + m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); + m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO , 218171138); + m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + 1, 3); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,11686); + Invisible = true; + + Invisible_Timer = 15000 + rand()%15000; + }else Invisible_Timer -= diff; + + if (Invisible) + { + if (Ambush_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) + { + m_creature->Relocate(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); + DoCast(target,SPELL_AMBUSH); + } + + Ambushed = true; + Ambush_Timer = 3000; + }else Ambush_Timer -= diff; + } + + if (Ambushed) + { + if (Visible_Timer < diff) + { + m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID,15268); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 31818); + m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO , 218171138); + m_creature->SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + 1, 3); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Invisible = false; + + Visible_Timer = 4000; + }else Visible_Timer -= diff; + } + + //Resetting some aggro so he attacks other gamers + if(!Invisible) + if (Aggro_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,1); + + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); + + if (target) + DoStartAttackAndMovement(target); + + Aggro_Timer = 7000 + rand()%13000; + }else Aggro_Timer -= diff; + + if (!Invisible) + if(ThousandBlades_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_THOUSANDBLADES); + ThousandBlades_Timer = 7000 + rand()%5000; + }else ThousandBlades_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_renataki(Creature *_Creature) +{ + return new boss_renatakiAI (_Creature); +} + +void AddSC_boss_renataki() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_renataki"; + newscript->GetAI = GetAI_boss_renataki; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_thekal.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_thekal.cpp index 91d0d6a290c..e46b2d72782 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_thekal.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_thekal.cpp @@ -1,545 +1,545 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Thekal -SD%Complete: 95 -SDComment: Almost finished. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#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 - -#define SAY_AGGRO "Shirvallah fill me with your rage!" -#define SOUND_AGGRO 8419 - -#define SAY_DEATH "Hakkar binds me no more. Peace at last." -#define SOUND_DEATH 8424 - -struct MANGOS_DLL_DECL boss_thekalAI : public ScriptedAI -{ - boss_thekalAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - 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; - - ScriptedInstance *pInstance; - bool Enraged; - bool PhaseTwo; - bool WasDead; - - 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; - - if(pInstance) - pInstance->SetData(DATA_THEKAL_ALIVE, 0); - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void JustDied(Unit* Killer) - { - DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_DEATH); - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - pInstance->SetData(DATA_THEKAL_DEATH, 0); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget()) - return; - - if( m_creature->getVictim() && m_creature->isAlive()) - { - - //Check_Timer for the death of LorKhan and Zath. - if(!WasDead && Check_Timer < diff) - { - if(pInstance) - { - if(pInstance->GetData(DATA_LORKHANISDEAD)) - { - //Resurrect LorKhan - Unit *pLorKhan = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LORKHAN)); - pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - pLorKhan->setFaction(14); - pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pLorKhan->SetHealth(int(pLorKhan->GetMaxHealth()*1.0)); - } - - if(pInstance->GetData(DATA_ZATHISDEAD)) - { - //Resurrect Zath - Unit *pZath = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ZATH)); - pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - pZath->setFaction(14); - pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pZath->SetHealth(int(pZath->GetMaxHealth()*1.0)); - } - } - - Check_Timer = 5000; - }else Check_Timer -= diff; - - if (!PhaseTwo && MortalCleave_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MORTALCLEAVE); - MortalCleave_Timer = 15000 + rand()%5000; - }else MortalCleave_Timer -= diff; - - if (!PhaseTwo && Silence_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SILENCE); - Silence_Timer = 20000 + rand()%5000; - }else Silence_Timer -= diff; - - if (!PhaseTwo && !WasDead && m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.05) - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); - m_creature->AttackStop(); - - if(pInstance) - pInstance->SetData(DATA_THEKALFAKE_DEATH, 0); - - WasDead=true; - } - - //Thekal will transform to Tiger if he died and was not resurrected after 10 seconds. - if(!PhaseTwo && WasDead) - { - if (Resurrect_Timer < diff) - { - DoCast(m_creature,SPELL_TIGER_FORM); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.00f); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - 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_creature->GetHealth()*100 / m_creature->GetMaxHealth() == 100) && WasDead) - { - WasDead = false; - } - - if (PhaseTwo) - { - if (Charge_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(target,SPELL_CHARGE); - m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); - DoStartAttackAndMovement(target); - DoResetThreat(); - - Charge_Timer = 15000 + rand()%7000; - }else Charge_Timer -= diff; - - if (Frenzy_Timer < diff) - { - DoCast(m_creature,SPELL_FRENZY); - Frenzy_Timer = 30000; - }else Frenzy_Timer -= diff; - - if (ForcePunch_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SILENCE); - ForcePunch_Timer = 16000 + rand()%5000; - }else ForcePunch_Timer -= diff; - - if (SummonTigers_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SUMMONTIGERS); - SummonTigers_Timer = 10000 + rand()%4000; - }else SummonTigers_Timer -= diff; - - if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11) && !Enraged) - { - DoCast(m_creature, SPELL_ENRAGE); - Enraged = true; - } - } - - DoMeleeAttackIfReady(); - } - } -}; - -//Zealot Lor'Khan -struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public ScriptedAI -{ - mob_zealot_lorkhanAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 Shield_Timer; - uint32 BloodLust_Timer; - uint32 GreaterHeal_Timer; - uint32 Disarm_Timer; - uint32 Check_Timer; - - bool FakeDeath; - - ScriptedInstance *pInstance; - - void Reset() - { - Shield_Timer = 1000; - BloodLust_Timer = 16000; - GreaterHeal_Timer = 32000; - Disarm_Timer = 6000; - Check_Timer = 10000; - - FakeDeath = false; - - if(pInstance) - pInstance->SetData(DATA_LORKHAN_ALIVE, 0); - - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit *who) - { - } - - void UpdateAI (const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //Shield_Timer - if(Shield_Timer < diff) - { - DoCast(m_creature,SPELL_SHIELD); - Shield_Timer = 61000; - }else Shield_Timer -= diff; - - //BloodLust_Timer - if(BloodLust_Timer < diff) - { - DoCast(m_creature,SPELL_BLOODLUST); - BloodLust_Timer = 20000+rand()%8000; - }else BloodLust_Timer -= diff; - - //Casting Greaterheal to Thekal or Zath if they are in meele range. - if(GreaterHeal_Timer < diff) - { - if(pInstance) - { - Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL)); - Unit *pZath = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ZATH)); - - switch(rand()%2) - { - case 0: - if(m_creature->IsWithinDistInMap(pThekal, ATTACK_DISTANCE)) - DoCast(pThekal, SPELL_GREATERHEAL); - break; - case 1: - if(m_creature->IsWithinDistInMap(pZath, ATTACK_DISTANCE)) - DoCast(pZath, SPELL_GREATERHEAL); - break; - } - } - - GreaterHeal_Timer = 15000+rand()%5000; - }else GreaterHeal_Timer -= diff; - - //Disarm_Timer - if(Disarm_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DISARM); - Disarm_Timer = 15000+rand()%10000; - }else Disarm_Timer -= diff; - - //Check_Timer for the death of LorKhan and Zath. - if(!FakeDeath && Check_Timer < diff) - { - if(pInstance) - { - if(pInstance->GetData(DATA_THEKALISFAKEDEAD)) - { - //Resurrect Thekal - Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL)); - pThekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pThekal->setFaction(14); - pThekal->SetHealth(int(pThekal->GetMaxHealth()*1.0)); - } - - if(pInstance->GetData(DATA_ZATHISDEAD)) - { - //Resurrect Zath - Unit *pZath = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ZATH)); - pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pZath->setFaction(14); - pZath->SetHealth(int(pZath->GetMaxHealth()*1.0)); - } - } - - Check_Timer = 5000; - }else Check_Timer -= diff; - - if (m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.05) - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); - m_creature->setFaction(35); - m_creature->AttackStop(); - - if(pInstance) - pInstance->SetData(DATA_LORKHAN_DEATH, 0); - - FakeDeath = true; - } - - DoMeleeAttackIfReady(); - } -}; - -//Zealot Zath -struct MANGOS_DLL_DECL mob_zealot_zathAI : public ScriptedAI -{ - mob_zealot_zathAI(Creature *c) : ScriptedAI(c) - { - pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; - Reset(); - } - - uint32 SweepingStrikes_Timer; - uint32 SinisterStrike_Timer; - uint32 Gouge_Timer; - uint32 Kick_Timer; - uint32 Blind_Timer; - uint32 Check_Timer; - - bool FakeDeath; - - ScriptedInstance *pInstance; - - void Reset() - { - SweepingStrikes_Timer = 13000; - SinisterStrike_Timer = 8000; - Gouge_Timer = 25000; - Kick_Timer = 18000; - Blind_Timer = 5000; - Check_Timer = 10000; - - FakeDeath = false; - - if(pInstance) - pInstance->SetData(DATA_ZATH_ALIVE, 0); - - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit *who) - { - } - - void UpdateAI (const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) - return; - - //SweepingStrikes_Timer - if(SweepingStrikes_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SWEEPINGSTRIKES); - SweepingStrikes_Timer = 22000+rand()%4000; - }else SweepingStrikes_Timer -= diff; - - //SinisterStrike_Timer - if(SinisterStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_SINISTERSTRIKE); - SinisterStrike_Timer = 8000+rand()%8000; - }else SinisterStrike_Timer -= diff; - - //Gouge_Timer - if(Gouge_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_GOUGE); - - if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); - - Gouge_Timer = 17000+rand()%10000; - }else Gouge_Timer -= diff; - - //Kick_Timer - if(Kick_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_KICK); - Kick_Timer = 15000+rand()%10000; - }else Kick_Timer -= diff; - - //Blind_Timer - if(Blind_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_BLIND); - Blind_Timer = 10000+rand()%10000; - }else Blind_Timer -= diff; - - //Check_Timer for the death of LorKhan and Zath. - if(!FakeDeath && Check_Timer < diff) - { - if(pInstance) - { - if(pInstance->GetData(DATA_LORKHANISDEAD)) - { - //Resurrect LorKhan - Unit *pLorKhan = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LORKHAN)); - pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pLorKhan->setFaction(14); - pLorKhan->SetHealth(int(pLorKhan->GetMaxHealth()*1.0)); - } - - if(pInstance->GetData(DATA_THEKALISFAKEDEAD)) - { - //Resurrect Thekal - Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL)); - pThekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pThekal->setFaction(14); - pThekal->SetHealth(int(pThekal->GetMaxHealth()*1.0)); - } - } - - Check_Timer = 5000; - }else Check_Timer -= diff; - - if (m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.05) - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); - m_creature->setFaction(35); - m_creature->AttackStop(); - - if(pInstance) - pInstance->SetData(DATA_ZATH_DEATH, 0); - - FakeDeath = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_thekal(Creature *_Creature) -{ - return new boss_thekalAI (_Creature); -} - -CreatureAI* GetAI_mob_zealot_lorkhan(Creature *_Creature) -{ - return new mob_zealot_lorkhanAI (_Creature); -} - -CreatureAI* GetAI_mob_zealot_zath(Creature *_Creature) -{ - return new mob_zealot_zathAI (_Creature); -} - -void AddSC_boss_thekal() -{ - Script *newscript; - - newscript = new Script; - newscript->Name="boss_thekal"; - newscript->GetAI = GetAI_boss_thekal; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_zealot_lorkhan"; - newscript->GetAI = GetAI_mob_zealot_lorkhan; - m_scripts[nrscripts++] = newscript; - - newscript = new Script; - newscript->Name="mob_zealot_zath"; - newscript->GetAI = GetAI_mob_zealot_zath; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Thekal +SD%Complete: 95 +SDComment: Almost finished. +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#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 + +#define SAY_AGGRO "Shirvallah fill me with your rage!" +#define SOUND_AGGRO 8419 + +#define SAY_DEATH "Hakkar binds me no more. Peace at last." +#define SOUND_DEATH 8424 + +struct MANGOS_DLL_DECL boss_thekalAI : public ScriptedAI +{ + boss_thekalAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + 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; + + ScriptedInstance *pInstance; + bool Enraged; + bool PhaseTwo; + bool WasDead; + + 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; + + if(pInstance) + pInstance->SetData(DATA_THEKAL_ALIVE, 0); + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void JustDied(Unit* Killer) + { + DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_DEATH); + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + pInstance->SetData(DATA_THEKAL_DEATH, 0); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget()) + return; + + if( m_creature->getVictim() && m_creature->isAlive()) + { + + //Check_Timer for the death of LorKhan and Zath. + if(!WasDead && Check_Timer < diff) + { + if(pInstance) + { + if(pInstance->GetData(DATA_LORKHANISDEAD)) + { + //Resurrect LorKhan + Unit *pLorKhan = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LORKHAN)); + pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + pLorKhan->setFaction(14); + pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pLorKhan->SetHealth(int(pLorKhan->GetMaxHealth()*1.0)); + } + + if(pInstance->GetData(DATA_ZATHISDEAD)) + { + //Resurrect Zath + Unit *pZath = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ZATH)); + pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + pZath->setFaction(14); + pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pZath->SetHealth(int(pZath->GetMaxHealth()*1.0)); + } + } + + Check_Timer = 5000; + }else Check_Timer -= diff; + + if (!PhaseTwo && MortalCleave_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_MORTALCLEAVE); + MortalCleave_Timer = 15000 + rand()%5000; + }else MortalCleave_Timer -= diff; + + if (!PhaseTwo && Silence_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SILENCE); + Silence_Timer = 20000 + rand()%5000; + }else Silence_Timer -= diff; + + if (!PhaseTwo && !WasDead && m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.05) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); + m_creature->AttackStop(); + + if(pInstance) + pInstance->SetData(DATA_THEKALFAKE_DEATH, 0); + + WasDead=true; + } + + //Thekal will transform to Tiger if he died and was not resurrected after 10 seconds. + if(!PhaseTwo && WasDead) + { + if (Resurrect_Timer < diff) + { + DoCast(m_creature,SPELL_TIGER_FORM); + m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.00f); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + 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_creature->GetHealth()*100 / m_creature->GetMaxHealth() == 100) && WasDead) + { + WasDead = false; + } + + if (PhaseTwo) + { + if (Charge_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(target,SPELL_CHARGE); + m_creature->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true,1); + DoStartAttackAndMovement(target); + DoResetThreat(); + + Charge_Timer = 15000 + rand()%7000; + }else Charge_Timer -= diff; + + if (Frenzy_Timer < diff) + { + DoCast(m_creature,SPELL_FRENZY); + Frenzy_Timer = 30000; + }else Frenzy_Timer -= diff; + + if (ForcePunch_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SILENCE); + ForcePunch_Timer = 16000 + rand()%5000; + }else ForcePunch_Timer -= diff; + + if (SummonTigers_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SUMMONTIGERS); + SummonTigers_Timer = 10000 + rand()%4000; + }else SummonTigers_Timer -= diff; + + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11) && !Enraged) + { + DoCast(m_creature, SPELL_ENRAGE); + Enraged = true; + } + } + + DoMeleeAttackIfReady(); + } + } +}; + +//Zealot Lor'Khan +struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public ScriptedAI +{ + mob_zealot_lorkhanAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 Shield_Timer; + uint32 BloodLust_Timer; + uint32 GreaterHeal_Timer; + uint32 Disarm_Timer; + uint32 Check_Timer; + + bool FakeDeath; + + ScriptedInstance *pInstance; + + void Reset() + { + Shield_Timer = 1000; + BloodLust_Timer = 16000; + GreaterHeal_Timer = 32000; + Disarm_Timer = 6000; + Check_Timer = 10000; + + FakeDeath = false; + + if(pInstance) + pInstance->SetData(DATA_LORKHAN_ALIVE, 0); + + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI (const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //Shield_Timer + if(Shield_Timer < diff) + { + DoCast(m_creature,SPELL_SHIELD); + Shield_Timer = 61000; + }else Shield_Timer -= diff; + + //BloodLust_Timer + if(BloodLust_Timer < diff) + { + DoCast(m_creature,SPELL_BLOODLUST); + BloodLust_Timer = 20000+rand()%8000; + }else BloodLust_Timer -= diff; + + //Casting Greaterheal to Thekal or Zath if they are in meele range. + if(GreaterHeal_Timer < diff) + { + if(pInstance) + { + Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL)); + Unit *pZath = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ZATH)); + + switch(rand()%2) + { + case 0: + if(m_creature->IsWithinDistInMap(pThekal, ATTACK_DISTANCE)) + DoCast(pThekal, SPELL_GREATERHEAL); + break; + case 1: + if(m_creature->IsWithinDistInMap(pZath, ATTACK_DISTANCE)) + DoCast(pZath, SPELL_GREATERHEAL); + break; + } + } + + GreaterHeal_Timer = 15000+rand()%5000; + }else GreaterHeal_Timer -= diff; + + //Disarm_Timer + if(Disarm_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_DISARM); + Disarm_Timer = 15000+rand()%10000; + }else Disarm_Timer -= diff; + + //Check_Timer for the death of LorKhan and Zath. + if(!FakeDeath && Check_Timer < diff) + { + if(pInstance) + { + if(pInstance->GetData(DATA_THEKALISFAKEDEAD)) + { + //Resurrect Thekal + Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL)); + pThekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pThekal->setFaction(14); + pThekal->SetHealth(int(pThekal->GetMaxHealth()*1.0)); + } + + if(pInstance->GetData(DATA_ZATHISDEAD)) + { + //Resurrect Zath + Unit *pZath = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ZATH)); + pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pZath->setFaction(14); + pZath->SetHealth(int(pZath->GetMaxHealth()*1.0)); + } + } + + Check_Timer = 5000; + }else Check_Timer -= diff; + + if (m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.05) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); + m_creature->setFaction(35); + m_creature->AttackStop(); + + if(pInstance) + pInstance->SetData(DATA_LORKHAN_DEATH, 0); + + FakeDeath = true; + } + + DoMeleeAttackIfReady(); + } +}; + +//Zealot Zath +struct MANGOS_DLL_DECL mob_zealot_zathAI : public ScriptedAI +{ + mob_zealot_zathAI(Creature *c) : ScriptedAI(c) + { + pInstance = (c->GetInstanceData()) ? ((ScriptedInstance*)c->GetInstanceData()) : NULL; + Reset(); + } + + uint32 SweepingStrikes_Timer; + uint32 SinisterStrike_Timer; + uint32 Gouge_Timer; + uint32 Kick_Timer; + uint32 Blind_Timer; + uint32 Check_Timer; + + bool FakeDeath; + + ScriptedInstance *pInstance; + + void Reset() + { + SweepingStrikes_Timer = 13000; + SinisterStrike_Timer = 8000; + Gouge_Timer = 25000; + Kick_Timer = 18000; + Blind_Timer = 5000; + Check_Timer = 10000; + + FakeDeath = false; + + if(pInstance) + pInstance->SetData(DATA_ZATH_ALIVE, 0); + + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit *who) + { + } + + void UpdateAI (const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) + return; + + //SweepingStrikes_Timer + if(SweepingStrikes_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SWEEPINGSTRIKES); + SweepingStrikes_Timer = 22000+rand()%4000; + }else SweepingStrikes_Timer -= diff; + + //SinisterStrike_Timer + if(SinisterStrike_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_SINISTERSTRIKE); + SinisterStrike_Timer = 8000+rand()%8000; + }else SinisterStrike_Timer -= diff; + + //Gouge_Timer + if(Gouge_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_GOUGE); + + if(m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); + + Gouge_Timer = 17000+rand()%10000; + }else Gouge_Timer -= diff; + + //Kick_Timer + if(Kick_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_KICK); + Kick_Timer = 15000+rand()%10000; + }else Kick_Timer -= diff; + + //Blind_Timer + if(Blind_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_BLIND); + Blind_Timer = 10000+rand()%10000; + }else Blind_Timer -= diff; + + //Check_Timer for the death of LorKhan and Zath. + if(!FakeDeath && Check_Timer < diff) + { + if(pInstance) + { + if(pInstance->GetData(DATA_LORKHANISDEAD)) + { + //Resurrect LorKhan + Unit *pLorKhan = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LORKHAN)); + pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pLorKhan->setFaction(14); + pLorKhan->SetHealth(int(pLorKhan->GetMaxHealth()*1.0)); + } + + if(pInstance->GetData(DATA_THEKALISFAKEDEAD)) + { + //Resurrect Thekal + Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL)); + pThekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pThekal->setFaction(14); + pThekal->SetHealth(int(pThekal->GetMaxHealth()*1.0)); + } + } + + Check_Timer = 5000; + }else Check_Timer -= diff; + + if (m_creature->GetHealth() <= m_creature->GetMaxHealth() * 0.05) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 3); + m_creature->setFaction(35); + m_creature->AttackStop(); + + if(pInstance) + pInstance->SetData(DATA_ZATH_DEATH, 0); + + FakeDeath = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_thekal(Creature *_Creature) +{ + return new boss_thekalAI (_Creature); +} + +CreatureAI* GetAI_mob_zealot_lorkhan(Creature *_Creature) +{ + return new mob_zealot_lorkhanAI (_Creature); +} + +CreatureAI* GetAI_mob_zealot_zath(Creature *_Creature) +{ + return new mob_zealot_zathAI (_Creature); +} + +void AddSC_boss_thekal() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_thekal"; + newscript->GetAI = GetAI_boss_thekal; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_zealot_lorkhan"; + newscript->GetAI = GetAI_mob_zealot_lorkhan; + m_scripts[nrscripts++] = newscript; + + newscript = new Script; + newscript->Name="mob_zealot_zath"; + newscript->GetAI = GetAI_mob_zealot_zath; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_venoxis.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_venoxis.cpp index a2405ec9c6f..345c05a88d4 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_venoxis.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_venoxis.cpp @@ -1,200 +1,200 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* ScriptData -SDName: Boss_Venoxis -SD%Complete: 100 -SDComment: -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -#define SPELL_HOLY_FIRE 23860 -#define SPELL_HOLY_WRATH 28883 //Not sure if this or 23979 -#define SPELL_VENOMSPIT 23862 -#define SPELL_HOLY_NOVA 23858 -#define SPELL_POISON_CLOUD 23861 -#define SPELL_SNAKE_FORM 23849 -#define SPELL_RENEW 23895 -#define SPELL_BERSERK 23537 -#define SPELL_DISPELL 23859 - -#define SAY_AGGRO "Let the coils of hate unfurl!" -#define SOUND_AGGRO 8421 - -struct MANGOS_DLL_DECL boss_venoxisAI : public ScriptedAI -{ - boss_venoxisAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 HolyFire_Timer; - uint32 HolyWrath_Timer; - uint32 VenomSpit_Timer; - uint32 Renew_Timer; - uint32 PoisonCloud_Timer; - uint32 HolyNova_Timer; - uint32 Dispell_Timer; - uint32 TargetInRange; - - bool PhaseTwo; - bool InBerserk; - - void Reset() - { - HolyFire_Timer = 10000; - HolyWrath_Timer = 60500; - VenomSpit_Timer = 5500; - Renew_Timer = 30500; - PoisonCloud_Timer = 2000; - HolyNova_Timer = 5000; - Dispell_Timer = 35000; - TargetInRange = 0; - - PhaseTwo = false; - InBerserk= false; - } - - void Aggro(Unit *who) - { - DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); - DoPlaySoundToSet(m_creature,SOUND_AGGRO); - } - - void JustDied(Unit* Killer) - { - ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; - if(pInstance) - pInstance->SetData(DATA_VENOXIS_DEATH, 0); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget()) - return; - - if( m_creature->getVictim() && m_creature->isAlive()) - { - if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > 50)) - { - if (Dispell_Timer < diff) - { - DoCast(m_creature, SPELL_DISPELL); - Dispell_Timer = 15000 + rand()%15000; - }else Dispell_Timer -= diff; - - if (Renew_Timer < diff) - { - DoCast(m_creature, SPELL_RENEW); - Renew_Timer = 20000 + rand()%10000; - }else Renew_Timer -= diff; - - if (HolyWrath_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_HOLY_WRATH); - HolyWrath_Timer = 15000 + rand()%10000; - }else HolyWrath_Timer -= diff; - - if (HolyNova_Timer < diff) - { - Unit* target = NULL; - TargetInRange = 0; - for(int i=0; i<10; i++) - { - target = SelectUnit(SELECT_TARGET_TOPAGGRO,i); - if(target) - if(m_creature->IsWithinDistInMap(target, ATTACK_DISTANCE)) - TargetInRange++; - } - - if(TargetInRange > 1) - { - DoCast(m_creature->getVictim(),SPELL_HOLY_NOVA); - HolyNova_Timer = 1000; - } - else - { - HolyNova_Timer = 2000; - } - - }else HolyNova_Timer -= diff; - - if (HolyFire_Timer < diff && TargetInRange < 3) - { - Unit* targetrandom = NULL; - targetrandom = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(targetrandom, SPELL_HOLY_FIRE); - HolyFire_Timer = 8000; - }else HolyFire_Timer -= diff; - } - else - { - if(!PhaseTwo) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature,SPELL_SNAKE_FORM); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.00f); - 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(); - PhaseTwo = true; - } - - if(PhaseTwo && PoisonCloud_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_POISON_CLOUD); - PoisonCloud_Timer = 15000; - }PoisonCloud_Timer -=diff; - - if (PhaseTwo && VenomSpit_Timer < diff) - { - Unit* targetrandom = NULL; - targetrandom = SelectUnit(SELECT_TARGET_RANDOM,0); - - DoCast(targetrandom, SPELL_VENOMSPIT); - VenomSpit_Timer = 15000 + rand()%5000; - }else VenomSpit_Timer -= diff; - - if (PhaseTwo && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11)) - { - if (!InBerserk) - { - m_creature->InterruptNonMeleeSpells(false); - DoCast(m_creature, SPELL_BERSERK); - InBerserk = true; - } - } - } - DoMeleeAttackIfReady(); - } - } -}; -CreatureAI* GetAI_boss_venoxis(Creature *_Creature) -{ - return new boss_venoxisAI (_Creature); -} - -void AddSC_boss_venoxis() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_venoxis"; - newscript->GetAI = GetAI_boss_venoxis; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss_Venoxis +SD%Complete: 100 +SDComment: +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +#define SPELL_HOLY_FIRE 23860 +#define SPELL_HOLY_WRATH 28883 //Not sure if this or 23979 +#define SPELL_VENOMSPIT 23862 +#define SPELL_HOLY_NOVA 23858 +#define SPELL_POISON_CLOUD 23861 +#define SPELL_SNAKE_FORM 23849 +#define SPELL_RENEW 23895 +#define SPELL_BERSERK 23537 +#define SPELL_DISPELL 23859 + +#define SAY_AGGRO "Let the coils of hate unfurl!" +#define SOUND_AGGRO 8421 + +struct MANGOS_DLL_DECL boss_venoxisAI : public ScriptedAI +{ + boss_venoxisAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 HolyFire_Timer; + uint32 HolyWrath_Timer; + uint32 VenomSpit_Timer; + uint32 Renew_Timer; + uint32 PoisonCloud_Timer; + uint32 HolyNova_Timer; + uint32 Dispell_Timer; + uint32 TargetInRange; + + bool PhaseTwo; + bool InBerserk; + + void Reset() + { + HolyFire_Timer = 10000; + HolyWrath_Timer = 60500; + VenomSpit_Timer = 5500; + Renew_Timer = 30500; + PoisonCloud_Timer = 2000; + HolyNova_Timer = 5000; + Dispell_Timer = 35000; + TargetInRange = 0; + + PhaseTwo = false; + InBerserk= false; + } + + void Aggro(Unit *who) + { + DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL); + DoPlaySoundToSet(m_creature,SOUND_AGGRO); + } + + void JustDied(Unit* Killer) + { + ScriptedInstance *pInstance = (m_creature->GetInstanceData()) ? ((ScriptedInstance*)m_creature->GetInstanceData()) : NULL; + if(pInstance) + pInstance->SetData(DATA_VENOXIS_DEATH, 0); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget()) + return; + + if( m_creature->getVictim() && m_creature->isAlive()) + { + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > 50)) + { + if (Dispell_Timer < diff) + { + DoCast(m_creature, SPELL_DISPELL); + Dispell_Timer = 15000 + rand()%15000; + }else Dispell_Timer -= diff; + + if (Renew_Timer < diff) + { + DoCast(m_creature, SPELL_RENEW); + Renew_Timer = 20000 + rand()%10000; + }else Renew_Timer -= diff; + + if (HolyWrath_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_HOLY_WRATH); + HolyWrath_Timer = 15000 + rand()%10000; + }else HolyWrath_Timer -= diff; + + if (HolyNova_Timer < diff) + { + Unit* target = NULL; + TargetInRange = 0; + for(int i=0; i<10; i++) + { + target = SelectUnit(SELECT_TARGET_TOPAGGRO,i); + if(target) + if(m_creature->IsWithinDistInMap(target, ATTACK_DISTANCE)) + TargetInRange++; + } + + if(TargetInRange > 1) + { + DoCast(m_creature->getVictim(),SPELL_HOLY_NOVA); + HolyNova_Timer = 1000; + } + else + { + HolyNova_Timer = 2000; + } + + }else HolyNova_Timer -= diff; + + if (HolyFire_Timer < diff && TargetInRange < 3) + { + Unit* targetrandom = NULL; + targetrandom = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(targetrandom, SPELL_HOLY_FIRE); + HolyFire_Timer = 8000; + }else HolyFire_Timer -= diff; + } + else + { + if(!PhaseTwo) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature,SPELL_SNAKE_FORM); + m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.00f); + 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(); + PhaseTwo = true; + } + + if(PhaseTwo && PoisonCloud_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_POISON_CLOUD); + PoisonCloud_Timer = 15000; + }PoisonCloud_Timer -=diff; + + if (PhaseTwo && VenomSpit_Timer < diff) + { + Unit* targetrandom = NULL; + targetrandom = SelectUnit(SELECT_TARGET_RANDOM,0); + + DoCast(targetrandom, SPELL_VENOMSPIT); + VenomSpit_Timer = 15000 + rand()%5000; + }else VenomSpit_Timer -= diff; + + if (PhaseTwo && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 11)) + { + if (!InBerserk) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_BERSERK); + InBerserk = true; + } + } + } + DoMeleeAttackIfReady(); + } + } +}; +CreatureAI* GetAI_boss_venoxis(Creature *_Creature) +{ + return new boss_venoxisAI (_Creature); +} + +void AddSC_boss_venoxis() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_venoxis"; + newscript->GetAI = GetAI_boss_venoxis; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_wushoolay.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_wushoolay.cpp index c94c665c1cb..200768cf84b 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_wushoolay.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_wushoolay.cpp @@ -1,84 +1,84 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 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 "def_zulgurub.h" - -#define SPELL_LIGHTNINGCLOUD 25033 -#define SPELL_LIGHTNINGWAVE 24819 - -struct MANGOS_DLL_DECL boss_wushoolayAI : public ScriptedAI -{ - boss_wushoolayAI(Creature *c) : ScriptedAI(c) {Reset();} - - uint32 LightningCloud_Timer; - uint32 LightningWave_Timer; - - void Reset() - { - LightningCloud_Timer = 5000 + rand()%5000; - LightningWave_Timer = 8000 + rand()%8000; - } - - void Aggro(Unit *who) - { - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) - return; - - //LightningCloud_Timer - if (LightningCloud_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_LIGHTNINGCLOUD); - LightningCloud_Timer = 15000 + rand()%5000; - }else LightningCloud_Timer -= diff; - - //LightningWave_Timer - if (LightningWave_Timer < diff) - { - Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM,0); - if (target) DoCast(target,SPELL_LIGHTNINGWAVE); - - LightningWave_Timer = 12000 + rand()%4000; - }else LightningWave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_wushoolay(Creature *_Creature) -{ - return new boss_wushoolayAI (_Creature); -} - -void AddSC_boss_wushoolay() -{ - Script *newscript; - newscript = new Script; - newscript->Name="boss_wushoolay"; - newscript->GetAI = GetAI_boss_wushoolay; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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 "def_zulgurub.h" + +#define SPELL_LIGHTNINGCLOUD 25033 +#define SPELL_LIGHTNINGWAVE 24819 + +struct MANGOS_DLL_DECL boss_wushoolayAI : public ScriptedAI +{ + boss_wushoolayAI(Creature *c) : ScriptedAI(c) {Reset();} + + uint32 LightningCloud_Timer; + uint32 LightningWave_Timer; + + void Reset() + { + LightningCloud_Timer = 5000 + rand()%5000; + LightningWave_Timer = 8000 + rand()%8000; + } + + void Aggro(Unit *who) + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) + return; + + //LightningCloud_Timer + if (LightningCloud_Timer < diff) + { + DoCast(m_creature->getVictim(),SPELL_LIGHTNINGCLOUD); + LightningCloud_Timer = 15000 + rand()%5000; + }else LightningCloud_Timer -= diff; + + //LightningWave_Timer + if (LightningWave_Timer < diff) + { + Unit* target = NULL; + target = SelectUnit(SELECT_TARGET_RANDOM,0); + if (target) DoCast(target,SPELL_LIGHTNINGWAVE); + + LightningWave_Timer = 12000 + rand()%4000; + }else LightningWave_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_wushoolay(Creature *_Creature) +{ + return new boss_wushoolayAI (_Creature); +} + +void AddSC_boss_wushoolay() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_wushoolay"; + newscript->GetAI = GetAI_boss_wushoolay; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/def_zulgurub.h b/src/bindings/scripts/scripts/zone/zulgurub/def_zulgurub.h index 0dcbb83c4df..d4d181db15a 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/def_zulgurub.h +++ b/src/bindings/scripts/scripts/zone/zulgurub/def_zulgurub.h @@ -1,36 +1,36 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_ZULGURUB_H -#define DEF_ZULGURUB_H - -#define DATA_ARLOKKISDEAD 1 -#define DATA_ARLOKK_DEATH 2 -#define DATA_JEKLIKISDEAD 3 -#define DATA_JEKLIK_DEATH 4 -#define DATA_JINDO 5 -#define DATA_LORKHAN 6 -#define DATA_LORKHANISALIVE 7 -#define DATA_LORKHANISDEAD 8 -#define DATA_LORKHAN_ALIVE 9 -#define DATA_LORKHAN_DEATH 10 -#define DATA_MARLIISDEAD 11 -#define DATA_MARLI_DEATH 12 -#define DATA_OHGANISDEAD 13 -#define DATA_OHGAN_DEATH 14 -#define DATA_THEKAL 15 -#define DATA_THEKALFAKE_DEATH 16 -#define DATA_THEKALISALIVE 17 -#define DATA_THEKALISDEAD 18 -#define DATA_THEKALISFAKEDEAD 19 -#define DATA_THEKAL_ALIVE 20 -#define DATA_THEKAL_DEATH 21 -#define DATA_VENOXISISDEAD 22 -#define DATA_VENOXIS_DEATH 23 -#define DATA_ZATH 24 -#define DATA_ZATHISALIVE 25 -#define DATA_ZATHISDEAD 26 -#define DATA_ZATH_ALIVE 27 -#define DATA_ZATH_DEATH 28 -#endif +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_ZULGURUB_H +#define DEF_ZULGURUB_H + +#define DATA_ARLOKKISDEAD 1 +#define DATA_ARLOKK_DEATH 2 +#define DATA_JEKLIKISDEAD 3 +#define DATA_JEKLIK_DEATH 4 +#define DATA_JINDO 5 +#define DATA_LORKHAN 6 +#define DATA_LORKHANISALIVE 7 +#define DATA_LORKHANISDEAD 8 +#define DATA_LORKHAN_ALIVE 9 +#define DATA_LORKHAN_DEATH 10 +#define DATA_MARLIISDEAD 11 +#define DATA_MARLI_DEATH 12 +#define DATA_OHGANISDEAD 13 +#define DATA_OHGAN_DEATH 14 +#define DATA_THEKAL 15 +#define DATA_THEKALFAKE_DEATH 16 +#define DATA_THEKALISALIVE 17 +#define DATA_THEKALISDEAD 18 +#define DATA_THEKALISFAKEDEAD 19 +#define DATA_THEKAL_ALIVE 20 +#define DATA_THEKAL_DEATH 21 +#define DATA_VENOXISISDEAD 22 +#define DATA_VENOXIS_DEATH 23 +#define DATA_ZATH 24 +#define DATA_ZATHISALIVE 25 +#define DATA_ZATHISDEAD 26 +#define DATA_ZATH_ALIVE 27 +#define DATA_ZATH_DEATH 28 +#endif diff --git a/src/bindings/scripts/scripts/zone/zulgurub/instance_zulgurub.cpp b/src/bindings/scripts/scripts/zone/zulgurub/instance_zulgurub.cpp index d0573414143..53d978bed18 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/instance_zulgurub.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/instance_zulgurub.cpp @@ -1,238 +1,238 @@ -/* Copyright (C) 2006 - 2008 ScriptDev2 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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_ZulGurub -SD%Complete: 80 -SDComment: Missing reset function after killing a boss for Ohgan, Thekal. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "def_zulgurub.h" - -struct MANGOS_DLL_DECL instance_zulgurub : public ScriptedInstance -{ - instance_zulgurub(Map *Map) : ScriptedInstance(Map) {Initialize();}; - - //If all High Priest bosses were killed. Lorkhan, Zath and Ohgan are added too. - bool IsBossDied[9]; - - //Storing Lorkhan, Zath and Thekal because we need to cast on them later. Jindo is needed for healfunction too. - uint64 LorKhanGUID; - uint64 ZathGUID; - uint64 ThekalGUID; - uint64 JindoGUID; - - void OnCreatureCreate (Creature *creature, uint32 creature_entry) - { - switch (creature_entry) - { - case 11347: - LorKhanGUID = creature->GetGUID(); - break; - - case 11348: - ZathGUID = creature->GetGUID(); - break; - - case 14509: - ThekalGUID = creature->GetGUID(); - break; - - case 11380: - JindoGUID = creature->GetGUID(); - break; - } - } - - void Initialize() - { - IsBossDied[0] = false; - IsBossDied[1] = false; - IsBossDied[2] = false; - IsBossDied[3] = false; - IsBossDied[4] = false; - IsBossDied[5] = false; - IsBossDied[6] = false; - - IsBossDied[7] = false; - IsBossDied[8] = false; - } - - bool IsEncounterInProgress() const - { - //not active in Zul'Gurub - return false; - } - - uint32 GetData(uint32 type) - { - switch(type) - { - case DATA_JEKLIKISDEAD: - if(IsBossDied[0]) - return 1; - break; - - case DATA_VENOXISISDEAD: - if(IsBossDied[1]) - return 1; - break; - - case DATA_MARLIISDEAD: - if(IsBossDied[2]) - return 1; - break; - - case DATA_THEKALISDEAD: - if(IsBossDied[3]) - return 1; - break; - - case DATA_ARLOKKISDEAD: - if(IsBossDied[4]) - return 1; - break; - - case DATA_LORKHANISDEAD: - if(IsBossDied[5]) - return 1; - break; - - case DATA_ZATHISDEAD: - if(IsBossDied[6]) - return 1; - break; - - case DATA_THEKALISFAKEDEAD: - if(IsBossDied[7]) - return 1; - break; - - case DATA_OHGANISDEAD: - if(IsBossDied[8]) - return 1; - break; - - //Boss is not dead. Resetting function for some bosses after killing them but whiping at the complete encounter. - - case DATA_THEKALISALIVE: - if(IsBossDied[3]) - return 0; - break; - - case DATA_LORKHANISALIVE: - if(IsBossDied[5]) - return 0; - break; - - case DATA_ZATHISALIVE: - if(IsBossDied[6]) - return 0; - break; - } - - return 0; - } - - uint64 GetData64 (uint32 identifier) - { - switch(identifier) - { - case DATA_LORKHAN: - return LorKhanGUID; - - case DATA_ZATH: - return ZathGUID; - - case DATA_THEKAL: - return ThekalGUID; - - case DATA_JINDO: - return JindoGUID; - } - return 0; - } // end GetData64 - - void SetData(uint32 type, uint32 data) - { - switch(type) - { - case DATA_JEKLIK_DEATH: - IsBossDied[0] = true; - break; - - case DATA_VENOXIS_DEATH: - IsBossDied[1] = true; - break; - - case DATA_MARLI_DEATH: - IsBossDied[2] = true; - break; - - case DATA_THEKAL_DEATH: - IsBossDied[3] = true; - break; - - case DATA_ARLOKK_DEATH: - IsBossDied[4] = true; - break; - - case DATA_LORKHAN_DEATH: - IsBossDied[5] = true; - break; - - case DATA_ZATH_DEATH: - IsBossDied[6] = true; - break; - - case DATA_THEKALFAKE_DEATH: - IsBossDied[7] = true; - break; - - case DATA_OHGAN_DEATH: - IsBossDied[8] = true; - break; - - case DATA_LORKHAN_ALIVE: - IsBossDied[5] = false; - break; - - case DATA_ZATH_ALIVE: - IsBossDied[6] = false; - break; - - case DATA_THEKAL_ALIVE: - IsBossDied[7] = false; - break; - } - } -}; - -InstanceData* GetInstanceData_instance_zulgurub(Map* map) -{ - return new instance_zulgurub(map); -} - -void AddSC_instance_zulgurub() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_zulgurub"; - newscript->GetInstanceData = GetInstanceData_instance_zulgurub; - m_scripts[nrscripts++] = newscript; -} +/* Copyright (C) 2006 - 2008 ScriptDev2 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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_ZulGurub +SD%Complete: 80 +SDComment: Missing reset function after killing a boss for Ohgan, Thekal. +SDCategory: Zul'Gurub +EndScriptData */ + +#include "precompiled.h" +#include "def_zulgurub.h" + +struct MANGOS_DLL_DECL instance_zulgurub : public ScriptedInstance +{ + instance_zulgurub(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + //If all High Priest bosses were killed. Lorkhan, Zath and Ohgan are added too. + bool IsBossDied[9]; + + //Storing Lorkhan, Zath and Thekal because we need to cast on them later. Jindo is needed for healfunction too. + uint64 LorKhanGUID; + uint64 ZathGUID; + uint64 ThekalGUID; + uint64 JindoGUID; + + void OnCreatureCreate (Creature *creature, uint32 creature_entry) + { + switch (creature_entry) + { + case 11347: + LorKhanGUID = creature->GetGUID(); + break; + + case 11348: + ZathGUID = creature->GetGUID(); + break; + + case 14509: + ThekalGUID = creature->GetGUID(); + break; + + case 11380: + JindoGUID = creature->GetGUID(); + break; + } + } + + void Initialize() + { + IsBossDied[0] = false; + IsBossDied[1] = false; + IsBossDied[2] = false; + IsBossDied[3] = false; + IsBossDied[4] = false; + IsBossDied[5] = false; + IsBossDied[6] = false; + + IsBossDied[7] = false; + IsBossDied[8] = false; + } + + bool IsEncounterInProgress() const + { + //not active in Zul'Gurub + return false; + } + + uint32 GetData(uint32 type) + { + switch(type) + { + case DATA_JEKLIKISDEAD: + if(IsBossDied[0]) + return 1; + break; + + case DATA_VENOXISISDEAD: + if(IsBossDied[1]) + return 1; + break; + + case DATA_MARLIISDEAD: + if(IsBossDied[2]) + return 1; + break; + + case DATA_THEKALISDEAD: + if(IsBossDied[3]) + return 1; + break; + + case DATA_ARLOKKISDEAD: + if(IsBossDied[4]) + return 1; + break; + + case DATA_LORKHANISDEAD: + if(IsBossDied[5]) + return 1; + break; + + case DATA_ZATHISDEAD: + if(IsBossDied[6]) + return 1; + break; + + case DATA_THEKALISFAKEDEAD: + if(IsBossDied[7]) + return 1; + break; + + case DATA_OHGANISDEAD: + if(IsBossDied[8]) + return 1; + break; + + //Boss is not dead. Resetting function for some bosses after killing them but whiping at the complete encounter. + + case DATA_THEKALISALIVE: + if(IsBossDied[3]) + return 0; + break; + + case DATA_LORKHANISALIVE: + if(IsBossDied[5]) + return 0; + break; + + case DATA_ZATHISALIVE: + if(IsBossDied[6]) + return 0; + break; + } + + return 0; + } + + uint64 GetData64 (uint32 identifier) + { + switch(identifier) + { + case DATA_LORKHAN: + return LorKhanGUID; + + case DATA_ZATH: + return ZathGUID; + + case DATA_THEKAL: + return ThekalGUID; + + case DATA_JINDO: + return JindoGUID; + } + return 0; + } // end GetData64 + + void SetData(uint32 type, uint32 data) + { + switch(type) + { + case DATA_JEKLIK_DEATH: + IsBossDied[0] = true; + break; + + case DATA_VENOXIS_DEATH: + IsBossDied[1] = true; + break; + + case DATA_MARLI_DEATH: + IsBossDied[2] = true; + break; + + case DATA_THEKAL_DEATH: + IsBossDied[3] = true; + break; + + case DATA_ARLOKK_DEATH: + IsBossDied[4] = true; + break; + + case DATA_LORKHAN_DEATH: + IsBossDied[5] = true; + break; + + case DATA_ZATH_DEATH: + IsBossDied[6] = true; + break; + + case DATA_THEKALFAKE_DEATH: + IsBossDied[7] = true; + break; + + case DATA_OHGAN_DEATH: + IsBossDied[8] = true; + break; + + case DATA_LORKHAN_ALIVE: + IsBossDied[5] = false; + break; + + case DATA_ZATH_ALIVE: + IsBossDied[6] = false; + break; + + case DATA_THEKAL_ALIVE: + IsBossDied[7] = false; + break; + } + } +}; + +InstanceData* GetInstanceData_instance_zulgurub(Map* map) +{ + return new instance_zulgurub(map); +} + +void AddSC_instance_zulgurub() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_zulgurub"; + newscript->GetInstanceData = GetInstanceData_instance_zulgurub; + m_scripts[nrscripts++] = newscript; +} diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp index 494acbb9a51..a4ef9e39f47 100644 --- a/src/game/AggressorAI.cpp +++ b/src/game/AggressorAI.cpp @@ -1,155 +1,157 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "AggressorAI.h" -#include "Errors.h" -#include "Creature.h" -#include "Player.h" -#include "ObjectAccessor.h" -#include "VMapFactory.h" -#include "World.h" - -#include - -int -AggressorAI::Permissible(const Creature *creature) -{ - // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight - if( !creature->isCivilian() && !creature->IsNeutralToAll() ) - return PERMIT_BASE_PROACTIVE; - - return PERMIT_BASE_NO; -} - -AggressorAI::AggressorAI(Creature &c) : i_creature(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK) -{ -} - -void -AggressorAI::MoveInLineOfSight(Unit *u) -{ - if( i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE ) - return; - if( !i_creature.getVictim() && !i_creature.hasUnitState(UNIT_STAT_STUNDED) && u->isTargetableForAttack() && - ( i_creature.IsHostileTo( u ) /*|| u->getVictim() && i_creature.IsFriendlyTo( u->getVictim() )*/ ) && - u->isInAccessablePlaceFor(&i_creature) ) - { - float attackRadius = i_creature.GetAttackDistance(u); - if(i_creature.IsWithinDistInMap(u, attackRadius) && i_creature.IsWithinLOSInMap(u) ) - { - AttackStart(u); - u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - } - } -} - -void AggressorAI::EnterEvadeMode() -{ - if( !i_creature.isAlive() ) - { - DEBUG_LOG("Creature stopped attacking cuz his dead [guid=%u]", i_creature.GetGUIDLow()); - i_victimGuid = 0; - i_creature.CombatStop(); - i_creature.DeleteThreatList(); - return; - } - - Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid ); - - if( !victim ) - { - DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow()); - } - else if( !victim->isAlive() ) - { - DEBUG_LOG("Creature stopped attacking cuz his victim is dead [guid=%u]", i_creature.GetGUIDLow()); - } - else if( victim->HasStealthAura() ) - { - DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", i_creature.GetGUIDLow()); - } - else if( victim->isInFlight() ) - { - DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", i_creature.GetGUIDLow()); - } - else - { - DEBUG_LOG("Creature stopped attacking due to target out run him [guid=%u]", i_creature.GetGUIDLow()); - //i_state = STATE_LOOK_AT_VICTIM; - //i_tracker.Reset(TIME_INTERVAL_LOOK); - } - - if(!i_creature.isCharmed()) - { - i_creature.RemoveAllAuras(); - - // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead - if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE ) - i_creature.GetMotionMaster()->MoveTargetedHome(); - } - - i_creature.DeleteThreatList(); - i_victimGuid = 0; - i_creature.CombatStop(); - i_creature.SetLootRecipient(NULL); -} - -void -AggressorAI::UpdateAI(const uint32 /*diff*/) -{ - // update i_victimGuid if i_creature.getVictim() !=0 and changed - if(!i_creature.SelectHostilTarget() || !i_creature.getVictim()) - return; - - i_victimGuid = i_creature.getVictim()->GetGUID(); - - if( i_creature.isAttackReady() ) - { - if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DISTANCE)) - { - i_creature.AttackerStateUpdate(i_creature.getVictim()); - i_creature.resetAttackTimer(); - } - } -} - -bool -AggressorAI::IsVisible(Unit *pl) const -{ - return i_creature.GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_MONSTER) - && pl->isVisibleForOrDetect(&i_creature,true); -} - -void -AggressorAI::AttackStart(Unit *u) -{ - if( !u ) - return; - - if(i_creature.Attack(u,true)) - { - i_creature.SetInCombatWith(u); - u->SetInCombatWith(&i_creature); - - i_creature.AddThreat(u, 0.0f); - // DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", i_creature.GetName(), u->GetGUIDLow()); - i_victimGuid = u->GetGUID(); - - i_creature.GetMotionMaster()->MoveChase(u); - } -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AggressorAI.h" +#include "Errors.h" +#include "Creature.h" +#include "Player.h" +#include "ObjectAccessor.h" +#include "VMapFactory.h" +#include "World.h" + +#include + +int +AggressorAI::Permissible(const Creature *creature) +{ + // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight + if( !creature->isCivilian() && !creature->IsNeutralToAll() ) + return PERMIT_BASE_PROACTIVE; + + return PERMIT_BASE_NO; +} + +AggressorAI::AggressorAI(Creature &c) : i_creature(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK) +{ +} + +void +AggressorAI::MoveInLineOfSight(Unit *u) +{ + // Ignore Z for flying creatures + if( !i_creature.canFly() && i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE ) + return; + + if( !i_creature.getVictim() && !i_creature.hasUnitState(UNIT_STAT_STUNDED) && u->isTargetableForAttack() && + ( i_creature.IsHostileTo( u ) /*|| u->getVictim() && i_creature.IsFriendlyTo( u->getVictim() )*/ ) && + u->isInAccessablePlaceFor(&i_creature) ) + { + float attackRadius = i_creature.GetAttackDistance(u); + if(i_creature.IsWithinDistInMap(u, attackRadius) && i_creature.IsWithinLOSInMap(u) ) + { + AttackStart(u); + u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + } +} + +void AggressorAI::EnterEvadeMode() +{ + if( !i_creature.isAlive() ) + { + DEBUG_LOG("Creature stopped attacking cuz his dead [guid=%u]", i_creature.GetGUIDLow()); + i_victimGuid = 0; + i_creature.CombatStop(); + i_creature.DeleteThreatList(); + return; + } + + Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid ); + + if( !victim ) + { + DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow()); + } + else if( !victim->isAlive() ) + { + DEBUG_LOG("Creature stopped attacking cuz his victim is dead [guid=%u]", i_creature.GetGUIDLow()); + } + else if( victim->HasStealthAura() ) + { + DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", i_creature.GetGUIDLow()); + } + else if( victim->isInFlight() ) + { + DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", i_creature.GetGUIDLow()); + } + else + { + DEBUG_LOG("Creature stopped attacking due to target out run him [guid=%u]", i_creature.GetGUIDLow()); + //i_state = STATE_LOOK_AT_VICTIM; + //i_tracker.Reset(TIME_INTERVAL_LOOK); + } + + if(!i_creature.isCharmed()) + { + i_creature.RemoveAllAuras(); + + // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead + if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE ) + i_creature.GetMotionMaster()->MoveTargetedHome(); + } + + i_creature.DeleteThreatList(); + i_victimGuid = 0; + i_creature.CombatStop(); + i_creature.SetLootRecipient(NULL); +} + +void +AggressorAI::UpdateAI(const uint32 /*diff*/) +{ + // update i_victimGuid if i_creature.getVictim() !=0 and changed + if(!i_creature.SelectHostilTarget() || !i_creature.getVictim()) + return; + + i_victimGuid = i_creature.getVictim()->GetGUID(); + + if( i_creature.isAttackReady() ) + { + if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DISTANCE)) + { + i_creature.AttackerStateUpdate(i_creature.getVictim()); + i_creature.resetAttackTimer(); + } + } +} + +bool +AggressorAI::IsVisible(Unit *pl) const +{ + return i_creature.GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_MONSTER) + && pl->isVisibleForOrDetect(&i_creature,true); +} + +void +AggressorAI::AttackStart(Unit *u) +{ + if( !u ) + return; + + if(i_creature.Attack(u,true)) + { + i_creature.SetInCombatWith(u); + u->SetInCombatWith(&i_creature); + + i_creature.AddThreat(u, 0.0f); + // DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", i_creature.GetName(), u->GetGUIDLow()); + i_victimGuid = u->GetGUID(); + + i_creature.GetMotionMaster()->MoveChase(u); + } +} diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index f63af7d7f81..929a0543f0b 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -19,7 +19,7 @@ #include "Common.h" #include "Database/DatabaseEnv.h" #include "WorldPacket.h" -#include "WorldSocket.h" +#include "SharedDefines.h" #include "WorldSession.h" #include "Opcodes.h" #include "Log.h" @@ -366,7 +366,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) data << (uint8)CHAR_CREATE_SUCCESS; SendPacket( &data ); - std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-"; + std::string IP_str = GetRemoteAddress().c_str(); sLog.outBasic("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str()); sLog.outChar("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str()); } @@ -416,7 +416,7 @@ void WorldSession::HandleCharDeleteOpcode( WorldPacket & recv_data ) if(accountId != GetAccountId()) return; - std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-"; + std::string IP_str = GetRemoteAddress(); sLog.outBasic("Account: %d (IP: %s) Delete Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); @@ -734,7 +734,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) if(pCurrChar->isGameMaster()) SendNotification("GM mode is ON"); - std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-"; + std::string IP_str = GetRemoteAddress(); sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),pCurrChar->GetName() ,pCurrChar->GetGUID()); m_playerLoading = false; @@ -966,7 +966,7 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data) CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME),GUID_LOPART(guid)); CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid)); - std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-"; + std::string IP_str = GetRemoteAddress(); sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s",GetAccountId(),IP_str.c_str(),oldname.c_str(),GUID_LOPART(guid),newname.c_str()); WorldPacket data(SMSG_CHAR_RENAME,1+8+(newname.size()+1)); diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 9635542cf4f..7415bfb405c 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -1,1103 +1,1131 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Language.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "UpdateMask.h" -#include "Chat.h" -#include "MapManager.h" -#include "GridNotifiersImpl.h" -#include "CellImpl.h" - -bool ChatHandler::load_command_table = true; - -LanguageDesc lang_description[LANGUAGES_COUNT] = -{ - { LANG_ADDON, 0, 0 }, - { LANG_UNIVERSAL, 0, 0 }, - { LANG_ORCISH, 669, SKILL_LANG_ORCISH }, - { LANG_DARNASSIAN, 671, SKILL_LANG_DARNASSIAN }, - { LANG_TAURAHE, 670, SKILL_LANG_TAURAHE }, - { LANG_DWARVISH, 672, SKILL_LANG_DWARVEN }, - { LANG_COMMON, 668, SKILL_LANG_COMMON }, - { LANG_DEMONIC, 815, SKILL_LANG_DEMON_TONGUE }, - { LANG_TITAN, 816, SKILL_LANG_TITAN }, - { LANG_THALASSIAN, 813, SKILL_LANG_THALASSIAN }, - { LANG_DRACONIC, 814, SKILL_LANG_DRACONIC }, - { LANG_KALIMAG, 817, SKILL_LANG_OLD_TONGUE }, - { LANG_GNOMISH, 7340, SKILL_LANG_GNOMISH }, - { LANG_TROLL, 7341, SKILL_LANG_TROLL }, - { LANG_GUTTERSPEAK, 17737, SKILL_LANG_GUTTERSPEAK }, - { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI }, - { LANG_ZOMBIE, 0, 0 }, - { LANG_GNOMISH_BINARY, 0, 0 }, - { LANG_GOBLIN_BINARY, 0, 0 } -}; - -LanguageDesc const* GetLanguageDescByID(uint32 lang) -{ - for(int i = 0; i < LANGUAGES_COUNT; ++i) - { - if(uint32(lang_description[i].lang_id) == lang) - return &lang_description[i]; - } - - return NULL; -} - -LanguageDesc const* GetLanguageDescBySpell(uint32 spell_id) -{ - for(int i = 0; i < LANGUAGES_COUNT; ++i) - { - if(lang_description[i].spell_id == spell_id) - return &lang_description[i]; - } - - return NULL; -} - -LanguageDesc const* GetLanguageDescBySkill(uint32 skill_id) -{ - for(int i = 0; i < LANGUAGES_COUNT; ++i) - { - if(lang_description[i].skill_id == skill_id) - return &lang_description[i]; - } - - return NULL; -} - -ChatCommand * ChatHandler::getCommandTable() -{ - static ChatCommand serverCommandTable[] = - { - { "idlerestart", SEC_ADMINISTRATOR, &ChatHandler::HandleIdleRestartCommand, "", NULL }, - { "idleshutdown", SEC_ADMINISTRATOR, &ChatHandler::HandleIdleShutDownCommand, "", NULL }, - { "info", SEC_PLAYER, &ChatHandler::HandleInfoCommand, "", NULL }, - { "restart", SEC_ADMINISTRATOR, &ChatHandler::HandleRestartCommand, "", NULL }, - { "shutdown", SEC_ADMINISTRATOR, &ChatHandler::HandleShutDownCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand modifyCommandTable[] = - { - { "hp", SEC_MODERATOR, &ChatHandler::HandleModifyHPCommand, "", NULL }, - { "mana", SEC_MODERATOR, &ChatHandler::HandleModifyManaCommand, "", NULL }, - { "rage", SEC_MODERATOR, &ChatHandler::HandleModifyRageCommand, "", NULL }, - { "energy", SEC_MODERATOR, &ChatHandler::HandleModifyEnergyCommand, "", NULL }, - { "money", SEC_MODERATOR, &ChatHandler::HandleModifyMoneyCommand, "", NULL }, - { "speed", SEC_MODERATOR, &ChatHandler::HandleModifySpeedCommand, "", NULL }, - { "swim", SEC_MODERATOR, &ChatHandler::HandleModifySwimCommand, "", NULL }, - { "scale", SEC_MODERATOR, &ChatHandler::HandleModifyScaleCommand, "", NULL }, - { "bit", SEC_MODERATOR, &ChatHandler::HandleModifyBitCommand, "", NULL }, - { "bwalk", SEC_MODERATOR, &ChatHandler::HandleModifyBWalkCommand, "", NULL }, - { "fly", SEC_MODERATOR, &ChatHandler::HandleModifyFlyCommand, "", NULL }, - { "aspeed", SEC_MODERATOR, &ChatHandler::HandleModifyASpeedCommand, "", NULL }, - { "faction", SEC_MODERATOR, &ChatHandler::HandleModifyFactionCommand, "", NULL }, - { "spell", SEC_MODERATOR, &ChatHandler::HandleModifySpellCommand, "", NULL }, - { "tp", SEC_MODERATOR, &ChatHandler::HandleModifyTalentCommand, "", NULL }, - { "titles", SEC_MODERATOR, &ChatHandler::HandleModifyKnownTitlesCommand, "", NULL }, - { "mount", SEC_MODERATOR, &ChatHandler::HandleModifyMountCommand, "", NULL }, - { "honor", SEC_MODERATOR, &ChatHandler::HandleModifyHonorCommand, "", NULL }, - { "rep", SEC_MODERATOR, &ChatHandler::HandleModifyRepCommand, "", NULL }, - { "arena", SEC_MODERATOR, &ChatHandler::HandleModifyArenaCommand, "", NULL }, - { "drunk", SEC_MODERATOR, &ChatHandler::HandleDrunkCommand, "", NULL }, - { "standstate", SEC_GAMEMASTER, &ChatHandler::HandleStandStateCommand, "", NULL }, - { "morph", SEC_GAMEMASTER, &ChatHandler::HandleMorphCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand wpCommandTable[] = - { - { "show", SEC_GAMEMASTER, &ChatHandler::HandleWpShowCommand, "", NULL }, - { "add", SEC_GAMEMASTER, &ChatHandler::HandleWpAddCommand, "", NULL }, - { "modify", SEC_GAMEMASTER, &ChatHandler::HandleWpModifyCommand, "", NULL }, - { "export", SEC_ADMINISTRATOR, &ChatHandler::HandleWpExportCommand, "", NULL }, - { "import", SEC_ADMINISTRATOR, &ChatHandler::HandleWpImportCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand debugCommandTable[] = - { - { "inarc", SEC_ADMINISTRATOR, &ChatHandler::HandleDebugInArcCommand, "", NULL }, - { "spellfail", SEC_ADMINISTRATOR, &ChatHandler::HandleDebugSpellFailCommand, "", NULL }, - { "setpoi", SEC_ADMINISTRATOR, &ChatHandler::HandleSetPoiCommand, "", NULL }, - { "qpartymsg", SEC_ADMINISTRATOR, &ChatHandler::HandleSendQuestPartyMsgCommand, "", NULL }, - { "qinvalidmsg", SEC_ADMINISTRATOR, &ChatHandler::HandleSendQuestInvalidMsgCommand, "", NULL }, - { "equiperr", SEC_ADMINISTRATOR, &ChatHandler::HandleEquipErrorCommand, "", NULL }, - { "sellerr", SEC_ADMINISTRATOR, &ChatHandler::HandleSellErrorCommand, "", NULL }, - { "buyerr", SEC_ADMINISTRATOR, &ChatHandler::HandleBuyErrorCommand, "", NULL }, - { "sendopcode", SEC_ADMINISTRATOR, &ChatHandler::HandleSendOpcodeCommand, "", NULL }, - { "uws", SEC_ADMINISTRATOR, &ChatHandler::HandleUpdateWorldStateCommand, "", NULL }, - { "ps", SEC_ADMINISTRATOR, &ChatHandler::HandlePlaySound2Command, "", NULL }, - { "scn", SEC_ADMINISTRATOR, &ChatHandler::HandleSendChannelNotifyCommand, "", NULL }, - { "scm", SEC_ADMINISTRATOR, &ChatHandler::HandleSendChatMsgCommand, "", NULL }, - { "getitemstate", SEC_ADMINISTRATOR, &ChatHandler::HandleGetItemState, "", NULL }, - { "playsound", SEC_MODERATOR, &ChatHandler::HandlePlaySoundCommand, "", NULL }, - { "update", SEC_ADMINISTRATOR, &ChatHandler::HandleUpdate, "", NULL }, - { "setvalue", SEC_ADMINISTRATOR, &ChatHandler::HandleSetValue, "", NULL }, - { "getvalue", SEC_ADMINISTRATOR, &ChatHandler::HandleGetValue, "", NULL }, - { "Mod32Value", SEC_ADMINISTRATOR, &ChatHandler::HandleMod32Value, "", NULL }, - { "anim", SEC_GAMEMASTER, &ChatHandler::HandleAnimCommand, "", NULL }, - { "lootrecipient", SEC_GAMEMASTER, &ChatHandler::HandleGetLootRecipient, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand eventCommandTable[] = - { - { "activelist", SEC_GAMEMASTER, &ChatHandler::HandleEventActiveListCommand, "", NULL }, - { "start", SEC_GAMEMASTER, &ChatHandler::HandleEventStartCommand, "", NULL }, - { "stop", SEC_GAMEMASTER, &ChatHandler::HandleEventStopCommand, "", NULL }, - { "", SEC_GAMEMASTER, &ChatHandler::HandleEventInfoCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand learnCommandTable[] = - { - { "all", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnAllCommand, "", NULL }, - { "all_gm", SEC_GAMEMASTER, &ChatHandler::HandleLearnAllGMCommand, "", NULL }, - { "all_crafts", SEC_GAMEMASTER, &ChatHandler::HandleLearnAllCraftsCommand, "", NULL }, - { "all_default", SEC_MODERATOR, &ChatHandler::HandleLearnAllDefaultCommand, "", NULL }, - { "all_lang", SEC_MODERATOR, &ChatHandler::HandleLearnAllLangCommand, "", NULL }, - { "all_myclass", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnAllMyClassCommand, "", NULL }, - { "all_myspells", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnAllMySpellsCommand, "", NULL }, - { "all_mytalents", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnAllMyTalentsCommand, "", NULL }, - { "all_recipes", SEC_GAMEMASTER, &ChatHandler::HandleLearnAllRecipesCommand, "", NULL }, - { "", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand reloadCommandTable[] = - { - { "all", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllCommand, "", NULL }, - { "all_quest", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllQuestCommand, "", NULL }, - { "all_loot", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllLootCommand, "", NULL }, - { "all_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllScriptsCommand, "", NULL }, - { "all_spell", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllSpellCommand, "", NULL }, - { "all_item", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllItemCommand, "", NULL }, - - { "config", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadConfigCommand, "", NULL }, - - { "areatrigger_tavern", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL }, - { "areatrigger_teleport", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL }, - { "areatrigger_involvedrelation",SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL }, - { "event_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL }, - { "command", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadCommandCommand, "", NULL }, - { "creature_involvedrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand,"",NULL }, - { "creature_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL }, - { "creature_questrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL }, - { "disenchant_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL }, - { "fishing_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesFishingCommand, "", NULL }, - { "game_graveyard_zone", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGameGraveyardZoneCommand, "", NULL }, - { "gameobject_involvedrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGOQuestInvRelationsCommand, "", NULL }, - { "gameobject_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesGameobjectCommand, "", NULL }, - { "gameobject_questrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGOQuestRelationsCommand, "", NULL }, - { "gameobject_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL }, - { "item_enchantment_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL }, - { "item_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, - { "mangos_string", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadMangosStringCommand, "", NULL }, - { "page_text", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadPageTextsCommand, "", NULL }, - { "pickpocketing_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand,"",NULL}, - { "prospecting_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesProspectingCommand,"", NULL }, - { "quest_mail_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesQuestMailCommand, "", NULL }, - { "quest_end_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestEndScriptsCommand, "", NULL }, - { "quest_start_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestStartScriptsCommand, "", NULL }, - { "quest_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestTemplateCommand, "", NULL }, - { "reference_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesReferenceCommand, "", NULL }, - { "reserved_name", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadReservedNameCommand, "", NULL }, - { "skill_discovery_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSkillDiscoveryTemplateCommand, "", NULL }, - { "skill_extra_item_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSkillExtraItemTemplateCommand, "", NULL }, - { "skill_fishing_base_level", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL }, - { "skinning_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL }, - { "spell_affect", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL }, - { "spell_chain", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellChainCommand, "", NULL }, - { "spell_elixir", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL }, - { "spell_learn_spell", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL }, - { "spell_pet_auras", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL }, - { "spell_proc_event", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL }, - { "spell_script_target", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL }, - { "spell_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL }, - { "spell_target_position", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL }, - { "spell_threats", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL }, - { "", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand honorCommandTable[] = - { - { "add", SEC_GAMEMASTER, &ChatHandler::HandleAddHonorCommand, "", NULL }, - { "addkill", SEC_GAMEMASTER, &ChatHandler::HandleHonorAddKillCommand, "", NULL }, - { "update", SEC_GAMEMASTER, &ChatHandler::HandleUpdateHonorFieldsCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand guildCommandTable[] = - { - { "create", SEC_GAMEMASTER, &ChatHandler::HandleGuildCreateCommand, "", NULL }, - { "delete", SEC_GAMEMASTER, &ChatHandler::HandleGuildDeleteCommand, "", NULL }, - { "invite", SEC_GAMEMASTER, &ChatHandler::HandleGuildInviteCommand, "", NULL }, - { "uninvite", SEC_GAMEMASTER, &ChatHandler::HandleGuildUninviteCommand, "", NULL }, - { "rank", SEC_GAMEMASTER, &ChatHandler::HandleGuildRankCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand lookupCommandTable[] = - { - { "area", SEC_MODERATOR, &ChatHandler::HandleLookupAreaCommand, "", NULL }, - { "creature", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupCreatureCommand, "", NULL }, - { "event", SEC_GAMEMASTER, &ChatHandler::HandleLookupEventCommand, "", NULL }, - { "faction", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupFactionCommand, "", NULL }, - { "item", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupItemCommand, "", NULL }, - { "itemset", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupItemSetCommand, "", NULL }, - { "object", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupObjectCommand, "", NULL }, - { "quest", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupQuestCommand, "", NULL }, - { "skill", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupSkillCommand, "", NULL }, - { "spell", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupSpellCommand, "", NULL }, - { "tele", SEC_MODERATOR, &ChatHandler::HandleLookupTeleCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand resetCommandTable[] = - { - { "honor", SEC_ADMINISTRATOR, &ChatHandler::HandleResetHonorCommand, "", NULL }, - { "level", SEC_ADMINISTRATOR, &ChatHandler::HandleResetLevelCommand, "", NULL }, - { "spells", SEC_ADMINISTRATOR, &ChatHandler::HandleResetSpellsCommand, "", NULL }, - { "stats", SEC_ADMINISTRATOR, &ChatHandler::HandleResetStatsCommand, "", NULL }, - { "talents", SEC_ADMINISTRATOR, &ChatHandler::HandleResetTalentsCommand, "", NULL }, - { "all", SEC_ADMINISTRATOR, &ChatHandler::HandleResetAllCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand castCommandTable[] = - { - { "back", SEC_ADMINISTRATOR, &ChatHandler::HandleCastBackCommand, "", NULL }, - { "dist", SEC_ADMINISTRATOR, &ChatHandler::HandleCastDistCommand, "", NULL }, - { "self", SEC_ADMINISTRATOR, &ChatHandler::HandleCastSelfCommand, "", NULL }, - { "target", SEC_ADMINISTRATOR, &ChatHandler::HandleCastTargetCommand, "", NULL }, - { "", SEC_ADMINISTRATOR, &ChatHandler::HandleCastCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand pdumpCommandTable[] = - { - { "load", SEC_ADMINISTRATOR, &ChatHandler::HandleLoadPDumpCommand, "", NULL }, - { "write", SEC_ADMINISTRATOR, &ChatHandler::HandleWritePDumpCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand listCommandTable[] = - { - { "creature", SEC_ADMINISTRATOR, &ChatHandler::HandleListCreatureCommand, "", NULL }, - { "item", SEC_ADMINISTRATOR, &ChatHandler::HandleListItemCommand, "", NULL }, - { "object", SEC_ADMINISTRATOR, &ChatHandler::HandleListObjectCommand, "", NULL }, - { "auras", SEC_ADMINISTRATOR, &ChatHandler::HandleListAurasCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand teleCommandTable[] = - { - { "add", SEC_ADMINISTRATOR, &ChatHandler::HandleAddTeleCommand, "", NULL }, - { "del", SEC_ADMINISTRATOR, &ChatHandler::HandleDelTeleCommand, "", NULL }, - { "name", SEC_MODERATOR, &ChatHandler::HandleNameTeleCommand, "", NULL }, - { "group", SEC_MODERATOR, &ChatHandler::HandleGroupTeleCommand, "", NULL }, - { "", SEC_MODERATOR, &ChatHandler::HandleTeleCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand npcCommandTable[] = - { - { "say", SEC_MODERATOR, &ChatHandler::HandleSayCommand, "", NULL }, - { "whisper", SEC_MODERATOR, &ChatHandler::HandleNpcWhisperCommand, "", NULL }, - { "yell", SEC_MODERATOR, &ChatHandler::HandleYellCommand, "", NULL }, - { "textemote", SEC_MODERATOR, &ChatHandler::HandleTextEmoteCommand, "", NULL }, - { "add", SEC_GAMEMASTER, &ChatHandler::HandleAddSpwCommand, "", NULL }, - { "delete", SEC_GAMEMASTER, &ChatHandler::HandleDelCreatureCommand, "", NULL }, - { "spawndist", SEC_GAMEMASTER, &ChatHandler::HandleSpawnDistCommand, "", NULL }, - { "spawntime", SEC_GAMEMASTER, &ChatHandler::HandleSpawnTimeCommand, "", NULL }, - { "factionid", SEC_GAMEMASTER, &ChatHandler::HandleFactionIdCommand, "", NULL }, - { "addmove", SEC_GAMEMASTER, &ChatHandler::HandleAddMoveCommand, "", NULL }, - { "setmovetype", SEC_GAMEMASTER, &ChatHandler::HandleSetMoveTypeCommand, "", NULL }, - { "move", SEC_GAMEMASTER, &ChatHandler::HandleMoveCreatureCommand, "", NULL }, - { "changelevel", SEC_GAMEMASTER, &ChatHandler::HandleChangeLevelCommand, "", NULL }, - { "setmodel", SEC_GAMEMASTER, &ChatHandler::HandleSetModelCommand, "", NULL }, - { "additem", SEC_GAMEMASTER, &ChatHandler::HandleAddVendorItemCommand, "", NULL }, - { "delitem", SEC_GAMEMASTER, &ChatHandler::HandleDelVendorItemCommand, "", NULL }, - { "flag", SEC_GAMEMASTER, &ChatHandler::HandleNPCFlagCommand, "", NULL }, - { "changeentry", SEC_ADMINISTRATOR, &ChatHandler::HandleChangeEntryCommand, "", NULL }, - { "info", SEC_ADMINISTRATOR, &ChatHandler::HandleNpcInfoCommand, "", NULL }, - { "playemote", SEC_ADMINISTRATOR, &ChatHandler::HandlePlayEmoteCommand, "", NULL }, - - //{ TODO: fix or remove this commands - { "name", SEC_GAMEMASTER, &ChatHandler::HandleNameCommand, "", NULL }, - { "subname", SEC_GAMEMASTER, &ChatHandler::HandleSubNameCommand, "", NULL }, - { "addweapon", SEC_ADMINISTRATOR, &ChatHandler::HandleAddWeaponCommand, "", NULL }, - //} - - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand goCommandTable[] = - { - { "grid", SEC_MODERATOR, &ChatHandler::HandleGoGridCommand, "", NULL }, - { "creature", SEC_GAMEMASTER, &ChatHandler::HandleGoCreatureCommand, "", NULL }, - { "object", SEC_GAMEMASTER, &ChatHandler::HandleGoObjectCommand, "", NULL }, - { "trigger", SEC_GAMEMASTER, &ChatHandler::HandleGoTriggerCommand, "", NULL }, - { "graveyard", SEC_GAMEMASTER, &ChatHandler::HandleGoGraveyardCommand, "", NULL }, - { "zonexy", SEC_MODERATOR, &ChatHandler::HandleGoZoneXYCommand, "", NULL }, - { "xy", SEC_MODERATOR, &ChatHandler::HandleGoXYCommand, "", NULL }, - { "xyz", SEC_MODERATOR, &ChatHandler::HandleGoXYZCommand, "", NULL }, - { "", SEC_MODERATOR, &ChatHandler::HandleGoXYZCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand gobjectCommandTable[] = - { - { "add", SEC_GAMEMASTER, &ChatHandler::HandleGameObjectCommand, "", NULL }, - { "delete", SEC_GAMEMASTER, &ChatHandler::HandleDelObjectCommand, "", NULL }, - { "target", SEC_GAMEMASTER, &ChatHandler::HandleTargetObjectCommand, "", NULL }, - { "turn", SEC_GAMEMASTER, &ChatHandler::HandleTurnObjectCommand, "", NULL }, - { "move", SEC_GAMEMASTER, &ChatHandler::HandleMoveObjectCommand, "", NULL }, - { "near", SEC_ADMINISTRATOR, &ChatHandler::HandleNearObjectCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand questCommandTable[] = - { - { "add", SEC_ADMINISTRATOR, &ChatHandler::HandleAddQuest, "", NULL }, - { "complete", SEC_ADMINISTRATOR, &ChatHandler::HandleCompleteQuest, "", NULL }, - { "remove", SEC_ADMINISTRATOR, &ChatHandler::HandleRemoveQuest, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand gmCommandTable[] = - { - { "list", SEC_PLAYER, &ChatHandler::HandleGMListCommand, "", NULL }, - { "visible", SEC_MODERATOR, &ChatHandler::HandleVisibleCommand, "", NULL }, - { "fly", SEC_ADMINISTRATOR, &ChatHandler::HandleFlyModeCommand, "", NULL }, - { "", SEC_MODERATOR, &ChatHandler::HandleGMmodeCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand instanceCommandTable[] = - { - { "listbinds", SEC_MODERATOR, &ChatHandler::HandleInstanceListBindsCommand, "", NULL }, - { "unbind", SEC_MODERATOR, &ChatHandler::HandleInstanceUnbindCommand, "", NULL }, - { "stats", SEC_MODERATOR, &ChatHandler::HandleInstanceStatsCommand, "", NULL }, - { "savedata", SEC_MODERATOR, &ChatHandler::HandleInstanceSaveDataCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } - }; - - static ChatCommand commandTable[] = - { - { "gm", SEC_MODERATOR, NULL, "", gmCommandTable }, - { "npc", SEC_MODERATOR, NULL, "", npcCommandTable }, - { "go", SEC_MODERATOR, NULL, "", goCommandTable }, - { "learn", SEC_MODERATOR, NULL, "", learnCommandTable }, - { "modify", SEC_MODERATOR, NULL, "", modifyCommandTable }, - { "debug", SEC_MODERATOR, NULL, "", debugCommandTable }, - { "tele", SEC_MODERATOR, NULL, "", teleCommandTable }, - { "event", SEC_GAMEMASTER, NULL, "", eventCommandTable }, - { "gobject", SEC_GAMEMASTER, NULL, "", gobjectCommandTable }, - { "honor", SEC_GAMEMASTER, NULL, "", honorCommandTable }, - { "wp", SEC_GAMEMASTER, NULL, "", wpCommandTable }, - { "quest", SEC_ADMINISTRATOR, NULL, "", questCommandTable }, - { "reload", SEC_ADMINISTRATOR, NULL, "", reloadCommandTable }, - { "list", SEC_ADMINISTRATOR, NULL, "", listCommandTable }, - { "lookup", SEC_ADMINISTRATOR, NULL, "", lookupCommandTable }, - { "pdump", SEC_ADMINISTRATOR, NULL, "", pdumpCommandTable }, - { "guild", SEC_ADMINISTRATOR, NULL, "", guildCommandTable }, - { "cast", SEC_ADMINISTRATOR, NULL, "", castCommandTable }, - { "reset", SEC_ADMINISTRATOR, NULL, "", resetCommandTable }, - { "instance", SEC_ADMINISTRATOR, NULL, "", instanceCommandTable }, - { "server", SEC_ADMINISTRATOR, NULL, "", serverCommandTable }, - - { "aura", SEC_ADMINISTRATOR, &ChatHandler::HandleAuraCommand, "", NULL }, - { "unaura", SEC_ADMINISTRATOR, &ChatHandler::HandleUnAuraCommand, "", NULL }, - { "acct", SEC_PLAYER, &ChatHandler::HandleAcctCommand, "", NULL }, - { "announce", SEC_MODERATOR, &ChatHandler::HandleAnnounceCommand, "", NULL }, - { "notify", SEC_MODERATOR, &ChatHandler::HandleNotifyCommand, "", NULL }, - { "goname", SEC_MODERATOR, &ChatHandler::HandleGonameCommand, "", NULL }, - { "namego", SEC_MODERATOR, &ChatHandler::HandleNamegoCommand, "", NULL }, - { "groupgo", SEC_MODERATOR, &ChatHandler::HandleGroupgoCommand, "", NULL }, - { "commands", SEC_PLAYER, &ChatHandler::HandleCommandsCommand, "", NULL }, - { "demorph", SEC_GAMEMASTER, &ChatHandler::HandleDeMorphCommand, "", NULL }, - { "die", SEC_ADMINISTRATOR, &ChatHandler::HandleDieCommand, "", NULL }, - { "revive", SEC_ADMINISTRATOR, &ChatHandler::HandleReviveCommand, "", NULL }, - { "dismount", SEC_PLAYER, &ChatHandler::HandleDismountCommand, "", NULL }, - { "gps", SEC_MODERATOR, &ChatHandler::HandleGPSCommand, "", NULL }, - { "guid", SEC_GAMEMASTER, &ChatHandler::HandleGUIDCommand, "", NULL }, - { "help", SEC_PLAYER, &ChatHandler::HandleHelpCommand, "", NULL }, - { "itemmove", SEC_GAMEMASTER, &ChatHandler::HandleItemMoveCommand, "", NULL }, - { "cooldown", SEC_ADMINISTRATOR, &ChatHandler::HandleCooldownCommand, "", NULL }, - { "unlearn", SEC_ADMINISTRATOR, &ChatHandler::HandleUnLearnCommand, "", NULL }, - { "distance", SEC_ADMINISTRATOR, &ChatHandler::HandleGetDistanceCommand, "", NULL }, - { "recall", SEC_MODERATOR, &ChatHandler::HandleRecallCommand, "", NULL }, - { "save", SEC_PLAYER, &ChatHandler::HandleSaveCommand, "", NULL }, - { "saveall", SEC_MODERATOR, &ChatHandler::HandleSaveAllCommand, "", NULL }, - { "kick", SEC_GAMEMASTER, &ChatHandler::HandleKickPlayerCommand, "", NULL }, - { "security", SEC_ADMINISTRATOR, &ChatHandler::HandleSecurityCommand, "", NULL }, - { "ban", SEC_ADMINISTRATOR, &ChatHandler::HandleBanCommand, "", NULL }, - { "unban", SEC_ADMINISTRATOR, &ChatHandler::HandleUnBanCommand, "", NULL }, - { "baninfo", SEC_ADMINISTRATOR, &ChatHandler::HandleBanInfoCommand, "", NULL }, - { "banlist", SEC_ADMINISTRATOR, &ChatHandler::HandleBanListCommand, "", NULL }, - { "plimit", SEC_ADMINISTRATOR, &ChatHandler::HandlePLimitCommand, "", NULL }, - { "start", SEC_PLAYER, &ChatHandler::HandleStartCommand, "", NULL }, - { "taxicheat", SEC_MODERATOR, &ChatHandler::HandleTaxiCheatCommand, "", NULL }, - { "allowmove", SEC_ADMINISTRATOR, &ChatHandler::HandleAllowMovementCommand, "", NULL }, - { "linkgrave", SEC_ADMINISTRATOR, &ChatHandler::HandleLinkGraveCommand, "", NULL }, - { "neargrave", SEC_ADMINISTRATOR, &ChatHandler::HandleNearGraveCommand, "", NULL }, - { "transport", SEC_ADMINISTRATOR, &ChatHandler::HandleSpawnTransportCommand, "", NULL }, - { "explorecheat", SEC_ADMINISTRATOR, &ChatHandler::HandleExploreCheatCommand, "", NULL }, - { "hover", SEC_ADMINISTRATOR, &ChatHandler::HandleHoverCommand, "", NULL }, - { "levelup", SEC_ADMINISTRATOR, &ChatHandler::HandleLevelUpCommand, "", NULL }, - { "showarea", SEC_ADMINISTRATOR, &ChatHandler::HandleShowAreaCommand, "", NULL }, - { "hidearea", SEC_ADMINISTRATOR, &ChatHandler::HandleHideAreaCommand, "", NULL }, - { "additem", SEC_ADMINISTRATOR, &ChatHandler::HandleAddItemCommand, "", NULL }, - { "additemset", SEC_ADMINISTRATOR, &ChatHandler::HandleAddItemSetCommand, "", NULL }, - { "bank", SEC_ADMINISTRATOR, &ChatHandler::HandleBankCommand, "", NULL }, - { "wchange", SEC_ADMINISTRATOR, &ChatHandler::HandleChangeWeather, "", NULL }, - { "ticket", SEC_GAMEMASTER, &ChatHandler::HandleTicketCommand, "", NULL }, - { "delticket", SEC_GAMEMASTER, &ChatHandler::HandleDelTicketCommand, "", NULL }, - { "maxskill", SEC_ADMINISTRATOR, &ChatHandler::HandleMaxSkillCommand, "", NULL }, - { "setskill", SEC_ADMINISTRATOR, &ChatHandler::HandleSetSkillCommand, "", NULL }, - { "whispers", SEC_MODERATOR, &ChatHandler::HandleWhispersCommand, "", NULL }, - { "pinfo", SEC_GAMEMASTER, &ChatHandler::HandlePInfoCommand, "", NULL }, - { "password", SEC_PLAYER, &ChatHandler::HandlePasswordCommand, "", NULL }, - { "lockaccount", SEC_PLAYER, &ChatHandler::HandleLockAccountCommand, "", NULL }, - { "respawn", SEC_ADMINISTRATOR, &ChatHandler::HandleRespawnCommand, "", NULL }, - { "sendmail", SEC_MODERATOR, &ChatHandler::HandleSendMailCommand, "", NULL }, - { "rename", SEC_GAMEMASTER, &ChatHandler::HandleRenameCommand, "", NULL }, - { "loadscripts", SEC_ADMINISTRATOR, &ChatHandler::HandleLoadScriptsCommand, "", NULL }, - { "mute", SEC_GAMEMASTER, &ChatHandler::HandleMuteCommand, "", NULL }, - { "unmute", SEC_GAMEMASTER, &ChatHandler::HandleUnmuteCommand, "", NULL }, - { "movegens", SEC_ADMINISTRATOR, &ChatHandler::HandleMovegensCommand, "", NULL }, - { "cometome", SEC_ADMINISTRATOR, &ChatHandler::HandleComeToMeCommand, "", NULL }, - { "damage", SEC_ADMINISTRATOR, &ChatHandler::HandleDamageCommand, "", NULL }, - { "combatstop", SEC_GAMEMASTER, &ChatHandler::HandleCombatStopCommand, "", NULL }, - - { NULL, 0, NULL, "", NULL } - }; - - if(load_command_table) - { - load_command_table = false; - - QueryResult *result = WorldDatabase.Query("SELECT name,security,help FROM command"); - if (result) - { - do - { - Field *fields = result->Fetch(); - std::string name = fields[0].GetCppString(); - for(uint32 i = 0; commandTable[i].Name != NULL; i++) - { - if (name == commandTable[i].Name) - { - commandTable[i].SecurityLevel = (uint16)fields[1].GetUInt16(); - commandTable[i].Help = fields[2].GetCppString(); - } - if(commandTable[i].ChildCommands != NULL) - { - ChatCommand *ptable = commandTable[i].ChildCommands; - for(uint32 j = 0; ptable[j].Name != NULL; j++) - { - // first case for "" named subcommand - if (ptable[j].Name[0]=='\0' && name == commandTable[i].Name || - name == fmtstring("%s %s", commandTable[i].Name, ptable[j].Name) ) - { - ptable[j].SecurityLevel = (uint16)fields[1].GetUInt16(); - ptable[j].Help = fields[2].GetCppString(); - } - } - } - } - } while(result->NextRow()); - delete result; - } - } - - return commandTable; -} - -const char *ChatHandler::GetMangosString(int32 entry) -{ - return m_session->GetMangosString(entry); -} - -bool ChatHandler::hasStringAbbr(const char* s1, const char* s2) -{ - for(;;) - { - if( !*s2 ) - return true; - else if( !*s1 ) - return false; - else if( tolower( *s1 ) != tolower( *s2 ) ) - return false; - ++s1; ++s2; - } -} - -void ChatHandler::SendSysMessage(const char *str) -{ - WorldPacket data; - - // need copy to prevent corruption by strtok call in LineFromMessage original string - char* buf = strdup(str); - char* pos = buf; - - while(char* line = LineFromMessage(pos)) - { - FillSystemMessageData(&data, line); - m_session->SendPacket(&data); - } - - free(buf); -} - -void ChatHandler::SendGlobalSysMessage(const char *str) -{ - WorldPacket data; - - // need copy to prevent corruption by strtok call in LineFromMessage original string - char* buf = strdup(str); - char* pos = buf; - - while(char* line = LineFromMessage(pos)) - { - FillSystemMessageData(&data, line); - sWorld.SendGlobalMessage(&data); - } - - free(buf); -} - -void ChatHandler::SendSysMessage(int32 entry) -{ - SendSysMessage(GetMangosString(entry)); -} - -void ChatHandler::PSendSysMessage(int32 entry, ...) -{ - const char *format = GetMangosString(entry); - va_list ap; - char str [1024]; - va_start(ap, entry); - vsnprintf(str,1024,format, ap ); - va_end(ap); - SendSysMessage(str); -} - -void ChatHandler::PSendSysMessage(const char *format, ...) -{ - va_list ap; - char str [1024]; - va_start(ap, format); - vsnprintf(str,1024,format, ap ); - va_end(ap); - SendSysMessage(str); -} - -bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, std::string fullcmd) -{ - char const* oldtext = text; - std::string cmd = ""; - - while (*text != ' ' && *text != '\0') - { - cmd += *text; - ++text; - } - - while (*text == ' ') ++text; - - if(!cmd.length()) - return false; - - for(uint32 i = 0; table[i].Name != NULL; i++) - { - // allow pass "" command name in table - if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, cmd.c_str())) - continue; - - // select subcommand from child commands list - if(table[i].ChildCommands != NULL) - { - if(!ExecuteCommandInTable(table[i].ChildCommands, text, fullcmd)) - { - if(text && text[0] != '\0') - SendSysMessage(LANG_NO_SUBCMD); - else - SendSysMessage(LANG_CMD_SYNTAX); - - ShowHelpForCommand(table[i].ChildCommands,text); - } - - return true; - } - - // check security level only for simple command (without child commands) - if(m_session->GetSecurity() < table[i].SecurityLevel) - continue; - - SetSentErrorMessage(false); - // table[i].Name == "" is special case: send original command to handler - if((this->*(table[i].Handler))(strlen(table[i].Name)!=0 ? text : oldtext)) - { - if(table[i].SecurityLevel > SEC_PLAYER) - { - Player* p = m_session->GetPlayer(); - uint64 sel_guid = p->GetSelection(); - sLog.outCommand("Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected: %s (GUID: %u)]", - fullcmd.c_str(),p->GetName(),m_session->GetAccountId(),p->GetPositionX(),p->GetPositionY(),p->GetPositionZ(),p->GetMapId(), - GetLogNameForGuid(sel_guid),GUID_LOPART(sel_guid)); - } - } - // some commands have custom error messages. Don't send the default one in these cases. - else if(!sentErrorMessage) - { - if(!table[i].Help.empty()) - SendSysMessage(table[i].Help.c_str()); - else - SendSysMessage(LANG_CMD_SYNTAX); - } - - return true; - } - - return false; -} - -int ChatHandler::ParseCommands(const char* text) -{ - ASSERT(text); - ASSERT(*text); - - //if(m_session->GetSecurity() == 0) - // return 0; - - if(text[0] != '!' && text[0] != '.') - return 0; - - // ignore single . and ! in line - if(strlen(text) < 2) - return 0; - - // ignore messages staring from many dots. - if(text[0] == '.' && text[1] == '.' || text[0] == '!' && text[1] == '!') - return 0; - - ++text; - - std::string fullcmd = text; // original `text` can't be used. It content destroyed in command code processing. - - if(!ExecuteCommandInTable(getCommandTable(), text, fullcmd)) - SendSysMessage(LANG_NO_CMD); - - return 1; -} - -bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd) -{ - std::string list; - for(uint32 i = 0; table[i].Name != NULL; ++i) - { - if(m_session->GetSecurity() < table[i].SecurityLevel) - continue; - - if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, subcmd)) - continue; - - (list += "\n ") += table[i].Name; - } - - if(list.empty()) - return false; - - if(table==getCommandTable()) - { - SendSysMessage(LANG_AVIABLE_CMD); - PSendSysMessage("%s",list.c_str()); - } - else - PSendSysMessage(LANG_SUBCMDS_LIST,cmd,list.c_str()); - - return true; -} - -bool ChatHandler::ShowHelpForCommand(ChatCommand *table, const char* cmd) -{ - if(*cmd) - { - for(uint32 i = 0; table[i].Name != NULL; ++i) - { - if(m_session->GetSecurity() < table[i].SecurityLevel) - continue; - - if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, cmd)) - continue; - - // have subcommand - char const* subcmd = (*cmd) ? strtok(NULL, " ") : ""; - - if(table[i].ChildCommands && subcmd && *subcmd) - { - if(ShowHelpForCommand(table[i].ChildCommands, subcmd)) - return true; - } - - if(!table[i].Help.empty()) - SendSysMessage(table[i].Help.c_str()); - - if(table[i].ChildCommands) - if(ShowHelpForSubCommands(table[i].ChildCommands,table[i].Name,subcmd ? subcmd : "")) - return true; - - return !table[i].Help.empty(); - } - } - else - { - for(uint32 i = 0; table[i].Name != NULL; ++i) - { - if(m_session->GetSecurity() < table[i].SecurityLevel) - continue; - - if(strlen(table[i].Name)) - continue; - - if(!table[i].Help.empty()) - SendSysMessage(table[i].Help.c_str()); - - if(table[i].ChildCommands) - if(ShowHelpForSubCommands(table[i].ChildCommands,"","")) - return true; - - return !table[i].Help.empty(); - } - } - - return ShowHelpForSubCommands(table,"",cmd); -} - -//Note: target_guid used only in CHAT_MSG_WHISPER_INFORM mode (in this case channelName ignored) -void ChatHandler::FillMessageData( WorldPacket *data, WorldSession* session, uint8 type, uint32 language, const char *channelName, uint64 target_guid, const char *message, Unit *speaker) -{ - uint32 messageLength = (message ? strlen(message) : 0) + 1; - - data->Initialize(SMSG_MESSAGECHAT, 100); // guess size - *data << uint8(type); - if ((type != CHAT_MSG_CHANNEL && type != CHAT_MSG_WHISPER) || language == LANG_ADDON) - *data << uint32(language); - else - *data << uint32(LANG_UNIVERSAL); - - switch(type) - { - case CHAT_MSG_SAY: - case CHAT_MSG_PARTY: - case CHAT_MSG_RAID: - case CHAT_MSG_GUILD: - case CHAT_MSG_OFFICER: - case CHAT_MSG_YELL: - case CHAT_MSG_WHISPER: - case CHAT_MSG_CHANNEL: - case CHAT_MSG_RAID_LEADER: - case CHAT_MSG_RAID_WARNING: - case CHAT_MSG_BG_SYSTEM_NEUTRAL: - case CHAT_MSG_BG_SYSTEM_ALLIANCE: - case CHAT_MSG_BG_SYSTEM_HORDE: - case CHAT_MSG_BATTLEGROUND: - case CHAT_MSG_BATTLEGROUND_LEADER: - target_guid = session ? session->GetPlayer()->GetGUID() : 0; - break; - case CHAT_MSG_MONSTER_SAY: - case CHAT_MSG_MONSTER_PARTY: - case CHAT_MSG_MONSTER_YELL: - case CHAT_MSG_MONSTER_WHISPER: - case CHAT_MSG_MONSTER_EMOTE: - case CHAT_MSG_RAID_BOSS_WHISPER: - case CHAT_MSG_RAID_BOSS_EMOTE: - { - *data << uint64(speaker->GetGUID()); - *data << uint32(0); // 2.1.0 - *data << uint32(strlen(speaker->GetName()) + 1); - *data << speaker->GetName(); - uint64 listener_guid = 0; - *data << uint64(listener_guid); - if(listener_guid && !IS_PLAYER_GUID(listener_guid)) - { - *data << uint32(1); // string listener_name_length - *data << uint8(0); // string listener_name - } - *data << uint32(messageLength); - *data << message; - *data << uint8(0); - return; - } - default: - if (type != CHAT_MSG_REPLY && type != CHAT_MSG_IGNORED && type != CHAT_MSG_DND && type != CHAT_MSG_AFK) - target_guid = 0; // only for CHAT_MSG_WHISPER_INFORM used original value target_guid - break; - } - - *data << uint64(target_guid); // there 0 for BG messages - *data << uint32(0); // can be chat msg group or something - - if (type == CHAT_MSG_CHANNEL) - { - ASSERT(channelName); - *data << channelName; - } - - *data << uint64(target_guid); - *data << uint32(messageLength); - *data << message; - if(session != 0 && type != CHAT_MSG_REPLY && type != CHAT_MSG_DND && type != CHAT_MSG_AFK) - *data << uint8(session->GetPlayer()->chatTag()); - else - *data << uint8(0); -} - -Player * ChatHandler::getSelectedPlayer() -{ - uint64 guid = m_session->GetPlayer()->GetSelection(); - - if (guid == 0) - return m_session->GetPlayer(); - - return objmgr.GetPlayer(guid); -} - -Unit* ChatHandler::getSelectedUnit() -{ - uint64 guid = m_session->GetPlayer()->GetSelection(); - - if (guid == 0) - return m_session->GetPlayer(); - - return ObjectAccessor::GetUnit(*m_session->GetPlayer(),guid); -} - -Creature* ChatHandler::getSelectedCreature() -{ - return ObjectAccessor::GetCreatureOrPet(*m_session->GetPlayer(),m_session->GetPlayer()->GetSelection()); -} - -char* ChatHandler::extractKeyFromLink(char* text, char const* linkType, char** something1) -{ - // skip empty - if(!text) - return NULL; - - // skip speces - while(*text==' '||*text=='\t'||*text=='\b') - ++text; - - if(!*text) - return NULL; - - // return non link case - if(text[0]!='|') - return strtok(text, " "); - - // [name] Shift-click form |color|linkType:key|h[name]|h|r - // or - // [name] Shift-click form |color|linkType:key:something1:...:somethingN|h[name]|h|r - - char* check = strtok(text, "|"); // skip color - if(!check) - return NULL; // end of data - - char* cLinkType = strtok(NULL, ":"); // linktype - if(!cLinkType) - return NULL; // end of data - - if(strcmp(cLinkType,linkType) != 0) - { - strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after retturn from function - SendSysMessage(LANG_WRONG_LINK_TYPE); - return NULL; - } - - char* cKeys = strtok(NULL, "|"); // extract keys and values - char* cKeysTail = strtok(NULL, ""); - - char* cKey = strtok(cKeys, ":|"); // extract key - if(something1) - *something1 = strtok(NULL, ":|"); // extract something - - strtok(cKeysTail, "]"); // restart scan tail and skip name with possible spaces - strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after retturn from function - return cKey; -} - -char* ChatHandler::extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1) -{ - // skip empty - if(!text) - return NULL; - - // skip speces - while(*text==' '||*text=='\t'||*text=='\b') - ++text; - - if(!*text) - return NULL; - - // return non link case - if(text[0]!='|') - return strtok(text, " "); - - // [name] Shift-click form |color|linkType:key|h[name]|h|r - // or - // [name] Shift-click form |color|linkType:key:something1:...:somethingN|h[name]|h|r - - char* check = strtok(text, "|"); // skip color - if(!check) - return NULL; // end of data - - char* cLinkType = strtok(NULL, ":"); // linktype - if(!cLinkType) - return NULL; // end of data - - for(int i = 0; linkTypes[i]; ++i) - { - if(strcmp(cLinkType,linkTypes[i]) == 0) - { - char* cKeys = strtok(NULL, "|"); // extract keys and values - char* cKeysTail = strtok(NULL, ""); - - char* cKey = strtok(cKeys, ":|"); // extract key - if(something1) - *something1 = strtok(NULL, ":|"); // extract something - - strtok(cKeysTail, "]"); // restart scan tail and skip name with possible spaces - strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after return from function - if(found_idx) - *found_idx = i; - return cKey; - } - } - - strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after return from function - SendSysMessage(LANG_WRONG_LINK_TYPE); - return NULL; -} - -char const *fmtstring( char const *format, ... ) -{ - va_list argptr; - #define MAX_FMT_STRING 32000 - static char temp_buffer[MAX_FMT_STRING]; - static char string[MAX_FMT_STRING]; - static int index = 0; - char *buf; - int len; - - va_start(argptr, format); - vsnprintf(temp_buffer,MAX_FMT_STRING, format, argptr); - va_end(argptr); - - len = strlen(temp_buffer); - - if( len >= MAX_FMT_STRING ) - return "ERROR"; - - if (len + index >= MAX_FMT_STRING-1) - { - index = 0; - } - - buf = &string[index]; - memcpy( buf, temp_buffer, len+1 ); - - index += len + 1; - - return buf; -} - -GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry) -{ - Player* pl = m_session->GetPlayer(); - - GameObject* obj = ObjectAccessor::GetGameObject(*pl, MAKE_NEW_GUID(lowguid, entry, HIGHGUID_GAMEOBJECT)); - - if(!obj && objmgr.GetGOData(lowguid)) // guid is DB guid of object - { - // search near player then - CellPair p(MaNGOS::ComputeCellPair(pl->GetPositionX(), pl->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - MaNGOS::GameObjectWithDbGUIDCheck go_check(*pl,lowguid); - MaNGOS::GameObjectSearcher checker(obj,go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(pl->GetMapId(), pl)); - } - - return obj; -} - -static char const* const spellTalentKeys[] = { - "Hspell", - "Htalent", - 0 -}; - -uint32 ChatHandler::extractSpellIdFromLink(char* text) -{ - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - // number or [name] Shift-click form |color|Htalent:telen_id,rank|h[name]|h|r - int type = 0; - char* rankS = NULL; - char* idS = extractKeyFromLink(text,spellTalentKeys,&type,&rankS); - if(!idS) - return 0; - - uint32 id = (uint32)atol(idS); - - // spell - if(type==0) - return id; - - // talent - TalentEntry const* talentEntry = sTalentStore.LookupEntry(id); - if(!talentEntry) - return 0; - - int32 rank = rankS ? (uint32)atol(rankS) : 0; - if(rank >= 5) - return 0; - - if(rank < 0) - rank = 0; - - return talentEntry->RankID[rank]; -} - +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Language.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "UpdateMask.h" +#include "Chat.h" +#include "MapManager.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +bool ChatHandler::load_command_table = true; + +LanguageDesc lang_description[LANGUAGES_COUNT] = +{ + { LANG_ADDON, 0, 0 }, + { LANG_UNIVERSAL, 0, 0 }, + { LANG_ORCISH, 669, SKILL_LANG_ORCISH }, + { LANG_DARNASSIAN, 671, SKILL_LANG_DARNASSIAN }, + { LANG_TAURAHE, 670, SKILL_LANG_TAURAHE }, + { LANG_DWARVISH, 672, SKILL_LANG_DWARVEN }, + { LANG_COMMON, 668, SKILL_LANG_COMMON }, + { LANG_DEMONIC, 815, SKILL_LANG_DEMON_TONGUE }, + { LANG_TITAN, 816, SKILL_LANG_TITAN }, + { LANG_THALASSIAN, 813, SKILL_LANG_THALASSIAN }, + { LANG_DRACONIC, 814, SKILL_LANG_DRACONIC }, + { LANG_KALIMAG, 817, SKILL_LANG_OLD_TONGUE }, + { LANG_GNOMISH, 7340, SKILL_LANG_GNOMISH }, + { LANG_TROLL, 7341, SKILL_LANG_TROLL }, + { LANG_GUTTERSPEAK, 17737, SKILL_LANG_GUTTERSPEAK }, + { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI }, + { LANG_ZOMBIE, 0, 0 }, + { LANG_GNOMISH_BINARY, 0, 0 }, + { LANG_GOBLIN_BINARY, 0, 0 } +}; + +LanguageDesc const* GetLanguageDescByID(uint32 lang) +{ + for(int i = 0; i < LANGUAGES_COUNT; ++i) + { + if(uint32(lang_description[i].lang_id) == lang) + return &lang_description[i]; + } + + return NULL; +} + +LanguageDesc const* GetLanguageDescBySpell(uint32 spell_id) +{ + for(int i = 0; i < LANGUAGES_COUNT; ++i) + { + if(lang_description[i].spell_id == spell_id) + return &lang_description[i]; + } + + return NULL; +} + +LanguageDesc const* GetLanguageDescBySkill(uint32 skill_id) +{ + for(int i = 0; i < LANGUAGES_COUNT; ++i) + { + if(lang_description[i].skill_id == skill_id) + return &lang_description[i]; + } + + return NULL; +} + +ChatCommand * ChatHandler::getCommandTable() +{ + static ChatCommand serverCommandTable[] = + { + { "idlerestart", SEC_ADMINISTRATOR, &ChatHandler::HandleIdleRestartCommand, "", NULL }, + { "idleshutdown", SEC_ADMINISTRATOR, &ChatHandler::HandleIdleShutDownCommand, "", NULL }, + { "info", SEC_PLAYER, &ChatHandler::HandleInfoCommand, "", NULL }, + { "restart", SEC_ADMINISTRATOR, &ChatHandler::HandleRestartCommand, "", NULL }, + { "shutdown", SEC_ADMINISTRATOR, &ChatHandler::HandleShutDownCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand modifyCommandTable[] = + { + { "hp", SEC_MODERATOR, &ChatHandler::HandleModifyHPCommand, "", NULL }, + { "mana", SEC_MODERATOR, &ChatHandler::HandleModifyManaCommand, "", NULL }, + { "rage", SEC_MODERATOR, &ChatHandler::HandleModifyRageCommand, "", NULL }, + { "energy", SEC_MODERATOR, &ChatHandler::HandleModifyEnergyCommand, "", NULL }, + { "money", SEC_MODERATOR, &ChatHandler::HandleModifyMoneyCommand, "", NULL }, + { "speed", SEC_MODERATOR, &ChatHandler::HandleModifySpeedCommand, "", NULL }, + { "swim", SEC_MODERATOR, &ChatHandler::HandleModifySwimCommand, "", NULL }, + { "scale", SEC_MODERATOR, &ChatHandler::HandleModifyScaleCommand, "", NULL }, + { "bit", SEC_MODERATOR, &ChatHandler::HandleModifyBitCommand, "", NULL }, + { "bwalk", SEC_MODERATOR, &ChatHandler::HandleModifyBWalkCommand, "", NULL }, + { "fly", SEC_MODERATOR, &ChatHandler::HandleModifyFlyCommand, "", NULL }, + { "aspeed", SEC_MODERATOR, &ChatHandler::HandleModifyASpeedCommand, "", NULL }, + { "faction", SEC_MODERATOR, &ChatHandler::HandleModifyFactionCommand, "", NULL }, + { "spell", SEC_MODERATOR, &ChatHandler::HandleModifySpellCommand, "", NULL }, + { "tp", SEC_MODERATOR, &ChatHandler::HandleModifyTalentCommand, "", NULL }, + { "titles", SEC_MODERATOR, &ChatHandler::HandleModifyKnownTitlesCommand, "", NULL }, + { "mount", SEC_MODERATOR, &ChatHandler::HandleModifyMountCommand, "", NULL }, + { "honor", SEC_MODERATOR, &ChatHandler::HandleModifyHonorCommand, "", NULL }, + { "rep", SEC_MODERATOR, &ChatHandler::HandleModifyRepCommand, "", NULL }, + { "arena", SEC_MODERATOR, &ChatHandler::HandleModifyArenaCommand, "", NULL }, + { "drunk", SEC_MODERATOR, &ChatHandler::HandleDrunkCommand, "", NULL }, + { "standstate", SEC_GAMEMASTER, &ChatHandler::HandleStandStateCommand, "", NULL }, + { "morph", SEC_GAMEMASTER, &ChatHandler::HandleMorphCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand wpCommandTable[] = + { + { "show", SEC_GAMEMASTER, &ChatHandler::HandleWpShowCommand, "", NULL }, + { "add", SEC_GAMEMASTER, &ChatHandler::HandleWpAddCommand, "", NULL }, + { "modify", SEC_GAMEMASTER, &ChatHandler::HandleWpModifyCommand, "", NULL }, + { "export", SEC_ADMINISTRATOR, &ChatHandler::HandleWpExportCommand, "", NULL }, + { "import", SEC_ADMINISTRATOR, &ChatHandler::HandleWpImportCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand debugCommandTable[] = + { + { "inarc", SEC_ADMINISTRATOR, &ChatHandler::HandleDebugInArcCommand, "", NULL }, + { "spellfail", SEC_ADMINISTRATOR, &ChatHandler::HandleDebugSpellFailCommand, "", NULL }, + { "setpoi", SEC_ADMINISTRATOR, &ChatHandler::HandleSetPoiCommand, "", NULL }, + { "qpartymsg", SEC_ADMINISTRATOR, &ChatHandler::HandleSendQuestPartyMsgCommand, "", NULL }, + { "qinvalidmsg", SEC_ADMINISTRATOR, &ChatHandler::HandleSendQuestInvalidMsgCommand, "", NULL }, + { "equiperr", SEC_ADMINISTRATOR, &ChatHandler::HandleEquipErrorCommand, "", NULL }, + { "sellerr", SEC_ADMINISTRATOR, &ChatHandler::HandleSellErrorCommand, "", NULL }, + { "buyerr", SEC_ADMINISTRATOR, &ChatHandler::HandleBuyErrorCommand, "", NULL }, + { "sendopcode", SEC_ADMINISTRATOR, &ChatHandler::HandleSendOpcodeCommand, "", NULL }, + { "uws", SEC_ADMINISTRATOR, &ChatHandler::HandleUpdateWorldStateCommand, "", NULL }, + { "ps", SEC_ADMINISTRATOR, &ChatHandler::HandlePlaySound2Command, "", NULL }, + { "scn", SEC_ADMINISTRATOR, &ChatHandler::HandleSendChannelNotifyCommand, "", NULL }, + { "scm", SEC_ADMINISTRATOR, &ChatHandler::HandleSendChatMsgCommand, "", NULL }, + { "getitemstate", SEC_ADMINISTRATOR, &ChatHandler::HandleGetItemState, "", NULL }, + { "playsound", SEC_MODERATOR, &ChatHandler::HandlePlaySoundCommand, "", NULL }, + { "update", SEC_ADMINISTRATOR, &ChatHandler::HandleUpdate, "", NULL }, + { "setvalue", SEC_ADMINISTRATOR, &ChatHandler::HandleSetValue, "", NULL }, + { "getvalue", SEC_ADMINISTRATOR, &ChatHandler::HandleGetValue, "", NULL }, + { "Mod32Value", SEC_ADMINISTRATOR, &ChatHandler::HandleMod32Value, "", NULL }, + { "anim", SEC_GAMEMASTER, &ChatHandler::HandleAnimCommand, "", NULL }, + { "lootrecipient", SEC_GAMEMASTER, &ChatHandler::HandleGetLootRecipient, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand eventCommandTable[] = + { + { "activelist", SEC_GAMEMASTER, &ChatHandler::HandleEventActiveListCommand, "", NULL }, + { "start", SEC_GAMEMASTER, &ChatHandler::HandleEventStartCommand, "", NULL }, + { "stop", SEC_GAMEMASTER, &ChatHandler::HandleEventStopCommand, "", NULL }, + { "", SEC_GAMEMASTER, &ChatHandler::HandleEventInfoCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand learnCommandTable[] = + { + { "all", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnAllCommand, "", NULL }, + { "all_gm", SEC_GAMEMASTER, &ChatHandler::HandleLearnAllGMCommand, "", NULL }, + { "all_crafts", SEC_GAMEMASTER, &ChatHandler::HandleLearnAllCraftsCommand, "", NULL }, + { "all_default", SEC_MODERATOR, &ChatHandler::HandleLearnAllDefaultCommand, "", NULL }, + { "all_lang", SEC_MODERATOR, &ChatHandler::HandleLearnAllLangCommand, "", NULL }, + { "all_myclass", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnAllMyClassCommand, "", NULL }, + { "all_myspells", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnAllMySpellsCommand, "", NULL }, + { "all_mytalents", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnAllMyTalentsCommand, "", NULL }, + { "all_recipes", SEC_GAMEMASTER, &ChatHandler::HandleLearnAllRecipesCommand, "", NULL }, + { "", SEC_ADMINISTRATOR, &ChatHandler::HandleLearnCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand reloadCommandTable[] = + { + { "all", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllCommand, "", NULL }, + { "all_loot", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllLootCommand, "", NULL }, + { "all_npc", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllNpcCommand, "", NULL }, + { "all_quest", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllQuestCommand, "", NULL }, + { "all_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllScriptsCommand, "", NULL }, + { "all_spell", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllSpellCommand, "", NULL }, + { "all_item", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllItemCommand, "", NULL }, + + { "config", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadConfigCommand, "", NULL }, + + { "areatrigger_tavern", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL }, + { "areatrigger_teleport", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL }, + { "areatrigger_involvedrelation",SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL }, + { "event_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL }, + { "command", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadCommandCommand, "", NULL }, + { "creature_involvedrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand,"",NULL }, + { "creature_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL }, + { "creature_questrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL }, + { "disenchant_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL }, + { "fishing_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesFishingCommand, "", NULL }, + { "game_graveyard_zone", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGameGraveyardZoneCommand, "", NULL }, + { "game_tele", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGameTeleCommand, "", NULL }, + { "gameobject_involvedrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGOQuestInvRelationsCommand, "", NULL }, + { "gameobject_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesGameobjectCommand, "", NULL }, + { "gameobject_questrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGOQuestRelationsCommand, "", NULL }, + { "gameobject_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL }, + { "item_enchantment_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL }, + { "item_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, + { "mangos_string", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadMangosStringCommand, "", NULL }, + { "npc_gossip", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadNpcGossipCommand, "", NULL }, + { "npc_trainer", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL }, + { "npc_vendor", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL }, + { "page_text", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadPageTextsCommand, "", NULL }, + { "pickpocketing_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand,"",NULL}, + { "prospecting_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesProspectingCommand,"", NULL }, + { "quest_mail_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesQuestMailCommand, "", NULL }, + { "quest_end_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestEndScriptsCommand, "", NULL }, + { "quest_start_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestStartScriptsCommand, "", NULL }, + { "quest_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestTemplateCommand, "", NULL }, + { "reference_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesReferenceCommand, "", NULL }, + { "reserved_name", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadReservedNameCommand, "", NULL }, + { "skill_discovery_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSkillDiscoveryTemplateCommand, "", NULL }, + { "skill_extra_item_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSkillExtraItemTemplateCommand, "", NULL }, + { "skill_fishing_base_level", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL }, + { "skinning_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL }, + { "spell_affect", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL }, + { "spell_chain", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellChainCommand, "", NULL }, + { "spell_elixir", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL }, + { "spell_learn_spell", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL }, + { "spell_pet_auras", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL }, + { "spell_proc_event", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL }, + { "spell_script_target", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL }, + { "spell_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL }, + { "spell_target_position", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL }, + { "spell_threats", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL }, + { "", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand honorCommandTable[] = + { + { "add", SEC_GAMEMASTER, &ChatHandler::HandleAddHonorCommand, "", NULL }, + { "addkill", SEC_GAMEMASTER, &ChatHandler::HandleHonorAddKillCommand, "", NULL }, + { "update", SEC_GAMEMASTER, &ChatHandler::HandleUpdateHonorFieldsCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand guildCommandTable[] = + { + { "create", SEC_GAMEMASTER, &ChatHandler::HandleGuildCreateCommand, "", NULL }, + { "delete", SEC_GAMEMASTER, &ChatHandler::HandleGuildDeleteCommand, "", NULL }, + { "invite", SEC_GAMEMASTER, &ChatHandler::HandleGuildInviteCommand, "", NULL }, + { "uninvite", SEC_GAMEMASTER, &ChatHandler::HandleGuildUninviteCommand, "", NULL }, + { "rank", SEC_GAMEMASTER, &ChatHandler::HandleGuildRankCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand lookupPlayerCommandTable[] = + { + { "ip", SEC_GAMEMASTER, &ChatHandler::HandleLookupPlayerIpCommand, "", NULL }, + { "account", SEC_GAMEMASTER, &ChatHandler::HandleLookupPlayerAccountCommand, "", NULL }, + { "email", SEC_GAMEMASTER, &ChatHandler::HandleLookupPlayerEmailCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand lookupCommandTable[] = + { + { "area", SEC_MODERATOR, &ChatHandler::HandleLookupAreaCommand, "", NULL }, + { "creature", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupCreatureCommand, "", NULL }, + { "event", SEC_GAMEMASTER, &ChatHandler::HandleLookupEventCommand, "", NULL }, + { "faction", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupFactionCommand, "", NULL }, + { "item", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupItemCommand, "", NULL }, + { "itemset", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupItemSetCommand, "", NULL }, + { "object", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupObjectCommand, "", NULL }, + { "quest", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupQuestCommand, "", NULL }, + { "player", SEC_GAMEMASTER, NULL, "", lookupPlayerCommandTable }, + { "skill", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupSkillCommand, "", NULL }, + { "spell", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupSpellCommand, "", NULL }, + { "tele", SEC_MODERATOR, &ChatHandler::HandleLookupTeleCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand resetCommandTable[] = + { + { "honor", SEC_ADMINISTRATOR, &ChatHandler::HandleResetHonorCommand, "", NULL }, + { "level", SEC_ADMINISTRATOR, &ChatHandler::HandleResetLevelCommand, "", NULL }, + { "spells", SEC_ADMINISTRATOR, &ChatHandler::HandleResetSpellsCommand, "", NULL }, + { "stats", SEC_ADMINISTRATOR, &ChatHandler::HandleResetStatsCommand, "", NULL }, + { "talents", SEC_ADMINISTRATOR, &ChatHandler::HandleResetTalentsCommand, "", NULL }, + { "all", SEC_ADMINISTRATOR, &ChatHandler::HandleResetAllCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand castCommandTable[] = + { + { "back", SEC_ADMINISTRATOR, &ChatHandler::HandleCastBackCommand, "", NULL }, + { "dist", SEC_ADMINISTRATOR, &ChatHandler::HandleCastDistCommand, "", NULL }, + { "self", SEC_ADMINISTRATOR, &ChatHandler::HandleCastSelfCommand, "", NULL }, + { "target", SEC_ADMINISTRATOR, &ChatHandler::HandleCastTargetCommand, "", NULL }, + { "", SEC_ADMINISTRATOR, &ChatHandler::HandleCastCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand pdumpCommandTable[] = + { + { "load", SEC_ADMINISTRATOR, &ChatHandler::HandleLoadPDumpCommand, "", NULL }, + { "write", SEC_ADMINISTRATOR, &ChatHandler::HandleWritePDumpCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand listCommandTable[] = + { + { "creature", SEC_ADMINISTRATOR, &ChatHandler::HandleListCreatureCommand, "", NULL }, + { "item", SEC_ADMINISTRATOR, &ChatHandler::HandleListItemCommand, "", NULL }, + { "object", SEC_ADMINISTRATOR, &ChatHandler::HandleListObjectCommand, "", NULL }, + { "auras", SEC_ADMINISTRATOR, &ChatHandler::HandleListAurasCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand teleCommandTable[] = + { + { "add", SEC_ADMINISTRATOR, &ChatHandler::HandleAddTeleCommand, "", NULL }, + { "del", SEC_ADMINISTRATOR, &ChatHandler::HandleDelTeleCommand, "", NULL }, + { "name", SEC_MODERATOR, &ChatHandler::HandleNameTeleCommand, "", NULL }, + { "group", SEC_MODERATOR, &ChatHandler::HandleGroupTeleCommand, "", NULL }, + { "", SEC_MODERATOR, &ChatHandler::HandleTeleCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand npcCommandTable[] = + { + { "say", SEC_MODERATOR, &ChatHandler::HandleSayCommand, "", NULL }, + { "whisper", SEC_MODERATOR, &ChatHandler::HandleNpcWhisperCommand, "", NULL }, + { "yell", SEC_MODERATOR, &ChatHandler::HandleYellCommand, "", NULL }, + { "textemote", SEC_MODERATOR, &ChatHandler::HandleTextEmoteCommand, "", NULL }, + { "add", SEC_GAMEMASTER, &ChatHandler::HandleAddSpwCommand, "", NULL }, + { "delete", SEC_GAMEMASTER, &ChatHandler::HandleDelCreatureCommand, "", NULL }, + { "spawndist", SEC_GAMEMASTER, &ChatHandler::HandleSpawnDistCommand, "", NULL }, + { "spawntime", SEC_GAMEMASTER, &ChatHandler::HandleSpawnTimeCommand, "", NULL }, + { "factionid", SEC_GAMEMASTER, &ChatHandler::HandleFactionIdCommand, "", NULL }, + { "addmove", SEC_GAMEMASTER, &ChatHandler::HandleAddMoveCommand, "", NULL }, + { "setmovetype", SEC_GAMEMASTER, &ChatHandler::HandleSetMoveTypeCommand, "", NULL }, + { "move", SEC_GAMEMASTER, &ChatHandler::HandleMoveCreatureCommand, "", NULL }, + { "changelevel", SEC_GAMEMASTER, &ChatHandler::HandleChangeLevelCommand, "", NULL }, + { "setmodel", SEC_GAMEMASTER, &ChatHandler::HandleSetModelCommand, "", NULL }, + { "additem", SEC_GAMEMASTER, &ChatHandler::HandleAddVendorItemCommand, "", NULL }, + { "delitem", SEC_GAMEMASTER, &ChatHandler::HandleDelVendorItemCommand, "", NULL }, + { "flag", SEC_GAMEMASTER, &ChatHandler::HandleNPCFlagCommand, "", NULL }, + { "changeentry", SEC_ADMINISTRATOR, &ChatHandler::HandleChangeEntryCommand, "", NULL }, + { "info", SEC_ADMINISTRATOR, &ChatHandler::HandleNpcInfoCommand, "", NULL }, + { "playemote", SEC_ADMINISTRATOR, &ChatHandler::HandlePlayEmoteCommand, "", NULL }, + + //{ TODO: fix or remove this commands + { "name", SEC_GAMEMASTER, &ChatHandler::HandleNameCommand, "", NULL }, + { "subname", SEC_GAMEMASTER, &ChatHandler::HandleSubNameCommand, "", NULL }, + { "addweapon", SEC_ADMINISTRATOR, &ChatHandler::HandleAddWeaponCommand, "", NULL }, + //} + + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand goCommandTable[] = + { + { "grid", SEC_MODERATOR, &ChatHandler::HandleGoGridCommand, "", NULL }, + { "creature", SEC_GAMEMASTER, &ChatHandler::HandleGoCreatureCommand, "", NULL }, + { "object", SEC_GAMEMASTER, &ChatHandler::HandleGoObjectCommand, "", NULL }, + { "trigger", SEC_GAMEMASTER, &ChatHandler::HandleGoTriggerCommand, "", NULL }, + { "graveyard", SEC_GAMEMASTER, &ChatHandler::HandleGoGraveyardCommand, "", NULL }, + { "zonexy", SEC_MODERATOR, &ChatHandler::HandleGoZoneXYCommand, "", NULL }, + { "xy", SEC_MODERATOR, &ChatHandler::HandleGoXYCommand, "", NULL }, + { "xyz", SEC_MODERATOR, &ChatHandler::HandleGoXYZCommand, "", NULL }, + { "", SEC_MODERATOR, &ChatHandler::HandleGoXYZCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand gobjectCommandTable[] = + { + { "add", SEC_GAMEMASTER, &ChatHandler::HandleGameObjectCommand, "", NULL }, + { "delete", SEC_GAMEMASTER, &ChatHandler::HandleDelObjectCommand, "", NULL }, + { "target", SEC_GAMEMASTER, &ChatHandler::HandleTargetObjectCommand, "", NULL }, + { "turn", SEC_GAMEMASTER, &ChatHandler::HandleTurnObjectCommand, "", NULL }, + { "move", SEC_GAMEMASTER, &ChatHandler::HandleMoveObjectCommand, "", NULL }, + { "near", SEC_ADMINISTRATOR, &ChatHandler::HandleNearObjectCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand questCommandTable[] = + { + { "add", SEC_ADMINISTRATOR, &ChatHandler::HandleAddQuest, "", NULL }, + { "complete", SEC_ADMINISTRATOR, &ChatHandler::HandleCompleteQuest, "", NULL }, + { "remove", SEC_ADMINISTRATOR, &ChatHandler::HandleRemoveQuest, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand gmCommandTable[] = + { + { "list", SEC_PLAYER, &ChatHandler::HandleGMListCommand, "", NULL }, + { "visible", SEC_MODERATOR, &ChatHandler::HandleVisibleCommand, "", NULL }, + { "fly", SEC_ADMINISTRATOR, &ChatHandler::HandleFlyModeCommand, "", NULL }, + { "", SEC_MODERATOR, &ChatHandler::HandleGMmodeCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand instanceCommandTable[] = + { + { "listbinds", SEC_MODERATOR, &ChatHandler::HandleInstanceListBindsCommand, "", NULL }, + { "unbind", SEC_MODERATOR, &ChatHandler::HandleInstanceUnbindCommand, "", NULL }, + { "stats", SEC_MODERATOR, &ChatHandler::HandleInstanceStatsCommand, "", NULL }, + { "savedata", SEC_MODERATOR, &ChatHandler::HandleInstanceSaveDataCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand commandTable[] = + { + { "gm", SEC_MODERATOR, NULL, "", gmCommandTable }, + { "npc", SEC_MODERATOR, NULL, "", npcCommandTable }, + { "go", SEC_MODERATOR, NULL, "", goCommandTable }, + { "learn", SEC_MODERATOR, NULL, "", learnCommandTable }, + { "modify", SEC_MODERATOR, NULL, "", modifyCommandTable }, + { "debug", SEC_MODERATOR, NULL, "", debugCommandTable }, + { "tele", SEC_MODERATOR, NULL, "", teleCommandTable }, + { "event", SEC_GAMEMASTER, NULL, "", eventCommandTable }, + { "gobject", SEC_GAMEMASTER, NULL, "", gobjectCommandTable }, + { "honor", SEC_GAMEMASTER, NULL, "", honorCommandTable }, + { "wp", SEC_GAMEMASTER, NULL, "", wpCommandTable }, + { "quest", SEC_ADMINISTRATOR, NULL, "", questCommandTable }, + { "reload", SEC_ADMINISTRATOR, NULL, "", reloadCommandTable }, + { "list", SEC_ADMINISTRATOR, NULL, "", listCommandTable }, + { "lookup", SEC_ADMINISTRATOR, NULL, "", lookupCommandTable }, + { "pdump", SEC_ADMINISTRATOR, NULL, "", pdumpCommandTable }, + { "guild", SEC_ADMINISTRATOR, NULL, "", guildCommandTable }, + { "cast", SEC_ADMINISTRATOR, NULL, "", castCommandTable }, + { "reset", SEC_ADMINISTRATOR, NULL, "", resetCommandTable }, + { "instance", SEC_ADMINISTRATOR, NULL, "", instanceCommandTable }, + { "server", SEC_ADMINISTRATOR, NULL, "", serverCommandTable }, + + { "aura", SEC_ADMINISTRATOR, &ChatHandler::HandleAuraCommand, "", NULL }, + { "unaura", SEC_ADMINISTRATOR, &ChatHandler::HandleUnAuraCommand, "", NULL }, + { "acct", SEC_PLAYER, &ChatHandler::HandleAcctCommand, "", NULL }, + { "announce", SEC_MODERATOR, &ChatHandler::HandleAnnounceCommand, "", NULL }, + { "notify", SEC_MODERATOR, &ChatHandler::HandleNotifyCommand, "", NULL }, + { "goname", SEC_MODERATOR, &ChatHandler::HandleGonameCommand, "", NULL }, + { "namego", SEC_MODERATOR, &ChatHandler::HandleNamegoCommand, "", NULL }, + { "groupgo", SEC_MODERATOR, &ChatHandler::HandleGroupgoCommand, "", NULL }, + { "commands", SEC_PLAYER, &ChatHandler::HandleCommandsCommand, "", NULL }, + { "demorph", SEC_GAMEMASTER, &ChatHandler::HandleDeMorphCommand, "", NULL }, + { "die", SEC_ADMINISTRATOR, &ChatHandler::HandleDieCommand, "", NULL }, + { "revive", SEC_ADMINISTRATOR, &ChatHandler::HandleReviveCommand, "", NULL }, + { "dismount", SEC_PLAYER, &ChatHandler::HandleDismountCommand, "", NULL }, + { "gps", SEC_MODERATOR, &ChatHandler::HandleGPSCommand, "", NULL }, + { "guid", SEC_GAMEMASTER, &ChatHandler::HandleGUIDCommand, "", NULL }, + { "help", SEC_PLAYER, &ChatHandler::HandleHelpCommand, "", NULL }, + { "itemmove", SEC_GAMEMASTER, &ChatHandler::HandleItemMoveCommand, "", NULL }, + { "cooldown", SEC_ADMINISTRATOR, &ChatHandler::HandleCooldownCommand, "", NULL }, + { "unlearn", SEC_ADMINISTRATOR, &ChatHandler::HandleUnLearnCommand, "", NULL }, + { "distance", SEC_ADMINISTRATOR, &ChatHandler::HandleGetDistanceCommand, "", NULL }, + { "recall", SEC_MODERATOR, &ChatHandler::HandleRecallCommand, "", NULL }, + { "save", SEC_PLAYER, &ChatHandler::HandleSaveCommand, "", NULL }, + { "saveall", SEC_MODERATOR, &ChatHandler::HandleSaveAllCommand, "", NULL }, + { "kick", SEC_GAMEMASTER, &ChatHandler::HandleKickPlayerCommand, "", NULL }, + { "security", SEC_ADMINISTRATOR, &ChatHandler::HandleSecurityCommand, "", NULL }, + { "ban", SEC_ADMINISTRATOR, &ChatHandler::HandleBanCommand, "", NULL }, + { "unban", SEC_ADMINISTRATOR, &ChatHandler::HandleUnBanCommand, "", NULL }, + { "baninfo", SEC_ADMINISTRATOR, &ChatHandler::HandleBanInfoCommand, "", NULL }, + { "banlist", SEC_ADMINISTRATOR, &ChatHandler::HandleBanListCommand, "", NULL }, + { "plimit", SEC_ADMINISTRATOR, &ChatHandler::HandlePLimitCommand, "", NULL }, + { "start", SEC_PLAYER, &ChatHandler::HandleStartCommand, "", NULL }, + { "taxicheat", SEC_MODERATOR, &ChatHandler::HandleTaxiCheatCommand, "", NULL }, + { "allowmove", SEC_ADMINISTRATOR, &ChatHandler::HandleAllowMovementCommand, "", NULL }, + { "linkgrave", SEC_ADMINISTRATOR, &ChatHandler::HandleLinkGraveCommand, "", NULL }, + { "neargrave", SEC_ADMINISTRATOR, &ChatHandler::HandleNearGraveCommand, "", NULL }, + { "transport", SEC_ADMINISTRATOR, &ChatHandler::HandleSpawnTransportCommand, "", NULL }, + { "explorecheat", SEC_ADMINISTRATOR, &ChatHandler::HandleExploreCheatCommand, "", NULL }, + { "hover", SEC_ADMINISTRATOR, &ChatHandler::HandleHoverCommand, "", NULL }, + { "levelup", SEC_ADMINISTRATOR, &ChatHandler::HandleLevelUpCommand, "", NULL }, + { "showarea", SEC_ADMINISTRATOR, &ChatHandler::HandleShowAreaCommand, "", NULL }, + { "hidearea", SEC_ADMINISTRATOR, &ChatHandler::HandleHideAreaCommand, "", NULL }, + { "additem", SEC_ADMINISTRATOR, &ChatHandler::HandleAddItemCommand, "", NULL }, + { "additemset", SEC_ADMINISTRATOR, &ChatHandler::HandleAddItemSetCommand, "", NULL }, + { "bank", SEC_ADMINISTRATOR, &ChatHandler::HandleBankCommand, "", NULL }, + { "wchange", SEC_ADMINISTRATOR, &ChatHandler::HandleChangeWeather, "", NULL }, + { "ticket", SEC_GAMEMASTER, &ChatHandler::HandleTicketCommand, "", NULL }, + { "delticket", SEC_GAMEMASTER, &ChatHandler::HandleDelTicketCommand, "", NULL }, + { "maxskill", SEC_ADMINISTRATOR, &ChatHandler::HandleMaxSkillCommand, "", NULL }, + { "setskill", SEC_ADMINISTRATOR, &ChatHandler::HandleSetSkillCommand, "", NULL }, + { "whispers", SEC_MODERATOR, &ChatHandler::HandleWhispersCommand, "", NULL }, + { "pinfo", SEC_GAMEMASTER, &ChatHandler::HandlePInfoCommand, "", NULL }, + { "password", SEC_PLAYER, &ChatHandler::HandlePasswordCommand, "", NULL }, + { "lockaccount", SEC_PLAYER, &ChatHandler::HandleLockAccountCommand, "", NULL }, + { "respawn", SEC_ADMINISTRATOR, &ChatHandler::HandleRespawnCommand, "", NULL }, + { "sendmail", SEC_MODERATOR, &ChatHandler::HandleSendMailCommand, "", NULL }, + { "rename", SEC_GAMEMASTER, &ChatHandler::HandleRenameCommand, "", NULL }, + { "loadscripts", SEC_ADMINISTRATOR, &ChatHandler::HandleLoadScriptsCommand, "", NULL }, + { "mute", SEC_GAMEMASTER, &ChatHandler::HandleMuteCommand, "", NULL }, + { "unmute", SEC_GAMEMASTER, &ChatHandler::HandleUnmuteCommand, "", NULL }, + { "movegens", SEC_ADMINISTRATOR, &ChatHandler::HandleMovegensCommand, "", NULL }, + { "cometome", SEC_ADMINISTRATOR, &ChatHandler::HandleComeToMeCommand, "", NULL }, + { "damage", SEC_ADMINISTRATOR, &ChatHandler::HandleDamageCommand, "", NULL }, + { "combatstop", SEC_GAMEMASTER, &ChatHandler::HandleCombatStopCommand, "", NULL }, + + { NULL, 0, NULL, "", NULL } + }; + + if(load_command_table) + { + load_command_table = false; + + QueryResult *result = WorldDatabase.Query("SELECT name,security,help FROM command"); + if (result) + { + do + { + Field *fields = result->Fetch(); + std::string name = fields[0].GetCppString(); + for(uint32 i = 0; commandTable[i].Name != NULL; i++) + { + if (name == commandTable[i].Name) + { + commandTable[i].SecurityLevel = (uint16)fields[1].GetUInt16(); + commandTable[i].Help = fields[2].GetCppString(); + } + if(commandTable[i].ChildCommands != NULL) + { + ChatCommand *ptable = commandTable[i].ChildCommands; + for(uint32 j = 0; ptable[j].Name != NULL; j++) + { + // first case for "" named subcommand + if (ptable[j].Name[0]=='\0' && name == commandTable[i].Name || + name == fmtstring("%s %s", commandTable[i].Name, ptable[j].Name) ) + { + ptable[j].SecurityLevel = (uint16)fields[1].GetUInt16(); + ptable[j].Help = fields[2].GetCppString(); + } + } + } + } + } while(result->NextRow()); + delete result; + } + } + + return commandTable; +} + +const char *ChatHandler::GetMangosString(int32 entry) +{ + return m_session->GetMangosString(entry); +} + +bool ChatHandler::hasStringAbbr(const char* s1, const char* s2) +{ + for(;;) + { + if( !*s2 ) + return true; + else if( !*s1 ) + return false; + else if( tolower( *s1 ) != tolower( *s2 ) ) + return false; + ++s1; ++s2; + } +} + +void ChatHandler::SendSysMessage(const char *str) +{ + WorldPacket data; + + // need copy to prevent corruption by strtok call in LineFromMessage original string + char* buf = strdup(str); + char* pos = buf; + + while(char* line = LineFromMessage(pos)) + { + FillSystemMessageData(&data, line); + m_session->SendPacket(&data); + } + + free(buf); +} + +void ChatHandler::SendGlobalSysMessage(const char *str) +{ + WorldPacket data; + + // need copy to prevent corruption by strtok call in LineFromMessage original string + char* buf = strdup(str); + char* pos = buf; + + while(char* line = LineFromMessage(pos)) + { + FillSystemMessageData(&data, line); + sWorld.SendGlobalMessage(&data); + } + + free(buf); +} + +void ChatHandler::SendSysMessage(int32 entry) +{ + SendSysMessage(GetMangosString(entry)); +} + +void ChatHandler::PSendSysMessage(int32 entry, ...) +{ + const char *format = GetMangosString(entry); + va_list ap; + char str [1024]; + va_start(ap, entry); + vsnprintf(str,1024,format, ap ); + va_end(ap); + SendSysMessage(str); +} + +void ChatHandler::PSendSysMessage(const char *format, ...) +{ + va_list ap; + char str [1024]; + va_start(ap, format); + vsnprintf(str,1024,format, ap ); + va_end(ap); + SendSysMessage(str); +} + +bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, std::string fullcmd) +{ + char const* oldtext = text; + std::string cmd = ""; + + while (*text != ' ' && *text != '\0') + { + cmd += *text; + ++text; + } + + while (*text == ' ') ++text; + + if(!cmd.length()) + return false; + + for(uint32 i = 0; table[i].Name != NULL; i++) + { + // allow pass "" command name in table + if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, cmd.c_str())) + continue; + + // select subcommand from child commands list + if(table[i].ChildCommands != NULL) + { + if(!ExecuteCommandInTable(table[i].ChildCommands, text, fullcmd)) + { + if(text && text[0] != '\0') + SendSysMessage(LANG_NO_SUBCMD); + else + SendSysMessage(LANG_CMD_SYNTAX); + + ShowHelpForCommand(table[i].ChildCommands,text); + } + + return true; + } + + // check security level only for simple command (without child commands) + if(m_session->GetSecurity() < table[i].SecurityLevel) + continue; + + SetSentErrorMessage(false); + // table[i].Name == "" is special case: send original command to handler + if((this->*(table[i].Handler))(strlen(table[i].Name)!=0 ? text : oldtext)) + { + if(table[i].SecurityLevel > SEC_PLAYER) + { + Player* p = m_session->GetPlayer(); + uint64 sel_guid = p->GetSelection(); + sLog.outCommand("Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected: %s (GUID: %u)]", + fullcmd.c_str(),p->GetName(),m_session->GetAccountId(),p->GetPositionX(),p->GetPositionY(),p->GetPositionZ(),p->GetMapId(), + GetLogNameForGuid(sel_guid),GUID_LOPART(sel_guid)); + } + } + // some commands have custom error messages. Don't send the default one in these cases. + else if(!sentErrorMessage) + { + if(!table[i].Help.empty()) + SendSysMessage(table[i].Help.c_str()); + else + SendSysMessage(LANG_CMD_SYNTAX); + } + + return true; + } + + return false; +} + +int ChatHandler::ParseCommands(const char* text) +{ + ASSERT(text); + ASSERT(*text); + + //if(m_session->GetSecurity() == 0) + // return 0; + + if(text[0] != '!' && text[0] != '.') + return 0; + + // ignore single . and ! in line + if(strlen(text) < 2) + return 0; + + // ignore messages staring from many dots. + if(text[0] == '.' && text[1] == '.' || text[0] == '!' && text[1] == '!') + return 0; + + ++text; + + std::string fullcmd = text; // original `text` can't be used. It content destroyed in command code processing. + + if(!ExecuteCommandInTable(getCommandTable(), text, fullcmd)) + SendSysMessage(LANG_NO_CMD); + + return 1; +} + +bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd) +{ + std::string list; + for(uint32 i = 0; table[i].Name != NULL; ++i) + { + if(m_session->GetSecurity() < table[i].SecurityLevel) + continue; + + if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, subcmd)) + continue; + + (list += "\n ") += table[i].Name; + } + + if(list.empty()) + return false; + + if(table==getCommandTable()) + { + SendSysMessage(LANG_AVIABLE_CMD); + PSendSysMessage("%s",list.c_str()); + } + else + PSendSysMessage(LANG_SUBCMDS_LIST,cmd,list.c_str()); + + return true; +} + +bool ChatHandler::ShowHelpForCommand(ChatCommand *table, const char* cmd) +{ + if(*cmd) + { + for(uint32 i = 0; table[i].Name != NULL; ++i) + { + if(m_session->GetSecurity() < table[i].SecurityLevel) + continue; + + if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, cmd)) + continue; + + // have subcommand + char const* subcmd = (*cmd) ? strtok(NULL, " ") : ""; + + if(table[i].ChildCommands && subcmd && *subcmd) + { + if(ShowHelpForCommand(table[i].ChildCommands, subcmd)) + return true; + } + + if(!table[i].Help.empty()) + SendSysMessage(table[i].Help.c_str()); + + if(table[i].ChildCommands) + if(ShowHelpForSubCommands(table[i].ChildCommands,table[i].Name,subcmd ? subcmd : "")) + return true; + + return !table[i].Help.empty(); + } + } + else + { + for(uint32 i = 0; table[i].Name != NULL; ++i) + { + if(m_session->GetSecurity() < table[i].SecurityLevel) + continue; + + if(strlen(table[i].Name)) + continue; + + if(!table[i].Help.empty()) + SendSysMessage(table[i].Help.c_str()); + + if(table[i].ChildCommands) + if(ShowHelpForSubCommands(table[i].ChildCommands,"","")) + return true; + + return !table[i].Help.empty(); + } + } + + return ShowHelpForSubCommands(table,"",cmd); +} + +//Note: target_guid used only in CHAT_MSG_WHISPER_INFORM mode (in this case channelName ignored) +void ChatHandler::FillMessageData( WorldPacket *data, WorldSession* session, uint8 type, uint32 language, const char *channelName, uint64 target_guid, const char *message, Unit *speaker) +{ + uint32 messageLength = (message ? strlen(message) : 0) + 1; + + data->Initialize(SMSG_MESSAGECHAT, 100); // guess size + *data << uint8(type); + if ((type != CHAT_MSG_CHANNEL && type != CHAT_MSG_WHISPER) || language == LANG_ADDON) + *data << uint32(language); + else + *data << uint32(LANG_UNIVERSAL); + + switch(type) + { + case CHAT_MSG_SAY: + case CHAT_MSG_PARTY: + case CHAT_MSG_RAID: + case CHAT_MSG_GUILD: + case CHAT_MSG_OFFICER: + case CHAT_MSG_YELL: + case CHAT_MSG_WHISPER: + case CHAT_MSG_CHANNEL: + case CHAT_MSG_RAID_LEADER: + case CHAT_MSG_RAID_WARNING: + case CHAT_MSG_BG_SYSTEM_NEUTRAL: + case CHAT_MSG_BG_SYSTEM_ALLIANCE: + case CHAT_MSG_BG_SYSTEM_HORDE: + case CHAT_MSG_BATTLEGROUND: + case CHAT_MSG_BATTLEGROUND_LEADER: + target_guid = session ? session->GetPlayer()->GetGUID() : 0; + break; + case CHAT_MSG_MONSTER_SAY: + case CHAT_MSG_MONSTER_PARTY: + case CHAT_MSG_MONSTER_YELL: + case CHAT_MSG_MONSTER_WHISPER: + case CHAT_MSG_MONSTER_EMOTE: + case CHAT_MSG_RAID_BOSS_WHISPER: + case CHAT_MSG_RAID_BOSS_EMOTE: + { + *data << uint64(speaker->GetGUID()); + *data << uint32(0); // 2.1.0 + *data << uint32(strlen(speaker->GetName()) + 1); + *data << speaker->GetName(); + uint64 listener_guid = 0; + *data << uint64(listener_guid); + if(listener_guid && !IS_PLAYER_GUID(listener_guid)) + { + *data << uint32(1); // string listener_name_length + *data << uint8(0); // string listener_name + } + *data << uint32(messageLength); + *data << message; + *data << uint8(0); + return; + } + default: + if (type != CHAT_MSG_REPLY && type != CHAT_MSG_IGNORED && type != CHAT_MSG_DND && type != CHAT_MSG_AFK) + target_guid = 0; // only for CHAT_MSG_WHISPER_INFORM used original value target_guid + break; + } + + *data << uint64(target_guid); // there 0 for BG messages + *data << uint32(0); // can be chat msg group or something + + if (type == CHAT_MSG_CHANNEL) + { + ASSERT(channelName); + *data << channelName; + } + + *data << uint64(target_guid); + *data << uint32(messageLength); + *data << message; + if(session != 0 && type != CHAT_MSG_REPLY && type != CHAT_MSG_DND && type != CHAT_MSG_AFK) + *data << uint8(session->GetPlayer()->chatTag()); + else + *data << uint8(0); +} + +Player * ChatHandler::getSelectedPlayer() +{ + uint64 guid = m_session->GetPlayer()->GetSelection(); + + if (guid == 0) + return m_session->GetPlayer(); + + return objmgr.GetPlayer(guid); +} + +Unit* ChatHandler::getSelectedUnit() +{ + uint64 guid = m_session->GetPlayer()->GetSelection(); + + if (guid == 0) + return m_session->GetPlayer(); + + return ObjectAccessor::GetUnit(*m_session->GetPlayer(),guid); +} + +Creature* ChatHandler::getSelectedCreature() +{ + return ObjectAccessor::GetCreatureOrPet(*m_session->GetPlayer(),m_session->GetPlayer()->GetSelection()); +} + +char* ChatHandler::extractKeyFromLink(char* text, char const* linkType, char** something1) +{ + // skip empty + if(!text) + return NULL; + + // skip speces + while(*text==' '||*text=='\t'||*text=='\b') + ++text; + + if(!*text) + return NULL; + + // return non link case + if(text[0]!='|') + return strtok(text, " "); + + // [name] Shift-click form |color|linkType:key|h[name]|h|r + // or + // [name] Shift-click form |color|linkType:key:something1:...:somethingN|h[name]|h|r + + char* check = strtok(text, "|"); // skip color + if(!check) + return NULL; // end of data + + char* cLinkType = strtok(NULL, ":"); // linktype + if(!cLinkType) + return NULL; // end of data + + if(strcmp(cLinkType,linkType) != 0) + { + strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after retturn from function + SendSysMessage(LANG_WRONG_LINK_TYPE); + return NULL; + } + + char* cKeys = strtok(NULL, "|"); // extract keys and values + char* cKeysTail = strtok(NULL, ""); + + char* cKey = strtok(cKeys, ":|"); // extract key + if(something1) + *something1 = strtok(NULL, ":|"); // extract something + + strtok(cKeysTail, "]"); // restart scan tail and skip name with possible spaces + strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after retturn from function + return cKey; +} + +char* ChatHandler::extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1) +{ + // skip empty + if(!text) + return NULL; + + // skip speces + while(*text==' '||*text=='\t'||*text=='\b') + ++text; + + if(!*text) + return NULL; + + // return non link case + if(text[0]!='|') + return strtok(text, " "); + + // [name] Shift-click form |color|linkType:key|h[name]|h|r + // or + // [name] Shift-click form |color|linkType:key:something1:...:somethingN|h[name]|h|r + + char* check = strtok(text, "|"); // skip color + if(!check) + return NULL; // end of data + + char* cLinkType = strtok(NULL, ":"); // linktype + if(!cLinkType) + return NULL; // end of data + + for(int i = 0; linkTypes[i]; ++i) + { + if(strcmp(cLinkType,linkTypes[i]) == 0) + { + char* cKeys = strtok(NULL, "|"); // extract keys and values + char* cKeysTail = strtok(NULL, ""); + + char* cKey = strtok(cKeys, ":|"); // extract key + if(something1) + *something1 = strtok(NULL, ":|"); // extract something + + strtok(cKeysTail, "]"); // restart scan tail and skip name with possible spaces + strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after return from function + if(found_idx) + *found_idx = i; + return cKey; + } + } + + strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after return from function + SendSysMessage(LANG_WRONG_LINK_TYPE); + return NULL; +} + +char const *fmtstring( char const *format, ... ) +{ + va_list argptr; + #define MAX_FMT_STRING 32000 + static char temp_buffer[MAX_FMT_STRING]; + static char string[MAX_FMT_STRING]; + static int index = 0; + char *buf; + int len; + + va_start(argptr, format); + vsnprintf(temp_buffer,MAX_FMT_STRING, format, argptr); + va_end(argptr); + + len = strlen(temp_buffer); + + if( len >= MAX_FMT_STRING ) + return "ERROR"; + + if (len + index >= MAX_FMT_STRING-1) + { + index = 0; + } + + buf = &string[index]; + memcpy( buf, temp_buffer, len+1 ); + + index += len + 1; + + return buf; +} + +GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry) +{ + Player* pl = m_session->GetPlayer(); + + GameObject* obj = ObjectAccessor::GetGameObject(*pl, MAKE_NEW_GUID(lowguid, entry, HIGHGUID_GAMEOBJECT)); + + if(!obj && objmgr.GetGOData(lowguid)) // guid is DB guid of object + { + // search near player then + CellPair p(MaNGOS::ComputeCellPair(pl->GetPositionX(), pl->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + MaNGOS::GameObjectWithDbGUIDCheck go_check(*pl,lowguid); + MaNGOS::GameObjectSearcher checker(obj,go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(pl->GetMapId(), pl)); + } + + return obj; +} + +static char const* const spellTalentKeys[] = { + "Hspell", + "Htalent", + 0 +}; + +uint32 ChatHandler::extractSpellIdFromLink(char* text) +{ + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r + // number or [name] Shift-click form |color|Htalent:telen_id,rank|h[name]|h|r + int type = 0; + char* rankS = NULL; + char* idS = extractKeyFromLink(text,spellTalentKeys,&type,&rankS); + if(!idS) + return 0; + + uint32 id = (uint32)atol(idS); + + // spell + if(type==0) + return id; + + // talent + TalentEntry const* talentEntry = sTalentStore.LookupEntry(id); + if(!talentEntry) + return 0; + + int32 rank = rankS ? (uint32)atol(rankS) : 0; + if(rank >= 5) + return 0; + + if(rank < 0) + rank = 0; + + return talentEntry->RankID[rank]; +} + +GameTele const* ChatHandler::extractGameTeleFromLink(char* text) +{ + // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r + char* cId = extractKeyFromLink(text,"Htele"); + if(!cId) + return false; + + // id case (explicit or from shift link) + if(cId[0] >= '0' || cId[0] >= '9') + if(uint32 id = atoi(cId)) + return objmgr.GetGameTele(id); + + return objmgr.GetGameTele(cId); +} diff --git a/src/game/Chat.h b/src/game/Chat.h index 49b219e875e..388cd83b951 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -1,406 +1,421 @@ -/* - * Copyright (C) 2005-2008 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 MANGOSSERVER_CHAT_H -#define MANGOSSERVER_CHAT_H - -#include "SharedDefines.h" - -class ChatHandler; -class WorldSession; -class Creature; -class Player; -class Unit; - -struct LanguageDesc -{ - Language lang_id; - uint32 spell_id; - uint32 skill_id; -}; - -extern LanguageDesc lang_description[LANGUAGES_COUNT]; - -LanguageDesc const* GetLanguageDescByID(uint32 lang); -LanguageDesc const* GetLanguageDescBySpell(uint32 spell_id); -LanguageDesc const* GetLanguageDescBySkill(uint32 skill_id); - -class ChatCommand -{ - public: - const char * Name; - uint32 SecurityLevel; // function pointer required correct align (use uint32) - bool (ChatHandler::*Handler)(const char* args); - std::string Help; - ChatCommand * ChildCommands; -}; - -class ChatHandler -{ - public: - explicit ChatHandler(WorldSession* session) : m_session(session) {} - explicit ChatHandler(Player* player) : m_session(player->GetSession()) {} - ~ChatHandler() {} - - static void FillMessageData( WorldPacket *data, WorldSession* session, uint8 type, uint32 language, const char *channelName, uint64 target_guid, const char *message, Unit *speaker); - - void FillMessageData( WorldPacket *data, uint8 type, uint32 language, uint64 target_guid, const char* message) - { - FillMessageData( data, m_session, type, language, NULL, target_guid, message, NULL); - } - - void FillSystemMessageData( WorldPacket *data, const char* message ) - { - FillMessageData( data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, 0, message ); - } - - static char* LineFromMessage(char*& pos) { char* start = strtok(pos,"\n"); pos = NULL; return start; } - - const char *GetMangosString(int32 entry); - - void SendSysMessage( const char *str); - void SendSysMessage( int32 entry); - void PSendSysMessage( const char *format, ...) ATTR_PRINTF(2,3); - void PSendSysMessage( int32 entry, ... ); - - int ParseCommands(const char* text); - - protected: - bool hasStringAbbr(const char* s1, const char* s2); - void SendGlobalSysMessage(const char *str); - - bool ExecuteCommandInTable(ChatCommand *table, const char* text, std::string fullcommand); - bool ShowHelpForCommand(ChatCommand *table, const char* cmd); - bool ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd); - - ChatCommand* getCommandTable(); - - bool HandleHelpCommand(const char* args); - bool HandleCommandsCommand(const char* args); - bool HandleAcctCommand(const char* args); - bool HandleStartCommand(const char* args); - bool HandleInfoCommand(const char* args); - bool HandleDismountCommand(const char* args); - bool HandleSaveCommand(const char* args); - bool HandleGMListCommand(const char* args); - - bool HandleNamegoCommand(const char* args); - bool HandleGonameCommand(const char* args); - bool HandleGroupgoCommand(const char* args); - bool HandleRecallCommand(const char* args); - bool HandleAnnounceCommand(const char* args); - bool HandleNotifyCommand(const char* args); - bool HandleGMmodeCommand(const char* args); - bool HandleVisibleCommand(const char* args); - bool HandleGPSCommand(const char* args); - bool HandleTaxiCheatCommand(const char* args); - bool HandleWhispersCommand(const char* args); - bool HandleSayCommand(const char* args); - bool HandleNpcWhisperCommand(const char* args); - bool HandleYellCommand(const char* args); - bool HandlePlayEmoteCommand(const char* args); - bool HandleSendMailCommand(const char* args); - bool HandleNameTeleCommand(const char* args); - bool HandleGroupTeleCommand(const char* args); - bool HandleDrunkCommand(const char* args); - - bool HandleEventActiveListCommand(const char* args); - bool HandleEventStartCommand(const char* args); - bool HandleEventStopCommand(const char* args); - bool HandleEventInfoCommand(const char* args); - - bool HandleModifyKnownTitlesCommand(const char* args); - bool HandleModifyHPCommand(const char* args); - bool HandleModifyManaCommand(const char* args); - bool HandleModifyRageCommand(const char* args); - bool HandleModifyEnergyCommand(const char* args); - bool HandleModifyMoneyCommand(const char* args); - bool HandleModifyASpeedCommand(const char* args); - bool HandleModifySpeedCommand(const char* args); - bool HandleModifyBWalkCommand(const char* args); - bool HandleModifyFlyCommand(const char* args); - bool HandleModifySwimCommand(const char* args); - bool HandleModifyScaleCommand(const char* args); - bool HandleModifyMountCommand(const char* args); - bool HandleModifyBitCommand(const char* args); - bool HandleModifyFactionCommand(const char* args); - bool HandleModifySpellCommand(const char* args); - bool HandleModifyTalentCommand (const char* args); - bool HandleModifyHonorCommand (const char* args); - bool HandleModifyRepCommand(const char* args); - bool HandleModifyArenaCommand(const char* args); - - bool HandleReloadCommand(const char* args); - bool HandleReloadAllCommand(const char* args); - bool HandleReloadAllAreaCommand(const char* args); - bool HandleReloadAllItemCommand(const char* args); - bool HandleReloadAllLootCommand(const char* args); - bool HandleReloadAllQuestCommand(const char* args); - bool HandleReloadAllScriptsCommand(const char* args); - bool HandleReloadAllSpellCommand(const char* args); - - bool HandleReloadConfigCommand(const char* args); - - bool HandleReloadAreaTriggerTavernCommand(const char* args); - bool HandleReloadAreaTriggerTeleportCommand(const char* args); - bool HandleReloadEventScriptsCommand(const char* args); - bool HandleReloadCommandCommand(const char* args); - bool HandleReloadCreatureQuestRelationsCommand(const char* args); - bool HandleReloadCreatureQuestInvRelationsCommand(const char* args); - bool HandleReloadGameGraveyardZoneCommand(const char* args); - bool HandleReloadGameObjectScriptsCommand(const char* args); - bool HandleReloadGOQuestRelationsCommand(const char* args); - bool HandleReloadGOQuestInvRelationsCommand(const char* args); - bool HandleReloadLootTemplatesCreatureCommand(const char* args); - bool HandleReloadLootTemplatesDisenchantCommand(const char* args); - bool HandleReloadLootTemplatesFishingCommand(const char* args); - bool HandleReloadLootTemplatesGameobjectCommand(const char* args); - bool HandleReloadLootTemplatesItemCommand(const char* args); - bool HandleReloadLootTemplatesPickpocketingCommand(const char* args); - bool HandleReloadLootTemplatesProspectingCommand(const char* args); - bool HandleReloadLootTemplatesReferenceCommand(const char* args); - bool HandleReloadLootTemplatesQuestMailCommand(const char* args); - bool HandleReloadLootTemplatesSkinningCommand(const char* args); - bool HandleReloadMangosStringCommand(const char* args); - bool HandleReloadQuestAreaTriggersCommand(const char* args); - bool HandleReloadQuestEndScriptsCommand(const char* args); - bool HandleReloadQuestStartScriptsCommand(const char* args); - bool HandleReloadQuestTemplateCommand(const char* args); - bool HandleReloadReservedNameCommand(const char*); - bool HandleReloadSkillDiscoveryTemplateCommand(const char* args); - bool HandleReloadSkillExtraItemTemplateCommand(const char* args); - bool HandleReloadSkillFishingBaseLevelCommand(const char* args); - bool HandleReloadSpellAffectCommand(const char* args); - bool HandleReloadSpellChainCommand(const char* args); - bool HandleReloadSpellElixirCommand(const char* args); - bool HandleReloadSpellLearnSpellCommand(const char* args); - bool HandleReloadSpellProcEventCommand(const char* args); - bool HandleReloadSpellScriptTargetCommand(const char* args); - bool HandleReloadSpellScriptsCommand(const char* args); - bool HandleReloadSpellTargetPositionCommand(const char* args); - bool HandleReloadSpellThreatsCommand(const char* args); - bool HandleReloadSpellPetAurasCommand(const char* args); - bool HandleReloadPageTextsCommand(const char* args); - bool HandleReloadItemEnchantementsCommand(const char* args); - - bool HandleInstanceListBindsCommand(const char* args); - bool HandleInstanceUnbindCommand(const char* args); - bool HandleInstanceStatsCommand(const char* args); - bool HandleInstanceSaveDataCommand(const char * args); - - bool HandleAddHonorCommand(const char* args); - bool HandleHonorAddKillCommand(const char* args); - bool HandleUpdateHonorFieldsCommand(const char* args); - - bool HandleLoadScriptsCommand(const char* args); - bool HandleSendQuestPartyMsgCommand(const char* args); - bool HandleSendQuestInvalidMsgCommand(const char* args); - - bool HandleDebugInArcCommand(const char* args); - bool HandleDebugSpellFailCommand(const char* args); - - bool HandleGUIDCommand(const char* args); - bool HandleNameCommand(const char* args); - bool HandleSubNameCommand(const char* args); - bool HandleItemMoveCommand(const char* args); - bool HandleDelCreatureCommand(const char* args); - bool HandleDeMorphCommand(const char* args); - bool HandleAddVendorItemCommand(const char* args); - bool HandleDelVendorItemCommand(const char* args); - bool HandleAddMoveCommand(const char* args); - bool HandleSetMoveTypeCommand(const char* args); - bool HandleChangeLevelCommand(const char* args); - bool HandleSetPoiCommand(const char* args); - bool HandleEquipErrorCommand(const char* args); - bool HandleNPCFlagCommand(const char* args); - bool HandleSetModelCommand(const char* args); - bool HandleFactionIdCommand(const char* args); - bool HandleAddSpwCommand(const char* args); - bool HandleSpawnDistCommand(const char* args); - bool HandleSpawnTimeCommand(const char* args); - bool HandleGoCreatureCommand(const char* args); - bool HandleGoObjectCommand(const char* args); - bool HandleGoTriggerCommand(const char* args); - bool HandleGoGraveyardCommand(const char* args); - bool HandleTargetObjectCommand(const char* args); - bool HandleDelObjectCommand(const char* args); - bool HandleMoveCreatureCommand(const char* args); - bool HandleMoveObjectCommand(const char* args); - bool HandleTurnObjectCommand(const char* args); - bool HandlePInfoCommand(const char* args); - bool HandlePLimitCommand(const char* args); - bool HandleMuteCommand(const char* args); - bool HandleUnmuteCommand(const char* args); - bool HandleMovegensCommand(const char* args); - - bool HandleBanCommand(const char* args); - bool HandleUnBanCommand(const char* args); - bool HandleBanInfoCommand(const char* args); - bool HandleBanListCommand(const char* args); - bool HandleIdleRestartCommand(const char* args); - bool HandleIdleShutDownCommand(const char* args); - bool HandleShutDownCommand(const char* args); - bool HandleRestartCommand(const char* args); - bool HandleSecurityCommand(const char* args); - bool HandleGoXYCommand(const char* args); - bool HandleGoXYZCommand(const char* args); - bool HandleGoZoneXYCommand(const char* args); - bool HandleGoGridCommand(const char* args); - bool HandleAddWeaponCommand(const char* args); - bool HandleAllowMovementCommand(const char* args); - bool HandleGoCommand(const char* args); - bool HandleLearnCommand(const char* args); - bool HandleLearnAllCommand(const char* args); - bool HandleLearnAllGMCommand(const char* args); - bool HandleLearnAllCraftsCommand(const char* args); - bool HandleLearnAllRecipesCommand(const char* args); - bool HandleLearnAllDefaultCommand(const char* args); - bool HandleLearnAllLangCommand(const char* args); - bool HandleLearnAllMyClassCommand(const char* args); - bool HandleLearnAllMySpellsCommand(const char* args); - bool HandleLearnAllMyTalentsCommand(const char* args); - bool HandleCooldownCommand(const char* args); - bool HandleUnLearnCommand(const char* args); - bool HandleGetDistanceCommand(const char* args); - bool HandleGameObjectCommand(const char* args); - bool HandleAnimCommand(const char* args); - bool HandlePlaySoundCommand(const char* args); - bool HandleStandStateCommand(const char* args); - bool HandleDieCommand(const char* args); - bool HandleDamageCommand(const char *args); - bool HandleReviveCommand(const char* args); - bool HandleMorphCommand(const char* args); - bool HandleAuraCommand(const char* args); - bool HandleUnAuraCommand(const char* args); - bool HandleLinkGraveCommand(const char* args); - bool HandleNearGraveCommand(const char* args); - bool HandleSpawnTransportCommand(const char* args); - bool HandleExploreCheatCommand(const char* args); - bool HandleTextEmoteCommand(const char* args); - bool HandleNpcInfoCommand(const char* args); - bool HandleHoverCommand(const char* args); - bool HandleLevelUpCommand(const char* args); - bool HandleShowAreaCommand(const char* args); - bool HandleHideAreaCommand(const char* args); - bool HandleAddItemCommand(const char* args); - bool HandleAddItemSetCommand(const char* args); - bool HandleLookupItemCommand(const char * args); - bool HandleLookupItemSetCommand(const char * args); - bool HandleGuildCreateCommand(const char* args); - bool HandleGuildInviteCommand(const char* args); - bool HandleGuildUninviteCommand(const char* args); - bool HandleGuildRankCommand(const char* args); - bool HandleGuildDeleteCommand(const char* args); - bool HandleUpdate(const char* args); - bool HandleBankCommand(const char* args); - bool HandleChangeWeather(const char* args); - bool HandleKickPlayerCommand(const char * args); - bool HandleTeleCommand(const char * args); - bool HandleAddTeleCommand(const char * args); - bool HandleDelTeleCommand(const char * args); - bool HandleListAurasCommand(const char * args); - bool HandleLookupTeleCommand(const char * args); - - bool HandleResetHonorCommand(const char * args); - bool HandleResetLevelCommand(const char * args); - bool HandleResetSpellsCommand(const char * args); - - bool HandleResetStatsCommand(const char * args); - bool HandleResetTalentsCommand(const char * args); - - bool HandleResetAllCommand(const char * args); - bool HandleTicketCommand(const char* args); - bool HandleDelTicketCommand(const char* args); - bool HandleMaxSkillCommand(const char* args); - bool HandleSetSkillCommand(const char* args); - bool HandleListCreatureCommand(const char* args); - bool HandleListItemCommand(const char* args); - bool HandleListObjectCommand(const char* args); - bool HandleNearObjectCommand(const char* args); - bool HandleLookupAreaCommand(const char* args); - bool HandleLookupCreatureCommand(const char* args); - bool HandleLookupEventCommand(const char* args); - bool HandleLookupFactionCommand(const char * args); - bool HandleLookupObjectCommand(const char* args); - bool HandleLookupQuestCommand(const char* args); - bool HandleLookupSkillCommand(const char* args); - bool HandleLookupSpellCommand(const char* args); - bool HandlePasswordCommand(const char* args); - bool HandleLockAccountCommand(const char* args); - bool HandleRespawnCommand(const char* args); - bool HandleWpAddCommand(const char* args); - bool HandleWpModifyCommand(const char* args); - bool HandleWpShowCommand(const char* args); - bool HandleWpExportCommand(const char* args); - bool HandleWpImportCommand(const char* args); - bool HandleFlyModeCommand(const char* args); - bool HandleSendOpcodeCommand(const char* args); - bool HandleSellErrorCommand(const char* args); - bool HandleBuyErrorCommand(const char* args); - bool HandleUpdateWorldStateCommand(const char* args); - bool HandlePlaySound2Command(const char* args); - bool HandleSendChannelNotifyCommand(const char* args); - bool HandleSendChatMsgCommand(const char* args); - bool HandleRenameCommand(const char * args); - bool HandleLoadPDumpCommand(const char *args); - bool HandleWritePDumpCommand(const char *args); - bool HandleChangeEntryCommand(const char *args); - bool HandleCastCommand(const char *args); - bool HandleCastBackCommand(const char *args); - bool HandleCastDistCommand(const char *args); - bool HandleCastSelfCommand(const char *args); - bool HandleCastTargetCommand(const char *args); - bool HandleComeToMeCommand(const char *args); - bool HandleCombatStopCommand(const char *args); - - //! Development Commands - bool HandleSetValue(const char* args); - bool HandleGetValue(const char* args); - bool HandleSet32Bit(const char* args); - bool HandleMod32Value(const char* args); - bool HandleAddQuest(const char * args); - bool HandleRemoveQuest(const char * args); - bool HandleCompleteQuest(const char * args); - bool HandleSaveAllCommand(const char* args); - bool HandleGetItemState(const char * args); - bool HandleGetLootRecipient(const char * args); - - Player* getSelectedPlayer(); - Creature* getSelectedCreature(); - Unit* getSelectedUnit(); - char* extractKeyFromLink(char* text, char const* linkType, char** something1 = NULL); - char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL); - uint32 extractSpellIdFromLink(char* text); - - GameObject* GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry); - - WorldSession * m_session; - - // Utility methods for commands - void ShowTicket(uint64 guid, char const* text, char const* time); - uint32 GetTicketIDByNum(uint32 num); - - void SetSentErrorMessage(bool val){ sentErrorMessage = val;}; - private: - // common global flag - static bool load_command_table; - bool sentErrorMessage; -}; -#endif - -char const *fmtstring( char const *format, ... ); +/* + * Copyright (C) 2005-2008 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 MANGOSSERVER_CHAT_H +#define MANGOSSERVER_CHAT_H + +#include "SharedDefines.h" + +class ChatHandler; +class WorldSession; +class Creature; +class Player; +class Unit; +struct GameTele; + +struct LanguageDesc +{ + Language lang_id; + uint32 spell_id; + uint32 skill_id; +}; + +extern LanguageDesc lang_description[LANGUAGES_COUNT]; + +LanguageDesc const* GetLanguageDescByID(uint32 lang); +LanguageDesc const* GetLanguageDescBySpell(uint32 spell_id); +LanguageDesc const* GetLanguageDescBySkill(uint32 skill_id); + +class ChatCommand +{ + public: + const char * Name; + uint32 SecurityLevel; // function pointer required correct align (use uint32) + bool (ChatHandler::*Handler)(const char* args); + std::string Help; + ChatCommand * ChildCommands; +}; + +class ChatHandler +{ + public: + explicit ChatHandler(WorldSession* session) : m_session(session) {} + explicit ChatHandler(Player* player) : m_session(player->GetSession()) {} + ~ChatHandler() {} + + static void FillMessageData( WorldPacket *data, WorldSession* session, uint8 type, uint32 language, const char *channelName, uint64 target_guid, const char *message, Unit *speaker); + + void FillMessageData( WorldPacket *data, uint8 type, uint32 language, uint64 target_guid, const char* message) + { + FillMessageData( data, m_session, type, language, NULL, target_guid, message, NULL); + } + + void FillSystemMessageData( WorldPacket *data, const char* message ) + { + FillMessageData( data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, 0, message ); + } + + static char* LineFromMessage(char*& pos) { char* start = strtok(pos,"\n"); pos = NULL; return start; } + + const char *GetMangosString(int32 entry); + + void SendSysMessage( const char *str); + void SendSysMessage( int32 entry); + void PSendSysMessage( const char *format, ...) ATTR_PRINTF(2,3); + void PSendSysMessage( int32 entry, ... ); + + int ParseCommands(const char* text); + + protected: + bool hasStringAbbr(const char* s1, const char* s2); + void SendGlobalSysMessage(const char *str); + + bool ExecuteCommandInTable(ChatCommand *table, const char* text, std::string fullcommand); + bool ShowHelpForCommand(ChatCommand *table, const char* cmd); + bool ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd); + + ChatCommand* getCommandTable(); + + bool HandleHelpCommand(const char* args); + bool HandleCommandsCommand(const char* args); + bool HandleAcctCommand(const char* args); + bool HandleStartCommand(const char* args); + bool HandleInfoCommand(const char* args); + bool HandleDismountCommand(const char* args); + bool HandleSaveCommand(const char* args); + bool HandleGMListCommand(const char* args); + + bool HandleNamegoCommand(const char* args); + bool HandleGonameCommand(const char* args); + bool HandleGroupgoCommand(const char* args); + bool HandleRecallCommand(const char* args); + bool HandleAnnounceCommand(const char* args); + bool HandleNotifyCommand(const char* args); + bool HandleGMmodeCommand(const char* args); + bool HandleVisibleCommand(const char* args); + bool HandleGPSCommand(const char* args); + bool HandleTaxiCheatCommand(const char* args); + bool HandleWhispersCommand(const char* args); + bool HandleSayCommand(const char* args); + bool HandleNpcWhisperCommand(const char* args); + bool HandleYellCommand(const char* args); + bool HandlePlayEmoteCommand(const char* args); + bool HandleSendMailCommand(const char* args); + bool HandleNameTeleCommand(const char* args); + bool HandleGroupTeleCommand(const char* args); + bool HandleDrunkCommand(const char* args); + + bool HandleEventActiveListCommand(const char* args); + bool HandleEventStartCommand(const char* args); + bool HandleEventStopCommand(const char* args); + bool HandleEventInfoCommand(const char* args); + + bool HandleModifyKnownTitlesCommand(const char* args); + bool HandleModifyHPCommand(const char* args); + bool HandleModifyManaCommand(const char* args); + bool HandleModifyRageCommand(const char* args); + bool HandleModifyEnergyCommand(const char* args); + bool HandleModifyMoneyCommand(const char* args); + bool HandleModifyASpeedCommand(const char* args); + bool HandleModifySpeedCommand(const char* args); + bool HandleModifyBWalkCommand(const char* args); + bool HandleModifyFlyCommand(const char* args); + bool HandleModifySwimCommand(const char* args); + bool HandleModifyScaleCommand(const char* args); + bool HandleModifyMountCommand(const char* args); + bool HandleModifyBitCommand(const char* args); + bool HandleModifyFactionCommand(const char* args); + bool HandleModifySpellCommand(const char* args); + bool HandleModifyTalentCommand (const char* args); + bool HandleModifyHonorCommand (const char* args); + bool HandleModifyRepCommand(const char* args); + bool HandleModifyArenaCommand(const char* args); + + bool HandleReloadCommand(const char* args); + bool HandleReloadAllCommand(const char* args); + bool HandleReloadAllAreaCommand(const char* args); + bool HandleReloadAllItemCommand(const char* args); + bool HandleReloadAllLootCommand(const char* args); + bool HandleReloadAllNpcCommand(const char* args); + bool HandleReloadAllQuestCommand(const char* args); + bool HandleReloadAllScriptsCommand(const char* args); + bool HandleReloadAllSpellCommand(const char* args); + + bool HandleReloadConfigCommand(const char* args); + + bool HandleReloadAreaTriggerTavernCommand(const char* args); + bool HandleReloadAreaTriggerTeleportCommand(const char* args); + bool HandleReloadEventScriptsCommand(const char* args); + bool HandleReloadCommandCommand(const char* args); + bool HandleReloadCreatureQuestRelationsCommand(const char* args); + bool HandleReloadCreatureQuestInvRelationsCommand(const char* args); + bool HandleReloadGameGraveyardZoneCommand(const char* args); + bool HandleReloadGameObjectScriptsCommand(const char* args); + bool HandleReloadGameTeleCommand(const char* args); + bool HandleReloadGOQuestRelationsCommand(const char* args); + bool HandleReloadGOQuestInvRelationsCommand(const char* args); + bool HandleReloadLootTemplatesCreatureCommand(const char* args); + bool HandleReloadLootTemplatesDisenchantCommand(const char* args); + bool HandleReloadLootTemplatesFishingCommand(const char* args); + bool HandleReloadLootTemplatesGameobjectCommand(const char* args); + bool HandleReloadLootTemplatesItemCommand(const char* args); + bool HandleReloadLootTemplatesPickpocketingCommand(const char* args); + bool HandleReloadLootTemplatesProspectingCommand(const char* args); + bool HandleReloadLootTemplatesReferenceCommand(const char* args); + bool HandleReloadLootTemplatesQuestMailCommand(const char* args); + bool HandleReloadLootTemplatesSkinningCommand(const char* args); + bool HandleReloadMangosStringCommand(const char* args); + bool HandleReloadNpcGossipCommand(const char* args); + bool HandleReloadNpcTrainerCommand(const char* args); + bool HandleReloadNpcVendorCommand(const char* args); + bool HandleReloadQuestAreaTriggersCommand(const char* args); + bool HandleReloadQuestEndScriptsCommand(const char* args); + bool HandleReloadQuestStartScriptsCommand(const char* args); + bool HandleReloadQuestTemplateCommand(const char* args); + bool HandleReloadReservedNameCommand(const char*); + bool HandleReloadSkillDiscoveryTemplateCommand(const char* args); + bool HandleReloadSkillExtraItemTemplateCommand(const char* args); + bool HandleReloadSkillFishingBaseLevelCommand(const char* args); + bool HandleReloadSpellAffectCommand(const char* args); + bool HandleReloadSpellChainCommand(const char* args); + bool HandleReloadSpellElixirCommand(const char* args); + bool HandleReloadSpellLearnSpellCommand(const char* args); + bool HandleReloadSpellProcEventCommand(const char* args); + bool HandleReloadSpellScriptTargetCommand(const char* args); + bool HandleReloadSpellScriptsCommand(const char* args); + bool HandleReloadSpellTargetPositionCommand(const char* args); + bool HandleReloadSpellThreatsCommand(const char* args); + bool HandleReloadSpellPetAurasCommand(const char* args); + bool HandleReloadPageTextsCommand(const char* args); + bool HandleReloadItemEnchantementsCommand(const char* args); + + bool HandleInstanceListBindsCommand(const char* args); + bool HandleInstanceUnbindCommand(const char* args); + bool HandleInstanceStatsCommand(const char* args); + bool HandleInstanceSaveDataCommand(const char * args); + + bool HandleAddHonorCommand(const char* args); + bool HandleHonorAddKillCommand(const char* args); + bool HandleUpdateHonorFieldsCommand(const char* args); + + bool HandleLoadScriptsCommand(const char* args); + bool HandleSendQuestPartyMsgCommand(const char* args); + bool HandleSendQuestInvalidMsgCommand(const char* args); + + bool HandleDebugInArcCommand(const char* args); + bool HandleDebugSpellFailCommand(const char* args); + + bool HandleGUIDCommand(const char* args); + bool HandleNameCommand(const char* args); + bool HandleSubNameCommand(const char* args); + bool HandleItemMoveCommand(const char* args); + bool HandleDelCreatureCommand(const char* args); + bool HandleDeMorphCommand(const char* args); + bool HandleAddVendorItemCommand(const char* args); + bool HandleDelVendorItemCommand(const char* args); + bool HandleAddMoveCommand(const char* args); + bool HandleSetMoveTypeCommand(const char* args); + bool HandleChangeLevelCommand(const char* args); + bool HandleSetPoiCommand(const char* args); + bool HandleEquipErrorCommand(const char* args); + bool HandleNPCFlagCommand(const char* args); + bool HandleSetModelCommand(const char* args); + bool HandleFactionIdCommand(const char* args); + bool HandleAddSpwCommand(const char* args); + bool HandleSpawnDistCommand(const char* args); + bool HandleSpawnTimeCommand(const char* args); + bool HandleGoCreatureCommand(const char* args); + bool HandleGoObjectCommand(const char* args); + bool HandleGoTriggerCommand(const char* args); + bool HandleGoGraveyardCommand(const char* args); + bool HandleTargetObjectCommand(const char* args); + bool HandleDelObjectCommand(const char* args); + bool HandleMoveCreatureCommand(const char* args); + bool HandleMoveObjectCommand(const char* args); + bool HandleTurnObjectCommand(const char* args); + bool HandlePInfoCommand(const char* args); + bool HandlePLimitCommand(const char* args); + bool HandleMuteCommand(const char* args); + bool HandleUnmuteCommand(const char* args); + bool HandleMovegensCommand(const char* args); + + bool HandleBanCommand(const char* args); + bool HandleUnBanCommand(const char* args); + bool HandleBanInfoCommand(const char* args); + bool HandleBanListCommand(const char* args); + bool HandleIdleRestartCommand(const char* args); + bool HandleIdleShutDownCommand(const char* args); + bool HandleShutDownCommand(const char* args); + bool HandleRestartCommand(const char* args); + bool HandleSecurityCommand(const char* args); + bool HandleGoXYCommand(const char* args); + bool HandleGoXYZCommand(const char* args); + bool HandleGoZoneXYCommand(const char* args); + bool HandleGoGridCommand(const char* args); + bool HandleAddWeaponCommand(const char* args); + bool HandleAllowMovementCommand(const char* args); + bool HandleGoCommand(const char* args); + + bool HandleLearnCommand(const char* args); + bool HandleLearnAllCommand(const char* args); + bool HandleLearnAllGMCommand(const char* args); + bool HandleLearnAllCraftsCommand(const char* args); + bool HandleLearnAllRecipesCommand(const char* args); + bool HandleLearnAllDefaultCommand(const char* args); + bool HandleLearnAllLangCommand(const char* args); + bool HandleLearnAllMyClassCommand(const char* args); + bool HandleLearnAllMySpellsCommand(const char* args); + bool HandleLearnAllMyTalentsCommand(const char* args); + + bool HandleLookupAreaCommand(const char* args); + bool HandleLookupCreatureCommand(const char* args); + bool HandleLookupEventCommand(const char* args); + bool HandleLookupFactionCommand(const char * args); + bool HandleLookupItemCommand(const char * args); + bool HandleLookupItemSetCommand(const char * args); + bool HandleLookupObjectCommand(const char* args); + bool HandleLookupPlayerIpCommand(const char* args); + bool HandleLookupPlayerAccountCommand(const char* args); + bool HandleLookupPlayerEmailCommand(const char* args); + bool HandleLookupQuestCommand(const char* args); + bool HandleLookupSkillCommand(const char* args); + bool HandleLookupSpellCommand(const char* args); + bool HandleLookupTeleCommand(const char * args); + + bool HandleCooldownCommand(const char* args); + bool HandleUnLearnCommand(const char* args); + bool HandleGetDistanceCommand(const char* args); + bool HandleGameObjectCommand(const char* args); + bool HandleAnimCommand(const char* args); + bool HandlePlaySoundCommand(const char* args); + bool HandleStandStateCommand(const char* args); + bool HandleDieCommand(const char* args); + bool HandleDamageCommand(const char *args); + bool HandleReviveCommand(const char* args); + bool HandleMorphCommand(const char* args); + bool HandleAuraCommand(const char* args); + bool HandleUnAuraCommand(const char* args); + bool HandleLinkGraveCommand(const char* args); + bool HandleNearGraveCommand(const char* args); + bool HandleSpawnTransportCommand(const char* args); + bool HandleExploreCheatCommand(const char* args); + bool HandleTextEmoteCommand(const char* args); + bool HandleNpcInfoCommand(const char* args); + bool HandleHoverCommand(const char* args); + bool HandleLevelUpCommand(const char* args); + bool HandleShowAreaCommand(const char* args); + bool HandleHideAreaCommand(const char* args); + bool HandleAddItemCommand(const char* args); + bool HandleAddItemSetCommand(const char* args); + + bool HandleGuildCreateCommand(const char* args); + bool HandleGuildInviteCommand(const char* args); + bool HandleGuildUninviteCommand(const char* args); + bool HandleGuildRankCommand(const char* args); + bool HandleGuildDeleteCommand(const char* args); + bool HandleUpdate(const char* args); + bool HandleBankCommand(const char* args); + bool HandleChangeWeather(const char* args); + bool HandleKickPlayerCommand(const char * args); + bool HandleTeleCommand(const char * args); + bool HandleAddTeleCommand(const char * args); + bool HandleDelTeleCommand(const char * args); + bool HandleListAurasCommand(const char * args); + + bool HandleResetHonorCommand(const char * args); + bool HandleResetLevelCommand(const char * args); + bool HandleResetSpellsCommand(const char * args); + + bool HandleResetStatsCommand(const char * args); + bool HandleResetTalentsCommand(const char * args); + + bool HandleResetAllCommand(const char * args); + bool HandleTicketCommand(const char* args); + bool HandleDelTicketCommand(const char* args); + bool HandleMaxSkillCommand(const char* args); + bool HandleSetSkillCommand(const char* args); + bool HandleListCreatureCommand(const char* args); + bool HandleListItemCommand(const char* args); + bool HandleListObjectCommand(const char* args); + bool HandleNearObjectCommand(const char* args); + bool HandlePasswordCommand(const char* args); + bool HandleLockAccountCommand(const char* args); + bool HandleRespawnCommand(const char* args); + bool HandleWpAddCommand(const char* args); + bool HandleWpModifyCommand(const char* args); + bool HandleWpShowCommand(const char* args); + bool HandleWpExportCommand(const char* args); + bool HandleWpImportCommand(const char* args); + bool HandleFlyModeCommand(const char* args); + bool HandleSendOpcodeCommand(const char* args); + bool HandleSellErrorCommand(const char* args); + bool HandleBuyErrorCommand(const char* args); + bool HandleUpdateWorldStateCommand(const char* args); + bool HandlePlaySound2Command(const char* args); + bool HandleSendChannelNotifyCommand(const char* args); + bool HandleSendChatMsgCommand(const char* args); + bool HandleRenameCommand(const char * args); + bool HandleLoadPDumpCommand(const char *args); + bool HandleWritePDumpCommand(const char *args); + bool HandleChangeEntryCommand(const char *args); + bool HandleCastCommand(const char *args); + bool HandleCastBackCommand(const char *args); + bool HandleCastDistCommand(const char *args); + bool HandleCastSelfCommand(const char *args); + bool HandleCastTargetCommand(const char *args); + bool HandleComeToMeCommand(const char *args); + bool HandleCombatStopCommand(const char *args); + + //! Development Commands + bool HandleSetValue(const char* args); + bool HandleGetValue(const char* args); + bool HandleSet32Bit(const char* args); + bool HandleMod32Value(const char* args); + bool HandleAddQuest(const char * args); + bool HandleRemoveQuest(const char * args); + bool HandleCompleteQuest(const char * args); + bool HandleSaveAllCommand(const char* args); + bool HandleGetItemState(const char * args); + bool HandleGetLootRecipient(const char * args); + + Player* getSelectedPlayer(); + Creature* getSelectedCreature(); + Unit* getSelectedUnit(); + char* extractKeyFromLink(char* text, char const* linkType, char** something1 = NULL); + char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL); + uint32 extractSpellIdFromLink(char* text); + GameTele const* extractGameTeleFromLink(char* text); + + GameObject* GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry); + + WorldSession * m_session; + + // Utility methods for commands + void ShowTicket(uint64 guid, char const* text, char const* time); + uint32 GetTicketIDByNum(uint32 num); + bool LookupPlayerSearchCommand(QueryResult* result, int32 limit); + + void SetSentErrorMessage(bool val){ sentErrorMessage = val;}; + private: + // common global flag + static bool load_command_table; + bool sentErrorMessage; +}; +#endif + +char const *fmtstring( char const *format, ... ); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index bab0c16b4e9..b8943f55061 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -1,1993 +1,1928 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Creature.h" -#include "QuestDef.h" -#include "GossipDef.h" -#include "Player.h" -#include "Opcodes.h" -#include "Log.h" -#include "LootMgr.h" -#include "MapManager.h" -#include "CreatureAI.h" -#include "CreatureAISelector.h" -#include "Formulas.h" -#include "SpellAuras.h" -#include "WaypointMovementGenerator.h" -#include "InstanceData.h" -#include "BattleGround.h" -#include "Util.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "CellImpl.h" - -// apply implementation of the singletons -#include "Policies/SingletonImp.h" - -Creature::Creature() : -Unit(), i_AI(NULL), -lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0), -m_itemsLoaded(false), m_trainerSpellsLoaded(false), m_trainer_type(0), m_lootMoney(0), m_lootRecipient(0), -m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f), -m_gossipOptionLoaded(false),m_NPCTextId(0), m_emoteState(0), m_isPet(false), m_isTotem(false), -m_regenTimer(2000), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0), -m_AlreadyCallAssistence(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), -m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),m_creatureInfo(NULL) -{ - m_valuesCount = UNIT_END; - - for(int i =0; i<4; ++i) - m_spells[i] = 0; - - m_CreatureSpellCooldowns.clear(); - m_CreatureCategoryCooldowns.clear(); - m_GlobalCooldown = 0; - m_unit_movement_flags = MOVEMENTFLAG_WALK_MODE; -} - -Creature::~Creature() -{ - CleanupsBeforeDelete(); - - m_trainer_spells.clear(); - m_vendor_items.clear(); - - delete i_AI; - i_AI = NULL; -} - -void Creature::AddToWorld() -{ - ///- Register the creature for guid lookup - if(!IsInWorld()) ObjectAccessor::Instance().AddObject(this); - Unit::AddToWorld(); -} - -void Creature::RemoveFromWorld() -{ - ///- Remove the creature from the accessor - if(IsInWorld()) ObjectAccessor::Instance().RemoveObject(this); - Unit::RemoveFromWorld(); -} - -void Creature::LoadTrainerSpells() -{ - if(m_trainerSpellsLoaded) - return; - - m_trainer_spells.clear(); - m_trainer_type = 0; - - Field *fields; - QueryResult *result = WorldDatabase.PQuery("SELECT spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer WHERE entry = '%u'", GetEntry()); - - if(!result) - return; - - do - { - fields = result->Fetch(); - - uint32 spellid = fields[0].GetUInt32(); - SpellEntry const *spellinfo = sSpellStore.LookupEntry(spellid); - - if(!spellinfo) - { - sLog.outErrorDb("Trainer (Entry: %u ) has non existing spell %u",GetEntry(),spellid); - continue; - } - - if(!SpellMgr::IsSpellValid(spellinfo)) - { - sLog.outErrorDb("LoadTrainerSpells: Trainer (Entry: %u) has broken learning spell %u.", GetEntry(), spellid); - continue; - } - - if(SpellMgr::IsProfessionSpell(spellinfo->Id)) - m_trainer_type = 2; - - TrainerSpell tspell; - tspell.spell = spellinfo; - tspell.spellcost = fields[1].GetUInt32(); - tspell.reqskill = fields[2].GetUInt32(); - tspell.reqskillvalue= fields[3].GetUInt32(); - tspell.reqlevel = fields[4].GetUInt32(); - - m_trainer_spells.push_back(tspell); - - } while( result->NextRow() ); - - delete result; - - m_trainerSpellsLoaded = true; -} - -void Creature::RemoveCorpse() -{ - if( getDeathState()!=CORPSE && !m_isDeadByDefault || getDeathState()!=ALIVE && m_isDeadByDefault ) - return; - - m_deathTimer = 0; - setDeathState(DEAD); - ObjectAccessor::UpdateObjectVisibility(this); - loot.clear(); - m_respawnTime = time(NULL) + m_respawnDelay; - - float x,y,z,o; - GetRespawnCoord(x, y, z, &o); - MapManager::Instance().GetMap(GetMapId(), this)->CreatureRelocation(this,x,y,z,o); -} - -/** - * change the entry of creature until respawn - */ -bool Creature::InitEntry(uint32 Entry, uint32 team, const CreatureData *data ) -{ - CreatureInfo const *normalInfo = objmgr.GetCreatureTemplate(Entry); - if(!normalInfo) - { - sLog.outErrorDb("Creature::UpdateEntry creature entry %u does not exist.", Entry); - return false; - } - - // get heroic mode entry - uint32 actualEntry = Entry; - CreatureInfo const *cinfo = normalInfo; - if(normalInfo->HeroicEntry) - { - Map *map = MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); - if(map && map->IsHeroic()) - { - cinfo = objmgr.GetCreatureTemplate(normalInfo->HeroicEntry); - if(!cinfo) - { - sLog.outErrorDb("Creature::UpdateEntry creature heroic entry %u does not exist.", actualEntry); - return false; - } - } - } - - SetUInt32Value(OBJECT_FIELD_ENTRY, Entry); // normal entry always - m_creatureInfo = cinfo; // map mode related always - - if (cinfo->DisplayID_A == 0 || cinfo->DisplayID_H == 0) // Cancel load if no model defined - { - sLog.outErrorDb("Creature (Entry: %u) has no model defined for Horde or Alliance in table `creature_template`, can't load. ",Entry); - return false; - } - - uint32 display_id = objmgr.ChooseDisplayId(team, GetCreatureInfo(), data); - CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id); - if (!minfo) - { - sLog.outErrorDb("Creature (Entry: %u) has model %u not found in table `creature_model_info`, can't load. ", Entry, display_id); - return false; - } - else - display_id = minfo->modelid; // it can be different (for another gender) - - SetDisplayId(display_id); - SetNativeDisplayId(display_id); - SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); - - // Load creature equipment - if(!data || data->equipmentId == 0) - { // use default from the template - LoadEquipment(cinfo->equipmentId); - } - else if(data && data->equipmentId != -1) - { // override, -1 means no equipment - LoadEquipment(data->equipmentId); - } - - SetName(normalInfo->Name); // at normal entry always - - SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,minfo->bounding_radius); - SetFloatValue(UNIT_FIELD_COMBATREACH,minfo->combat_reach ); - - SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); - - SetSpeed(MOVE_WALK, cinfo->speed ); - SetSpeed(MOVE_RUN, cinfo->speed ); - SetSpeed(MOVE_SWIM, cinfo->speed ); - - SetFloatValue(OBJECT_FIELD_SCALE_X, cinfo->scale); - - // checked at loading - m_defaultMovementType = MovementGeneratorType(cinfo->MovementType); - if(!m_respawnradius && m_defaultMovementType==RANDOM_MOTION_TYPE) - m_defaultMovementType = IDLE_MOTION_TYPE; - - return true; -} - -bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data ) -{ - if(!InitEntry(Entry,team,data)) - return false; - - m_regenHealth = GetCreatureInfo()->RegenHealth; - - // creatures always have melee weapon ready if any - SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); - SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_AURAS ); - - SelectLevel(GetCreatureInfo()); - if (team == HORDE) - SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, GetCreatureInfo()->faction_H); - else - SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, GetCreatureInfo()->faction_A); - - SetUInt32Value(UNIT_NPC_FLAGS,GetCreatureInfo()->npcflag); - - SetAttackTime(BASE_ATTACK, GetCreatureInfo()->baseattacktime); - SetAttackTime(OFF_ATTACK, GetCreatureInfo()->baseattacktime); - SetAttackTime(RANGED_ATTACK,GetCreatureInfo()->rangeattacktime); - - SetUInt32Value(UNIT_FIELD_FLAGS,GetCreatureInfo()->Flags); - SetUInt32Value(UNIT_DYNAMIC_FLAGS,GetCreatureInfo()->dynamicflags); - - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->armor)); - SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1)); - SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2)); - SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->resistance3)); - SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->resistance4)); - SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->resistance5)); - SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->resistance6)); - - SetCanModifyStats(true); - UpdateAllStats(); - - FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(GetCreatureInfo()->faction_A); - if (factionTemplate) // check and error show at loading templates - { - FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->faction); - if (factionEntry) - if( !(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN) && - (factionEntry->team == ALLIANCE || factionEntry->team == HORDE) ) - SetPvP(true); - } - - m_spells[0] = GetCreatureInfo()->spell1; - m_spells[1] = GetCreatureInfo()->spell2; - m_spells[2] = GetCreatureInfo()->spell3; - m_spells[3] = GetCreatureInfo()->spell4; - - return true; -} - -void Creature::Update(uint32 diff) -{ - if(m_GlobalCooldown <= diff) - m_GlobalCooldown = 0; - else - m_GlobalCooldown -= diff; - - switch( m_deathState ) - { - case JUST_ALIVED: - // Dont must be called, see Creature::setDeathState JUST_ALIVED -> ALIVE promoting. - sLog.outError("Creature (GUIDLow: %u Entry: %u ) in wrong state: JUST_ALIVED (4)",GetGUIDLow(),GetEntry()); - break; - case JUST_DIED: - // Dont must be called, see Creature::setDeathState JUST_DIED -> CORPSE promoting. - sLog.outError("Creature (GUIDLow: %u Entry: %u ) in wrong state: JUST_DEAD (1)",GetGUIDLow(),GetEntry()); - break; - case DEAD: - { - if( m_respawnTime <= time(NULL) ) - { - DEBUG_LOG("Respawning..."); - m_respawnTime = 0; - lootForPickPocketed = false; - lootForBody = false; - - if(m_originalEntry != GetUInt32Value(OBJECT_FIELD_ENTRY)) - UpdateEntry(m_originalEntry); - - CreatureInfo const *cinfo = GetCreatureInfo(); - - SelectLevel(cinfo); - SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - if (m_isDeadByDefault) - { - setDeathState(JUST_DIED); - SetHealth(0); - i_motionMaster.Clear(); - clearUnitState(UNIT_STAT_ALL_STATE); - LoadCreaturesAddon(true); - } - else - setDeathState( JUST_ALIVED ); - - //Call AI respawn virtual function - i_AI->JustRespawned(); - - MapManager::Instance().GetMap(GetMapId(), this)->Add(this); - } - break; - } - case CORPSE: - { - if (m_isDeadByDefault) - break; - - if( m_deathTimer <= diff ) - { - RemoveCorpse(); - DEBUG_LOG("Removing corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY)); - } - else - { - m_deathTimer -= diff; - if (m_groupLootTimer && lootingGroupLeaderGUID) - { - if(diff <= m_groupLootTimer) - { - m_groupLootTimer -= diff; - } - else - { - Group* group = objmgr.GetGroupByLeader(lootingGroupLeaderGUID); - if (group) - group->EndRoll(); - m_groupLootTimer = 0; - lootingGroupLeaderGUID = 0; - } - } - } - - break; - } - case ALIVE: - { - if (m_isDeadByDefault) - { - if( m_deathTimer <= diff ) - { - RemoveCorpse(); - DEBUG_LOG("Removing alive corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY)); - } - else - { - m_deathTimer -= diff; - } - } - - Unit::Update( diff ); - - // creature can be dead after Unit::Update call - // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) - if(!isAlive()) - break; - - if(!IsInEvadeMode()) - { - // do not allow the AI to be changed during update - m_AI_locked = true; - i_AI->UpdateAI(diff); - m_AI_locked = false; - } - - // creature can be dead after UpdateAI call - // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) - if(!isAlive()) - break; - if(m_regenTimer > 0) - { - if(diff >= m_regenTimer) - m_regenTimer = 0; - else - m_regenTimer -= diff; - } - if (m_regenTimer != 0) - break; - - if (!isInCombat() || IsPolymorphed()) - RegenerateHealth(); - - RegenerateMana(); - - m_regenTimer = 2000; - break; - } - default: - break; - } -} - -void Creature::RegenerateMana() -{ - uint32 curValue = GetPower(POWER_MANA); - uint32 maxValue = GetMaxPower(POWER_MANA); - - if (curValue >= maxValue) - return; - - uint32 addvalue = 0; - - // Combat and any controlled creature - if (isInCombat() || GetCharmerOrOwnerGUID()) - { - if(!IsUnderLastManaUseEffect()) - { - float ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA); - float Spirit = GetStat(STAT_SPIRIT); - - addvalue = uint32((Spirit/5.0f + 17.0f) * ManaIncreaseRate); - } - } - else - addvalue = maxValue/3; - - ModifyPower(POWER_MANA, addvalue); -} - -void Creature::RegenerateHealth() -{ - if (!isRegeneratingHealth()) - return; - - uint32 curValue = GetHealth(); - uint32 maxValue = GetMaxHealth(); - - if (curValue >= maxValue) - return; - - uint32 addvalue = 0; - - // Not only pet, but any controelled creature - if(GetCharmerOrOwnerGUID()) - { - float HealthIncreaseRate = sWorld.getRate(RATE_HEALTH); - float Spirit = GetStat(STAT_SPIRIT); - - if( GetPower(POWER_MANA) > 0 ) - addvalue = uint32(Spirit * 0.25 * HealthIncreaseRate); - else - addvalue = uint32(Spirit * 0.80 * HealthIncreaseRate); - } - else - addvalue = maxValue/3; - - ModifyHealth(addvalue); -} - -bool Creature::AIM_Initialize() -{ - // make sure nothing can change the AI during AI update - if(m_AI_locked) - { - sLog.outDebug("AIM_Initialize: failed to init, locked."); - return false; - } - - CreatureAI * oldAI = i_AI; - i_motionMaster.Initialize(); - i_AI = FactorySelector::selectAI(this); - if (oldAI) - delete oldAI; - return true; -} - -bool Creature::Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, const CreatureData *data) -{ - SetMapId(map->GetId()); - SetInstanceId(map->GetInstanceId()); - - //oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0; - const bool bResult = CreateFromProto(guidlow, Entry, team, data); - - if (bResult) - { - switch (GetCreatureInfo()->rank) - { - case CREATURE_ELITE_RARE: - m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_RARE); - break; - case CREATURE_ELITE_ELITE: - m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_ELITE); - break; - case CREATURE_ELITE_RAREELITE: - m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_RAREELITE); - break; - case CREATURE_ELITE_WORLDBOSS: - m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_WORLDBOSS); - break; - default: - m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_NORMAL); - break; - } - } - - return bResult; -} - -bool Creature::isCanTrainingOf(Player* pPlayer, bool msg) const -{ - if(!isTrainer()) - return false; - - if(m_trainer_spells.empty()) - { - sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_TRAINER but have empty trainer spell list.", - GetGUIDLow(),GetEntry()); - return false; - } - - switch(GetCreatureInfo()->trainer_type) - { - case TRAINER_TYPE_CLASS: - if(pPlayer->getClass()!=GetCreatureInfo()->classNum) - { - if(msg) - { - pPlayer->PlayerTalkClass->ClearMenus(); - switch(GetCreatureInfo()->classNum) - { - case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu( 4913,GetGUID()); break; - case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090,GetGUID()); break; - case CLASS_MAGE: pPlayer->PlayerTalkClass->SendGossipMenu( 328,GetGUID()); break; - case CLASS_PALADIN:pPlayer->PlayerTalkClass->SendGossipMenu( 1635,GetGUID()); break; - case CLASS_PRIEST: pPlayer->PlayerTalkClass->SendGossipMenu( 4436,GetGUID()); break; - case CLASS_ROGUE: pPlayer->PlayerTalkClass->SendGossipMenu( 4797,GetGUID()); break; - case CLASS_SHAMAN: pPlayer->PlayerTalkClass->SendGossipMenu( 5003,GetGUID()); break; - case CLASS_WARLOCK:pPlayer->PlayerTalkClass->SendGossipMenu( 5836,GetGUID()); break; - case CLASS_WARRIOR:pPlayer->PlayerTalkClass->SendGossipMenu( 4985,GetGUID()); break; - } - } - return false; - } - break; - case TRAINER_TYPE_PETS: - if(pPlayer->getClass()!=CLASS_HUNTER) - { - pPlayer->PlayerTalkClass->ClearMenus(); - pPlayer->PlayerTalkClass->SendGossipMenu(3620,GetGUID()); - return false; - } - break; - case TRAINER_TYPE_MOUNTS: - if(GetCreatureInfo()->race && pPlayer->getRace() != GetCreatureInfo()->race) - { - if(msg) - { - pPlayer->PlayerTalkClass->ClearMenus(); - switch(GetCreatureInfo()->classNum) - { - case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865,GetGUID()); break; - case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881,GetGUID()); break; - case RACE_HUMAN: pPlayer->PlayerTalkClass->SendGossipMenu(5861,GetGUID()); break; - case RACE_NIGHTELF: pPlayer->PlayerTalkClass->SendGossipMenu(5862,GetGUID()); break; - case RACE_ORC: pPlayer->PlayerTalkClass->SendGossipMenu(5863,GetGUID()); break; - case RACE_TAUREN: pPlayer->PlayerTalkClass->SendGossipMenu(5864,GetGUID()); break; - case RACE_TROLL: pPlayer->PlayerTalkClass->SendGossipMenu(5816,GetGUID()); break; - case RACE_UNDEAD_PLAYER:pPlayer->PlayerTalkClass->SendGossipMenu( 624,GetGUID()); break; - case RACE_BLOODELF: pPlayer->PlayerTalkClass->SendGossipMenu(5862,GetGUID()); break; - case RACE_DRAENEI: pPlayer->PlayerTalkClass->SendGossipMenu(5864,GetGUID()); break; - } - } - return false; - } - break; - case TRAINER_TYPE_TRADESKILLS: - if(GetCreatureInfo()->trainer_spell && !pPlayer->HasSpell(GetCreatureInfo()->trainer_spell)) - { - if(msg) - { - pPlayer->PlayerTalkClass->ClearMenus(); - pPlayer->PlayerTalkClass->SendGossipMenu(11031,GetGUID()); - } - return false; - } - break; - default: - return false; // checked and error output at creature_template loading - } - return true; -} - -bool Creature::isCanIneractWithBattleMaster(Player* pPlayer, bool msg) const -{ - if(!isBattleMaster()) - return false; - - uint32 bgTypeId = objmgr.GetBattleMasterBG(GetEntry()); - if(!msg) - return pPlayer->GetBGAccessByLevel(bgTypeId); - - if(!pPlayer->GetBGAccessByLevel(bgTypeId)) - { - pPlayer->PlayerTalkClass->ClearMenus(); - switch(bgTypeId) - { - case BATTLEGROUND_AV: pPlayer->PlayerTalkClass->SendGossipMenu(7616,GetGUID()); break; - case BATTLEGROUND_WS: pPlayer->PlayerTalkClass->SendGossipMenu(7599,GetGUID()); break; - case BATTLEGROUND_AB: pPlayer->PlayerTalkClass->SendGossipMenu(7642,GetGUID()); break; - case BATTLEGROUND_EY: - case BATTLEGROUND_NA: - case BATTLEGROUND_BE: - case BATTLEGROUND_AA: - case BATTLEGROUND_RL: pPlayer->PlayerTalkClass->SendGossipMenu(10024,GetGUID()); break; - break; - } - return false; - } - return true; -} - -bool Creature::isCanTrainingAndResetTalentsOf(Player* pPlayer) const -{ - return pPlayer->getLevel() >= 10 - && GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS - && pPlayer->getClass() == GetCreatureInfo()->classNum; -} - -void Creature::prepareGossipMenu( Player *pPlayer,uint32 gossipid ) -{ - PlayerMenu* pm=pPlayer->PlayerTalkClass; - pm->ClearMenus(); - - // lazy loading single time at use - LoadGossipOptions(); - - GossipOption* gso; - GossipOption* ingso; - - for( GossipOptionList::iterator i = m_goptions.begin( ); i != m_goptions.end( ); i++ ) - { - gso=&*i; - if(gso->GossipId == gossipid) - { - bool cantalking=true; - if(gso->Id==1) - { - uint32 textid=GetNpcTextId(); - GossipText * gossiptext=objmgr.GetGossipText(textid); - if(!gossiptext) - cantalking=false; - } - else - { - switch (gso->Action) - { - case GOSSIP_OPTION_QUESTGIVER: - pPlayer->PrepareQuestMenu(GetGUID()); - //if (pm->GetQuestMenu()->MenuItemCount() == 0) - cantalking=false; - //pm->GetQuestMenu()->ClearMenu(); - break; - case GOSSIP_OPTION_ARMORER: - cantalking=false; // added in special mode - break; - case GOSSIP_OPTION_SPIRITHEALER: - if( !pPlayer->isDead() ) - cantalking=false; - break; - case GOSSIP_OPTION_VENDOR: - // load vendor items if not yet - LoadGoods(); - - if(!GetItemCount()) - { - sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", - GetGUIDLow(),GetEntry()); - cantalking=false; - } - break; - case GOSSIP_OPTION_TRAINER: - // Lazy loading at first access - LoadTrainerSpells(); - - if(!isCanTrainingOf(pPlayer,false)) - cantalking=false; - break; - case GOSSIP_OPTION_UNLEARNTALENTS: - if(!isCanTrainingAndResetTalentsOf(pPlayer)) - cantalking=false; - break; - case GOSSIP_OPTION_UNLEARNPETSKILLS: - if(!pPlayer->GetPet() || pPlayer->GetPet()->getPetType() != HUNTER_PET || pPlayer->GetPet()->m_spells.size() <= 1 || GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || GetCreatureInfo()->classNum != CLASS_HUNTER) - cantalking=false; - break; - case GOSSIP_OPTION_TAXIVENDOR: - if ( pPlayer->GetSession()->SendLearnNewTaxiNode(this) ) - return; - break; - case GOSSIP_OPTION_BATTLEFIELD: - if(!isCanIneractWithBattleMaster(pPlayer,false)) - cantalking=false; - break; - case GOSSIP_OPTION_SPIRITGUIDE: - case GOSSIP_OPTION_INNKEEPER: - case GOSSIP_OPTION_BANKER: - case GOSSIP_OPTION_PETITIONER: - case GOSSIP_OPTION_STABLEPET: - case GOSSIP_OPTION_TABARDDESIGNER: - case GOSSIP_OPTION_AUCTIONEER: - break; // no checks - default: - sLog.outErrorDb("Creature %u (entry: %u) have unknown gossip option %u",GetGUIDLow(),GetEntry(),gso->Action); - break; - } - } - - if(!gso->Option.empty() && cantalking ) - { //note for future dev: should have database fields for BoxMessage & BoxMoney - pm->GetGossipMenu()->AddMenuItem((uint8)gso->Icon,gso->Option, gossipid,gso->Action,"",0,false); - ingso=gso; - } - } - } - - ///some gossips aren't handled in normal way ... so we need to do it this way .. TODO: handle it in normal way ;-) - if(pm->GetGossipMenu()->MenuItemCount()==0 && !pm->GetQuestMenu()->MenuItemCount()) - { - if(HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_TRAINER)) - { - LoadTrainerSpells(); // Lazy loading at first access - isCanTrainingOf(pPlayer,true); // output error message if need - } - if(HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_BATTLEMASTER)) - { - isCanIneractWithBattleMaster(pPlayer,true); // output error message if need - } - } -} - -void Creature::sendPreparedGossip(Player* player) -{ - if(!player) - return; - - GossipMenu* gossipmenu = player->PlayerTalkClass->GetGossipMenu(); - - // in case empty gossip menu open quest menu if any - if (gossipmenu->MenuItemCount() == 0 && GetNpcTextId() == 0) - { - player->SendPreparedQuest(GetGUID()); - return; - } - - // in case non empty gossip menu (that not included quests list size) show it - // (quest entries from quest menu wiill be included in list) - player->PlayerTalkClass->SendGossipMenu(GetNpcTextId(), GetGUID()); -} - -void Creature::OnGossipSelect(Player* player, uint32 option) -{ - GossipMenu* gossipmenu = player->PlayerTalkClass->GetGossipMenu(); - uint32 action=gossipmenu->GetItem(option).m_gAction; - uint32 zoneid=GetZoneId(); - uint64 guid=GetGUID(); - GossipOption const *gossip=GetGossipOption( action ); - uint32 textid; - if(!gossip) - { - zoneid=0; - gossip=GetGossipOption( action ); - if(!gossip) - return; - } - textid=GetGossipTextId( action, zoneid); - if(textid==0) - textid=GetNpcTextId(); - - switch (gossip->Action) - { - case GOSSIP_OPTION_GOSSIP: - player->PlayerTalkClass->CloseGossip(); - player->PlayerTalkClass->SendTalking( textid ); - break; - case GOSSIP_OPTION_SPIRITHEALER: - if( player->isDead() ) - CastSpell(this,17251,true,NULL,NULL,player->GetGUID()); - break; - case GOSSIP_OPTION_QUESTGIVER: - player->PrepareQuestMenu( guid ); - player->SendPreparedQuest( guid ); - break; - case GOSSIP_OPTION_VENDOR: - case GOSSIP_OPTION_ARMORER: - player->GetSession()->SendListInventory(guid); - break; - case GOSSIP_OPTION_STABLEPET: - player->GetSession()->SendStablePet(guid); - break; - case GOSSIP_OPTION_TRAINER: - player->GetSession()->SendTrainerList(guid); - break; - case GOSSIP_OPTION_UNLEARNTALENTS: - player->PlayerTalkClass->CloseGossip(); - player->SendTalentWipeConfirm(guid); - break; - case GOSSIP_OPTION_UNLEARNPETSKILLS: - player->PlayerTalkClass->CloseGossip(); - player->SendPetSkillWipeConfirm(); - break; - case GOSSIP_OPTION_TAXIVENDOR: - player->GetSession()->SendTaxiMenu(this); - break; - case GOSSIP_OPTION_INNKEEPER: - player->PlayerTalkClass->CloseGossip(); - player->SetBindPoint( guid ); - break; - case GOSSIP_OPTION_BANKER: - player->GetSession()->SendShowBank( guid ); - break; - case GOSSIP_OPTION_PETITIONER: - player->PlayerTalkClass->CloseGossip(); - player->GetSession()->SendPetitionShowList( guid ); - break; - case GOSSIP_OPTION_TABARDDESIGNER: - player->PlayerTalkClass->CloseGossip(); - player->GetSession()->SendTabardVendorActivate( guid ); - break; - case GOSSIP_OPTION_AUCTIONEER: - player->GetSession()->SendAuctionHello( guid, this ); - break; - case GOSSIP_OPTION_SPIRITGUIDE: - case GOSSIP_GUARD_SPELLTRAINER: - case GOSSIP_GUARD_SKILLTRAINER: - prepareGossipMenu( player,gossip->Id ); - sendPreparedGossip( player ); - break; - case GOSSIP_OPTION_BATTLEFIELD: - { - uint32 bgTypeId = objmgr.GetBattleMasterBG(GetEntry()); - player->GetSession()->SendBattlegGroundList( GetGUID(), bgTypeId ); - break; - } - default: - OnPoiSelect( player, gossip ); - break; - } - -} - -void Creature::OnPoiSelect(Player* player, GossipOption const *gossip) -{ - if(gossip->GossipId==GOSSIP_GUARD_SPELLTRAINER || gossip->GossipId==GOSSIP_GUARD_SKILLTRAINER) - { - //float x,y; - //bool findnpc=false; - Poi_Icon icon = ICON_POI_0; - //QueryResult *result; - //Field *fields; - uint32 mapid=GetMapId(); - Map const* map=MapManager::Instance().GetBaseMap( mapid ); - uint16 areaflag=map->GetAreaFlag(GetPositionX(),GetPositionY()); - uint32 zoneid=Map::GetZoneId(areaflag,mapid); - std::string areaname= gossip->Option; - /* - uint16 pflag; - - // use the action relate to creaturetemplate.trainer_type ? - result= WorldDatabase.PQuery("SELECT creature.position_x,creature.position_y FROM creature,creature_template WHERE creature.map = '%u' AND creature.id = creature_template.entry AND creature_template.trainer_type = '%u'", mapid, gossip->Action ); - if(!result) - return; - do - { - fields = result->Fetch(); - x=fields[0].GetFloat(); - y=fields[1].GetFloat(); - pflag=map->GetAreaFlag(GetPositionX(),GetPositionY()); - if(pflag==areaflag) - { - findnpc=true; - break; - } - }while(result->NextRow()); - - delete result; - - if(!findnpc) - { - player->PlayerTalkClass->SendTalking( "$NSorry", "Here no this person."); - return; - }*/ - - //need add more case. - switch(gossip->Action) - { - case GOSSIP_GUARD_BANK: - icon=ICON_POI_HOUSE; - break; - case GOSSIP_GUARD_RIDE: - icon=ICON_POI_RWHORSE; - break; - case GOSSIP_GUARD_GUILD: - icon=ICON_POI_BLUETOWER; - break; - default: - icon=ICON_POI_TOWER; - break; - } - uint32 textid=GetGossipTextId( gossip->Action, zoneid ); - player->PlayerTalkClass->SendTalking( textid ); - // how this could worked player->PlayerTalkClass->SendPointOfInterest( x, y, icon, 2, 15, areaname.c_str() ); - } -} - -uint32 Creature::GetGossipTextId(uint32 action, uint32 zoneid) -{ - QueryResult *result= WorldDatabase.PQuery("SELECT textid FROM npc_gossip_textid WHERE action = '%u' AND zoneid ='%u'", action, zoneid ); - - if(!result) - return 0; - - Field *fields = result->Fetch(); - uint32 id = fields[0].GetUInt32(); - - delete result; - - return id; -} - -uint32 Creature::GetNpcTextId() -{ - // already loaded and cached - if(m_NPCTextId) - return m_NPCTextId; - - QueryResult* result = WorldDatabase.PQuery("SELECT textid FROM npc_gossip WHERE npc_guid= '%u'", m_DBTableGuid); - if(result) - { - Field *fields = result->Fetch(); - m_NPCTextId = fields[0].GetUInt32(); - delete result; - } - else - m_NPCTextId = DEFAULT_GOSSIP_MESSAGE; - - return m_NPCTextId; -} - -GossipOption const* Creature::GetGossipOption( uint32 id ) const -{ - for( GossipOptionList::const_iterator i = m_goptions.begin( ); i != m_goptions.end( ); i++ ) - { - if(i->Action==id ) - return &*i; - } - return NULL; -} - -void Creature::LoadGossipOptions() -{ - if(m_gossipOptionLoaded) - return; - - uint32 npcflags=GetUInt32Value(UNIT_NPC_FLAGS); - - QueryResult *result = WorldDatabase.PQuery( "SELECT id,gossip_id,npcflag,icon,action,option_text FROM npc_option WHERE (npcflag & %u)<>0", npcflags ); - - if(!result) - return; - - GossipOption go; - do - { - Field *fields = result->Fetch(); - go.Id= fields[0].GetUInt32(); - go.GossipId = fields[1].GetUInt32(); - go.NpcFlag=fields[2].GetUInt32(); - go.Icon=fields[3].GetUInt32(); - go.Action=fields[4].GetUInt32(); - go.Option=fields[5].GetCppString(); - addGossipOption(go); - }while( result->NextRow() ); - delete result; - - m_gossipOptionLoaded = true; -} - -void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type) -{ - /* uint32 timeElap = getMSTime(); - if ((timeElap - m_startMove) < m_moveTime) - { - oX = (dX - oX) * ( (timeElap - m_startMove) / m_moveTime ); - oY = (dY - oY) * ( (timeElap - m_startMove) / m_moveTime ); - } - else - { - oX = dX; - oY = dY; - } - - dX = x; - dY = y; - m_orientation = atan2((oY - dY), (oX - dX)); - - m_startMove = getMSTime(); - m_moveTime = time;*/ - SendMonsterMove(x, y, z, type, MovementFlags, time); -} - -Player *Creature::GetLootRecipient() const -{ - if (!m_lootRecipient) return NULL; - else return ObjectAccessor::FindPlayer(m_lootRecipient); -} - -void Creature::SetLootRecipient(Unit *unit) -{ - // set the player whose group should receive the right - // to loot the creature after it dies - // should be set to NULL after the loot disappears - - if (!unit) - { - m_lootRecipient = 0; - RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER); - return; - } - - Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself(); - if(!player) // normal creature, no player involved - return; - - m_lootRecipient = player->GetGUID(); - SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER); -} - -void Creature::SaveToDB() -{ - // this should only be used when the creature has already been loaded - // perferably after adding to map, because mapid may not be valid otherwise - CreatureData const *data = objmgr.GetCreatureData(m_DBTableGuid); - if(!data) - { - sLog.outError("Creature::SaveToDB failed, cannot get creature data!"); - return; - } - - SaveToDB(GetMapId(), data->spawnMask); -} - -void Creature::SaveToDB(uint32 mapid, uint8 spawnMask) -{ - // update in loaded data - CreatureData& data = objmgr.NewOrExistCreatureData(m_DBTableGuid); - - uint32 displayId = GetNativeDisplayId(); - - // check if it's a custom model and if not, use 0 for displayId - CreatureInfo const *cinfo = GetCreatureInfo(); - if(cinfo) - { - if(displayId != cinfo->DisplayID_A && displayId != cinfo->DisplayID_H) - { - CreatureModelInfo const *minfo = objmgr.GetCreatureModelInfo(cinfo->DisplayID_A); - if(!minfo || displayId != minfo->modelid_other_gender) - { - minfo = objmgr.GetCreatureModelInfo(cinfo->DisplayID_H); - if(minfo && displayId == minfo->modelid_other_gender) - displayId = 0; - } - else - displayId = 0; - } - else - displayId = 0; - } - - // data->guid = guid don't must be update at save - data.id = GetEntry(); - data.mapid = mapid; - data.displayid = displayId; - data.equipmentId = GetEquipmentId(); - data.posX = GetPositionX(); - data.posY = GetPositionY(); - data.posZ = GetPositionZ(); - data.orientation = GetOrientation(); - data.spawntimesecs = m_respawnDelay; - // prevent add data integrity problems - data.spawndist = GetDefaultMovementType()==IDLE_MOTION_TYPE ? 0 : m_respawnradius; - data.currentwaypoint = 0; - data.curhealth = GetHealth(); - data.curmana = GetPower(POWER_MANA); - data.is_dead = m_isDeadByDefault; - // prevent add data integrity problems - data.movementType = !m_respawnradius && GetDefaultMovementType()==RANDOM_MOTION_TYPE - ? IDLE_MOTION_TYPE : GetDefaultMovementType(); - data.spawnMask = spawnMask; - - // updated in DB - WorldDatabase.BeginTransaction(); - - WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid); - - std::ostringstream ss; - ss << "INSERT INTO creature VALUES (" - << m_DBTableGuid << "," - << GetEntry() << "," - << mapid <<"," - << (uint32)spawnMask << "," - << displayId <<"," - << GetEquipmentId() <<"," - << GetPositionX() << "," - << GetPositionY() << "," - << GetPositionZ() << "," - << GetOrientation() << "," - << m_respawnDelay << "," //respawn time - << (float) m_respawnradius << "," //spawn distance (float) - << (uint32) (0) << "," //currentwaypoint - << GetHealth() << "," //curhealth - << GetPower(POWER_MANA) << "," //curmana - << (m_isDeadByDefault ? 1 : 0) << "," //is_dead - << GetDefaultMovementType() << ")"; //default movement generator type - - WorldDatabase.PExecuteLog( ss.str( ).c_str( ) ); - - WorldDatabase.CommitTransaction(); -} - -void Creature::SelectLevel(const CreatureInfo *cinfo) -{ - uint32 rank = isPet()? 0 : cinfo->rank; - - // level - uint32 minlevel = std::min(cinfo->maxlevel, cinfo->minlevel); - uint32 maxlevel = std::max(cinfo->maxlevel, cinfo->minlevel); - uint32 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel); - SetLevel(level); - - float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel))/(maxlevel - minlevel); - - // health - float healthmod = _GetHealthMod(rank); - - uint32 minhealth = std::min(cinfo->maxhealth, cinfo->minhealth); - uint32 maxhealth = std::max(cinfo->maxhealth, cinfo->minhealth); - uint32 health = uint32(healthmod * (minhealth + uint32(rellevel*(maxhealth - minhealth)))); - - SetCreateHealth(health); - SetMaxHealth(health); - SetHealth(health); - - // mana - uint32 minmana = std::min(cinfo->maxmana, cinfo->minmana); - uint32 maxmana = std::max(cinfo->maxmana, cinfo->minmana); - uint32 mana = minmana + uint32(rellevel*(maxmana - minmana)); - - SetCreateMana(mana); - SetMaxPower(POWER_MANA, mana); //MAX Mana - SetPower(POWER_MANA, mana); - - SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, health); - SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, mana); - - // damage - float damagemod = _GetDamageMod(rank); - - SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); - SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); - - SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,cinfo->minrangedmg * damagemod); - SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,cinfo->maxrangedmg * damagemod); - - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod); -} - -float Creature::_GetHealthMod(int32 Rank) -{ - switch (Rank) // define rates for each elite rank - { - case CREATURE_ELITE_NORMAL: - return sWorld.getRate(RATE_CREATURE_NORMAL_HP); - case CREATURE_ELITE_ELITE: - return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_HP); - case CREATURE_ELITE_RAREELITE: - return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_HP); - case CREATURE_ELITE_WORLDBOSS: - return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_HP); - case CREATURE_ELITE_RARE: - return sWorld.getRate(RATE_CREATURE_ELITE_RARE_HP); - default: - return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_HP); - } -} - -float Creature::_GetDamageMod(int32 Rank) -{ - switch (Rank) // define rates for each elite rank - { - case CREATURE_ELITE_NORMAL: - return sWorld.getRate(RATE_CREATURE_NORMAL_DAMAGE); - case CREATURE_ELITE_ELITE: - return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE); - case CREATURE_ELITE_RAREELITE: - return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_DAMAGE); - case CREATURE_ELITE_WORLDBOSS: - return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE); - case CREATURE_ELITE_RARE: - return sWorld.getRate(RATE_CREATURE_ELITE_RARE_DAMAGE); - default: - return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE); - } -} - -float Creature::GetSpellDamageMod(int32 Rank) -{ - switch (Rank) // define rates for each elite rank - { - case CREATURE_ELITE_NORMAL: - return sWorld.getRate(RATE_CREATURE_NORMAL_SPELLDAMAGE); - case CREATURE_ELITE_ELITE: - return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE); - case CREATURE_ELITE_RAREELITE: - return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE); - case CREATURE_ELITE_WORLDBOSS: - return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE); - case CREATURE_ELITE_RARE: - return sWorld.getRate(RATE_CREATURE_ELITE_RARE_SPELLDAMAGE); - default: - return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE); - } -} - -bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 team, const CreatureData *data) -{ - CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(Entry); - if(!cinfo) - { - sLog.outErrorDb("Error: creature entry %u does not exist.", Entry); - return false; - } - m_originalEntry = Entry; - - Object::_Create(guidlow, Entry, HIGHGUID_UNIT); - - m_DBTableGuid = guidlow; - if(!UpdateEntry(Entry, team, data)) - return false; - - //Notify the map's instance data. - //Only works if you create the object in it, not if it is moves to that map. - //Normally non-players do not teleport to other maps. - Map *map = MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); - if(map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) - { - ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this, Entry); - } - - return true; -} - -bool Creature::LoadFromDB(uint32 guid, Map *map) -{ - CreatureData const* data = objmgr.GetCreatureData(guid); - - if(!data) - { - sLog.outErrorDb("Creature (GUID: %u) not found in table `creature`, can't load. ",guid); - return false; - } - - uint32 stored_guid = guid; - if (map->GetInstanceId() != 0) guid = objmgr.GenerateLowGuid(HIGHGUID_UNIT); - - uint16 team = 0; - if(!Create(guid,map,data->id,team,data)) - return false; - - Relocate(data->posX,data->posY,data->posZ,data->orientation); - - if(!IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",GetGUIDLow(),GetEntry(),GetPositionX(),GetPositionY()); - return false; - } - - m_DBTableGuid = stored_guid; - LoadCreaturesAddon(); - - m_respawnradius = data->spawndist; - - m_respawnDelay = data->spawntimesecs; - m_isDeadByDefault = data->is_dead; - m_deathState = m_isDeadByDefault ? DEAD : ALIVE; - - m_respawnTime = objmgr.GetCreatureRespawnTime(m_DBTableGuid,GetInstanceId()); - if(m_respawnTime > time(NULL)) // not ready to respawn - m_deathState = DEAD; - else if(m_respawnTime) // respawn time set but expired - { - m_respawnTime = 0; - objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); - } - - uint32 curhealth = data->curhealth; - if(curhealth) - { - curhealth = uint32(curhealth*_GetHealthMod(GetCreatureInfo()->rank)); - if(curhealth < 1) - curhealth = 1; - } - - SetHealth(m_deathState == ALIVE ? curhealth : 0); - SetPower(POWER_MANA,data->curmana); - - SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool)); - - // checked at creature_template loading - m_defaultMovementType = MovementGeneratorType(data->movementType); - - AIM_Initialize(); - return true; -} - -void Creature::LoadEquipment(uint32 equip_entry, bool force) -{ - if(equip_entry == 0) - { - if (force) - { - for (uint8 i=0;i<3;i++) - { - SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + i, 0); - SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2), 0); - SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2) + 1, 0); - } - m_equipmentId = 0; - } - return; - } - - EquipmentInfo const *einfo = objmgr.GetEquipmentInfo(equip_entry); - if (!einfo) - return; - - m_equipmentId = equip_entry; - for (uint8 i=0;i<3;i++) - { - SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + i, einfo->equipmodel[i]); - SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2), einfo->equipinfo[i]); - SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2) + 1, einfo->equipslot[i]); - } -} - -void Creature::LoadGoods() -{ - // already loaded; - if(m_itemsLoaded) - return; - - m_vendor_items.clear(); - - QueryResult *result = WorldDatabase.PQuery("SELECT item, maxcount, incrtime, ExtendedCost FROM npc_vendor WHERE entry = '%u'", GetEntry()); - - if(!result) - return; - - do - { - Field *fields = result->Fetch(); - - if (GetItemCount() >= MAX_VENDOR_ITEMS) - { - sLog.outErrorDb( "Vendor %u has too many items (%u >= %i). Check the DB!", GetEntry(), GetItemCount(), MAX_VENDOR_ITEMS ); - break; - } - - uint32 item_id = fields[0].GetUInt32(); - if(!sItemStorage.LookupEntry(item_id)) - { - sLog.outErrorDb("Vendor %u have in item list non-existed item %u",GetEntry(),item_id); - continue; - } - - uint32 ExtendedCost = fields[3].GetUInt32(); - if(ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) - sLog.outErrorDb("Item (Entry: %u) has wrong ExtendedCost (%u) for vendor (%u)",item_id,ExtendedCost,GetEntry()); - - AddItem( item_id, fields[1].GetUInt32(), fields[2].GetUInt32(), ExtendedCost); - } - while( result->NextRow() ); - - delete result; - - m_itemsLoaded = true; -} - -bool Creature::hasQuest(uint32 quest_id) const -{ - QuestRelations const& qr = objmgr.mCreatureQuestRelations; - for(QuestRelations::const_iterator itr = qr.lower_bound(GetEntry()); itr != qr.upper_bound(GetEntry()); ++itr) - { - if(itr->second==quest_id) - return true; - } - return false; -} - -bool Creature::hasInvolvedQuest(uint32 quest_id) const -{ - QuestRelations const& qr = objmgr.mCreatureQuestInvolvedRelations; - for(QuestRelations::const_iterator itr = qr.lower_bound(GetEntry()); itr != qr.upper_bound(GetEntry()); ++itr) - { - if(itr->second==quest_id) - return true; - } - return false; -} - -void Creature::DeleteFromDB() -{ - objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); - objmgr.DeleteCreatureData(m_DBTableGuid); - - WorldDatabase.BeginTransaction(); - WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid); - WorldDatabase.PExecuteLog("DELETE FROM creature_addon WHERE guid = '%u'", m_DBTableGuid); - WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id = '%u'", m_DBTableGuid); - WorldDatabase.PExecuteLog("DELETE FROM game_event_creature WHERE guid = '%u'", m_DBTableGuid); - WorldDatabase.PExecuteLog("DELETE FROM game_event_model_equip WHERE guid = '%u'", m_DBTableGuid); - WorldDatabase.CommitTransaction(); -} - -float Creature::GetAttackDistance(Unit const* pl) const -{ - float aggroRate = sWorld.getRate(RATE_CREATURE_AGGRO); - if(aggroRate==0) - return 0.0f; - - int32 playerlevel = pl->getLevelForTarget(this); - int32 creaturelevel = getLevelForTarget(pl); - - int32 leveldif = playerlevel - creaturelevel; - - // "The maximum Aggro Radius has a cap of 25 levels under. Example: A level 30 char has the same Aggro Radius of a level 5 char on a level 60 mob." - if ( leveldif < - 25) - leveldif = -25; - - // "The aggro radius of a mob having the same level as the player is roughly 20 yards" - float RetDistance = 20; - - // "Aggro Radius varries with level difference at a rate of roughly 1 yard/level" - // radius grow if playlevel < creaturelevel - RetDistance -= (float)leveldif; - - if(creaturelevel+5 <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - // detect range auras - RetDistance += GetTotalAuraModifier(SPELL_AURA_MOD_DETECT_RANGE); - - // detected range auras - RetDistance += pl->GetTotalAuraModifier(SPELL_AURA_MOD_DETECTED_RANGE); - } - - // "Minimum Aggro Radius for a mob seems to be combat range (5 yards)" - if(RetDistance < 5) - RetDistance = 5; - - return (RetDistance*aggroRate); -} - -void Creature::setDeathState(DeathState s) -{ - if((s == JUST_DIED && !m_isDeadByDefault)||(s == JUST_ALIVED && m_isDeadByDefault)) - { - m_deathTimer = m_corpseDelay*1000; - - // always save boss respawn time at death to prevent crash cheating - if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY) || isWorldBoss()) - SaveRespawnTime(); - - if(!IsStopped()) - StopMoving(); - } - Unit::setDeathState(s); - - if(s == JUST_DIED) - { - SetUInt64Value (UNIT_FIELD_TARGET,0); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState) - SetUInt32Value(UNIT_NPC_FLAGS, 0); - - if(!isPet() && GetCreatureInfo()->SkinLootId) - if ( LootTemplates_Skinning.HaveLootFor(GetCreatureInfo()->SkinLootId) ) - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - - Unit::setDeathState(CORPSE); - } - if(s == JUST_ALIVED) - { - SetHealth(GetMaxHealth()); - SetLootRecipient(NULL); - Unit::setDeathState(ALIVE); - CreatureInfo const *cinfo = GetCreatureInfo(); - SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); - SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag); - clearUnitState(UNIT_STAT_ALL_STATE); - i_motionMaster.Clear(); - SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); - LoadCreaturesAddon(true); - } -} - -void Creature::Respawn() -{ - RemoveCorpse(); - - // forced recreate creature object at clients - UnitVisibility currentVis = GetVisibility(); - SetVisibility(VISIBILITY_RESPAWN); - ObjectAccessor::UpdateObjectVisibility(this); - SetVisibility(currentVis); // restore visibility state - ObjectAccessor::UpdateObjectVisibility(this); - - if(getDeathState()==DEAD) - { - objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); - m_respawnTime = time(NULL); // respawn at next tick - } -} - -bool Creature::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges) -{ - if (!spellInfo) - return false; - - if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1))) - return true; - - return Unit::IsImmunedToSpell(spellInfo, useCharges); -} - -bool Creature::IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const -{ - if (GetCreatureInfo()->MechanicImmuneMask & (1 << (mechanic-1))) - return true; - - return Unit::IsImmunedToSpellEffect(effect, mechanic); -} - -SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim) -{ - if(!pVictim) - return NULL; - - for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++) - { - if(!m_spells[i]) - continue; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] ); - if(!spellInfo) - { - sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]); - continue; - } - - bool bcontinue = true; - for(uint32 j=0;j<3;j++) - { - if( (spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE ) || - (spellInfo->Effect[j] == SPELL_EFFECT_INSTAKILL) || - (spellInfo->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) || - (spellInfo->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ) - ) - { - bcontinue = false; - break; - } - } - if(bcontinue) continue; - - if(spellInfo->manaCost > GetPower(POWER_MANA)) - continue; - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); - float range = GetSpellMaxRange(srange); - float minrange = GetSpellMinRange(srange); - float dist = GetDistance(pVictim); - //if(!isInFront( pVictim, range ) && spellInfo->AttributesEx ) - // continue; - if( dist > range || dist < minrange ) - continue; - if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) - continue; - return spellInfo; - } - return NULL; -} - -SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim) -{ - if(!pVictim) - return NULL; - - for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++) - { - if(!m_spells[i]) - continue; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] ); - if(!spellInfo) - { - sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]); - continue; - } - - bool bcontinue = true; - for(uint32 j=0;j<3;j++) - { - if( (spellInfo->Effect[j] == SPELL_EFFECT_HEAL ) ) - { - bcontinue = false; - break; - } - } - if(bcontinue) continue; - - if(spellInfo->manaCost > GetPower(POWER_MANA)) - continue; - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); - float range = GetSpellMaxRange(srange); - float minrange = GetSpellMinRange(srange); - float dist = GetDistance(pVictim); - //if(!isInFront( pVictim, range ) && spellInfo->AttributesEx ) - // continue; - if( dist > range || dist < minrange ) - continue; - if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) - continue; - return spellInfo; - } - return NULL; -} - -bool Creature::IsVisibleInGridForPlayer(Player* pl) const -{ - // gamemaster in GM mode see all, including ghosts - if(pl->isGameMaster()) - return true; - - // Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0 - if(pl->isAlive() || pl->GetDeathTimer() > 0) - { - if( GetEntry() == VISUAL_WAYPOINT && !pl->isGameMaster() ) - return false; - return isAlive() || m_deathTimer > 0 || m_isDeadByDefault && m_deathState==CORPSE; - } - - // Dead player see live creatures near own corpse - if(isAlive()) - { - Corpse *corpse = pl->GetCorpse(); - if(corpse) - { - // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level - if(corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO))) - return true; - } - } - - // Dead player see Spirit Healer or Spirit Guide - if(isSpiritService()) - return true; - - // and not see any other - return false; -} - -void Creature::CallAssistence() -{ - if( !m_AlreadyCallAssistence && getVictim() && !isPet() && !isCharmed()) - { - SetNoCallAssistence(true); - - float radius = sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTEMCE_RADIUS); - if(radius > 0) - { - std::list assistList; - - { - CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::AnyAssistCreatureInRangeCheck u_check(this, getVictim(), radius); - MaNGOS::CreatureListSearcher searcher(assistList, u_check); - - TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); - } - - for(std::list::iterator iter = assistList.begin(); iter != assistList.end(); ++iter) - { - (*iter)->SetNoCallAssistence(true); - if((*iter)->AI()) - (*iter)->AI()->AttackStart(getVictim()); - } - } - } -} - -void Creature::SaveRespawnTime() -{ - if(isPet()) - return; - - if(m_respawnTime > time(NULL)) // dead (no corpse) - objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime); - else if(m_deathTimer > 0) // dead (corpse) - objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),time(NULL)+m_respawnDelay+m_deathTimer/1000); -} - -bool Creature::IsOutOfThreatArea(Unit* pVictim) const -{ - if(!pVictim) - return true; - - if(!pVictim->IsInMap(this)) - return true; - - if(!pVictim->isTargetableForAttack()) - return true; - - if(!pVictim->isInAccessablePlaceFor(this)) - return true; - - if(sMapStore.LookupEntry(GetMapId())->Instanceable()) - return false; - - float length = pVictim->GetDistance(CombatStartX,CombatStartY,CombatStartZ); - float AttackDist = GetAttackDistance(pVictim); - uint32 ThreatRadius = sWorld.getConfig(CONFIG_THREAT_RADIUS); - - //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and ouf of combat every update tick. - return ( length > (ThreatRadius > AttackDist ? ThreatRadius : AttackDist)); -} - -CreatureDataAddon const* Creature::GetCreatureAddon() const -{ - if(CreatureDataAddon const* addon = ObjectMgr::GetCreatureAddon(m_DBTableGuid)) - return addon; - - // dependent from heroic mode entry - return ObjectMgr::GetCreatureTemplateAddon(GetCreatureInfo()->Entry); -} - -//creature_addon table -bool Creature::LoadCreaturesAddon(bool reload) -{ - CreatureDataAddon const *cainfo = GetCreatureAddon(); - if(!cainfo) - return false; - - if (cainfo->mount != 0) - Mount(cainfo->mount); - - if (cainfo->bytes0 != 0) - SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0); - - if (cainfo->bytes1 != 0) - SetUInt32Value(UNIT_FIELD_BYTES_1, cainfo->bytes1); - - if (cainfo->bytes2 != 0) - SetUInt32Value(UNIT_FIELD_BYTES_2, cainfo->bytes2); - - if (cainfo->emote != 0) - SetUInt32Value(UNIT_NPC_EMOTESTATE, cainfo->emote); - - if (cainfo->move_flags != 0) - SetUnitMovementFlags(cainfo->move_flags); - - if(cainfo->auras) - { - for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura) - { - SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura->spell_id); - if (!AdditionalSpellInfo) - { - sLog.outErrorDb("Creature (GUIDLow: %u Entry: %u ) has wrong spell %u defined in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id); - continue; - } - - // skip already applied aura - if(HasAura(cAura->spell_id,cAura->effect_idx)) - { - if(!reload) - sLog.outErrorDb("Creature (GUIDLow: %u Entry: %u ) has duplicate aura (spell %u effect %u) in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id,cAura->effect_idx); - - continue; - } - - Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, cAura->effect_idx, NULL, this, this, 0); - AddAura(AdditionalAura); - sLog.outDebug("Spell: %u with Aura %u added to creature (GUIDLow: %u Entry: %u )", cAura->spell_id, AdditionalSpellInfo->EffectApplyAuraName[0],GetGUIDLow(),GetEntry()); - } - } - return true; -} - -/// Send a message to LocalDefense channel for players oposition team in the zone -void Creature::SendZoneUnderAttackMessage(Player* attacker) -{ - uint32 enemy_team = attacker->GetTeam(); - - WorldPacket data(SMSG_ZONE_UNDER_ATTACK,4); - data << (uint32)GetZoneId(); - sWorld.SendGlobalMessage(&data,NULL,(enemy_team==ALLIANCE ? HORDE : ALLIANCE)); -} - -void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time) -{ - m_CreatureSpellCooldowns[spell_id] = end_time; -} - -void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time) -{ - m_CreatureCategoryCooldowns[category] = apply_time; -} - -void Creature::AddCreatureSpellCooldown(uint32 spellid) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); - if(!spellInfo) - return; - - uint32 cooldown = GetSpellRecoveryTime(spellInfo); - if(cooldown) - _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/1000); - - if(spellInfo->Category) - _AddCreatureCategoryCooldown(spellInfo->Category, time(NULL)); - - m_GlobalCooldown = spellInfo->StartRecoveryTime; -} - -bool Creature::HasCategoryCooldown(uint32 spell_id) const -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); - if(!spellInfo) - return false; - - // check global cooldown if spell affected by it - if (spellInfo->StartRecoveryCategory > 0 && m_GlobalCooldown > 0) - return true; - - CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category); - return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / 1000)) > time(NULL)); -} - -bool Creature::HasSpellCooldown(uint32 spell_id) const -{ - CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id); - return (itr != m_CreatureSpellCooldowns.end() && itr->second > time(NULL)) || HasCategoryCooldown(spell_id); -} - -bool Creature::IsInEvadeMode() const -{ - return !i_motionMaster.empty() && i_motionMaster.GetCurrentMovementGeneratorType() == HOME_MOTION_TYPE; -} - -bool Creature::HasSpell(uint32 spellID) const -{ - uint8 i; - for(i = 0; i < CREATURE_MAX_SPELLS; ++i) - if(spellID == m_spells[i]) - break; - return i < CREATURE_MAX_SPELLS; //broke before end of iteration of known spells -} - -time_t Creature::GetRespawnTimeEx() const -{ - time_t now = time(NULL); - if(m_respawnTime > now) // dead (no corpse) - return m_respawnTime; - else if(m_deathTimer > 0) // dead (corpse) - return now+m_respawnDelay+m_deathTimer/1000; - else - return now; -} - -void Creature::GetRespawnCoord( float &x, float &y, float &z, float* ori, float* dist ) const -{ - if(CreatureData const* data = objmgr.GetCreatureData(GetDBTableGUIDLow())) - { - x = data->posX; - y = data->posY; - z = data->posZ; - if(ori) - *ori = data->orientation; - if(dist) - *dist = data->spawndist; - } - else - { - x = GetPositionX(); - y = GetPositionY(); - z = GetPositionZ(); - if(ori) - *ori = GetOrientation(); - if(dist) - *dist = 0; - } -} - -void Creature::AllLootRemovedFromCorpse() -{ - if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE)) - { - uint32 nDeathTimer; - - CreatureInfo const *cinfo = GetCreatureInfo(); - - // corpse was not skinnable -> apply corpse looted timer - if (!cinfo || !cinfo->SkinLootId) - nDeathTimer = (uint32)((m_corpseDelay * 1000) * sWorld.getRate(RATE_CORPSE_DECAY_LOOTED)); - // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update - else - nDeathTimer = 0; - - // update death timer only if looted timer is shorter - if (m_deathTimer > nDeathTimer) - m_deathTimer = nDeathTimer; - } -} - -uint32 Creature::getLevelForTarget( Unit const* target ) const -{ - if(!isWorldBoss()) - return Unit::getLevelForTarget(target); - - uint32 level = target->getLevel()+sWorld.getConfig(CONFIG_WORLD_BOSS_LEVEL_DIFF); - if(level < 1) - return 1; - if(level > 255) - return 255; - return level; -} - -char const* Creature::GetScriptName() const -{ - return ObjectMgr::GetCreatureTemplate(GetEntry())->ScriptName; -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Creature.h" +#include "QuestDef.h" +#include "GossipDef.h" +#include "Player.h" +#include "Opcodes.h" +#include "Log.h" +#include "LootMgr.h" +#include "MapManager.h" +#include "CreatureAI.h" +#include "CreatureAISelector.h" +#include "Formulas.h" +#include "SpellAuras.h" +#include "WaypointMovementGenerator.h" +#include "InstanceData.h" +#include "BattleGround.h" +#include "Util.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +// apply implementation of the singletons +#include "Policies/SingletonImp.h" + +void TrainerSpellData::Clear() +{ + for (TrainerSpellList::iterator itr = spellList.begin(); itr != spellList.end(); ++itr) + delete (*itr); + spellList.empty(); +} + +TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const +{ + for(TrainerSpellList::const_iterator itr = spellList.begin(); itr != spellList.end(); ++itr) + if((*itr)->spell == spell_id) + return *itr; + + return NULL; +} + +Creature::Creature() : +Unit(), i_AI(NULL), +lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0), +m_itemsLoaded(false), m_lootMoney(0), m_lootRecipient(0), +m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f), +m_gossipOptionLoaded(false),m_emoteState(0), m_isPet(false), m_isTotem(false), +m_regenTimer(2000), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0), +m_AlreadyCallAssistence(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), +m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),m_creatureInfo(NULL) +{ + m_valuesCount = UNIT_END; + + for(int i =0; i<4; ++i) + m_spells[i] = 0; + + m_CreatureSpellCooldowns.clear(); + m_CreatureCategoryCooldowns.clear(); + m_GlobalCooldown = 0; + m_unit_movement_flags = MOVEMENTFLAG_WALK_MODE; +} + +Creature::~Creature() +{ + CleanupsBeforeDelete(); + + m_vendor_items.clear(); + + delete i_AI; + i_AI = NULL; +} + +void Creature::AddToWorld() +{ + ///- Register the creature for guid lookup + if(!IsInWorld()) ObjectAccessor::Instance().AddObject(this); + Unit::AddToWorld(); +} + +void Creature::RemoveFromWorld() +{ + ///- Remove the creature from the accessor + if(IsInWorld()) ObjectAccessor::Instance().RemoveObject(this); + Unit::RemoveFromWorld(); +} + +void Creature::RemoveCorpse() +{ + if( getDeathState()!=CORPSE && !m_isDeadByDefault || getDeathState()!=ALIVE && m_isDeadByDefault ) + return; + + m_deathTimer = 0; + setDeathState(DEAD); + ObjectAccessor::UpdateObjectVisibility(this); + loot.clear(); + m_respawnTime = time(NULL) + m_respawnDelay; + + float x,y,z,o; + GetRespawnCoord(x, y, z, &o); + MapManager::Instance().GetMap(GetMapId(), this)->CreatureRelocation(this,x,y,z,o); +} + +/** + * change the entry of creature until respawn + */ +bool Creature::InitEntry(uint32 Entry, uint32 team, const CreatureData *data ) +{ + CreatureInfo const *normalInfo = objmgr.GetCreatureTemplate(Entry); + if(!normalInfo) + { + sLog.outErrorDb("Creature::UpdateEntry creature entry %u does not exist.", Entry); + return false; + } + + // get heroic mode entry + uint32 actualEntry = Entry; + CreatureInfo const *cinfo = normalInfo; + if(normalInfo->HeroicEntry) + { + Map *map = MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); + if(map && map->IsHeroic()) + { + cinfo = objmgr.GetCreatureTemplate(normalInfo->HeroicEntry); + if(!cinfo) + { + sLog.outErrorDb("Creature::UpdateEntry creature heroic entry %u does not exist.", actualEntry); + return false; + } + } + } + + SetUInt32Value(OBJECT_FIELD_ENTRY, Entry); // normal entry always + m_creatureInfo = cinfo; // map mode related always + + if (cinfo->DisplayID_A == 0 || cinfo->DisplayID_H == 0) // Cancel load if no model defined + { + sLog.outErrorDb("Creature (Entry: %u) has no model defined for Horde or Alliance in table `creature_template`, can't load. ",Entry); + return false; + } + + uint32 display_id = objmgr.ChooseDisplayId(team, GetCreatureInfo(), data); + CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id); + if (!minfo) + { + sLog.outErrorDb("Creature (Entry: %u) has model %u not found in table `creature_model_info`, can't load. ", Entry, display_id); + return false; + } + else + display_id = minfo->modelid; // it can be different (for another gender) + + SetDisplayId(display_id); + SetNativeDisplayId(display_id); + SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + + // Load creature equipment + if(!data || data->equipmentId == 0) + { // use default from the template + LoadEquipment(cinfo->equipmentId); + } + else if(data && data->equipmentId != -1) + { // override, -1 means no equipment + LoadEquipment(data->equipmentId); + } + + SetName(normalInfo->Name); // at normal entry always + + SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,minfo->bounding_radius); + SetFloatValue(UNIT_FIELD_COMBATREACH,minfo->combat_reach ); + + SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); + + SetSpeed(MOVE_WALK, cinfo->speed ); + SetSpeed(MOVE_RUN, cinfo->speed ); + SetSpeed(MOVE_SWIM, cinfo->speed ); + + SetFloatValue(OBJECT_FIELD_SCALE_X, cinfo->scale); + + // checked at loading + m_defaultMovementType = MovementGeneratorType(cinfo->MovementType); + if(!m_respawnradius && m_defaultMovementType==RANDOM_MOTION_TYPE) + m_defaultMovementType = IDLE_MOTION_TYPE; + + return true; +} + +bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data ) +{ + if(!InitEntry(Entry,team,data)) + return false; + + m_regenHealth = GetCreatureInfo()->RegenHealth; + + // creatures always have melee weapon ready if any + SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); + SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_AURAS ); + + SelectLevel(GetCreatureInfo()); + if (team == HORDE) + SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, GetCreatureInfo()->faction_H); + else + SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, GetCreatureInfo()->faction_A); + + SetUInt32Value(UNIT_NPC_FLAGS,GetCreatureInfo()->npcflag); + + SetAttackTime(BASE_ATTACK, GetCreatureInfo()->baseattacktime); + SetAttackTime(OFF_ATTACK, GetCreatureInfo()->baseattacktime); + SetAttackTime(RANGED_ATTACK,GetCreatureInfo()->rangeattacktime); + + SetUInt32Value(UNIT_FIELD_FLAGS,GetCreatureInfo()->Flags); + SetUInt32Value(UNIT_DYNAMIC_FLAGS,GetCreatureInfo()->dynamicflags); + + SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->armor)); + SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1)); + SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2)); + SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->resistance3)); + SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->resistance4)); + SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->resistance5)); + SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->resistance6)); + + SetCanModifyStats(true); + UpdateAllStats(); + + FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(GetCreatureInfo()->faction_A); + if (factionTemplate) // check and error show at loading templates + { + FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->faction); + if (factionEntry) + if( !(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN) && + (factionEntry->team == ALLIANCE || factionEntry->team == HORDE) ) + SetPvP(true); + } + + m_spells[0] = GetCreatureInfo()->spell1; + m_spells[1] = GetCreatureInfo()->spell2; + m_spells[2] = GetCreatureInfo()->spell3; + m_spells[3] = GetCreatureInfo()->spell4; + + return true; +} + +void Creature::Update(uint32 diff) +{ + if(m_GlobalCooldown <= diff) + m_GlobalCooldown = 0; + else + m_GlobalCooldown -= diff; + + switch( m_deathState ) + { + case JUST_ALIVED: + // Dont must be called, see Creature::setDeathState JUST_ALIVED -> ALIVE promoting. + sLog.outError("Creature (GUIDLow: %u Entry: %u ) in wrong state: JUST_ALIVED (4)",GetGUIDLow(),GetEntry()); + break; + case JUST_DIED: + // Dont must be called, see Creature::setDeathState JUST_DIED -> CORPSE promoting. + sLog.outError("Creature (GUIDLow: %u Entry: %u ) in wrong state: JUST_DEAD (1)",GetGUIDLow(),GetEntry()); + break; + case DEAD: + { + if( m_respawnTime <= time(NULL) ) + { + DEBUG_LOG("Respawning..."); + m_respawnTime = 0; + lootForPickPocketed = false; + lootForBody = false; + + if(m_originalEntry != GetUInt32Value(OBJECT_FIELD_ENTRY)) + UpdateEntry(m_originalEntry); + + CreatureInfo const *cinfo = GetCreatureInfo(); + + SelectLevel(cinfo); + SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); + if (m_isDeadByDefault) + { + setDeathState(JUST_DIED); + SetHealth(0); + i_motionMaster.Clear(); + clearUnitState(UNIT_STAT_ALL_STATE); + LoadCreaturesAddon(true); + } + else + setDeathState( JUST_ALIVED ); + + //Call AI respawn virtual function + i_AI->JustRespawned(); + + MapManager::Instance().GetMap(GetMapId(), this)->Add(this); + } + break; + } + case CORPSE: + { + if (m_isDeadByDefault) + break; + + if( m_deathTimer <= diff ) + { + RemoveCorpse(); + DEBUG_LOG("Removing corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY)); + } + else + { + m_deathTimer -= diff; + if (m_groupLootTimer && lootingGroupLeaderGUID) + { + if(diff <= m_groupLootTimer) + { + m_groupLootTimer -= diff; + } + else + { + Group* group = objmgr.GetGroupByLeader(lootingGroupLeaderGUID); + if (group) + group->EndRoll(); + m_groupLootTimer = 0; + lootingGroupLeaderGUID = 0; + } + } + } + + break; + } + case ALIVE: + { + if (m_isDeadByDefault) + { + if( m_deathTimer <= diff ) + { + RemoveCorpse(); + DEBUG_LOG("Removing alive corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY)); + } + else + { + m_deathTimer -= diff; + } + } + + Unit::Update( diff ); + + // creature can be dead after Unit::Update call + // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) + if(!isAlive()) + break; + + if(!IsInEvadeMode()) + { + // do not allow the AI to be changed during update + m_AI_locked = true; + i_AI->UpdateAI(diff); + m_AI_locked = false; + } + + // creature can be dead after UpdateAI call + // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) + if(!isAlive()) + break; + if(m_regenTimer > 0) + { + if(diff >= m_regenTimer) + m_regenTimer = 0; + else + m_regenTimer -= diff; + } + if (m_regenTimer != 0) + break; + + if (!isInCombat() || IsPolymorphed()) + RegenerateHealth(); + + RegenerateMana(); + + m_regenTimer = 2000; + break; + } + default: + break; + } +} + +void Creature::RegenerateMana() +{ + uint32 curValue = GetPower(POWER_MANA); + uint32 maxValue = GetMaxPower(POWER_MANA); + + if (curValue >= maxValue) + return; + + uint32 addvalue = 0; + + // Combat and any controlled creature + if (isInCombat() || GetCharmerOrOwnerGUID()) + { + if(!IsUnderLastManaUseEffect()) + { + float ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA); + float Spirit = GetStat(STAT_SPIRIT); + + addvalue = uint32((Spirit/5.0f + 17.0f) * ManaIncreaseRate); + } + } + else + addvalue = maxValue/3; + + ModifyPower(POWER_MANA, addvalue); +} + +void Creature::RegenerateHealth() +{ + if (!isRegeneratingHealth()) + return; + + uint32 curValue = GetHealth(); + uint32 maxValue = GetMaxHealth(); + + if (curValue >= maxValue) + return; + + uint32 addvalue = 0; + + // Not only pet, but any controelled creature + if(GetCharmerOrOwnerGUID()) + { + float HealthIncreaseRate = sWorld.getRate(RATE_HEALTH); + float Spirit = GetStat(STAT_SPIRIT); + + if( GetPower(POWER_MANA) > 0 ) + addvalue = uint32(Spirit * 0.25 * HealthIncreaseRate); + else + addvalue = uint32(Spirit * 0.80 * HealthIncreaseRate); + } + else + addvalue = maxValue/3; + + ModifyHealth(addvalue); +} + +bool Creature::AIM_Initialize() +{ + // make sure nothing can change the AI during AI update + if(m_AI_locked) + { + sLog.outDebug("AIM_Initialize: failed to init, locked."); + return false; + } + + CreatureAI * oldAI = i_AI; + i_motionMaster.Initialize(); + i_AI = FactorySelector::selectAI(this); + if (oldAI) + delete oldAI; + return true; +} + +bool Creature::Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, const CreatureData *data) +{ + SetMapId(map->GetId()); + SetInstanceId(map->GetInstanceId()); + + //oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0; + const bool bResult = CreateFromProto(guidlow, Entry, team, data); + + if (bResult) + { + switch (GetCreatureInfo()->rank) + { + case CREATURE_ELITE_RARE: + m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_RARE); + break; + case CREATURE_ELITE_ELITE: + m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_ELITE); + break; + case CREATURE_ELITE_RAREELITE: + m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_RAREELITE); + break; + case CREATURE_ELITE_WORLDBOSS: + m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_WORLDBOSS); + break; + default: + m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_NORMAL); + break; + } + } + + return bResult; +} + +bool Creature::isCanTrainingOf(Player* pPlayer, bool msg) const +{ + if(!isTrainer()) + return false; + + TrainerSpellData const* trainer_spells = GetTrainerSpells(); + + + if(!trainer_spells || trainer_spells->spellList.empty()) + { + sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_TRAINER but have empty trainer spell list.", + GetGUIDLow(),GetEntry()); + return false; + } + + switch(GetCreatureInfo()->trainer_type) + { + case TRAINER_TYPE_CLASS: + if(pPlayer->getClass()!=GetCreatureInfo()->classNum) + { + if(msg) + { + pPlayer->PlayerTalkClass->ClearMenus(); + switch(GetCreatureInfo()->classNum) + { + case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu( 4913,GetGUID()); break; + case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090,GetGUID()); break; + case CLASS_MAGE: pPlayer->PlayerTalkClass->SendGossipMenu( 328,GetGUID()); break; + case CLASS_PALADIN:pPlayer->PlayerTalkClass->SendGossipMenu( 1635,GetGUID()); break; + case CLASS_PRIEST: pPlayer->PlayerTalkClass->SendGossipMenu( 4436,GetGUID()); break; + case CLASS_ROGUE: pPlayer->PlayerTalkClass->SendGossipMenu( 4797,GetGUID()); break; + case CLASS_SHAMAN: pPlayer->PlayerTalkClass->SendGossipMenu( 5003,GetGUID()); break; + case CLASS_WARLOCK:pPlayer->PlayerTalkClass->SendGossipMenu( 5836,GetGUID()); break; + case CLASS_WARRIOR:pPlayer->PlayerTalkClass->SendGossipMenu( 4985,GetGUID()); break; + } + } + return false; + } + break; + case TRAINER_TYPE_PETS: + if(pPlayer->getClass()!=CLASS_HUNTER) + { + pPlayer->PlayerTalkClass->ClearMenus(); + pPlayer->PlayerTalkClass->SendGossipMenu(3620,GetGUID()); + return false; + } + break; + case TRAINER_TYPE_MOUNTS: + if(GetCreatureInfo()->race && pPlayer->getRace() != GetCreatureInfo()->race) + { + if(msg) + { + pPlayer->PlayerTalkClass->ClearMenus(); + switch(GetCreatureInfo()->classNum) + { + case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865,GetGUID()); break; + case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881,GetGUID()); break; + case RACE_HUMAN: pPlayer->PlayerTalkClass->SendGossipMenu(5861,GetGUID()); break; + case RACE_NIGHTELF: pPlayer->PlayerTalkClass->SendGossipMenu(5862,GetGUID()); break; + case RACE_ORC: pPlayer->PlayerTalkClass->SendGossipMenu(5863,GetGUID()); break; + case RACE_TAUREN: pPlayer->PlayerTalkClass->SendGossipMenu(5864,GetGUID()); break; + case RACE_TROLL: pPlayer->PlayerTalkClass->SendGossipMenu(5816,GetGUID()); break; + case RACE_UNDEAD_PLAYER:pPlayer->PlayerTalkClass->SendGossipMenu( 624,GetGUID()); break; + case RACE_BLOODELF: pPlayer->PlayerTalkClass->SendGossipMenu(5862,GetGUID()); break; + case RACE_DRAENEI: pPlayer->PlayerTalkClass->SendGossipMenu(5864,GetGUID()); break; + } + } + return false; + } + break; + case TRAINER_TYPE_TRADESKILLS: + if(GetCreatureInfo()->trainer_spell && !pPlayer->HasSpell(GetCreatureInfo()->trainer_spell)) + { + if(msg) + { + pPlayer->PlayerTalkClass->ClearMenus(); + pPlayer->PlayerTalkClass->SendGossipMenu(11031,GetGUID()); + } + return false; + } + break; + default: + return false; // checked and error output at creature_template loading + } + return true; +} + +bool Creature::isCanIneractWithBattleMaster(Player* pPlayer, bool msg) const +{ + if(!isBattleMaster()) + return false; + + uint32 bgTypeId = objmgr.GetBattleMasterBG(GetEntry()); + if(!msg) + return pPlayer->GetBGAccessByLevel(bgTypeId); + + if(!pPlayer->GetBGAccessByLevel(bgTypeId)) + { + pPlayer->PlayerTalkClass->ClearMenus(); + switch(bgTypeId) + { + case BATTLEGROUND_AV: pPlayer->PlayerTalkClass->SendGossipMenu(7616,GetGUID()); break; + case BATTLEGROUND_WS: pPlayer->PlayerTalkClass->SendGossipMenu(7599,GetGUID()); break; + case BATTLEGROUND_AB: pPlayer->PlayerTalkClass->SendGossipMenu(7642,GetGUID()); break; + case BATTLEGROUND_EY: + case BATTLEGROUND_NA: + case BATTLEGROUND_BE: + case BATTLEGROUND_AA: + case BATTLEGROUND_RL: pPlayer->PlayerTalkClass->SendGossipMenu(10024,GetGUID()); break; + break; + } + return false; + } + return true; +} + +bool Creature::isCanTrainingAndResetTalentsOf(Player* pPlayer) const +{ + return pPlayer->getLevel() >= 10 + && GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS + && pPlayer->getClass() == GetCreatureInfo()->classNum; +} + +void Creature::prepareGossipMenu( Player *pPlayer,uint32 gossipid ) +{ + PlayerMenu* pm=pPlayer->PlayerTalkClass; + pm->ClearMenus(); + + // lazy loading single time at use + LoadGossipOptions(); + + GossipOption* gso; + GossipOption* ingso; + + for( GossipOptionList::iterator i = m_goptions.begin( ); i != m_goptions.end( ); i++ ) + { + gso=&*i; + if(gso->GossipId == gossipid) + { + bool cantalking=true; + if(gso->Id==1) + { + uint32 textid=GetNpcTextId(); + GossipText * gossiptext=objmgr.GetGossipText(textid); + if(!gossiptext) + cantalking=false; + } + else + { + switch (gso->Action) + { + case GOSSIP_OPTION_QUESTGIVER: + pPlayer->PrepareQuestMenu(GetGUID()); + //if (pm->GetQuestMenu()->MenuItemCount() == 0) + cantalking=false; + //pm->GetQuestMenu()->ClearMenu(); + break; + case GOSSIP_OPTION_ARMORER: + cantalking=false; // added in special mode + break; + case GOSSIP_OPTION_SPIRITHEALER: + if( !pPlayer->isDead() ) + cantalking=false; + break; + case GOSSIP_OPTION_VENDOR: + // load vendor items if not yet + LoadGoods(); + + if(!GetItemCount()) + { + sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", + GetGUIDLow(),GetEntry()); + cantalking=false; + } + break; + case GOSSIP_OPTION_TRAINER: + if(!isCanTrainingOf(pPlayer,false)) + cantalking=false; + break; + case GOSSIP_OPTION_UNLEARNTALENTS: + if(!isCanTrainingAndResetTalentsOf(pPlayer)) + cantalking=false; + break; + case GOSSIP_OPTION_UNLEARNPETSKILLS: + if(!pPlayer->GetPet() || pPlayer->GetPet()->getPetType() != HUNTER_PET || pPlayer->GetPet()->m_spells.size() <= 1 || GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || GetCreatureInfo()->classNum != CLASS_HUNTER) + cantalking=false; + break; + case GOSSIP_OPTION_TAXIVENDOR: + if ( pPlayer->GetSession()->SendLearnNewTaxiNode(this) ) + return; + break; + case GOSSIP_OPTION_BATTLEFIELD: + if(!isCanIneractWithBattleMaster(pPlayer,false)) + cantalking=false; + break; + case GOSSIP_OPTION_SPIRITGUIDE: + case GOSSIP_OPTION_INNKEEPER: + case GOSSIP_OPTION_BANKER: + case GOSSIP_OPTION_PETITIONER: + case GOSSIP_OPTION_STABLEPET: + case GOSSIP_OPTION_TABARDDESIGNER: + case GOSSIP_OPTION_AUCTIONEER: + break; // no checks + default: + sLog.outErrorDb("Creature %u (entry: %u) have unknown gossip option %u",GetGUIDLow(),GetEntry(),gso->Action); + break; + } + } + + if(!gso->Option.empty() && cantalking ) + { //note for future dev: should have database fields for BoxMessage & BoxMoney + pm->GetGossipMenu().AddMenuItem((uint8)gso->Icon,gso->Option, gossipid,gso->Action,"",0,false); + ingso=gso; + } + } + } + + ///some gossips aren't handled in normal way ... so we need to do it this way .. TODO: handle it in normal way ;-) + if(pm->Empty()) + { + if(HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_TRAINER)) + { + isCanTrainingOf(pPlayer,true); // output error message if need + } + if(HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_BATTLEMASTER)) + { + isCanIneractWithBattleMaster(pPlayer,true); // output error message if need + } + } +} + +void Creature::sendPreparedGossip(Player* player) +{ + if(!player) + return; + + GossipMenu& gossipmenu = player->PlayerTalkClass->GetGossipMenu(); + + // in case empty gossip menu open quest menu if any + if (gossipmenu.Empty() && GetNpcTextId() == 0) + { + player->SendPreparedQuest(GetGUID()); + return; + } + + // in case non empty gossip menu (that not included quests list size) show it + // (quest entries from quest menu wiill be included in list) + player->PlayerTalkClass->SendGossipMenu(GetNpcTextId(), GetGUID()); +} + +void Creature::OnGossipSelect(Player* player, uint32 option) +{ + GossipMenu& gossipmenu = player->PlayerTalkClass->GetGossipMenu(); + + if(option >= gossipmenu.MenuItemCount()) + return; + + uint32 action=gossipmenu.GetItem(option).m_gAction; + uint32 zoneid=GetZoneId(); + uint64 guid=GetGUID(); + GossipOption const *gossip=GetGossipOption( action ); + uint32 textid; + if(!gossip) + { + zoneid=0; + gossip=GetGossipOption( action ); + if(!gossip) + return; + } + textid=GetGossipTextId( action, zoneid); + if(textid==0) + textid=GetNpcTextId(); + + switch (gossip->Action) + { + case GOSSIP_OPTION_GOSSIP: + player->PlayerTalkClass->CloseGossip(); + player->PlayerTalkClass->SendTalking( textid ); + break; + case GOSSIP_OPTION_SPIRITHEALER: + if( player->isDead() ) + CastSpell(this,17251,true,NULL,NULL,player->GetGUID()); + break; + case GOSSIP_OPTION_QUESTGIVER: + player->PrepareQuestMenu( guid ); + player->SendPreparedQuest( guid ); + break; + case GOSSIP_OPTION_VENDOR: + case GOSSIP_OPTION_ARMORER: + player->GetSession()->SendListInventory(guid); + break; + case GOSSIP_OPTION_STABLEPET: + player->GetSession()->SendStablePet(guid); + break; + case GOSSIP_OPTION_TRAINER: + player->GetSession()->SendTrainerList(guid); + break; + case GOSSIP_OPTION_UNLEARNTALENTS: + player->PlayerTalkClass->CloseGossip(); + player->SendTalentWipeConfirm(guid); + break; + case GOSSIP_OPTION_UNLEARNPETSKILLS: + player->PlayerTalkClass->CloseGossip(); + player->SendPetSkillWipeConfirm(); + break; + case GOSSIP_OPTION_TAXIVENDOR: + player->GetSession()->SendTaxiMenu(this); + break; + case GOSSIP_OPTION_INNKEEPER: + player->PlayerTalkClass->CloseGossip(); + player->SetBindPoint( guid ); + break; + case GOSSIP_OPTION_BANKER: + player->GetSession()->SendShowBank( guid ); + break; + case GOSSIP_OPTION_PETITIONER: + player->PlayerTalkClass->CloseGossip(); + player->GetSession()->SendPetitionShowList( guid ); + break; + case GOSSIP_OPTION_TABARDDESIGNER: + player->PlayerTalkClass->CloseGossip(); + player->GetSession()->SendTabardVendorActivate( guid ); + break; + case GOSSIP_OPTION_AUCTIONEER: + player->GetSession()->SendAuctionHello( guid, this ); + break; + case GOSSIP_OPTION_SPIRITGUIDE: + case GOSSIP_GUARD_SPELLTRAINER: + case GOSSIP_GUARD_SKILLTRAINER: + prepareGossipMenu( player,gossip->Id ); + sendPreparedGossip( player ); + break; + case GOSSIP_OPTION_BATTLEFIELD: + { + uint32 bgTypeId = objmgr.GetBattleMasterBG(GetEntry()); + player->GetSession()->SendBattlegGroundList( GetGUID(), bgTypeId ); + break; + } + default: + OnPoiSelect( player, gossip ); + break; + } + +} + +void Creature::OnPoiSelect(Player* player, GossipOption const *gossip) +{ + if(gossip->GossipId==GOSSIP_GUARD_SPELLTRAINER || gossip->GossipId==GOSSIP_GUARD_SKILLTRAINER) + { + //float x,y; + //bool findnpc=false; + Poi_Icon icon = ICON_POI_0; + //QueryResult *result; + //Field *fields; + uint32 mapid=GetMapId(); + Map const* map=MapManager::Instance().GetBaseMap( mapid ); + uint16 areaflag=map->GetAreaFlag(GetPositionX(),GetPositionY()); + uint32 zoneid=Map::GetZoneId(areaflag,mapid); + std::string areaname= gossip->Option; + /* + uint16 pflag; + + // use the action relate to creaturetemplate.trainer_type ? + result= WorldDatabase.PQuery("SELECT creature.position_x,creature.position_y FROM creature,creature_template WHERE creature.map = '%u' AND creature.id = creature_template.entry AND creature_template.trainer_type = '%u'", mapid, gossip->Action ); + if(!result) + return; + do + { + fields = result->Fetch(); + x=fields[0].GetFloat(); + y=fields[1].GetFloat(); + pflag=map->GetAreaFlag(GetPositionX(),GetPositionY()); + if(pflag==areaflag) + { + findnpc=true; + break; + } + }while(result->NextRow()); + + delete result; + + if(!findnpc) + { + player->PlayerTalkClass->SendTalking( "$NSorry", "Here no this person."); + return; + }*/ + + //need add more case. + switch(gossip->Action) + { + case GOSSIP_GUARD_BANK: + icon=ICON_POI_HOUSE; + break; + case GOSSIP_GUARD_RIDE: + icon=ICON_POI_RWHORSE; + break; + case GOSSIP_GUARD_GUILD: + icon=ICON_POI_BLUETOWER; + break; + default: + icon=ICON_POI_TOWER; + break; + } + uint32 textid=GetGossipTextId( gossip->Action, zoneid ); + player->PlayerTalkClass->SendTalking( textid ); + // how this could worked player->PlayerTalkClass->SendPointOfInterest( x, y, icon, 2, 15, areaname.c_str() ); + } +} + +uint32 Creature::GetGossipTextId(uint32 action, uint32 zoneid) +{ + QueryResult *result= WorldDatabase.PQuery("SELECT textid FROM npc_gossip_textid WHERE action = '%u' AND zoneid ='%u'", action, zoneid ); + + if(!result) + return 0; + + Field *fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + + delete result; + + return id; +} + +uint32 Creature::GetNpcTextId() +{ + if(uint32 pos = objmgr.GetNpcGossip(m_DBTableGuid)) + return pos; + + return DEFAULT_GOSSIP_MESSAGE; +} + +GossipOption const* Creature::GetGossipOption( uint32 id ) const +{ + for( GossipOptionList::const_iterator i = m_goptions.begin( ); i != m_goptions.end( ); i++ ) + { + if(i->Action==id ) + return &*i; + } + return NULL; +} + +void Creature::LoadGossipOptions() +{ + if(m_gossipOptionLoaded) + return; + + uint32 npcflags=GetUInt32Value(UNIT_NPC_FLAGS); + + QueryResult *result = WorldDatabase.PQuery( "SELECT id,gossip_id,npcflag,icon,action,option_text FROM npc_option WHERE (npcflag & %u)<>0", npcflags ); + + if(!result) + return; + + GossipOption go; + do + { + Field *fields = result->Fetch(); + go.Id= fields[0].GetUInt32(); + go.GossipId = fields[1].GetUInt32(); + go.NpcFlag=fields[2].GetUInt32(); + go.Icon=fields[3].GetUInt32(); + go.Action=fields[4].GetUInt32(); + go.Option=fields[5].GetCppString(); + addGossipOption(go); + }while( result->NextRow() ); + delete result; + + m_gossipOptionLoaded = true; +} + +void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type) +{ + /* uint32 timeElap = getMSTime(); + if ((timeElap - m_startMove) < m_moveTime) + { + oX = (dX - oX) * ( (timeElap - m_startMove) / m_moveTime ); + oY = (dY - oY) * ( (timeElap - m_startMove) / m_moveTime ); + } + else + { + oX = dX; + oY = dY; + } + + dX = x; + dY = y; + m_orientation = atan2((oY - dY), (oX - dX)); + + m_startMove = getMSTime(); + m_moveTime = time;*/ + SendMonsterMove(x, y, z, type, MovementFlags, time); +} + +Player *Creature::GetLootRecipient() const +{ + if (!m_lootRecipient) return NULL; + else return ObjectAccessor::FindPlayer(m_lootRecipient); +} + +void Creature::SetLootRecipient(Unit *unit) +{ + // set the player whose group should receive the right + // to loot the creature after it dies + // should be set to NULL after the loot disappears + + if (!unit) + { + m_lootRecipient = 0; + RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER); + return; + } + + Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself(); + if(!player) // normal creature, no player involved + return; + + m_lootRecipient = player->GetGUID(); + SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER); +} + +void Creature::SaveToDB() +{ + // this should only be used when the creature has already been loaded + // perferably after adding to map, because mapid may not be valid otherwise + CreatureData const *data = objmgr.GetCreatureData(m_DBTableGuid); + if(!data) + { + sLog.outError("Creature::SaveToDB failed, cannot get creature data!"); + return; + } + + SaveToDB(GetMapId(), data->spawnMask); +} + +void Creature::SaveToDB(uint32 mapid, uint8 spawnMask) +{ + // update in loaded data + CreatureData& data = objmgr.NewOrExistCreatureData(m_DBTableGuid); + + uint32 displayId = GetNativeDisplayId(); + + // check if it's a custom model and if not, use 0 for displayId + CreatureInfo const *cinfo = GetCreatureInfo(); + if(cinfo) + { + if(displayId != cinfo->DisplayID_A && displayId != cinfo->DisplayID_H) + { + CreatureModelInfo const *minfo = objmgr.GetCreatureModelInfo(cinfo->DisplayID_A); + if(!minfo || displayId != minfo->modelid_other_gender) + { + minfo = objmgr.GetCreatureModelInfo(cinfo->DisplayID_H); + if(minfo && displayId == minfo->modelid_other_gender) + displayId = 0; + } + else + displayId = 0; + } + else + displayId = 0; + } + + // data->guid = guid don't must be update at save + data.id = GetEntry(); + data.mapid = mapid; + data.displayid = displayId; + data.equipmentId = GetEquipmentId(); + data.posX = GetPositionX(); + data.posY = GetPositionY(); + data.posZ = GetPositionZ(); + data.orientation = GetOrientation(); + data.spawntimesecs = m_respawnDelay; + // prevent add data integrity problems + data.spawndist = GetDefaultMovementType()==IDLE_MOTION_TYPE ? 0 : m_respawnradius; + data.currentwaypoint = 0; + data.curhealth = GetHealth(); + data.curmana = GetPower(POWER_MANA); + data.is_dead = m_isDeadByDefault; + // prevent add data integrity problems + data.movementType = !m_respawnradius && GetDefaultMovementType()==RANDOM_MOTION_TYPE + ? IDLE_MOTION_TYPE : GetDefaultMovementType(); + data.spawnMask = spawnMask; + + // updated in DB + WorldDatabase.BeginTransaction(); + + WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid); + + std::ostringstream ss; + ss << "INSERT INTO creature VALUES (" + << m_DBTableGuid << "," + << GetEntry() << "," + << mapid <<"," + << (uint32)spawnMask << "," + << displayId <<"," + << GetEquipmentId() <<"," + << GetPositionX() << "," + << GetPositionY() << "," + << GetPositionZ() << "," + << GetOrientation() << "," + << m_respawnDelay << "," //respawn time + << (float) m_respawnradius << "," //spawn distance (float) + << (uint32) (0) << "," //currentwaypoint + << GetHealth() << "," //curhealth + << GetPower(POWER_MANA) << "," //curmana + << (m_isDeadByDefault ? 1 : 0) << "," //is_dead + << GetDefaultMovementType() << ")"; //default movement generator type + + WorldDatabase.PExecuteLog( ss.str( ).c_str( ) ); + + WorldDatabase.CommitTransaction(); +} + +void Creature::SelectLevel(const CreatureInfo *cinfo) +{ + uint32 rank = isPet()? 0 : cinfo->rank; + + // level + uint32 minlevel = std::min(cinfo->maxlevel, cinfo->minlevel); + uint32 maxlevel = std::max(cinfo->maxlevel, cinfo->minlevel); + uint32 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel); + SetLevel(level); + + float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel))/(maxlevel - minlevel); + + // health + float healthmod = _GetHealthMod(rank); + + uint32 minhealth = std::min(cinfo->maxhealth, cinfo->minhealth); + uint32 maxhealth = std::max(cinfo->maxhealth, cinfo->minhealth); + uint32 health = uint32(healthmod * (minhealth + uint32(rellevel*(maxhealth - minhealth)))); + + SetCreateHealth(health); + SetMaxHealth(health); + SetHealth(health); + + // mana + uint32 minmana = std::min(cinfo->maxmana, cinfo->minmana); + uint32 maxmana = std::max(cinfo->maxmana, cinfo->minmana); + uint32 mana = minmana + uint32(rellevel*(maxmana - minmana)); + + SetCreateMana(mana); + SetMaxPower(POWER_MANA, mana); //MAX Mana + SetPower(POWER_MANA, mana); + + SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, health); + SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, mana); + + // damage + float damagemod = _GetDamageMod(rank); + + SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); + SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); + + SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,cinfo->minrangedmg * damagemod); + SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,cinfo->maxrangedmg * damagemod); + + SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod); +} + +float Creature::_GetHealthMod(int32 Rank) +{ + switch (Rank) // define rates for each elite rank + { + case CREATURE_ELITE_NORMAL: + return sWorld.getRate(RATE_CREATURE_NORMAL_HP); + case CREATURE_ELITE_ELITE: + return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_HP); + case CREATURE_ELITE_RAREELITE: + return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_HP); + case CREATURE_ELITE_WORLDBOSS: + return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_HP); + case CREATURE_ELITE_RARE: + return sWorld.getRate(RATE_CREATURE_ELITE_RARE_HP); + default: + return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_HP); + } +} + +float Creature::_GetDamageMod(int32 Rank) +{ + switch (Rank) // define rates for each elite rank + { + case CREATURE_ELITE_NORMAL: + return sWorld.getRate(RATE_CREATURE_NORMAL_DAMAGE); + case CREATURE_ELITE_ELITE: + return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE); + case CREATURE_ELITE_RAREELITE: + return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_DAMAGE); + case CREATURE_ELITE_WORLDBOSS: + return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE); + case CREATURE_ELITE_RARE: + return sWorld.getRate(RATE_CREATURE_ELITE_RARE_DAMAGE); + default: + return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE); + } +} + +float Creature::GetSpellDamageMod(int32 Rank) +{ + switch (Rank) // define rates for each elite rank + { + case CREATURE_ELITE_NORMAL: + return sWorld.getRate(RATE_CREATURE_NORMAL_SPELLDAMAGE); + case CREATURE_ELITE_ELITE: + return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE); + case CREATURE_ELITE_RAREELITE: + return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE); + case CREATURE_ELITE_WORLDBOSS: + return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE); + case CREATURE_ELITE_RARE: + return sWorld.getRate(RATE_CREATURE_ELITE_RARE_SPELLDAMAGE); + default: + return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE); + } +} + +bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 team, const CreatureData *data) +{ + CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(Entry); + if(!cinfo) + { + sLog.outErrorDb("Error: creature entry %u does not exist.", Entry); + return false; + } + m_originalEntry = Entry; + + Object::_Create(guidlow, Entry, HIGHGUID_UNIT); + + m_DBTableGuid = guidlow; + if(!UpdateEntry(Entry, team, data)) + return false; + + //Notify the map's instance data. + //Only works if you create the object in it, not if it is moves to that map. + //Normally non-players do not teleport to other maps. + Map *map = MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); + if(map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) + { + ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this, Entry); + } + + return true; +} + +bool Creature::LoadFromDB(uint32 guid, Map *map) +{ + CreatureData const* data = objmgr.GetCreatureData(guid); + + if(!data) + { + sLog.outErrorDb("Creature (GUID: %u) not found in table `creature`, can't load. ",guid); + return false; + } + + uint32 stored_guid = guid; + if (map->GetInstanceId() != 0) guid = objmgr.GenerateLowGuid(HIGHGUID_UNIT); + + uint16 team = 0; + if(!Create(guid,map,data->id,team,data)) + return false; + + Relocate(data->posX,data->posY,data->posZ,data->orientation); + + if(!IsPositionValid()) + { + sLog.outError("ERROR: Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",GetGUIDLow(),GetEntry(),GetPositionX(),GetPositionY()); + return false; + } + + m_DBTableGuid = stored_guid; + LoadCreaturesAddon(); + + m_respawnradius = data->spawndist; + + m_respawnDelay = data->spawntimesecs; + m_isDeadByDefault = data->is_dead; + m_deathState = m_isDeadByDefault ? DEAD : ALIVE; + + m_respawnTime = objmgr.GetCreatureRespawnTime(m_DBTableGuid,GetInstanceId()); + if(m_respawnTime > time(NULL)) // not ready to respawn + m_deathState = DEAD; + else if(m_respawnTime) // respawn time set but expired + { + m_respawnTime = 0; + objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); + } + + uint32 curhealth = data->curhealth; + if(curhealth) + { + curhealth = uint32(curhealth*_GetHealthMod(GetCreatureInfo()->rank)); + if(curhealth < 1) + curhealth = 1; + } + + SetHealth(m_deathState == ALIVE ? curhealth : 0); + SetPower(POWER_MANA,data->curmana); + + SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool)); + + // checked at creature_template loading + m_defaultMovementType = MovementGeneratorType(data->movementType); + + AIM_Initialize(); + return true; +} + +void Creature::LoadEquipment(uint32 equip_entry, bool force) +{ + if(equip_entry == 0) + { + if (force) + { + for (uint8 i=0;i<3;i++) + { + SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + i, 0); + SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2), 0); + SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2) + 1, 0); + } + m_equipmentId = 0; + } + return; + } + + EquipmentInfo const *einfo = objmgr.GetEquipmentInfo(equip_entry); + if (!einfo) + return; + + m_equipmentId = equip_entry; + for (uint8 i=0;i<3;i++) + { + SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + i, einfo->equipmodel[i]); + SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2), einfo->equipinfo[i]); + SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2) + 1, einfo->equipslot[i]); + } +} + +void Creature::LoadGoods() +{ + // already loaded; + if(m_itemsLoaded) + return; + + m_vendor_items.clear(); + + VendorItemList const* vList = objmgr.GetNpcVendorItemList(GetEntry()); + if(!vList) + return; + + for (VendorItemList::const_iterator _item_iter = vList->begin(); _item_iter != vList->end(); ++_item_iter) + AddItem( (*_item_iter)->item, (*_item_iter)->maxcount, (*_item_iter)->incrtime, (*_item_iter)->ExtendedCost); + + m_itemsLoaded = true; +} + +bool Creature::hasQuest(uint32 quest_id) const +{ + QuestRelations const& qr = objmgr.mCreatureQuestRelations; + for(QuestRelations::const_iterator itr = qr.lower_bound(GetEntry()); itr != qr.upper_bound(GetEntry()); ++itr) + { + if(itr->second==quest_id) + return true; + } + return false; +} + +bool Creature::hasInvolvedQuest(uint32 quest_id) const +{ + QuestRelations const& qr = objmgr.mCreatureQuestInvolvedRelations; + for(QuestRelations::const_iterator itr = qr.lower_bound(GetEntry()); itr != qr.upper_bound(GetEntry()); ++itr) + { + if(itr->second==quest_id) + return true; + } + return false; +} + +void Creature::DeleteFromDB() +{ + objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); + objmgr.DeleteCreatureData(m_DBTableGuid); + + WorldDatabase.BeginTransaction(); + WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid); + WorldDatabase.PExecuteLog("DELETE FROM creature_addon WHERE guid = '%u'", m_DBTableGuid); + WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id = '%u'", m_DBTableGuid); + WorldDatabase.PExecuteLog("DELETE FROM game_event_creature WHERE guid = '%u'", m_DBTableGuid); + WorldDatabase.PExecuteLog("DELETE FROM game_event_model_equip WHERE guid = '%u'", m_DBTableGuid); + WorldDatabase.CommitTransaction(); +} + +float Creature::GetAttackDistance(Unit const* pl) const +{ + float aggroRate = sWorld.getRate(RATE_CREATURE_AGGRO); + if(aggroRate==0) + return 0.0f; + + int32 playerlevel = pl->getLevelForTarget(this); + int32 creaturelevel = getLevelForTarget(pl); + + int32 leveldif = playerlevel - creaturelevel; + + // "The maximum Aggro Radius has a cap of 25 levels under. Example: A level 30 char has the same Aggro Radius of a level 5 char on a level 60 mob." + if ( leveldif < - 25) + leveldif = -25; + + // "The aggro radius of a mob having the same level as the player is roughly 20 yards" + float RetDistance = 20; + + // "Aggro Radius varries with level difference at a rate of roughly 1 yard/level" + // radius grow if playlevel < creaturelevel + RetDistance -= (float)leveldif; + + if(creaturelevel+5 <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + // detect range auras + RetDistance += GetTotalAuraModifier(SPELL_AURA_MOD_DETECT_RANGE); + + // detected range auras + RetDistance += pl->GetTotalAuraModifier(SPELL_AURA_MOD_DETECTED_RANGE); + } + + // "Minimum Aggro Radius for a mob seems to be combat range (5 yards)" + if(RetDistance < 5) + RetDistance = 5; + + return (RetDistance*aggroRate); +} + +void Creature::setDeathState(DeathState s) +{ + if((s == JUST_DIED && !m_isDeadByDefault)||(s == JUST_ALIVED && m_isDeadByDefault)) + { + m_deathTimer = m_corpseDelay*1000; + + // always save boss respawn time at death to prevent crash cheating + if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY) || isWorldBoss()) + SaveRespawnTime(); + + if(!IsStopped()) + StopMoving(); + } + Unit::setDeathState(s); + + if(s == JUST_DIED) + { + SetUInt64Value (UNIT_FIELD_TARGET,0); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState) + SetUInt32Value(UNIT_NPC_FLAGS, 0); + + if(!isPet() && GetCreatureInfo()->SkinLootId) + if ( LootTemplates_Skinning.HaveLootFor(GetCreatureInfo()->SkinLootId) ) + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + + Unit::setDeathState(CORPSE); + } + if(s == JUST_ALIVED) + { + SetHealth(GetMaxHealth()); + SetLootRecipient(NULL); + Unit::setDeathState(ALIVE); + CreatureInfo const *cinfo = GetCreatureInfo(); + SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); + RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag); + clearUnitState(UNIT_STAT_ALL_STATE); + i_motionMaster.Clear(); + SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); + LoadCreaturesAddon(true); + } +} + +void Creature::Respawn() +{ + RemoveCorpse(); + + // forced recreate creature object at clients + UnitVisibility currentVis = GetVisibility(); + SetVisibility(VISIBILITY_RESPAWN); + ObjectAccessor::UpdateObjectVisibility(this); + SetVisibility(currentVis); // restore visibility state + ObjectAccessor::UpdateObjectVisibility(this); + + if(getDeathState()==DEAD) + { + objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); + m_respawnTime = time(NULL); // respawn at next tick + } +} + +bool Creature::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges) +{ + if (!spellInfo) + return false; + + if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1))) + return true; + + return Unit::IsImmunedToSpell(spellInfo, useCharges); +} + +bool Creature::IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const +{ + if (GetCreatureInfo()->MechanicImmuneMask & (1 << (mechanic-1))) + return true; + + return Unit::IsImmunedToSpellEffect(effect, mechanic); +} + +SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim) +{ + if(!pVictim) + return NULL; + + for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++) + { + if(!m_spells[i]) + continue; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] ); + if(!spellInfo) + { + sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]); + continue; + } + + bool bcontinue = true; + for(uint32 j=0;j<3;j++) + { + if( (spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE ) || + (spellInfo->Effect[j] == SPELL_EFFECT_INSTAKILL) || + (spellInfo->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) || + (spellInfo->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ) + ) + { + bcontinue = false; + break; + } + } + if(bcontinue) continue; + + if(spellInfo->manaCost > GetPower(POWER_MANA)) + continue; + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); + float range = GetSpellMaxRange(srange); + float minrange = GetSpellMinRange(srange); + float dist = GetDistance(pVictim); + //if(!isInFront( pVictim, range ) && spellInfo->AttributesEx ) + // continue; + if( dist > range || dist < minrange ) + continue; + if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) + continue; + return spellInfo; + } + return NULL; +} + +SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim) +{ + if(!pVictim) + return NULL; + + for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++) + { + if(!m_spells[i]) + continue; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] ); + if(!spellInfo) + { + sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]); + continue; + } + + bool bcontinue = true; + for(uint32 j=0;j<3;j++) + { + if( (spellInfo->Effect[j] == SPELL_EFFECT_HEAL ) ) + { + bcontinue = false; + break; + } + } + if(bcontinue) continue; + + if(spellInfo->manaCost > GetPower(POWER_MANA)) + continue; + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); + float range = GetSpellMaxRange(srange); + float minrange = GetSpellMinRange(srange); + float dist = GetDistance(pVictim); + //if(!isInFront( pVictim, range ) && spellInfo->AttributesEx ) + // continue; + if( dist > range || dist < minrange ) + continue; + if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) + continue; + return spellInfo; + } + return NULL; +} + +bool Creature::IsVisibleInGridForPlayer(Player* pl) const +{ + // gamemaster in GM mode see all, including ghosts + if(pl->isGameMaster()) + return true; + + // Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0 + if(pl->isAlive() || pl->GetDeathTimer() > 0) + { + if( GetEntry() == VISUAL_WAYPOINT && !pl->isGameMaster() ) + return false; + return isAlive() || m_deathTimer > 0 || m_isDeadByDefault && m_deathState==CORPSE; + } + + // Dead player see live creatures near own corpse + if(isAlive()) + { + Corpse *corpse = pl->GetCorpse(); + if(corpse) + { + // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level + if(corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO))) + return true; + } + } + + // Dead player see Spirit Healer or Spirit Guide + if(isSpiritService()) + return true; + + // and not see any other + return false; +} + +void Creature::CallAssistence() +{ + if( !m_AlreadyCallAssistence && getVictim() && !isPet() && !isCharmed()) + { + SetNoCallAssistence(true); + + float radius = sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTEMCE_RADIUS); + if(radius > 0) + { + std::list assistList; + + { + CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::AnyAssistCreatureInRangeCheck u_check(this, getVictim(), radius); + MaNGOS::CreatureListSearcher searcher(assistList, u_check); + + TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); + } + + for(std::list::iterator iter = assistList.begin(); iter != assistList.end(); ++iter) + { + (*iter)->SetNoCallAssistence(true); + if((*iter)->AI()) + (*iter)->AI()->AttackStart(getVictim()); + } + } + } +} + +void Creature::SaveRespawnTime() +{ + if(isPet()) + return; + + if(m_respawnTime > time(NULL)) // dead (no corpse) + objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime); + else if(m_deathTimer > 0) // dead (corpse) + objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),time(NULL)+m_respawnDelay+m_deathTimer/1000); +} + +bool Creature::IsOutOfThreatArea(Unit* pVictim) const +{ + if(!pVictim) + return true; + + if(!pVictim->IsInMap(this)) + return true; + + if(!pVictim->isTargetableForAttack()) + return true; + + if(!pVictim->isInAccessablePlaceFor(this)) + return true; + + if(sMapStore.LookupEntry(GetMapId())->Instanceable()) + return false; + + float length = pVictim->GetDistance(CombatStartX,CombatStartY,CombatStartZ); + float AttackDist = GetAttackDistance(pVictim); + uint32 ThreatRadius = sWorld.getConfig(CONFIG_THREAT_RADIUS); + + //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and ouf of combat every update tick. + return ( length > (ThreatRadius > AttackDist ? ThreatRadius : AttackDist)); +} + +CreatureDataAddon const* Creature::GetCreatureAddon() const +{ + if(CreatureDataAddon const* addon = ObjectMgr::GetCreatureAddon(m_DBTableGuid)) + return addon; + + // dependent from heroic mode entry + return ObjectMgr::GetCreatureTemplateAddon(GetCreatureInfo()->Entry); +} + +//creature_addon table +bool Creature::LoadCreaturesAddon(bool reload) +{ + CreatureDataAddon const *cainfo = GetCreatureAddon(); + if(!cainfo) + return false; + + if (cainfo->mount != 0) + Mount(cainfo->mount); + + if (cainfo->bytes0 != 0) + SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0); + + if (cainfo->bytes1 != 0) + SetUInt32Value(UNIT_FIELD_BYTES_1, cainfo->bytes1); + + if (cainfo->bytes2 != 0) + SetUInt32Value(UNIT_FIELD_BYTES_2, cainfo->bytes2); + + if (cainfo->emote != 0) + SetUInt32Value(UNIT_NPC_EMOTESTATE, cainfo->emote); + + if (cainfo->move_flags != 0) + SetUnitMovementFlags(cainfo->move_flags); + + if(cainfo->auras) + { + for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura) + { + SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura->spell_id); + if (!AdditionalSpellInfo) + { + sLog.outErrorDb("Creature (GUIDLow: %u Entry: %u ) has wrong spell %u defined in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id); + continue; + } + + // skip already applied aura + if(HasAura(cAura->spell_id,cAura->effect_idx)) + { + if(!reload) + sLog.outErrorDb("Creature (GUIDLow: %u Entry: %u ) has duplicate aura (spell %u effect %u) in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id,cAura->effect_idx); + + continue; + } + + Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, cAura->effect_idx, NULL, this, this, 0); + AddAura(AdditionalAura); + sLog.outDebug("Spell: %u with Aura %u added to creature (GUIDLow: %u Entry: %u )", cAura->spell_id, AdditionalSpellInfo->EffectApplyAuraName[0],GetGUIDLow(),GetEntry()); + } + } + return true; +} + +/// Send a message to LocalDefense channel for players oposition team in the zone +void Creature::SendZoneUnderAttackMessage(Player* attacker) +{ + uint32 enemy_team = attacker->GetTeam(); + + WorldPacket data(SMSG_ZONE_UNDER_ATTACK,4); + data << (uint32)GetZoneId(); + sWorld.SendGlobalMessage(&data,NULL,(enemy_team==ALLIANCE ? HORDE : ALLIANCE)); +} + +void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time) +{ + m_CreatureSpellCooldowns[spell_id] = end_time; +} + +void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time) +{ + m_CreatureCategoryCooldowns[category] = apply_time; +} + +void Creature::AddCreatureSpellCooldown(uint32 spellid) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); + if(!spellInfo) + return; + + uint32 cooldown = GetSpellRecoveryTime(spellInfo); + if(cooldown) + _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/1000); + + if(spellInfo->Category) + _AddCreatureCategoryCooldown(spellInfo->Category, time(NULL)); + + m_GlobalCooldown = spellInfo->StartRecoveryTime; +} + +bool Creature::HasCategoryCooldown(uint32 spell_id) const +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + if(!spellInfo) + return false; + + // check global cooldown if spell affected by it + if (spellInfo->StartRecoveryCategory > 0 && m_GlobalCooldown > 0) + return true; + + CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category); + return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / 1000)) > time(NULL)); +} + +bool Creature::HasSpellCooldown(uint32 spell_id) const +{ + CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id); + return (itr != m_CreatureSpellCooldowns.end() && itr->second > time(NULL)) || HasCategoryCooldown(spell_id); +} + +bool Creature::IsInEvadeMode() const +{ + return !i_motionMaster.empty() && i_motionMaster.GetCurrentMovementGeneratorType() == HOME_MOTION_TYPE; +} + +bool Creature::HasSpell(uint32 spellID) const +{ + uint8 i; + for(i = 0; i < CREATURE_MAX_SPELLS; ++i) + if(spellID == m_spells[i]) + break; + return i < CREATURE_MAX_SPELLS; //broke before end of iteration of known spells +} + +time_t Creature::GetRespawnTimeEx() const +{ + time_t now = time(NULL); + if(m_respawnTime > now) // dead (no corpse) + return m_respawnTime; + else if(m_deathTimer > 0) // dead (corpse) + return now+m_respawnDelay+m_deathTimer/1000; + else + return now; +} + +void Creature::GetRespawnCoord( float &x, float &y, float &z, float* ori, float* dist ) const +{ + if(CreatureData const* data = objmgr.GetCreatureData(GetDBTableGUIDLow())) + { + x = data->posX; + y = data->posY; + z = data->posZ; + if(ori) + *ori = data->orientation; + if(dist) + *dist = data->spawndist; + } + else + { + x = GetPositionX(); + y = GetPositionY(); + z = GetPositionZ(); + if(ori) + *ori = GetOrientation(); + if(dist) + *dist = 0; + } +} + +void Creature::AllLootRemovedFromCorpse() +{ + if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE)) + { + uint32 nDeathTimer; + + CreatureInfo const *cinfo = GetCreatureInfo(); + + // corpse was not skinnable -> apply corpse looted timer + if (!cinfo || !cinfo->SkinLootId) + nDeathTimer = (uint32)((m_corpseDelay * 1000) * sWorld.getRate(RATE_CORPSE_DECAY_LOOTED)); + // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update + else + nDeathTimer = 0; + + // update death timer only if looted timer is shorter + if (m_deathTimer > nDeathTimer) + m_deathTimer = nDeathTimer; + } +} + +uint32 Creature::getLevelForTarget( Unit const* target ) const +{ + if(!isWorldBoss()) + return Unit::getLevelForTarget(target); + + uint32 level = target->getLevel()+sWorld.getConfig(CONFIG_WORLD_BOSS_LEVEL_DIFF); + if(level < 1) + return 1; + if(level > 255) + return 255; + return level; +} + +char const* Creature::GetScriptName() const +{ + return ObjectMgr::GetCreatureTemplate(GetEntry())->ScriptName; +} + +TrainerSpellData const* Creature::GetTrainerSpells() const +{ + return objmgr.GetNpcTrainerSpells(GetEntry()); +} diff --git a/src/game/Creature.h b/src/game/Creature.h index d70954acefe..394d75f5355 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -1,611 +1,612 @@ -/* - * Copyright (C) 2005-2008 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 MANGOSSERVER_CREATURE_H -#define MANGOSSERVER_CREATURE_H - -#include "Common.h" -#include "Unit.h" -#include "UpdateMask.h" -#include "ItemPrototype.h" -#include "LootMgr.h" -#include "Database/DatabaseEnv.h" -#include "Cell.h" - -struct SpellEntry; - -class CreatureAI; -class Quest; -class Player; -class WorldSession; - -enum Gossip_Option -{ - GOSSIP_OPTION_NONE = 0, //UNIT_NPC_FLAG_NONE = 0, - GOSSIP_OPTION_GOSSIP = 1, //UNIT_NPC_FLAG_GOSSIP = 1, - GOSSIP_OPTION_QUESTGIVER = 2, //UNIT_NPC_FLAG_QUESTGIVER = 2, - GOSSIP_OPTION_VENDOR = 3, //UNIT_NPC_FLAG_VENDOR = 4, - GOSSIP_OPTION_TAXIVENDOR = 4, //UNIT_NPC_FLAG_TAXIVENDOR = 8, - GOSSIP_OPTION_TRAINER = 5, //UNIT_NPC_FLAG_TRAINER = 16, - GOSSIP_OPTION_SPIRITHEALER = 6, //UNIT_NPC_FLAG_SPIRITHEALER = 32, - GOSSIP_OPTION_SPIRITGUIDE = 7, //UNIT_NPC_FLAG_SPIRITGUIDE = 64, - GOSSIP_OPTION_INNKEEPER = 8, //UNIT_NPC_FLAG_INNKEEPER = 128, - GOSSIP_OPTION_BANKER = 9, //UNIT_NPC_FLAG_BANKER = 256, - GOSSIP_OPTION_PETITIONER = 10, //UNIT_NPC_FLAG_PETITIONER = 512, - GOSSIP_OPTION_TABARDDESIGNER = 11, //UNIT_NPC_FLAG_TABARDDESIGNER = 1024, - GOSSIP_OPTION_BATTLEFIELD = 12, //UNIT_NPC_FLAG_BATTLEFIELDPERSON = 2048, - GOSSIP_OPTION_AUCTIONEER = 13, //UNIT_NPC_FLAG_AUCTIONEER = 4096, - GOSSIP_OPTION_STABLEPET = 14, //UNIT_NPC_FLAG_STABLE = 8192, - GOSSIP_OPTION_ARMORER = 15, //UNIT_NPC_FLAG_ARMORER = 16384, - GOSSIP_OPTION_UNLEARNTALENTS = 16, //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER) - GOSSIP_OPTION_UNLEARNPETSKILLS = 17 //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER) -}; - -enum Gossip_Guard -{ - GOSSIP_GUARD_BANK = 32, - GOSSIP_GUARD_RIDE = 33, - GOSSIP_GUARD_GUILD = 34, - GOSSIP_GUARD_INN = 35, - GOSSIP_GUARD_MAIL = 36, - GOSSIP_GUARD_AUCTION = 37, - GOSSIP_GUARD_WEAPON = 38, - GOSSIP_GUARD_STABLE = 39, - GOSSIP_GUARD_BATTLE = 40, - GOSSIP_GUARD_SPELLTRAINER = 41, - GOSSIP_GUARD_SKILLTRAINER = 42 -}; - -enum Gossip_Guard_Spell -{ - GOSSIP_GUARD_SPELL_WARRIOR = 64, - GOSSIP_GUARD_SPELL_PALADIN = 65, - GOSSIP_GUARD_SPELL_HUNTER = 66, - GOSSIP_GUARD_SPELL_ROGUE = 67, - GOSSIP_GUARD_SPELL_PRIEST = 68, - GOSSIP_GUARD_SPELL_UNKNOWN1 = 69, - GOSSIP_GUARD_SPELL_SHAMAN = 70, - GOSSIP_GUARD_SPELL_MAGE = 71, - GOSSIP_GUARD_SPELL_WARLOCK = 72, - GOSSIP_GUARD_SPELL_UNKNOWN2 = 73, - GOSSIP_GUARD_SPELL_DRUID = 74 -}; - -enum Gossip_Guard_Skill -{ - GOSSIP_GUARD_SKILL_ALCHEMY = 80, - GOSSIP_GUARD_SKILL_BLACKSMITH = 81, - GOSSIP_GUARD_SKILL_COOKING = 82, - GOSSIP_GUARD_SKILL_ENCHANT = 83, - GOSSIP_GUARD_SKILL_FIRSTAID = 84, - GOSSIP_GUARD_SKILL_FISHING = 85, - GOSSIP_GUARD_SKILL_HERBALISM = 86, - GOSSIP_GUARD_SKILL_LEATHER = 87, - GOSSIP_GUARD_SKILL_MINING = 88, - GOSSIP_GUARD_SKILL_SKINNING = 89, - GOSSIP_GUARD_SKILL_TAILORING = 90, - GOSSIP_GUARD_SKILL_ENGINERING = 91 -}; - -struct GossipOption -{ - uint32 Id; - uint32 GossipId; - uint32 NpcFlag; - uint32 Icon; - uint32 Action; - std::string Option; -}; - -struct CreatureItem -{ - CreatureItem(uint32 _item, uint32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost) - : id(_item), count(_maxcount), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost), lastincr((uint32)time(NULL)) {} - - uint32 id; - uint32 count; - uint32 maxcount; - uint32 incrtime; - uint32 lastincr; - uint32 ExtendedCost; -}; - -struct TrainerSpell -{ - SpellEntry const* spell; - uint32 spellcost; - uint32 reqskill; - uint32 reqskillvalue; - uint32 reqlevel; -}; - -enum CreatureFlagsExtra -{ - CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group - CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) - CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry - CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry - CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block - CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks - CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP -}; - -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform -#if defined( __GNUC__ ) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -// from `creature_template` table -struct CreatureInfo -{ - uint32 Entry; - uint32 HeroicEntry; - uint32 DisplayID_A; - uint32 DisplayID_A2; - uint32 DisplayID_H; - uint32 DisplayID_H2; - char* Name; - char* SubName; - char* IconName; - uint32 minlevel; - uint32 maxlevel; - uint32 minhealth; - uint32 maxhealth; - uint32 minmana; - uint32 maxmana; - uint32 armor; - uint32 faction_A; - uint32 faction_H; - uint32 npcflag; - float speed; - float scale; - uint32 rank; - float mindmg; - float maxdmg; - uint32 dmgschool; - uint32 attackpower; - uint32 baseattacktime; - uint32 rangeattacktime; - uint32 Flags; - uint32 dynamicflags; - uint32 family; - uint32 trainer_type; - uint32 trainer_spell; - uint32 classNum; - uint32 race; - float minrangedmg; - float maxrangedmg; - uint32 rangedattackpower; - uint32 type; - uint32 flag1; - uint32 lootid; - uint32 pickpocketLootId; - uint32 SkinLootId; - int32 resistance1; - int32 resistance2; - int32 resistance3; - int32 resistance4; - int32 resistance5; - int32 resistance6; - uint32 spell1; - uint32 spell2; - uint32 spell3; - uint32 spell4; - uint32 PetSpellDataId; - uint32 mingold; - uint32 maxgold; - char const* AIName; - uint32 MovementType; - uint32 InhabitType; - bool RacialLeader; - bool RegenHealth; - uint32 equipmentId; - uint32 MechanicImmuneMask; - uint32 flags_extra; - char const* ScriptName; -}; - -struct CreatureLocale -{ - std::vector Name; - std::vector SubName; -}; - -struct EquipmentInfo -{ - uint32 entry; - uint32 equipmodel[3]; - uint32 equipinfo[3]; - uint32 equipslot[3]; -}; - -// from `creature` table -struct CreatureData -{ - uint32 id; // entry in creature_template - uint16 mapid; - uint32 displayid; - int32 equipmentId; - float posX; - float posY; - float posZ; - float orientation; - uint32 spawntimesecs; - float spawndist; - uint32 currentwaypoint; - uint32 curhealth; - uint32 curmana; - bool is_dead; - uint8 movementType; - uint8 spawnMask; -}; - -struct CreatureDataAddonAura -{ - uint16 spell_id; - uint8 effect_idx; -}; - -// from `creature_addon` table -struct CreatureDataAddon -{ - uint32 guidOrEntry; - uint32 mount; - uint32 bytes0; - uint32 bytes1; - uint32 bytes2; - uint32 emote; - uint32 move_flags; - CreatureDataAddonAura const* auras; // loaded as char* "spell1 eff1 spell2 eff2 ... " -}; - -struct CreatureModelInfo -{ - uint32 modelid; - float bounding_radius; - float combat_reach; - uint8 gender; - uint32 modelid_other_gender; -}; - -enum InhabitTypeValues -{ - INHABIT_GROUND = 1, - INHABIT_WATER = 2, - INHABIT_AIR = 4, - INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR -}; - -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform -#if defined( __GNUC__ ) -#pragma pack() -#else -#pragma pack(pop) -#endif - -typedef std::list GossipOptionList; - -typedef std::map CreatureSpellCooldowns; - -// max different by z coordinate for creature aggro reaction -#define CREATURE_Z_ATTACK_RANGE 3 - -#define MAX_VENDOR_ITEMS 255 // Limitation in item count field size in SMSG_LIST_INVENTORY - -class MANGOS_DLL_SPEC Creature : public Unit -{ - CreatureAI *i_AI; - - public: - - explicit Creature(); - virtual ~Creature(); - - void AddToWorld(); - void RemoveFromWorld(); - - bool Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, const CreatureData *data = NULL); - bool LoadCreaturesAddon(bool reload = false); - void SelectLevel(const CreatureInfo *cinfo); - void LoadEquipment(uint32 equip_entry, bool force=false); - - uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; } - char const* GetSubName() const { return GetCreatureInfo()->SubName; } - - void Update( uint32 time ); // overwrited Unit::Update - void GetRespawnCoord(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const; - uint32 GetEquipmentId() const { return m_equipmentId; } - - bool isPet() const { return m_isPet; } - void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } - bool isTotem() const { return m_isTotem; } - bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; } - bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; } - bool canWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; } - bool canSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; } - bool canFly() const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; } - ///// TODO RENAME THIS!!!!! - bool isCanTrainingOf(Player* player, bool msg) const; - bool isCanIneractWithBattleMaster(Player* player, bool msg) const; - bool isCanTrainingAndResetTalentsOf(Player* pPlayer) const; - bool IsOutOfThreatArea(Unit* pVictim) const; - bool IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges = false); - // redefine Unit::IsImmunedToSpell - bool IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const; - // redefine Unit::IsImmunedToSpellEffect - bool isElite() const - { - if(isPet()) - return false; - - uint32 rank = GetCreatureInfo()->rank; - return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE; - } - - bool isWorldBoss() const - { - if(isPet()) - return false; - - return GetCreatureInfo()->rank == CREATURE_ELITE_WORLDBOSS; - } - - uint32 getLevelForTarget(Unit const* target) const; // overwrite Unit::getLevelForTarget for boss level support - - bool IsInEvadeMode() const; - - bool AIM_Initialize(); - - void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type); - CreatureAI* AI() { return i_AI; } - - uint32 GetShieldBlockValue() const //dunno mob block value - { - return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20)); - } - - SpellSchoolMask GetMeleeDamageSchoolMask() const { return m_meleeDamageSchoolMask; } - void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); } - - void _AddCreatureSpellCooldown(uint32 spell_id, time_t end_time); - void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time); - void AddCreatureSpellCooldown(uint32 spellid); - bool HasSpellCooldown(uint32 spell_id) const; - bool HasCategoryCooldown(uint32 spell_id) const; - - bool HasSpell(uint32 spellID) const; - - bool UpdateEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); - bool UpdateStats(Stats stat); - bool UpdateAllStats(); - void UpdateResistances(uint32 school); - void UpdateArmor(); - void UpdateMaxHealth(); - void UpdateMaxPower(Powers power); - void UpdateAttackPowerAndDamage(bool ranged = false); - void UpdateDamagePhysical(WeaponAttackType attType); - uint32 GetCurrentEquipmentId() { return m_equipmentId; } - float GetSpellDamageMod(int32 Rank); - - /*********************************************************/ - /*** VENDOR SYSTEM ***/ - /*********************************************************/ - void LoadGoods(); // must be called before access to vendor items, lazy loading at first call - void ReloadGoods() { m_itemsLoaded = false; LoadGoods(); } - - CreatureItem* GetItem(uint32 slot) - { - if(slot>=m_vendor_items.size()) return NULL; - return &m_vendor_items[slot]; - } - uint8 GetItemCount() const { return m_vendor_items.size(); } - void AddItem( uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost) - { - m_vendor_items.push_back(CreatureItem(item, maxcount, ptime, ExtendedCost)); - } - bool RemoveItem( uint32 item_id ) - { - for(CreatureItems::iterator i = m_vendor_items.begin(); i != m_vendor_items.end(); ++i ) - { - if(i->id==item_id) - { - m_vendor_items.erase(i); - return true; - } - } - return false; - } - CreatureItem* FindItem(uint32 item_id) - { - for(CreatureItems::iterator i = m_vendor_items.begin(); i != m_vendor_items.end(); ++i ) - if(i->id==item_id) - return &*i; - return NULL; - } - - /*********************************************************/ - /*** TRAINER SYSTEM ***/ - /*********************************************************/ - typedef std::list SpellsList; - void LoadTrainerSpells(); // must be called before access to trainer spells, lazy loading at first call - void ReloadTrainerSpells() { m_trainerSpellsLoaded = false; LoadTrainerSpells(); } - SpellsList const& GetTrainerSpells() const { return m_trainer_spells; } - uint32 GetTrainerType() const { return m_trainer_type; } - - CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; } - CreatureDataAddon const* GetCreatureAddon() const; - char const* GetScriptName() const; - - void prepareGossipMenu( Player *pPlayer,uint32 gossipid ); - void sendPreparedGossip( Player* player); - void OnGossipSelect(Player* player, uint32 option); - void OnPoiSelect(Player* player, GossipOption const *gossip); - - uint32 GetGossipTextId(uint32 action, uint32 zoneid); - uint32 GetNpcTextId(); - void LoadGossipOptions(); - GossipOption const* GetGossipOption( uint32 id ) const; - void addGossipOption(GossipOption const& gso) { m_goptions.push_back(gso); } - - void setEmoteState(uint8 emote) { m_emoteState = emote; }; - void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); } - void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); } - void TextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(text,TargetGuid,IsBossEmote); } - void Whisper(const char* text, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(text,receiver,IsBossWhisper); } - void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } - void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } - void TextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(textId,TargetGuid,IsBossEmote); } - void Whisper(int32 textId, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(textId,receiver,IsBossWhisper); } - - void setDeathState(DeathState s); // overwrite virtual Unit::setDeathState - - bool LoadFromDB(uint32 guid, Map *map); - void SaveToDB(); - // overwrited in Pet - virtual void SaveToDB(uint32 mapid, uint8 spawnMask); - virtual void DeleteFromDB(); // overwrited in Pet - - Loot loot; - bool lootForPickPocketed; - bool lootForBody; - Player *GetLootRecipient() const; - bool hasLootRecipient() const { return m_lootRecipient!=0; } - - void SetLootRecipient (Unit* unit); - void AllLootRemovedFromCorpse(); - - SpellEntry const *reachWithSpellAttack(Unit *pVictim); - SpellEntry const *reachWithSpellCure(Unit *pVictim); - - uint32 m_spells[CREATURE_MAX_SPELLS]; - CreatureSpellCooldowns m_CreatureSpellCooldowns; - CreatureSpellCooldowns m_CreatureCategoryCooldowns; - uint32 m_GlobalCooldown; - - float GetAttackDistance(Unit const* pl) const; - - void CallAssistence(); - void SetNoCallAssistence(bool val) { m_AlreadyCallAssistence = val; } - - MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; } - void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; } - - // for use only in LoadHelper, Map::Add Map::CreatureCellRelocation - Cell const& GetCurrentCell() const { return m_currentCell; } - void SetCurrentCell(Cell const& cell) { m_currentCell = cell; } - - bool IsVisibleInGridForPlayer(Player* pl) const; - - void RemoveCorpse(); - - time_t const& GetRespawnTime() const { return m_respawnTime; } - time_t GetRespawnTimeEx() const; - void SetRespawnTime(uint32 respawn) { m_respawnTime = respawn ? time(NULL) + respawn : 0; } - void Respawn(); - void SaveRespawnTime(); - - uint32 GetRespawnDelay() const { return m_respawnDelay; } - void SetRespawnDelay(uint32 delay) { m_respawnDelay = delay; } - - float GetRespawnRadius() const { return m_respawnradius; } - void SetRespawnRadius(float dist) { m_respawnradius = dist; } - - uint32 m_groupLootTimer; // (msecs)timer used for group loot - uint64 lootingGroupLeaderGUID; // used to find group which is looting corpse - - void SendZoneUnderAttackMessage(Player* attacker); - - bool hasQuest(uint32 quest_id) const; - bool hasInvolvedQuest(uint32 quest_id) const; - - GridReference &GetGridRef() { return m_gridRef; } - bool isRegeneratingHealth() { return m_regenHealth; } - virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; } - virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const - { - if (pos >= CREATURE_MAX_SPELLS || m_charmInfo->GetCharmSpell(pos)->active != ACT_ENABLED) - return 0; - else - return m_charmInfo->GetCharmSpell(pos)->spellId; - } - - void SetCombatStartPosition(float x, float y, float z) { CombatStartX = x; CombatStartY = y; CombatStartZ = z; } - void GetCombatStartPosition(float &x, float &y, float &z) { x = CombatStartX; y = CombatStartY; z = CombatStartZ; } - - protected: - bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); - bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); - - // vendor items - typedef std::vector CreatureItems; - CreatureItems m_vendor_items; - bool m_itemsLoaded; // vendor items loading state - - // trainer spells - bool m_trainerSpellsLoaded; // trainer spells loading state - SpellsList m_trainer_spells; - uint32 m_trainer_type; // trainer type based at trainer spells, can be different from creature_template value. - // req. for correct show non-prof. trainers like weaponmaster. - void _RealtimeSetCreatureInfo(); - - static float _GetHealthMod(int32 Rank); - static float _GetDamageMod(int32 Rank); - - uint32 m_lootMoney; - uint64 m_lootRecipient; - - /// Timers - uint32 m_deathTimer; // (msecs)timer for death or corpse disappearance - time_t m_respawnTime; // (secs) time of next respawn - uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning - uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance - float m_respawnradius; - - bool m_gossipOptionLoaded; - GossipOptionList m_goptions; - uint32 m_NPCTextId; // cached value - - uint8 m_emoteState; - bool m_isPet; // set only in Pet::Pet - bool m_isTotem; // set only in Totem::Totem - void RegenerateMana(); - void RegenerateHealth(); - uint32 m_regenTimer; - MovementGeneratorType m_defaultMovementType; - Cell m_currentCell; // store current cell where creature listed - uint32 m_DBTableGuid; - uint32 m_equipmentId; - - bool m_AlreadyCallAssistence; - bool m_regenHealth; - bool m_AI_locked; - bool m_isDeadByDefault; - - SpellSchoolMask m_meleeDamageSchoolMask; - uint32 m_originalEntry; - - float CombatStartX; - float CombatStartY; - float CombatStartZ; - private: - GridReference m_gridRef; - CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry()) -}; -#endif +/* + * Copyright (C) 2005-2008 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 MANGOSSERVER_CREATURE_H +#define MANGOSSERVER_CREATURE_H + +#include "Common.h" +#include "Unit.h" +#include "UpdateMask.h" +#include "ItemPrototype.h" +#include "LootMgr.h" +#include "Database/DatabaseEnv.h" +#include "Cell.h" + +struct SpellEntry; + +class CreatureAI; +class Quest; +class Player; +class WorldSession; + +enum Gossip_Option +{ + GOSSIP_OPTION_NONE = 0, //UNIT_NPC_FLAG_NONE = 0, + GOSSIP_OPTION_GOSSIP = 1, //UNIT_NPC_FLAG_GOSSIP = 1, + GOSSIP_OPTION_QUESTGIVER = 2, //UNIT_NPC_FLAG_QUESTGIVER = 2, + GOSSIP_OPTION_VENDOR = 3, //UNIT_NPC_FLAG_VENDOR = 4, + GOSSIP_OPTION_TAXIVENDOR = 4, //UNIT_NPC_FLAG_TAXIVENDOR = 8, + GOSSIP_OPTION_TRAINER = 5, //UNIT_NPC_FLAG_TRAINER = 16, + GOSSIP_OPTION_SPIRITHEALER = 6, //UNIT_NPC_FLAG_SPIRITHEALER = 32, + GOSSIP_OPTION_SPIRITGUIDE = 7, //UNIT_NPC_FLAG_SPIRITGUIDE = 64, + GOSSIP_OPTION_INNKEEPER = 8, //UNIT_NPC_FLAG_INNKEEPER = 128, + GOSSIP_OPTION_BANKER = 9, //UNIT_NPC_FLAG_BANKER = 256, + GOSSIP_OPTION_PETITIONER = 10, //UNIT_NPC_FLAG_PETITIONER = 512, + GOSSIP_OPTION_TABARDDESIGNER = 11, //UNIT_NPC_FLAG_TABARDDESIGNER = 1024, + GOSSIP_OPTION_BATTLEFIELD = 12, //UNIT_NPC_FLAG_BATTLEFIELDPERSON = 2048, + GOSSIP_OPTION_AUCTIONEER = 13, //UNIT_NPC_FLAG_AUCTIONEER = 4096, + GOSSIP_OPTION_STABLEPET = 14, //UNIT_NPC_FLAG_STABLE = 8192, + GOSSIP_OPTION_ARMORER = 15, //UNIT_NPC_FLAG_ARMORER = 16384, + GOSSIP_OPTION_UNLEARNTALENTS = 16, //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER) + GOSSIP_OPTION_UNLEARNPETSKILLS = 17 //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER) +}; + +enum Gossip_Guard +{ + GOSSIP_GUARD_BANK = 32, + GOSSIP_GUARD_RIDE = 33, + GOSSIP_GUARD_GUILD = 34, + GOSSIP_GUARD_INN = 35, + GOSSIP_GUARD_MAIL = 36, + GOSSIP_GUARD_AUCTION = 37, + GOSSIP_GUARD_WEAPON = 38, + GOSSIP_GUARD_STABLE = 39, + GOSSIP_GUARD_BATTLE = 40, + GOSSIP_GUARD_SPELLTRAINER = 41, + GOSSIP_GUARD_SKILLTRAINER = 42 +}; + +enum Gossip_Guard_Spell +{ + GOSSIP_GUARD_SPELL_WARRIOR = 64, + GOSSIP_GUARD_SPELL_PALADIN = 65, + GOSSIP_GUARD_SPELL_HUNTER = 66, + GOSSIP_GUARD_SPELL_ROGUE = 67, + GOSSIP_GUARD_SPELL_PRIEST = 68, + GOSSIP_GUARD_SPELL_UNKNOWN1 = 69, + GOSSIP_GUARD_SPELL_SHAMAN = 70, + GOSSIP_GUARD_SPELL_MAGE = 71, + GOSSIP_GUARD_SPELL_WARLOCK = 72, + GOSSIP_GUARD_SPELL_UNKNOWN2 = 73, + GOSSIP_GUARD_SPELL_DRUID = 74 +}; + +enum Gossip_Guard_Skill +{ + GOSSIP_GUARD_SKILL_ALCHEMY = 80, + GOSSIP_GUARD_SKILL_BLACKSMITH = 81, + GOSSIP_GUARD_SKILL_COOKING = 82, + GOSSIP_GUARD_SKILL_ENCHANT = 83, + GOSSIP_GUARD_SKILL_FIRSTAID = 84, + GOSSIP_GUARD_SKILL_FISHING = 85, + GOSSIP_GUARD_SKILL_HERBALISM = 86, + GOSSIP_GUARD_SKILL_LEATHER = 87, + GOSSIP_GUARD_SKILL_MINING = 88, + GOSSIP_GUARD_SKILL_SKINNING = 89, + GOSSIP_GUARD_SKILL_TAILORING = 90, + GOSSIP_GUARD_SKILL_ENGINERING = 91 +}; + +struct GossipOption +{ + uint32 Id; + uint32 GossipId; + uint32 NpcFlag; + uint32 Icon; + uint32 Action; + std::string Option; +}; + +struct CreatureItem +{ + CreatureItem(uint32 _item, uint32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost) + : id(_item), count(_maxcount), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost), lastincr((uint32)time(NULL)) {} + + uint32 id; + uint32 count; + uint32 maxcount; + uint32 incrtime; + uint32 lastincr; + uint32 ExtendedCost; +}; + +enum CreatureFlagsExtra +{ + CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group + CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) + CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry + CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry + CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block + CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks + CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP +}; + +// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform +#if defined( __GNUC__ ) +#pragma pack(1) +#else +#pragma pack(push,1) +#endif + +// from `creature_template` table +struct CreatureInfo +{ + uint32 Entry; + uint32 HeroicEntry; + uint32 DisplayID_A; + uint32 DisplayID_A2; + uint32 DisplayID_H; + uint32 DisplayID_H2; + char* Name; + char* SubName; + char* IconName; + uint32 minlevel; + uint32 maxlevel; + uint32 minhealth; + uint32 maxhealth; + uint32 minmana; + uint32 maxmana; + uint32 armor; + uint32 faction_A; + uint32 faction_H; + uint32 npcflag; + float speed; + float scale; + uint32 rank; + float mindmg; + float maxdmg; + uint32 dmgschool; + uint32 attackpower; + uint32 baseattacktime; + uint32 rangeattacktime; + uint32 Flags; + uint32 dynamicflags; + uint32 family; + uint32 trainer_type; + uint32 trainer_spell; + uint32 classNum; + uint32 race; + float minrangedmg; + float maxrangedmg; + uint32 rangedattackpower; + uint32 type; + uint32 flag1; + uint32 lootid; + uint32 pickpocketLootId; + uint32 SkinLootId; + int32 resistance1; + int32 resistance2; + int32 resistance3; + int32 resistance4; + int32 resistance5; + int32 resistance6; + uint32 spell1; + uint32 spell2; + uint32 spell3; + uint32 spell4; + uint32 PetSpellDataId; + uint32 mingold; + uint32 maxgold; + char const* AIName; + uint32 MovementType; + uint32 InhabitType; + bool RacialLeader; + bool RegenHealth; + uint32 equipmentId; + uint32 MechanicImmuneMask; + uint32 flags_extra; + char const* ScriptName; +}; + +struct CreatureLocale +{ + std::vector Name; + std::vector SubName; +}; + +struct EquipmentInfo +{ + uint32 entry; + uint32 equipmodel[3]; + uint32 equipinfo[3]; + uint32 equipslot[3]; +}; + +// from `creature` table +struct CreatureData +{ + uint32 id; // entry in creature_template + uint16 mapid; + uint32 displayid; + int32 equipmentId; + float posX; + float posY; + float posZ; + float orientation; + uint32 spawntimesecs; + float spawndist; + uint32 currentwaypoint; + uint32 curhealth; + uint32 curmana; + bool is_dead; + uint8 movementType; + uint8 spawnMask; +}; + +struct CreatureDataAddonAura +{ + uint16 spell_id; + uint8 effect_idx; +}; + +// from `creature_addon` table +struct CreatureDataAddon +{ + uint32 guidOrEntry; + uint32 mount; + uint32 bytes0; + uint32 bytes1; + uint32 bytes2; + uint32 emote; + uint32 move_flags; + CreatureDataAddonAura const* auras; // loaded as char* "spell1 eff1 spell2 eff2 ... " +}; + +struct CreatureModelInfo +{ + uint32 modelid; + float bounding_radius; + float combat_reach; + uint8 gender; + uint32 modelid_other_gender; +}; + +enum InhabitTypeValues +{ + INHABIT_GROUND = 1, + INHABIT_WATER = 2, + INHABIT_AIR = 4, + INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR +}; + +// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform +#if defined( __GNUC__ ) +#pragma pack() +#else +#pragma pack(pop) +#endif + +struct TrainerSpell +{ + uint32 spell; + uint32 spellcost; + uint32 reqskill; + uint32 reqskillvalue; + uint32 reqlevel; +}; + +typedef std::vector TrainerSpellList; + +struct TrainerSpellData +{ + TrainerSpellData() : trainerType(0) {} + + TrainerSpellList spellList; + uint32 trainerType; // trainer type based at trainer spells, can be different from creature_template value. + // req. for correct show non-prof. trainers like weaponmaster, allowed values 0 and 2. + + void Clear(); + TrainerSpell const* Find(uint32 spell_id) const; +}; + +typedef std::list GossipOptionList; + +typedef std::map CreatureSpellCooldowns; + +// max different by z coordinate for creature aggro reaction +#define CREATURE_Z_ATTACK_RANGE 3 + +#define MAX_VENDOR_ITEMS 255 // Limitation in item count field size in SMSG_LIST_INVENTORY + +class MANGOS_DLL_SPEC Creature : public Unit +{ + CreatureAI *i_AI; + + public: + + explicit Creature(); + virtual ~Creature(); + + void AddToWorld(); + void RemoveFromWorld(); + + bool Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, const CreatureData *data = NULL); + bool LoadCreaturesAddon(bool reload = false); + void SelectLevel(const CreatureInfo *cinfo); + void LoadEquipment(uint32 equip_entry, bool force=false); + + uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; } + char const* GetSubName() const { return GetCreatureInfo()->SubName; } + + void Update( uint32 time ); // overwrited Unit::Update + void GetRespawnCoord(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const; + uint32 GetEquipmentId() const { return m_equipmentId; } + + bool isPet() const { return m_isPet; } + void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } + bool isTotem() const { return m_isTotem; } + bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; } + bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; } + bool canWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; } + bool canSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; } + bool canFly() const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; } + ///// TODO RENAME THIS!!!!! + bool isCanTrainingOf(Player* player, bool msg) const; + bool isCanIneractWithBattleMaster(Player* player, bool msg) const; + bool isCanTrainingAndResetTalentsOf(Player* pPlayer) const; + bool IsOutOfThreatArea(Unit* pVictim) const; + bool IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges = false); + // redefine Unit::IsImmunedToSpell + bool IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const; + // redefine Unit::IsImmunedToSpellEffect + bool isElite() const + { + if(isPet()) + return false; + + uint32 rank = GetCreatureInfo()->rank; + return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE; + } + + bool isWorldBoss() const + { + if(isPet()) + return false; + + return GetCreatureInfo()->rank == CREATURE_ELITE_WORLDBOSS; + } + + uint32 getLevelForTarget(Unit const* target) const; // overwrite Unit::getLevelForTarget for boss level support + + bool IsInEvadeMode() const; + + bool AIM_Initialize(); + + void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type); + CreatureAI* AI() { return i_AI; } + + uint32 GetShieldBlockValue() const //dunno mob block value + { + return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20)); + } + + SpellSchoolMask GetMeleeDamageSchoolMask() const { return m_meleeDamageSchoolMask; } + void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); } + + void _AddCreatureSpellCooldown(uint32 spell_id, time_t end_time); + void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time); + void AddCreatureSpellCooldown(uint32 spellid); + bool HasSpellCooldown(uint32 spell_id) const; + bool HasCategoryCooldown(uint32 spell_id) const; + + bool HasSpell(uint32 spellID) const; + + bool UpdateEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); + bool UpdateStats(Stats stat); + bool UpdateAllStats(); + void UpdateResistances(uint32 school); + void UpdateArmor(); + void UpdateMaxHealth(); + void UpdateMaxPower(Powers power); + void UpdateAttackPowerAndDamage(bool ranged = false); + void UpdateDamagePhysical(WeaponAttackType attType); + uint32 GetCurrentEquipmentId() { return m_equipmentId; } + float GetSpellDamageMod(int32 Rank); + + /*********************************************************/ + /*** VENDOR SYSTEM ***/ + /*********************************************************/ + void LoadGoods(); // must be called before access to vendor items, lazy loading at first call + void ReloadGoods() { m_itemsLoaded = false; LoadGoods(); } + + CreatureItem* GetItem(uint32 slot) + { + if(slot>=m_vendor_items.size()) return NULL; + return &m_vendor_items[slot]; + } + uint8 GetItemCount() const { return m_vendor_items.size(); } + void AddItem( uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost) + { + m_vendor_items.push_back(CreatureItem(item, maxcount, ptime, ExtendedCost)); + } + bool RemoveItem( uint32 item_id ) + { + for(CreatureItems::iterator i = m_vendor_items.begin(); i != m_vendor_items.end(); ++i ) + { + if(i->id==item_id) + { + m_vendor_items.erase(i); + return true; + } + } + return false; + } + CreatureItem* FindItem(uint32 item_id) + { + for(CreatureItems::iterator i = m_vendor_items.begin(); i != m_vendor_items.end(); ++i ) + if(i->id==item_id) + return &*i; + return NULL; + } + + TrainerSpellData const* GetTrainerSpells() const; + + CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; } + CreatureDataAddon const* GetCreatureAddon() const; + char const* GetScriptName() const; + + void prepareGossipMenu( Player *pPlayer,uint32 gossipid ); + void sendPreparedGossip( Player* player); + void OnGossipSelect(Player* player, uint32 option); + void OnPoiSelect(Player* player, GossipOption const *gossip); + + uint32 GetGossipTextId(uint32 action, uint32 zoneid); + uint32 GetNpcTextId(); + void LoadGossipOptions(); + GossipOption const* GetGossipOption( uint32 id ) const; + void addGossipOption(GossipOption const& gso) { m_goptions.push_back(gso); } + + void setEmoteState(uint8 emote) { m_emoteState = emote; }; + void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); } + void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); } + void TextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(text,TargetGuid,IsBossEmote); } + void Whisper(const char* text, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(text,receiver,IsBossWhisper); } + void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } + void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } + void TextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(textId,TargetGuid,IsBossEmote); } + void Whisper(int32 textId, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(textId,receiver,IsBossWhisper); } + + void setDeathState(DeathState s); // overwrite virtual Unit::setDeathState + + bool LoadFromDB(uint32 guid, Map *map); + void SaveToDB(); + // overwrited in Pet + virtual void SaveToDB(uint32 mapid, uint8 spawnMask); + virtual void DeleteFromDB(); // overwrited in Pet + + Loot loot; + bool lootForPickPocketed; + bool lootForBody; + Player *GetLootRecipient() const; + bool hasLootRecipient() const { return m_lootRecipient!=0; } + + void SetLootRecipient (Unit* unit); + void AllLootRemovedFromCorpse(); + + SpellEntry const *reachWithSpellAttack(Unit *pVictim); + SpellEntry const *reachWithSpellCure(Unit *pVictim); + + uint32 m_spells[CREATURE_MAX_SPELLS]; + CreatureSpellCooldowns m_CreatureSpellCooldowns; + CreatureSpellCooldowns m_CreatureCategoryCooldowns; + uint32 m_GlobalCooldown; + + float GetAttackDistance(Unit const* pl) const; + + void CallAssistence(); + void SetNoCallAssistence(bool val) { m_AlreadyCallAssistence = val; } + + MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; } + void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; } + + // for use only in LoadHelper, Map::Add Map::CreatureCellRelocation + Cell const& GetCurrentCell() const { return m_currentCell; } + void SetCurrentCell(Cell const& cell) { m_currentCell = cell; } + + bool IsVisibleInGridForPlayer(Player* pl) const; + + void RemoveCorpse(); + + time_t const& GetRespawnTime() const { return m_respawnTime; } + time_t GetRespawnTimeEx() const; + void SetRespawnTime(uint32 respawn) { m_respawnTime = respawn ? time(NULL) + respawn : 0; } + void Respawn(); + void SaveRespawnTime(); + + uint32 GetRespawnDelay() const { return m_respawnDelay; } + void SetRespawnDelay(uint32 delay) { m_respawnDelay = delay; } + + float GetRespawnRadius() const { return m_respawnradius; } + void SetRespawnRadius(float dist) { m_respawnradius = dist; } + + uint32 m_groupLootTimer; // (msecs)timer used for group loot + uint64 lootingGroupLeaderGUID; // used to find group which is looting corpse + + void SendZoneUnderAttackMessage(Player* attacker); + + bool hasQuest(uint32 quest_id) const; + bool hasInvolvedQuest(uint32 quest_id) const; + + GridReference &GetGridRef() { return m_gridRef; } + bool isRegeneratingHealth() { return m_regenHealth; } + virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; } + virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const + { + if (pos >= CREATURE_MAX_SPELLS || m_charmInfo->GetCharmSpell(pos)->active != ACT_ENABLED) + return 0; + else + return m_charmInfo->GetCharmSpell(pos)->spellId; + } + + void SetCombatStartPosition(float x, float y, float z) { CombatStartX = x; CombatStartY = y; CombatStartZ = z; } + void GetCombatStartPosition(float &x, float &y, float &z) { x = CombatStartX; y = CombatStartY; z = CombatStartZ; } + + protected: + bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); + bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); + + // vendor items + typedef std::vector CreatureItems; + CreatureItems m_vendor_items; + bool m_itemsLoaded; // vendor items loading state + + void _RealtimeSetCreatureInfo(); + + static float _GetHealthMod(int32 Rank); + static float _GetDamageMod(int32 Rank); + + uint32 m_lootMoney; + uint64 m_lootRecipient; + + /// Timers + uint32 m_deathTimer; // (msecs)timer for death or corpse disappearance + time_t m_respawnTime; // (secs) time of next respawn + uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning + uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance + float m_respawnradius; + + bool m_gossipOptionLoaded; + GossipOptionList m_goptions; + + uint8 m_emoteState; + bool m_isPet; // set only in Pet::Pet + bool m_isTotem; // set only in Totem::Totem + void RegenerateMana(); + void RegenerateHealth(); + uint32 m_regenTimer; + MovementGeneratorType m_defaultMovementType; + Cell m_currentCell; // store current cell where creature listed + uint32 m_DBTableGuid; + uint32 m_equipmentId; + + bool m_AlreadyCallAssistence; + bool m_regenHealth; + bool m_AI_locked; + bool m_isDeadByDefault; + + SpellSchoolMask m_meleeDamageSchoolMask; + uint32 m_originalEntry; + + float CombatStartX; + float CombatStartY; + float CombatStartZ; + private: + GridReference m_gridRef; + CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry()) +}; +#endif diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp index 2e8b6f1a230..a113a3f1c7e 100644 --- a/src/game/CreatureAISelector.cpp +++ b/src/game/CreatureAISelector.cpp @@ -1,120 +1,118 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Creature.h" -#include "CreatureAIImpl.h" -#include "CreatureAISelector.h" -#include "NullCreatureAI.h" -#include "Policies/SingletonImp.h" -#include "MovementGenerator.h" -#include "ScriptCalls.h" -#include "Pet.h" - -INSTANTIATE_SINGLETON_1(CreatureAIRegistry); -INSTANTIATE_SINGLETON_1(MovementGeneratorRegistry); - -namespace FactorySelector -{ - CreatureAI* selectAI(Creature *creature) - { - // Allow scripting AI for normal creatures and not controlled pets (guardians and mini-pets) - if((!creature->isPet() || !((Pet*)creature)->isControlled()) && !creature->isCharmed()) - if(CreatureAI* scriptedAI = Script->GetAI(creature)) - return scriptedAI; - - CreatureAIRegistry &ai_registry(CreatureAIRepository::Instance()); - assert( creature->GetCreatureInfo() != NULL ); - CreatureInfo const *cinfo=creature->GetCreatureInfo(); - - const CreatureAICreator *ai_factory = NULL; - - std::string ainame=cinfo->AIName; - - // select by script name - if( !ainame.empty()) - ai_factory = ai_registry.GetRegistryItem( ainame.c_str() ); - - // select by NPC flags - if(!ai_factory) - { - if( creature->isGuard() ) - ainame="GuardAI"; - else if(creature->isPet() || creature->isCharmed()) - ainame="PetAI"; - else if(creature->isTotem()) - ainame="TotemAI"; - - ai_factory = ai_registry.GetRegistryItem( ainame.c_str() ); - } - - // select by permit check - if(!ai_factory) - { - int best_val = -1; - typedef CreatureAIRegistry::RegistryMapType RMT; - RMT const &l = ai_registry.GetRegisteredItems(); - for( RMT::const_iterator iter = l.begin(); iter != l.end(); ++iter) - { - const CreatureAICreator *factory = iter->second; - const SelectableAI *p = dynamic_cast(factory); - assert( p != NULL ); - int val = p->Permit(creature); - if( val > best_val ) - { - best_val = val; - ai_factory = p; - } - } - } - - // select NullCreatureAI if not another cases - ainame = (ai_factory == NULL) ? "NullCreatureAI" : ai_factory->key(); - - DEBUG_LOG("Creature %u used AI is %s.", creature->GetGUIDLow(), ainame.c_str() ); - return ( ai_factory == NULL ? new NullCreatureAI : ai_factory->Create(creature) ); - } - - MovementGenerator* selectMovementGenerator(Creature *creature) - { - MovementGeneratorRegistry &mv_registry(MovementGeneratorRepository::Instance()); - assert( creature->GetCreatureInfo() != NULL ); - const MovementGeneratorCreator *mv_factory = mv_registry.GetRegistryItem( creature->GetDefaultMovementType()); - - /* if( mv_factory == NULL ) - { - int best_val = -1; - std::vector l; - mv_registry.GetRegisteredItems(l); - for( std::vector::iterator iter = l.begin(); iter != l.end(); ++iter) - { - const MovementGeneratorCreator *factory = mv_registry.GetRegistryItem((*iter).c_str()); - const SelectableMovement *p = dynamic_cast(factory); - assert( p != NULL ); - int val = p->Permit(creature); - if( val > best_val ) - { - best_val = val; - mv_factory = p; - } - } - }*/ - - return ( mv_factory == NULL ? NULL : mv_factory->Create(creature) ); - - } -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Creature.h" +#include "CreatureAIImpl.h" +#include "CreatureAISelector.h" +#include "NullCreatureAI.h" +#include "Policies/SingletonImp.h" +#include "MovementGenerator.h" +#include "ScriptCalls.h" +#include "Pet.h" + +INSTANTIATE_SINGLETON_1(CreatureAIRegistry); +INSTANTIATE_SINGLETON_1(MovementGeneratorRegistry); + +namespace FactorySelector +{ + CreatureAI* selectAI(Creature *creature) + { + // Allow scripting AI for normal creatures and not controlled pets (guardians and mini-pets) + if((!creature->isPet() || !((Pet*)creature)->isControlled()) && !creature->isCharmed()) + if(CreatureAI* scriptedAI = Script->GetAI(creature)) + return scriptedAI; + + CreatureAIRegistry &ai_registry(CreatureAIRepository::Instance()); + assert( creature->GetCreatureInfo() != NULL ); + CreatureInfo const *cinfo=creature->GetCreatureInfo(); + + const CreatureAICreator *ai_factory = NULL; + + std::string ainame=cinfo->AIName; + + // select by script name + if( !ainame.empty()) + ai_factory = ai_registry.GetRegistryItem( ainame.c_str() ); + + // select by NPC flags + if(!ai_factory) + { + if( creature->isGuard() ) + ai_factory = ai_registry.GetRegistryItem("GuardAI"); + else if(creature->isPet() || creature->isCharmed()) + ai_factory = ai_registry.GetRegistryItem("PetAI"); + else if(creature->isTotem()) + ai_factory = ai_registry.GetRegistryItem("TotemAI"); + } + + // select by permit check + if(!ai_factory) + { + int best_val = -1; + typedef CreatureAIRegistry::RegistryMapType RMT; + RMT const &l = ai_registry.GetRegisteredItems(); + for( RMT::const_iterator iter = l.begin(); iter != l.end(); ++iter) + { + const CreatureAICreator *factory = iter->second; + const SelectableAI *p = dynamic_cast(factory); + assert( p != NULL ); + int val = p->Permit(creature); + if( val > best_val ) + { + best_val = val; + ai_factory = p; + } + } + } + + // select NullCreatureAI if not another cases + ainame = (ai_factory == NULL) ? "NullCreatureAI" : ai_factory->key(); + + DEBUG_LOG("Creature %u used AI is %s.", creature->GetGUIDLow(), ainame.c_str() ); + return ( ai_factory == NULL ? new NullCreatureAI : ai_factory->Create(creature) ); + } + + MovementGenerator* selectMovementGenerator(Creature *creature) + { + MovementGeneratorRegistry &mv_registry(MovementGeneratorRepository::Instance()); + assert( creature->GetCreatureInfo() != NULL ); + const MovementGeneratorCreator *mv_factory = mv_registry.GetRegistryItem( creature->GetDefaultMovementType()); + + /* if( mv_factory == NULL ) + { + int best_val = -1; + std::vector l; + mv_registry.GetRegisteredItems(l); + for( std::vector::iterator iter = l.begin(); iter != l.end(); ++iter) + { + const MovementGeneratorCreator *factory = mv_registry.GetRegistryItem((*iter).c_str()); + const SelectableMovement *p = dynamic_cast(factory); + assert( p != NULL ); + int val = p->Permit(creature); + if( val > best_val ) + { + best_val = val; + mv_factory = p; + } + } + }*/ + + return ( mv_factory == NULL ? NULL : mv_factory->Create(creature) ); + + } +} diff --git a/src/game/GossipDef.cpp b/src/game/GossipDef.cpp index 57c3597a7b8..08f35c8618b 100644 --- a/src/game/GossipDef.cpp +++ b/src/game/GossipDef.cpp @@ -1,765 +1,762 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "QuestDef.h" -#include "GossipDef.h" -#include "ObjectMgr.h" -#include "Opcodes.h" -#include "WorldPacket.h" -#include "WorldSession.h" - -GossipMenu::GossipMenu() -{ - m_gItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use -} - -GossipMenu::~GossipMenu() -{ - ClearMenu(); -} - -void GossipMenu::AddMenuItem(uint8 Icon, std::string Message, uint32 dtSender, uint32 dtAction, std::string BoxMessage, uint32 BoxMoney, bool Coded) -{ - ASSERT( m_gItems.size() <= GOSSIP_MAX_MENU_ITEMS ); - - GossipMenuItem gItem; - - gItem.m_gIcon = Icon; - gItem.m_gMessage = Message; - gItem.m_gCoded = Coded; - gItem.m_gSender = dtSender; - gItem.m_gAction = dtAction; - gItem.m_gBoxMessage = BoxMessage; - gItem.m_gBoxMoney = BoxMoney; - - m_gItems.push_back(gItem); -} - -void GossipMenu::AddMenuItem(uint8 Icon, std::string Message, bool Coded) -{ - AddMenuItem( Icon, Message, 0, 0, "", 0, Coded); -} - -void GossipMenu::AddMenuItem(uint8 Icon, char const* Message, bool Coded) -{ - AddMenuItem(Icon, std::string(Message ? Message : ""),Coded); -} - -void GossipMenu::AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded) -{ - AddMenuItem(Icon, std::string(Message ? Message : ""), dtSender, dtAction, std::string(BoxMessage ? BoxMessage : ""), BoxMoney, Coded); -} - -uint32 GossipMenu::MenuItemSender( unsigned int ItemId ) -{ - if ( ItemId >= m_gItems.size() ) return 0; - - return m_gItems[ ItemId ].m_gSender; -} - -uint32 GossipMenu::MenuItemAction( unsigned int ItemId ) -{ - if ( ItemId >= m_gItems.size() ) return 0; - - return m_gItems[ ItemId ].m_gAction; -} - -bool GossipMenu::MenuItemCoded( unsigned int ItemId ) -{ - if ( ItemId >= m_gItems.size() ) return 0; - - return m_gItems[ ItemId ].m_gCoded; -} - -void GossipMenu::ClearMenu() -{ - m_gItems.clear(); -} - -PlayerMenu::PlayerMenu( WorldSession *Session ) -{ - pGossipMenu = new GossipMenu(); - pQuestMenu = new QuestMenu(); - pSession = Session; -} - -PlayerMenu::~PlayerMenu() -{ - delete pGossipMenu; - delete pQuestMenu; -} - -void PlayerMenu::ClearMenus() -{ - pGossipMenu->ClearMenu(); - pQuestMenu->ClearMenu(); -} - -uint32 PlayerMenu::GossipOptionSender( unsigned int Selection ) -{ - return pGossipMenu->MenuItemSender( Selection ); -} - -uint32 PlayerMenu::GossipOptionAction( unsigned int Selection ) -{ - return pGossipMenu->MenuItemAction( Selection ); -} - -bool PlayerMenu::GossipOptionCoded( unsigned int Selection ) -{ - return pGossipMenu->MenuItemCoded( Selection ); -} - -void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID ) -{ - WorldPacket data( SMSG_GOSSIP_MESSAGE, (100) ); // guess size - data << npcGUID; - data << uint32(0); // new 2.4.0 - data << uint32( TitleTextId ); - data << uint32( pGossipMenu->MenuItemCount() ); // max count 0x0F - - for ( unsigned int iI = 0; iI < pGossipMenu->MenuItemCount(); iI++ ) - { - GossipMenuItem const& gItem = pGossipMenu->GetItem(iI); - data << uint32( iI ); - data << uint8( gItem.m_gIcon ); - // icons: - // 0 unlearn talents/misc - // 1 trader - // 2 taxi - // 3 trainer - // 9 BG/arena - data << uint8( gItem.m_gCoded ); // makes pop up box password - data << uint32(gItem.m_gBoxMoney); // money required to open menu, 2.0.3 - data << gItem.m_gMessage; // text for gossip item - data << gItem.m_gBoxMessage; // accept text (related to money) pop up box, 2.0.3 - } - - data << uint32( pQuestMenu->MenuItemCount() ); // max count 0x20 - - for ( uint16 iI = 0; iI < pQuestMenu->MenuItemCount(); iI++ ) - { - QuestMenuItem const& qItem = pQuestMenu->GetItem(iI); - uint32 questID = qItem.m_qId; - Quest const* pQuest = objmgr.GetQuestTemplate(questID); - - data << questID; - data << uint32( qItem.m_qIcon ); - data << uint32( pQuest ? pQuest->GetQuestLevel() : 0 ); - std::string Title = pQuest->GetTitle(); - - int loc_idx = pSession->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - QuestLocale const *ql = objmgr.GetQuestLocale(questID); - if (ql) - { - if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) - Title=ql->Title[loc_idx]; - } - } - data << Title; - } - - pSession->SendPacket( &data ); - //sLog.outDebug( "WORLD: Sent SMSG_GOSSIP_MESSAGE NPCGuid=%u",GUID_LOPART(npcGUID) ); -} - -void PlayerMenu::CloseGossip() -{ - WorldPacket data( SMSG_GOSSIP_COMPLETE, 0 ); - pSession->SendPacket( &data ); - - //sLog.outDebug( "WORLD: Sent SMSG_GOSSIP_COMPLETE" ); -} - -void PlayerMenu::SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, char const * locName ) -{ - WorldPacket data( SMSG_GOSSIP_POI, (4+4+4+4+4+10) ); // guess size - data << Flags; - data << X << Y; - data << uint32(Icon); - data << uint32(Data); - data << locName; - - pSession->SendPacket( &data ); - //sLog.outDebug("WORLD: Sent SMSG_GOSSIP_POI"); -} - -void PlayerMenu::SendTalking( uint32 textID ) -{ - GossipText *pGossip; - std::string GossipStr; - - pGossip = objmgr.GetGossipText(textID); - - WorldPacket data( SMSG_NPC_TEXT_UPDATE, 100 ); // guess size - data << textID; // can be < 0 - - if (!pGossip) - { - for(uint32 i = 0; i < 8; ++i) - { - data << float(0); - data << "Greetings $N"; - data << "Greetings $N"; - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - } - } - else - { - std::string Text_0[8],Text_1[8]; - for (int i=0;i<8;i++) - { - Text_0[i]=pGossip->Options[i].Text_0; - Text_1[i]=pGossip->Options[i].Text_1; - } - int loc_idx = pSession->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID); - if (nl) - { - for (int i=0;i<8;i++) - { - if (nl->Text_0[i].size() > loc_idx && !nl->Text_0[i][loc_idx].empty()) - Text_0[i]=nl->Text_0[i][loc_idx]; - if (nl->Text_1[i].size() > loc_idx && !nl->Text_1[i][loc_idx].empty()) - Text_1[i]=nl->Text_1[i][loc_idx]; - } - } - } - for (int i=0; i<8; i++) - { - data << pGossip->Options[i].Probability; - - if ( Text_0[i].empty() ) - data << Text_1[i]; - else - data << Text_0[i]; - - if ( Text_1[i].empty() ) - data << Text_0[i]; - else - data << Text_1[i]; - - data << pGossip->Options[i].Language; - - data << pGossip->Options[i].Emotes[0]._Delay; - data << pGossip->Options[i].Emotes[0]._Emote; - - data << pGossip->Options[i].Emotes[1]._Delay; - data << pGossip->Options[i].Emotes[1]._Emote; - - data << pGossip->Options[i].Emotes[2]._Delay; - data << pGossip->Options[i].Emotes[2]._Emote; - } - } - pSession->SendPacket( &data ); - - sLog.outDebug( "WORLD: Sent SMSG_NPC_TEXT_UPDATE " ); -} - -void PlayerMenu::SendTalking( char const * title, char const * text ) -{ - WorldPacket data( SMSG_NPC_TEXT_UPDATE, 50 ); // guess size - data << uint32(0); - for(uint32 i = 0; i < 8; ++i) - { - data << float(0); - data << title; - data << text; - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - } - - pSession->SendPacket( &data ); - - sLog.outDebug( "WORLD: Sent SMSG_NPC_TEXT_UPDATE " ); -} - -/*********************************************************/ -/*** QUEST SYSTEM ***/ -/*********************************************************/ - -QuestMenu::QuestMenu() -{ - m_qItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use -} - -QuestMenu::~QuestMenu() -{ - ClearMenu(); -} - -void QuestMenu::AddMenuItem( uint32 QuestId, uint8 Icon) -{ - Quest const* qinfo = objmgr.GetQuestTemplate(QuestId); - if (!qinfo) return; - - ASSERT( m_qItems.size() <= GOSSIP_MAX_MENU_ITEMS ); - - QuestMenuItem qItem; - - qItem.m_qId = QuestId; - qItem.m_qIcon = Icon; - - m_qItems.push_back(qItem); -} - -bool QuestMenu::HasItem( uint32 questid ) -{ - for (QuestMenuItemList::iterator i = m_qItems.begin(); i != m_qItems.end(); i++) - { - if(i->m_qId==questid) - { - return true; - } - } - return false; -} - -void QuestMenu::ClearMenu() -{ - m_qItems.clear(); -} - -void PlayerMenu::SendQuestGiverQuestList( QEmote eEmote, std::string Title, uint64 npcGUID ) -{ - WorldPacket data( SMSG_QUESTGIVER_QUEST_LIST, 100 ); // guess size - data << uint64(npcGUID); - data << Title; - data << uint32(eEmote._Delay ); // player emote - data << uint32(eEmote._Emote ); // NPC emote - data << uint8 ( pQuestMenu->MenuItemCount() ); - - for ( uint16 iI = 0; iI < pQuestMenu->MenuItemCount(); iI++ ) - { - QuestMenuItem qmi=pQuestMenu->GetItem(iI); - uint32 questID = qmi.m_qId; - Quest const *pQuest = objmgr.GetQuestTemplate(questID); - - std::string title = pQuest ? pQuest->GetTitle() : ""; - - int loc_idx = pSession->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - if(QuestLocale const *ql = objmgr.GetQuestLocale(questID)) - { - if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) - title=ql->Title[loc_idx]; - } - } - - data << uint32(questID); - data << uint32(qmi.m_qIcon); - data << uint32(pQuest ? pQuest->GetQuestLevel() : 0); - data << title; - } - pSession->SendPacket( &data ); - //uint32 fqid=pQuestMenu->GetItem(0).m_qId; - //sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_LIST NPC Guid=%u, questid-0=%u",npcGUID,fqid); -} - -void PlayerMenu::SendQuestGiverStatus( uint8 questStatus, uint64 npcGUID ) -{ - WorldPacket data( SMSG_QUESTGIVER_STATUS, 9 ); - data << uint64(npcGUID); - data << uint8(questStatus); - - pSession->SendPacket( &data ); - //sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_STATUS NPC Guid=%u, status=%u",GUID_LOPART(npcGUID),questStatus); -} - -void PlayerMenu::SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID, bool ActivateAccept ) -{ - WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size - - std::string Title = pQuest->GetTitle(); - std::string Details = pQuest->GetDetails(); - std::string Objectives = pQuest->GetObjectives(); - std::string EndText = pQuest->GetEndText(); - - int loc_idx = pSession->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId()); - if (ql) - { - if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) - Title=ql->Title[loc_idx]; - if (ql->Details.size() > loc_idx && !ql->Details[loc_idx].empty()) - Details=ql->Details[loc_idx]; - if (ql->Objectives.size() > loc_idx && !ql->Objectives[loc_idx].empty()) - Objectives=ql->Objectives[loc_idx]; - if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty()) - EndText=ql->EndText[loc_idx]; - } - } - - data << uint64(npcGUID); - data << uint32(pQuest->GetQuestId()); - data << Title << Details << Objectives; - data << uint32(ActivateAccept); - data << uint32(pQuest->GetSuggestedPlayers()); - - if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) - { - data << uint32(0); // Rewarded chosen items hidden - data << uint32(0); // Rewarded items hidden - data << uint32(0); // Rewarded money hidden - } - else - { - ItemPrototype const* IProto; - - data << uint32(pQuest->GetRewChoiceItemsCount()); - for (uint32 i=0; i < QUEST_REWARD_CHOICES_COUNT; i++) - { - if ( !pQuest->RewChoiceItemId[i] ) continue; - data << uint32(pQuest->RewChoiceItemId[i]); - data << uint32(pQuest->RewChoiceItemCount[i]); - IProto = objmgr.GetItemPrototype(pQuest->RewChoiceItemId[i]); - if ( IProto ) - data << uint32(IProto->DisplayInfoID); - else - data << uint32( 0x00 ); - } - - data << uint32(pQuest->GetRewItemsCount()); - for (uint32 i=0; i < QUEST_REWARDS_COUNT; i++) - { - if ( !pQuest->RewItemId[i] ) continue; - data << uint32(pQuest->RewItemId[i]); - data << uint32(pQuest->RewItemCount[i]); - IProto = objmgr.GetItemPrototype(pQuest->RewItemId[i]); - if ( IProto ) - data << uint32(IProto->DisplayInfoID); - else - data << uint32(0); - } - data << uint32(pQuest->GetRewOrReqMoney()); - } - - data << uint32(0); // Honor points reward, not implemented - data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0) - data << uint32(pQuest->GetRewSpellCast()); // casted spell - data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles) - - data << uint32(QUEST_EMOTE_COUNT); - for (uint32 i=0; i < QUEST_EMOTE_COUNT; i++) - { - data << uint32(pQuest->DetailsEmote[i]); - data << uint32(0); // DetailsEmoteDelay - } - pSession->SendPacket( &data ); - - //sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_DETAILS NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId()); -} - -void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) -{ - std::string Title,Details,Objectives,EndText; - std::string ObjectiveText[QUEST_OBJECTIVES_COUNT]; - Title = pQuest->GetTitle(); - Details = pQuest->GetDetails(); - Objectives = pQuest->GetObjectives(); - EndText = pQuest->GetEndText(); - for (int i=0;iObjectiveText[i]; - - int loc_idx = pSession->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId()); - if (ql) - { - if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) - Title=ql->Title[loc_idx]; - if (ql->Details.size() > loc_idx && !ql->Details[loc_idx].empty()) - Details=ql->Details[loc_idx]; - if (ql->Objectives.size() > loc_idx && !ql->Objectives[loc_idx].empty()) - Objectives=ql->Objectives[loc_idx]; - if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty()) - EndText=ql->EndText[loc_idx]; - - for (int i=0;iObjectiveText[i].size() > loc_idx && !ql->ObjectiveText[i][loc_idx].empty()) - ObjectiveText[i]=ql->ObjectiveText[i][loc_idx]; - } - } - - WorldPacket data( SMSG_QUEST_QUERY_RESPONSE, 100 ); // guess size - - data << uint32(pQuest->GetQuestId()); - data << uint32(pQuest->GetMinLevel()); // not MinLevel. Accepted values: 0, 1 or 2 Possible theory for future dev: 0==cannot in quest log, 1==can in quest log session only(removed on log out), 2==can in quest log always (save to db) - data << uint32(pQuest->GetQuestLevel()); // may be 0 - data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log - - data << uint32(pQuest->GetType()); - data << uint32(pQuest->GetSuggestedPlayers()); - - data << uint32(pQuest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective - data << uint32(pQuest->GetRepObjectiveValue()); // shown in quest log as part of quest objective - - data << uint32(0); // RequiredOpositeRepFaction - data << uint32(0); // RequiredOpositeRepValue, required faction value with another (oposite) faction (objective) - - data << uint32(pQuest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0 - - if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) - data << uint32(0); // Hide money rewarded - else - data << uint32(pQuest->GetRewOrReqMoney()); - - data << uint32(pQuest->GetRewMoneyMaxLevel()); // used in XP calculation at client - data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0) - data << uint32(pQuest->GetRewSpellCast()); // casted spell - - data << uint32(0); // Honor points reward, not implemented - data << uint32(pQuest->GetSrcItemId()); - data << uint32(pQuest->GetFlags() & 0xFFFF); - data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles) - - int iI; - - if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) - { - for (iI = 0; iI < QUEST_REWARDS_COUNT; iI++) - data << uint32(0) << uint32(0); - for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; iI++) - data << uint32(0) << uint32(0); - } - else - { - for (iI = 0; iI < QUEST_REWARDS_COUNT; iI++) - { - data << uint32(pQuest->RewItemId[iI]); - data << uint32(pQuest->RewItemCount[iI]); - } - for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; iI++) - { - data << uint32(pQuest->RewChoiceItemId[iI]); - data << uint32(pQuest->RewChoiceItemCount[iI]); - } - } - - data << pQuest->GetPointMapId(); - data << pQuest->GetPointX(); - data << pQuest->GetPointY(); - data << pQuest->GetPointOpt(); - - data << Title; - data << Objectives; - data << Details; - data << EndText; - - for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++) - { - if (pQuest->ReqCreatureOrGOId[iI] < 0) - { - // client expected gameobject template id in form (id|0x80000000) - data << uint32((pQuest->ReqCreatureOrGOId[iI]*(-1))|0x80000000); - } - else - { - data << uint32(pQuest->ReqCreatureOrGOId[iI]); - } - data << uint32(pQuest->ReqCreatureOrGOCount[iI]); - data << uint32(pQuest->ReqItemId[iI]); - data << uint32(pQuest->ReqItemCount[iI]); - } - - for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++) - data << ObjectiveText[iI]; - - pSession->SendPacket( &data ); - //sLog.outDebug( "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u",pQuest->GetQuestId() ); -} - -void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnbleNext ) -{ - std::string Title = pQuest->GetTitle(); - std::string OfferRewardText = pQuest->GetOfferRewardText(); - - int loc_idx = pSession->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId()); - if (ql) - { - if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) - Title=ql->Title[loc_idx]; - if (ql->OfferRewardText.size() > loc_idx && !ql->OfferRewardText[loc_idx].empty()) - OfferRewardText=ql->OfferRewardText[loc_idx]; - } - } - - WorldPacket data( SMSG_QUESTGIVER_OFFER_REWARD, 50 ); // guess size - - data << npcGUID; - data << pQuest->GetQuestId(); - data << Title; - data << OfferRewardText; - - data << uint32( EnbleNext ); - data << uint32(0); // unk - - uint32 EmoteCount = 0; - for (uint32 i = 0; i < QUEST_EMOTE_COUNT; i++) - { - if(pQuest->OfferRewardEmote[i] <= 0) - break; - ++EmoteCount; - } - - data << EmoteCount; // Emote Count - for (uint32 i = 0; i < EmoteCount; i++) - { - data << uint32(0); // Delay Emote - data << pQuest->OfferRewardEmote[i]; - } - - ItemPrototype const *pItem; - - data << uint32(pQuest->GetRewChoiceItemsCount()); - for (uint32 i=0; i < pQuest->GetRewChoiceItemsCount(); i++) - { - pItem = objmgr.GetItemPrototype( pQuest->RewChoiceItemId[i] ); - - data << uint32(pQuest->RewChoiceItemId[i]); - data << uint32(pQuest->RewChoiceItemCount[i]); - - if ( pItem ) - data << uint32(pItem->DisplayInfoID); - else - data << uint32(0); - } - - data << uint32(pQuest->GetRewItemsCount()); - for (uint16 i=0; i < pQuest->GetRewItemsCount(); i++) - { - pItem = objmgr.GetItemPrototype(pQuest->RewItemId[i]); - data << uint32(pQuest->RewItemId[i]); - data << uint32(pQuest->RewItemCount[i]); - - if ( pItem ) - data << uint32(pItem->DisplayInfoID); - else - data << uint32(0); - } - - data << uint32(pQuest->GetRewOrReqMoney()); - data << uint32(0x00); // new 2.3.0. Honor points - data << uint32(0x08); // unused by client? - data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0) - data << uint32(pQuest->GetRewSpellCast()); // casted spell - data << uint32(0); // Honor points reward, not implemented - pSession->SendPacket( &data ); - //sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId() ); -} - -void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel ) -{ - // We can always call to RequestItems, but this packet only goes out if there are actually - // items. Otherwise, we'll skip straight to the OfferReward - - // We may wish a better check, perhaps checking the real quest requirements - if (pQuest->GetRequestItemsText().empty()) - { - SendQuestGiverOfferReward(pQuest, npcGUID, true); - return; - } - - std::string Title,RequestItemsText; - Title = pQuest->GetTitle(); - RequestItemsText = pQuest->GetRequestItemsText(); - - int loc_idx = pSession->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId()); - if (ql) - { - if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) - Title=ql->Title[loc_idx]; - if (ql->RequestItemsText.size() > loc_idx && !ql->RequestItemsText[loc_idx].empty()) - RequestItemsText=ql->RequestItemsText[loc_idx]; - } - } - - WorldPacket data( SMSG_QUESTGIVER_REQUEST_ITEMS, 50 ); // guess size - data << npcGUID; - data << pQuest->GetQuestId(); - data << Title; - data << RequestItemsText; - - data << uint32(0x00); // unknown - - if(Completable) - data << pQuest->GetCompleteEmote(); - else - data << pQuest->GetIncompleteEmote(); - - // Close Window after cancel - if (CloseOnCancel) - data << uint32(0x01); - else - data << uint32(0x00); - - data << uint32(0x00); // unknown - - // Required Money - data << uint32(pQuest->GetRewOrReqMoney() < 0 ? -pQuest->GetRewOrReqMoney() : 0); - - data << uint32( pQuest->GetReqItemsCount() ); - ItemPrototype const *pItem; - for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - { - if ( !pQuest->ReqItemId[i] ) continue; - pItem = objmgr.GetItemPrototype(pQuest->ReqItemId[i]); - data << uint32(pQuest->ReqItemId[i]); - data << uint32(pQuest->ReqItemCount[i]); - - if ( pItem ) - data << uint32(pItem->DisplayInfoID); - else - data << uint32(0); - } - - if ( !Completable ) - data << uint32(0x00); - else - data << uint32(0x03); - - data << uint32(0x04) << uint32(0x08) << uint32(0x10); - - pSession->SendPacket( &data ); - //sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId() ); -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "QuestDef.h" +#include "GossipDef.h" +#include "ObjectMgr.h" +#include "Opcodes.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +GossipMenu::GossipMenu() +{ + m_gItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use +} + +GossipMenu::~GossipMenu() +{ + ClearMenu(); +} + +void GossipMenu::AddMenuItem(uint8 Icon, std::string Message, uint32 dtSender, uint32 dtAction, std::string BoxMessage, uint32 BoxMoney, bool Coded) +{ + ASSERT( m_gItems.size() <= GOSSIP_MAX_MENU_ITEMS ); + + GossipMenuItem gItem; + + gItem.m_gIcon = Icon; + gItem.m_gMessage = Message; + gItem.m_gCoded = Coded; + gItem.m_gSender = dtSender; + gItem.m_gAction = dtAction; + gItem.m_gBoxMessage = BoxMessage; + gItem.m_gBoxMoney = BoxMoney; + + m_gItems.push_back(gItem); +} + +void GossipMenu::AddMenuItem(uint8 Icon, std::string Message, bool Coded) +{ + AddMenuItem( Icon, Message, 0, 0, "", 0, Coded); +} + +void GossipMenu::AddMenuItem(uint8 Icon, char const* Message, bool Coded) +{ + AddMenuItem(Icon, std::string(Message ? Message : ""),Coded); +} + +void GossipMenu::AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded) +{ + AddMenuItem(Icon, std::string(Message ? Message : ""), dtSender, dtAction, std::string(BoxMessage ? BoxMessage : ""), BoxMoney, Coded); +} + +uint32 GossipMenu::MenuItemSender( unsigned int ItemId ) +{ + if ( ItemId >= m_gItems.size() ) return 0; + + return m_gItems[ ItemId ].m_gSender; +} + +uint32 GossipMenu::MenuItemAction( unsigned int ItemId ) +{ + if ( ItemId >= m_gItems.size() ) return 0; + + return m_gItems[ ItemId ].m_gAction; +} + +bool GossipMenu::MenuItemCoded( unsigned int ItemId ) +{ + if ( ItemId >= m_gItems.size() ) return 0; + + return m_gItems[ ItemId ].m_gCoded; +} + +void GossipMenu::ClearMenu() +{ + m_gItems.clear(); +} + +PlayerMenu::PlayerMenu( WorldSession *session ) : pSession(session) +{ +} + +PlayerMenu::~PlayerMenu() +{ + ClearMenus(); +} + +void PlayerMenu::ClearMenus() +{ + mGossipMenu.ClearMenu(); + mQuestMenu.ClearMenu(); +} + +uint32 PlayerMenu::GossipOptionSender( unsigned int Selection ) +{ + return mGossipMenu.MenuItemSender( Selection ); +} + +uint32 PlayerMenu::GossipOptionAction( unsigned int Selection ) +{ + return mGossipMenu.MenuItemAction( Selection ); +} + +bool PlayerMenu::GossipOptionCoded( unsigned int Selection ) +{ + return mGossipMenu.MenuItemCoded( Selection ); +} + +void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID ) +{ + WorldPacket data( SMSG_GOSSIP_MESSAGE, (100) ); // guess size + data << npcGUID; + data << uint32(0); // new 2.4.0 + data << uint32( TitleTextId ); + data << uint32( mGossipMenu.MenuItemCount() ); // max count 0x0F + + for ( unsigned int iI = 0; iI < mGossipMenu.MenuItemCount(); iI++ ) + { + GossipMenuItem const& gItem = mGossipMenu.GetItem(iI); + data << uint32( iI ); + data << uint8( gItem.m_gIcon ); + // icons: + // 0 unlearn talents/misc + // 1 trader + // 2 taxi + // 3 trainer + // 9 BG/arena + data << uint8( gItem.m_gCoded ); // makes pop up box password + data << uint32(gItem.m_gBoxMoney); // money required to open menu, 2.0.3 + data << gItem.m_gMessage; // text for gossip item + data << gItem.m_gBoxMessage; // accept text (related to money) pop up box, 2.0.3 + } + + data << uint32( mQuestMenu.MenuItemCount() ); // max count 0x20 + + for ( uint16 iI = 0; iI < mQuestMenu.MenuItemCount(); iI++ ) + { + QuestMenuItem const& qItem = mQuestMenu.GetItem(iI); + uint32 questID = qItem.m_qId; + Quest const* pQuest = objmgr.GetQuestTemplate(questID); + + data << questID; + data << uint32( qItem.m_qIcon ); + data << uint32( pQuest ? pQuest->GetQuestLevel() : 0 ); + std::string Title = pQuest->GetTitle(); + + int loc_idx = pSession->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + QuestLocale const *ql = objmgr.GetQuestLocale(questID); + if (ql) + { + if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) + Title=ql->Title[loc_idx]; + } + } + data << Title; + } + + pSession->SendPacket( &data ); + //sLog.outDebug( "WORLD: Sent SMSG_GOSSIP_MESSAGE NPCGuid=%u",GUID_LOPART(npcGUID) ); +} + +void PlayerMenu::CloseGossip() +{ + WorldPacket data( SMSG_GOSSIP_COMPLETE, 0 ); + pSession->SendPacket( &data ); + + //sLog.outDebug( "WORLD: Sent SMSG_GOSSIP_COMPLETE" ); +} + +void PlayerMenu::SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, char const * locName ) +{ + WorldPacket data( SMSG_GOSSIP_POI, (4+4+4+4+4+10) ); // guess size + data << Flags; + data << X << Y; + data << uint32(Icon); + data << uint32(Data); + data << locName; + + pSession->SendPacket( &data ); + //sLog.outDebug("WORLD: Sent SMSG_GOSSIP_POI"); +} + +void PlayerMenu::SendTalking( uint32 textID ) +{ + GossipText *pGossip; + std::string GossipStr; + + pGossip = objmgr.GetGossipText(textID); + + WorldPacket data( SMSG_NPC_TEXT_UPDATE, 100 ); // guess size + data << textID; // can be < 0 + + if (!pGossip) + { + for(uint32 i = 0; i < 8; ++i) + { + data << float(0); + data << "Greetings $N"; + data << "Greetings $N"; + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + } + } + else + { + std::string Text_0[8],Text_1[8]; + for (int i=0;i<8;i++) + { + Text_0[i]=pGossip->Options[i].Text_0; + Text_1[i]=pGossip->Options[i].Text_1; + } + int loc_idx = pSession->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID); + if (nl) + { + for (int i=0;i<8;i++) + { + if (nl->Text_0[i].size() > loc_idx && !nl->Text_0[i][loc_idx].empty()) + Text_0[i]=nl->Text_0[i][loc_idx]; + if (nl->Text_1[i].size() > loc_idx && !nl->Text_1[i][loc_idx].empty()) + Text_1[i]=nl->Text_1[i][loc_idx]; + } + } + } + for (int i=0; i<8; i++) + { + data << pGossip->Options[i].Probability; + + if ( Text_0[i].empty() ) + data << Text_1[i]; + else + data << Text_0[i]; + + if ( Text_1[i].empty() ) + data << Text_0[i]; + else + data << Text_1[i]; + + data << pGossip->Options[i].Language; + + data << pGossip->Options[i].Emotes[0]._Delay; + data << pGossip->Options[i].Emotes[0]._Emote; + + data << pGossip->Options[i].Emotes[1]._Delay; + data << pGossip->Options[i].Emotes[1]._Emote; + + data << pGossip->Options[i].Emotes[2]._Delay; + data << pGossip->Options[i].Emotes[2]._Emote; + } + } + pSession->SendPacket( &data ); + + sLog.outDebug( "WORLD: Sent SMSG_NPC_TEXT_UPDATE " ); +} + +void PlayerMenu::SendTalking( char const * title, char const * text ) +{ + WorldPacket data( SMSG_NPC_TEXT_UPDATE, 50 ); // guess size + data << uint32(0); + for(uint32 i = 0; i < 8; ++i) + { + data << float(0); + data << title; + data << text; + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + } + + pSession->SendPacket( &data ); + + sLog.outDebug( "WORLD: Sent SMSG_NPC_TEXT_UPDATE " ); +} + +/*********************************************************/ +/*** QUEST SYSTEM ***/ +/*********************************************************/ + +QuestMenu::QuestMenu() +{ + m_qItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use +} + +QuestMenu::~QuestMenu() +{ + ClearMenu(); +} + +void QuestMenu::AddMenuItem( uint32 QuestId, uint8 Icon) +{ + Quest const* qinfo = objmgr.GetQuestTemplate(QuestId); + if (!qinfo) return; + + ASSERT( m_qItems.size() <= GOSSIP_MAX_MENU_ITEMS ); + + QuestMenuItem qItem; + + qItem.m_qId = QuestId; + qItem.m_qIcon = Icon; + + m_qItems.push_back(qItem); +} + +bool QuestMenu::HasItem( uint32 questid ) +{ + for (QuestMenuItemList::iterator i = m_qItems.begin(); i != m_qItems.end(); i++) + { + if(i->m_qId==questid) + { + return true; + } + } + return false; +} + +void QuestMenu::ClearMenu() +{ + m_qItems.clear(); +} + +void PlayerMenu::SendQuestGiverQuestList( QEmote eEmote, std::string Title, uint64 npcGUID ) +{ + WorldPacket data( SMSG_QUESTGIVER_QUEST_LIST, 100 ); // guess size + data << uint64(npcGUID); + data << Title; + data << uint32(eEmote._Delay ); // player emote + data << uint32(eEmote._Emote ); // NPC emote + data << uint8 ( mQuestMenu.MenuItemCount() ); + + for ( uint16 iI = 0; iI < mQuestMenu.MenuItemCount(); iI++ ) + { + QuestMenuItem const& qmi = mQuestMenu.GetItem(iI); + + uint32 questID = qmi.m_qId; + Quest const *pQuest = objmgr.GetQuestTemplate(questID); + + std::string title = pQuest ? pQuest->GetTitle() : ""; + + int loc_idx = pSession->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + if(QuestLocale const *ql = objmgr.GetQuestLocale(questID)) + { + if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) + title=ql->Title[loc_idx]; + } + } + + data << uint32(questID); + data << uint32(qmi.m_qIcon); + data << uint32(pQuest ? pQuest->GetQuestLevel() : 0); + data << title; + } + pSession->SendPacket( &data ); + //uint32 fqid=pQuestMenu->GetItem(0).m_qId; + //sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_LIST NPC Guid=%u, questid-0=%u",npcGUID,fqid); +} + +void PlayerMenu::SendQuestGiverStatus( uint8 questStatus, uint64 npcGUID ) +{ + WorldPacket data( SMSG_QUESTGIVER_STATUS, 9 ); + data << uint64(npcGUID); + data << uint8(questStatus); + + pSession->SendPacket( &data ); + //sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_STATUS NPC Guid=%u, status=%u",GUID_LOPART(npcGUID),questStatus); +} + +void PlayerMenu::SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID, bool ActivateAccept ) +{ + WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size + + std::string Title = pQuest->GetTitle(); + std::string Details = pQuest->GetDetails(); + std::string Objectives = pQuest->GetObjectives(); + std::string EndText = pQuest->GetEndText(); + + int loc_idx = pSession->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId()); + if (ql) + { + if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) + Title=ql->Title[loc_idx]; + if (ql->Details.size() > loc_idx && !ql->Details[loc_idx].empty()) + Details=ql->Details[loc_idx]; + if (ql->Objectives.size() > loc_idx && !ql->Objectives[loc_idx].empty()) + Objectives=ql->Objectives[loc_idx]; + if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty()) + EndText=ql->EndText[loc_idx]; + } + } + + data << uint64(npcGUID); + data << uint32(pQuest->GetQuestId()); + data << Title << Details << Objectives; + data << uint32(ActivateAccept); + data << uint32(pQuest->GetSuggestedPlayers()); + + if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) + { + data << uint32(0); // Rewarded chosen items hidden + data << uint32(0); // Rewarded items hidden + data << uint32(0); // Rewarded money hidden + } + else + { + ItemPrototype const* IProto; + + data << uint32(pQuest->GetRewChoiceItemsCount()); + for (uint32 i=0; i < QUEST_REWARD_CHOICES_COUNT; i++) + { + if ( !pQuest->RewChoiceItemId[i] ) continue; + data << uint32(pQuest->RewChoiceItemId[i]); + data << uint32(pQuest->RewChoiceItemCount[i]); + IProto = objmgr.GetItemPrototype(pQuest->RewChoiceItemId[i]); + if ( IProto ) + data << uint32(IProto->DisplayInfoID); + else + data << uint32( 0x00 ); + } + + data << uint32(pQuest->GetRewItemsCount()); + for (uint32 i=0; i < QUEST_REWARDS_COUNT; i++) + { + if ( !pQuest->RewItemId[i] ) continue; + data << uint32(pQuest->RewItemId[i]); + data << uint32(pQuest->RewItemCount[i]); + IProto = objmgr.GetItemPrototype(pQuest->RewItemId[i]); + if ( IProto ) + data << uint32(IProto->DisplayInfoID); + else + data << uint32(0); + } + data << uint32(pQuest->GetRewOrReqMoney()); + } + + data << uint32(0); // Honor points reward, not implemented + data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0) + data << uint32(pQuest->GetRewSpellCast()); // casted spell + data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles) + + data << uint32(QUEST_EMOTE_COUNT); + for (uint32 i=0; i < QUEST_EMOTE_COUNT; i++) + { + data << uint32(pQuest->DetailsEmote[i]); + data << uint32(0); // DetailsEmoteDelay + } + pSession->SendPacket( &data ); + + //sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_DETAILS NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId()); +} + +void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) +{ + std::string Title,Details,Objectives,EndText; + std::string ObjectiveText[QUEST_OBJECTIVES_COUNT]; + Title = pQuest->GetTitle(); + Details = pQuest->GetDetails(); + Objectives = pQuest->GetObjectives(); + EndText = pQuest->GetEndText(); + for (int i=0;iObjectiveText[i]; + + int loc_idx = pSession->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId()); + if (ql) + { + if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) + Title=ql->Title[loc_idx]; + if (ql->Details.size() > loc_idx && !ql->Details[loc_idx].empty()) + Details=ql->Details[loc_idx]; + if (ql->Objectives.size() > loc_idx && !ql->Objectives[loc_idx].empty()) + Objectives=ql->Objectives[loc_idx]; + if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty()) + EndText=ql->EndText[loc_idx]; + + for (int i=0;iObjectiveText[i].size() > loc_idx && !ql->ObjectiveText[i][loc_idx].empty()) + ObjectiveText[i]=ql->ObjectiveText[i][loc_idx]; + } + } + + WorldPacket data( SMSG_QUEST_QUERY_RESPONSE, 100 ); // guess size + + data << uint32(pQuest->GetQuestId()); + data << uint32(pQuest->GetMinLevel()); // not MinLevel. Accepted values: 0, 1 or 2 Possible theory for future dev: 0==cannot in quest log, 1==can in quest log session only(removed on log out), 2==can in quest log always (save to db) + data << uint32(pQuest->GetQuestLevel()); // may be 0 + data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log + + data << uint32(pQuest->GetType()); + data << uint32(pQuest->GetSuggestedPlayers()); + + data << uint32(pQuest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective + data << uint32(pQuest->GetRepObjectiveValue()); // shown in quest log as part of quest objective + + data << uint32(0); // RequiredOpositeRepFaction + data << uint32(0); // RequiredOpositeRepValue, required faction value with another (oposite) faction (objective) + + data << uint32(pQuest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0 + + if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) + data << uint32(0); // Hide money rewarded + else + data << uint32(pQuest->GetRewOrReqMoney()); + + data << uint32(pQuest->GetRewMoneyMaxLevel()); // used in XP calculation at client + data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0) + data << uint32(pQuest->GetRewSpellCast()); // casted spell + + data << uint32(0); // Honor points reward, not implemented + data << uint32(pQuest->GetSrcItemId()); + data << uint32(pQuest->GetFlags() & 0xFFFF); + data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles) + + int iI; + + if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) + { + for (iI = 0; iI < QUEST_REWARDS_COUNT; iI++) + data << uint32(0) << uint32(0); + for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; iI++) + data << uint32(0) << uint32(0); + } + else + { + for (iI = 0; iI < QUEST_REWARDS_COUNT; iI++) + { + data << uint32(pQuest->RewItemId[iI]); + data << uint32(pQuest->RewItemCount[iI]); + } + for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; iI++) + { + data << uint32(pQuest->RewChoiceItemId[iI]); + data << uint32(pQuest->RewChoiceItemCount[iI]); + } + } + + data << pQuest->GetPointMapId(); + data << pQuest->GetPointX(); + data << pQuest->GetPointY(); + data << pQuest->GetPointOpt(); + + data << Title; + data << Objectives; + data << Details; + data << EndText; + + for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++) + { + if (pQuest->ReqCreatureOrGOId[iI] < 0) + { + // client expected gameobject template id in form (id|0x80000000) + data << uint32((pQuest->ReqCreatureOrGOId[iI]*(-1))|0x80000000); + } + else + { + data << uint32(pQuest->ReqCreatureOrGOId[iI]); + } + data << uint32(pQuest->ReqCreatureOrGOCount[iI]); + data << uint32(pQuest->ReqItemId[iI]); + data << uint32(pQuest->ReqItemCount[iI]); + } + + for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++) + data << ObjectiveText[iI]; + + pSession->SendPacket( &data ); + //sLog.outDebug( "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u",pQuest->GetQuestId() ); +} + +void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnbleNext ) +{ + std::string Title = pQuest->GetTitle(); + std::string OfferRewardText = pQuest->GetOfferRewardText(); + + int loc_idx = pSession->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId()); + if (ql) + { + if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) + Title=ql->Title[loc_idx]; + if (ql->OfferRewardText.size() > loc_idx && !ql->OfferRewardText[loc_idx].empty()) + OfferRewardText=ql->OfferRewardText[loc_idx]; + } + } + + WorldPacket data( SMSG_QUESTGIVER_OFFER_REWARD, 50 ); // guess size + + data << npcGUID; + data << pQuest->GetQuestId(); + data << Title; + data << OfferRewardText; + + data << uint32( EnbleNext ); + data << uint32(0); // unk + + uint32 EmoteCount = 0; + for (uint32 i = 0; i < QUEST_EMOTE_COUNT; i++) + { + if(pQuest->OfferRewardEmote[i] <= 0) + break; + ++EmoteCount; + } + + data << EmoteCount; // Emote Count + for (uint32 i = 0; i < EmoteCount; i++) + { + data << uint32(0); // Delay Emote + data << pQuest->OfferRewardEmote[i]; + } + + ItemPrototype const *pItem; + + data << uint32(pQuest->GetRewChoiceItemsCount()); + for (uint32 i=0; i < pQuest->GetRewChoiceItemsCount(); i++) + { + pItem = objmgr.GetItemPrototype( pQuest->RewChoiceItemId[i] ); + + data << uint32(pQuest->RewChoiceItemId[i]); + data << uint32(pQuest->RewChoiceItemCount[i]); + + if ( pItem ) + data << uint32(pItem->DisplayInfoID); + else + data << uint32(0); + } + + data << uint32(pQuest->GetRewItemsCount()); + for (uint16 i=0; i < pQuest->GetRewItemsCount(); i++) + { + pItem = objmgr.GetItemPrototype(pQuest->RewItemId[i]); + data << uint32(pQuest->RewItemId[i]); + data << uint32(pQuest->RewItemCount[i]); + + if ( pItem ) + data << uint32(pItem->DisplayInfoID); + else + data << uint32(0); + } + + data << uint32(pQuest->GetRewOrReqMoney()); + data << uint32(0x00); // new 2.3.0. Honor points + data << uint32(0x08); // unused by client? + data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0) + data << uint32(pQuest->GetRewSpellCast()); // casted spell + data << uint32(0); // Honor points reward, not implemented + pSession->SendPacket( &data ); + //sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId() ); +} + +void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel ) +{ + // We can always call to RequestItems, but this packet only goes out if there are actually + // items. Otherwise, we'll skip straight to the OfferReward + + // We may wish a better check, perhaps checking the real quest requirements + if (pQuest->GetRequestItemsText().empty()) + { + SendQuestGiverOfferReward(pQuest, npcGUID, true); + return; + } + + std::string Title,RequestItemsText; + Title = pQuest->GetTitle(); + RequestItemsText = pQuest->GetRequestItemsText(); + + int loc_idx = pSession->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId()); + if (ql) + { + if (ql->Title.size() > loc_idx && !ql->Title[loc_idx].empty()) + Title=ql->Title[loc_idx]; + if (ql->RequestItemsText.size() > loc_idx && !ql->RequestItemsText[loc_idx].empty()) + RequestItemsText=ql->RequestItemsText[loc_idx]; + } + } + + WorldPacket data( SMSG_QUESTGIVER_REQUEST_ITEMS, 50 ); // guess size + data << npcGUID; + data << pQuest->GetQuestId(); + data << Title; + data << RequestItemsText; + + data << uint32(0x00); // unknown + + if(Completable) + data << pQuest->GetCompleteEmote(); + else + data << pQuest->GetIncompleteEmote(); + + // Close Window after cancel + if (CloseOnCancel) + data << uint32(0x01); + else + data << uint32(0x00); + + data << uint32(0x00); // unknown + + // Required Money + data << uint32(pQuest->GetRewOrReqMoney() < 0 ? -pQuest->GetRewOrReqMoney() : 0); + + data << uint32( pQuest->GetReqItemsCount() ); + ItemPrototype const *pItem; + for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + { + if ( !pQuest->ReqItemId[i] ) continue; + pItem = objmgr.GetItemPrototype(pQuest->ReqItemId[i]); + data << uint32(pQuest->ReqItemId[i]); + data << uint32(pQuest->ReqItemCount[i]); + + if ( pItem ) + data << uint32(pItem->DisplayInfoID); + else + data << uint32(0); + } + + if ( !Completable ) + data << uint32(0x00); + else + data << uint32(0x03); + + data << uint32(0x04) << uint32(0x08) << uint32(0x10); + + pSession->SendPacket( &data ); + //sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId() ); +} diff --git a/src/game/GossipDef.h b/src/game/GossipDef.h index aacf7a8fcb8..18f7c007aa1 100644 --- a/src/game/GossipDef.h +++ b/src/game/GossipDef.h @@ -1,193 +1,206 @@ -/* - * Copyright (C) 2005-2008 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 MANGOSSERVER_GOSSIP_H -#define MANGOSSERVER_GOSSIP_H - -#include "Common.h" -#include "QuestDef.h" -#include "NPCHandler.h" - -class WorldSession; - -#define GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough -#define DEFAULT_GOSSIP_MESSAGE 0xffffff - -//POI defines -enum Poi_Icon -{ - ICON_POI_0 = 0, // Grey ? - ICON_POI_1 = 1, // Red ? - ICON_POI_2 = 2, // Blue ? - ICON_POI_BWTOMB = 3, // Blue and White Tomb Stone - ICON_POI_HOUSE = 4, // House - ICON_POI_TOWER = 5, // Tower - ICON_POI_REDFLAG = 6, // Red Flag with Yellow ! - ICON_POI_TOMB = 7, // Tomb Stone - ICON_POI_BWTOWER = 8, // Blue and White Tower - ICON_POI_REDTOWER = 9, // Red Tower - ICON_POI_BLUETOWER = 10, // Blue Tower - ICON_POI_RWTOWER = 11, // Red and White Tower - ICON_POI_REDTOMB = 12, // Red Tomb Stone - ICON_POI_RWTOMB = 13, // Red and White Tomb Stone - ICON_POI_BLUETOMB = 14, // Blue Tomb Stone - ICON_POI_NOTHING = 15, // NOTHING - ICON_POI_16 = 16, // Red ? - ICON_POI_17 = 17, // Grey ? - ICON_POI_18 = 18, // Blue ? - ICON_POI_19 = 19, // Red and White ? - ICON_POI_20 = 20, // Red ? - ICON_POI_GREYLOGS = 21, // Grey Wood Logs - ICON_POI_BWLOGS = 22, // Blue and White Wood Logs - ICON_POI_BLUELOGS = 23, // Blue Wood Logs - ICON_POI_RWLOGS = 24, // Red and White Wood Logs - ICON_POI_REDLOGS = 25, // Red Wood Logs - ICON_POI_26 = 26, // Grey ? - ICON_POI_27 = 27, // Blue and White ? - ICON_POI_28 = 28, // Blue ? - ICON_POI_29 = 29, // Red and White ? - ICON_POI_30 = 30, // Red ? - ICON_POI_GREYHOUSE = 31, // Grey House - ICON_POI_BWHOUSE = 32, // Blue and White House - ICON_POI_BLUEHOUSE = 33, // Blue House - ICON_POI_RWHOUSE = 34, // Red and White House - ICON_POI_REDHOUSE = 35, // Red House - ICON_POI_GREYHORSE = 36, // Grey Horse - ICON_POI_BWHORSE = 37, // Blue and White Horse - ICON_POI_BLUEHORSE = 38, // Blue Horse - ICON_POI_RWHORSE = 39, // Red and White Horse - ICON_POI_REDHORSE = 40 // Red Horse -}; - -struct GossipMenuItem -{ - uint8 m_gIcon; - bool m_gCoded; - std::string m_gMessage; - uint32 m_gSender; - uint32 m_gAction; - std::string m_gBoxMessage; - uint32 m_gBoxMoney; -}; - -typedef std::vector GossipMenuItemList; - -struct QuestMenuItem -{ - uint32 m_qId; - uint8 m_qIcon; -}; - -typedef std::vector QuestMenuItemList; - -class MANGOS_DLL_SPEC GossipMenu -{ - public: - GossipMenu(); - ~GossipMenu(); - - void AddMenuItem(uint8 Icon, std::string Message, bool Coded = false); - void AddMenuItem(uint8 Icon, std::string Message, uint32 dtSender, uint32 dtAction, std::string BoxMessage, uint32 BoxMoney, bool Coded = false); - - // for using from scripts, don't must be inlined - void AddMenuItem(uint8 Icon, char const* Message, bool Coded = false); - void AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded = false); - - unsigned int MenuItemCount() - { - return m_gItems.size(); - } - - GossipMenuItem const& GetItem( unsigned int Id ) - { - return m_gItems[ Id ]; - } - - uint32 MenuItemSender( unsigned int ItemId ); - uint32 MenuItemAction( unsigned int ItemId ); - bool MenuItemCoded( unsigned int ItemId ); - - void ClearMenu(); - - protected: - GossipMenuItemList m_gItems; -}; - -class QuestMenu -{ - public: - QuestMenu(); - ~QuestMenu(); - - void AddMenuItem( uint32 QuestId, uint8 Icon); - void ClearMenu(); - - uint8 MenuItemCount() - { - return m_qItems.size(); - } - bool HasItem( uint32 questid ); - - QuestMenuItem const& GetItem( uint16 Id ) - { - return m_qItems[ Id ]; - } - - protected: - QuestMenuItemList m_qItems; -}; - -class MANGOS_DLL_SPEC PlayerMenu -{ - private: - GossipMenu* pGossipMenu; - QuestMenu* pQuestMenu; - WorldSession* pSession; - - public: - PlayerMenu( WorldSession *Session ); - ~PlayerMenu(); - - GossipMenu* GetGossipMenu() { return pGossipMenu; } - QuestMenu* GetQuestMenu() { return pQuestMenu; } - - void ClearMenus(); - uint32 GossipOptionSender( unsigned int Selection ); - uint32 GossipOptionAction( unsigned int Selection ); - bool GossipOptionCoded( unsigned int Selection ); - - void SendGossipMenu( uint32 TitleTextId, uint64 npcGUID ); - void CloseGossip(); - void SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, const char * locName ); - void SendTalking( uint32 textID ); - void SendTalking( char const * title, char const * text ); - - /*********************************************************/ - /*** QUEST SYSTEM ***/ - /*********************************************************/ - void SendQuestGiverStatus( uint8 questStatus, uint64 npcGUID ); - - void SendQuestGiverQuestList( QEmote eEmote, std::string Title, uint64 npcGUID ); - - void SendQuestQueryResponse ( Quest const *pQuest ); - void SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID, bool ActivateAccept); - - void SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnbleNext ); - void SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel ); -}; -#endif +/* + * Copyright (C) 2005-2008 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 MANGOSSERVER_GOSSIP_H +#define MANGOSSERVER_GOSSIP_H + +#include "Common.h" +#include "QuestDef.h" +#include "NPCHandler.h" + +class WorldSession; + +#define GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough +#define DEFAULT_GOSSIP_MESSAGE 0xffffff + +//POI defines +enum Poi_Icon +{ + ICON_POI_0 = 0, // Grey ? + ICON_POI_1 = 1, // Red ? + ICON_POI_2 = 2, // Blue ? + ICON_POI_BWTOMB = 3, // Blue and White Tomb Stone + ICON_POI_HOUSE = 4, // House + ICON_POI_TOWER = 5, // Tower + ICON_POI_REDFLAG = 6, // Red Flag with Yellow ! + ICON_POI_TOMB = 7, // Tomb Stone + ICON_POI_BWTOWER = 8, // Blue and White Tower + ICON_POI_REDTOWER = 9, // Red Tower + ICON_POI_BLUETOWER = 10, // Blue Tower + ICON_POI_RWTOWER = 11, // Red and White Tower + ICON_POI_REDTOMB = 12, // Red Tomb Stone + ICON_POI_RWTOMB = 13, // Red and White Tomb Stone + ICON_POI_BLUETOMB = 14, // Blue Tomb Stone + ICON_POI_NOTHING = 15, // NOTHING + ICON_POI_16 = 16, // Red ? + ICON_POI_17 = 17, // Grey ? + ICON_POI_18 = 18, // Blue ? + ICON_POI_19 = 19, // Red and White ? + ICON_POI_20 = 20, // Red ? + ICON_POI_GREYLOGS = 21, // Grey Wood Logs + ICON_POI_BWLOGS = 22, // Blue and White Wood Logs + ICON_POI_BLUELOGS = 23, // Blue Wood Logs + ICON_POI_RWLOGS = 24, // Red and White Wood Logs + ICON_POI_REDLOGS = 25, // Red Wood Logs + ICON_POI_26 = 26, // Grey ? + ICON_POI_27 = 27, // Blue and White ? + ICON_POI_28 = 28, // Blue ? + ICON_POI_29 = 29, // Red and White ? + ICON_POI_30 = 30, // Red ? + ICON_POI_GREYHOUSE = 31, // Grey House + ICON_POI_BWHOUSE = 32, // Blue and White House + ICON_POI_BLUEHOUSE = 33, // Blue House + ICON_POI_RWHOUSE = 34, // Red and White House + ICON_POI_REDHOUSE = 35, // Red House + ICON_POI_GREYHORSE = 36, // Grey Horse + ICON_POI_BWHORSE = 37, // Blue and White Horse + ICON_POI_BLUEHORSE = 38, // Blue Horse + ICON_POI_RWHORSE = 39, // Red and White Horse + ICON_POI_REDHORSE = 40 // Red Horse +}; + +struct GossipMenuItem +{ + uint8 m_gIcon; + bool m_gCoded; + std::string m_gMessage; + uint32 m_gSender; + uint32 m_gAction; + std::string m_gBoxMessage; + uint32 m_gBoxMoney; +}; + +typedef std::vector GossipMenuItemList; + +struct QuestMenuItem +{ + uint32 m_qId; + uint8 m_qIcon; +}; + +typedef std::vector QuestMenuItemList; + +class MANGOS_DLL_SPEC GossipMenu +{ + public: + GossipMenu(); + ~GossipMenu(); + + void AddMenuItem(uint8 Icon, std::string Message, bool Coded = false); + void AddMenuItem(uint8 Icon, std::string Message, uint32 dtSender, uint32 dtAction, std::string BoxMessage, uint32 BoxMoney, bool Coded = false); + + // for using from scripts, don't must be inlined + void AddMenuItem(uint8 Icon, char const* Message, bool Coded = false); + void AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded = false); + + unsigned int MenuItemCount() const + { + return m_gItems.size(); + } + + bool Empty() const + { + return m_gItems.empty(); + } + + GossipMenuItem const& GetItem( unsigned int Id ) + { + return m_gItems[ Id ]; + } + + uint32 MenuItemSender( unsigned int ItemId ); + uint32 MenuItemAction( unsigned int ItemId ); + bool MenuItemCoded( unsigned int ItemId ); + + void ClearMenu(); + + protected: + GossipMenuItemList m_gItems; +}; + +class QuestMenu +{ + public: + QuestMenu(); + ~QuestMenu(); + + void AddMenuItem( uint32 QuestId, uint8 Icon); + void ClearMenu(); + + uint8 MenuItemCount() const + { + return m_qItems.size(); + } + + bool Empty() const + { + return m_qItems.empty(); + } + + bool HasItem( uint32 questid ); + + QuestMenuItem const& GetItem( uint16 Id ) + { + return m_qItems[ Id ]; + } + + protected: + QuestMenuItemList m_qItems; +}; + +class MANGOS_DLL_SPEC PlayerMenu +{ + private: + GossipMenu mGossipMenu; + QuestMenu mQuestMenu; + WorldSession* pSession; + + public: + PlayerMenu( WorldSession *Session ); + ~PlayerMenu(); + + GossipMenu& GetGossipMenu() { return mGossipMenu; } + QuestMenu& GetQuestMenu() { return mQuestMenu; } + + bool Empty() const { return mGossipMenu.Empty() && mQuestMenu.Empty(); } + + void ClearMenus(); + uint32 GossipOptionSender( unsigned int Selection ); + uint32 GossipOptionAction( unsigned int Selection ); + bool GossipOptionCoded( unsigned int Selection ); + + void SendGossipMenu( uint32 TitleTextId, uint64 npcGUID ); + void CloseGossip(); + void SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, const char * locName ); + void SendTalking( uint32 textID ); + void SendTalking( char const * title, char const * text ); + + /*********************************************************/ + /*** QUEST SYSTEM ***/ + /*********************************************************/ + void SendQuestGiverStatus( uint8 questStatus, uint64 npcGUID ); + + void SendQuestGiverQuestList( QEmote eEmote, std::string Title, uint64 npcGUID ); + + void SendQuestQueryResponse ( Quest const *pQuest ); + void SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID, bool ActivateAccept); + + void SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnbleNext ); + void SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel ); +}; +#endif diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index 215cf9152e6..98e25857638 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -1,812 +1,812 @@ -/* - * Copyright (C) 2005-2008 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 MANGOS_GRIDNOTIFIERS_H -#define MANGOS_GRIDNOTIFIERS_H - -#include "ObjectGridLoader.h" -#include "ByteBuffer.h" -#include "UpdateData.h" -#include - -#include "Corpse.h" -#include "Object.h" -#include "DynamicObject.h" -#include "GameObject.h" -#include "Player.h" -#include "Unit.h" - -class Player; -//class Map; - -namespace MaNGOS -{ - - struct MANGOS_DLL_DECL PlayerNotifier - { - explicit PlayerNotifier(Player &pl) : i_player(pl) {} - void Visit(PlayerMapType &); - template void Visit(GridRefManager &) {} - Player &i_player; - }; - - struct MANGOS_DLL_DECL VisibleNotifier - { - Player &i_player; - UpdateData i_data; - UpdateDataMapType i_data_updates; - Player::ClientGUIDs i_clientGUIDs; - std::set i_visibleNow; - - explicit VisibleNotifier(Player &player) : i_player(player),i_clientGUIDs(player.m_clientGUIDs) {} - template void Visit(GridRefManager &m); - void Visit(PlayerMapType &); - void Notify(void); - }; - - struct MANGOS_DLL_DECL VisibleChangesNotifier - { - WorldObject &i_object; - - explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {} - template void Visit(GridRefManager &) {} - void Visit(PlayerMapType &); - }; - - struct MANGOS_DLL_DECL GridUpdater - { - GridType &i_grid; - uint32 i_timeDiff; - GridUpdater(GridType &grid, uint32 diff) : i_grid(grid), i_timeDiff(diff) {} - - template void updateObjects(GridRefManager &m) - { - for(typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) - iter->getSource()->Update(i_timeDiff); - } - - void Visit(PlayerMapType &m) { updateObjects(m); } - void Visit(CreatureMapType &m){ updateObjects(m); } - void Visit(GameObjectMapType &m) { updateObjects(m); } - void Visit(DynamicObjectMapType &m) { updateObjects(m); } - void Visit(CorpseMapType &m) { updateObjects(m); } - }; - - struct MANGOS_DLL_DECL MessageDeliverer - { - Player &i_player; - WorldPacket *i_message; - bool i_toSelf; - MessageDeliverer(Player &pl, WorldPacket *msg, bool to_self) : i_player(pl), i_message(msg), i_toSelf(to_self) {} - void Visit(PlayerMapType &m); - template void Visit(GridRefManager &) {} - }; - - struct MANGOS_DLL_DECL ObjectMessageDeliverer - { - WorldPacket *i_message; - explicit ObjectMessageDeliverer(WorldPacket *msg) : i_message(msg) {} - void Visit(PlayerMapType &m); - template void Visit(GridRefManager &) {} - }; - - struct MANGOS_DLL_DECL MessageDistDeliverer - { - Player &i_player; - WorldPacket *i_message; - bool i_toSelf; - bool i_ownTeamOnly; - float i_dist; - MessageDistDeliverer(Player &pl, WorldPacket *msg, bool to_self, bool ownTeamOnly, float dist) : i_player(pl), i_message(msg), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly), i_dist(dist) {} - void Visit(PlayerMapType &m); - template void Visit(GridRefManager &) {} - }; - - struct MANGOS_DLL_DECL ObjectMessageDistDeliverer - { - WorldObject &i_object; - WorldPacket *i_message; - float i_dist; - ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {} - void Visit(PlayerMapType &m); - template void Visit(GridRefManager &) {} - }; - - struct MANGOS_DLL_DECL ObjectUpdater - { - uint32 i_timeDiff; - explicit ObjectUpdater(const uint32 &diff) : i_timeDiff(diff) {} - template void Visit(GridRefManager &m); - void Visit(PlayerMapType &) {} - void Visit(CorpseMapType &) {} - void Visit(CreatureMapType &); - }; - - template - struct MANGOS_DLL_DECL ObjectAccessorNotifier - { - T *& i_object; - - uint64 i_id; - ObjectAccessorNotifier(T * &obj, uint64 id) : i_object(obj), i_id(id) - { - i_object = NULL; - } - - void Visit(GridRefManager &m ) - { - if( i_object == NULL ) - { - GridRefManager *iter = m.find(i_id); - if( iter != m.end() ) - { - assert( iter->second != NULL ); - i_object = iter->second; - } - } - } - - template void Visit(GridRefManager &) {} - }; - - struct MANGOS_DLL_DECL PlayerRelocationNotifier - { - Player &i_player; - PlayerRelocationNotifier(Player &pl) : i_player(pl) {} - template void Visit(GridRefManager &) {} - void Visit(PlayerMapType &); - void Visit(CreatureMapType &); - }; - - struct MANGOS_DLL_DECL CreatureRelocationNotifier - { - Creature &i_creature; - CreatureRelocationNotifier(Creature &c) : i_creature(c) {} - template void Visit(GridRefManager &) {} - #ifdef WIN32 - template<> void Visit(PlayerMapType &); - #endif - }; - - struct MANGOS_DLL_DECL DynamicObjectUpdater - { - DynamicObject &i_dynobject; - Unit* i_check; - DynamicObjectUpdater(DynamicObject &dynobject, Unit* caster) : i_dynobject(dynobject) - { - i_check = caster; - Unit* owner = i_check->GetOwner(); - if(owner) - i_check = owner; - } - - template inline void Visit(GridRefManager &) {} - #ifdef WIN32 - template<> inline void Visit(PlayerMapType &); - template<> inline void Visit(CreatureMapType &); - #endif - - void VisitHelper(Unit* target); - }; - - // SEARCHERS & LIST SEARCHERS & WORKERS - - // WorldObject searchers & workers - - template - struct MANGOS_DLL_DECL WorldObjectSearcher - { - WorldObject* &i_object; - Check &i_check; - - WorldObjectSearcher(WorldObject* & result, Check& check) : i_object(result),i_check(check) {} - - void Visit(GameObjectMapType &m); - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - void Visit(CorpseMapType &m); - void Visit(DynamicObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct MANGOS_DLL_DECL WorldObjectListSearcher - { - std::list &i_objects; - Check& i_check; - - WorldObjectListSearcher(std::list &objects, Check & check) : i_objects(objects),i_check(check) {} - - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - void Visit(CorpseMapType &m); - void Visit(GameObjectMapType &m); - void Visit(DynamicObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct MANGOS_DLL_DECL WorldObjectWorker - { - Do const& i_do; - - explicit WorldObjectWorker(Do const& _do) : i_do(_do) {} - - void Visit(GameObjectMapType &m) - { - for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - i_do(itr->getSource()); - } - - void Visit(PlayerMapType &m) - { - for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - i_do(itr->getSource()); - } - void Visit(CreatureMapType &m) - { - for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - i_do(itr->getSource()); - } - - void Visit(CorpseMapType &m) - { - for(CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - i_do(itr->getSource()); - } - - void Visit(DynamicObjectMapType &m) - { - for(DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - i_do(itr->getSource()); - } - - template void Visit(GridRefManager &) {} - }; - - // Gameobject searchers - - template - struct MANGOS_DLL_DECL GameObjectSearcher - { - GameObject* &i_object; - Check &i_check; - - GameObjectSearcher(GameObject* & result, Check& check) : i_object(result),i_check(check) {} - - void Visit(GameObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Last accepted by Check GO if any (Check can change requirements at each call) - template - struct MANGOS_DLL_DECL GameObjectLastSearcher - { - GameObject* &i_object; - Check& i_check; - - GameObjectLastSearcher(GameObject* & result, Check& check) : i_object(result),i_check(check) {} - - void Visit(GameObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct MANGOS_DLL_DECL GameObjectListSearcher - { - std::list &i_objects; - Check& i_check; - - GameObjectListSearcher(std::list &objects, Check & check) : i_objects(objects),i_check(check) {} - - void Visit(GameObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Unit searchers - - // First accepted by Check Unit if any - template - struct MANGOS_DLL_DECL UnitSearcher - { - Unit* &i_object; - Check & i_check; - - UnitSearcher(Unit* & result, Check & check) : i_object(result),i_check(check) {} - - void Visit(CreatureMapType &m); - void Visit(PlayerMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Last accepted by Check Unit if any (Check can change requirements at each call) - template - struct MANGOS_DLL_DECL UnitLastSearcher - { - Unit* &i_object; - Check & i_check; - - UnitLastSearcher(Unit* & result, Check & check) : i_object(result),i_check(check) {} - - void Visit(CreatureMapType &m); - void Visit(PlayerMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // All accepted by Check units if any - template - struct MANGOS_DLL_DECL UnitListSearcher - { - std::list &i_objects; - Check& i_check; - - UnitListSearcher(std::list &objects, Check & check) : i_objects(objects),i_check(check) {} - - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Creature searchers - - template - struct MANGOS_DLL_DECL CreatureSearcher - { - Creature* &i_object; - Check & i_check; - - CreatureSearcher(Creature* & result, Check & check) : i_object(result),i_check(check) {} - - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Last accepted by Check Creature if any (Check can change requirements at each call) - template - struct MANGOS_DLL_DECL CreatureLastSearcher - { - Creature* &i_object; - Check & i_check; - - CreatureLastSearcher(Creature* & result, Check & check) : i_object(result),i_check(check) {} - - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct MANGOS_DLL_DECL CreatureListSearcher - { - std::list &i_objects; - Check& i_check; - - CreatureListSearcher(std::list &objects, Check & check) : i_objects(objects),i_check(check) {} - - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Player searchers - - template - struct MANGOS_DLL_DECL PlayerSearcher - { - Player* &i_object; - Check & i_check; - - PlayerSearcher(Player* & result, Check & check) : i_object(result),i_check(check) {} - - void Visit(PlayerMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct MANGOS_DLL_DECL PlayerWorker - { - Do& i_do; - - explicit PlayerWorker(Do& _do) : i_do(_do) {} - - void Visit(PlayerMapType &m) - { - for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - i_do(itr->getSource()); - } - - template void Visit(GridRefManager &) {} - }; - - // CHECKS && DO classes - - // WorldObject check classes - class CannibalizeObjectCheck - { - public: - CannibalizeObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} - bool operator()(Player* u) - { - if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() ) - return false; - - if(i_funit->IsWithinDistInMap(u, i_range) ) - return true; - - return false; - } - bool operator()(Corpse* u); - bool operator()(Creature* u) - { - if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() || - (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD)==0) - return false; - - if(i_funit->IsWithinDistInMap(u, i_range) ) - return true; - - return false; - } - template bool operator()(NOT_INTERESTED* u) { return false; } - private: - Unit* const i_funit; - float i_range; - }; - - // WorldObject do classes - - class RespawnDo - { - public: - RespawnDo() {} - void operator()(Creature* u) const { u->Respawn(); } - void operator()(GameObject* u) const { u->Respawn(); } - void operator()(WorldObject*) const {} - void operator()(Corpse*) const {} - }; - - // GameObject checks - - class GameObjectFocusCheck - { - public: - GameObjectFocusCheck(Unit const* unit,uint32 focusId) : i_unit(unit), i_focusId(focusId) {} - bool operator()(GameObject* go) const - { - if(go->GetGOInfo()->type != GAMEOBJECT_TYPE_SPELL_FOCUS) - return false; - - if(go->GetGOInfo()->spellFocus.focusId != i_focusId) - return false; - - float dist = go->GetGOInfo()->spellFocus.dist; - - return go->IsWithinDistInMap(i_unit, dist); - } - private: - Unit const* i_unit; - uint32 i_focusId; - }; - - // Find the nearest Fishing hole and return true only if source object is in range of hole - class NearestGameObjectFishingHole - { - public: - NearestGameObjectFishingHole(WorldObject const& obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(GameObject* go) - { - if(go->GetGOInfo()->type == GAMEOBJECT_TYPE_FISHINGHOLE && go->isSpawned() && i_obj.IsWithinDistInMap(go, i_range) && i_obj.IsWithinDistInMap(go, go->GetGOInfo()->fishinghole.radius)) - { - i_range = i_obj.GetDistance(go); - return true; - } - return false; - } - float GetLastRange() const { return i_range; } - private: - WorldObject const& i_obj; - float i_range; - - // prevent clone - NearestGameObjectFishingHole(NearestGameObjectFishingHole const&); - }; - - // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO) - class NearestGameObjectEntryInObjectRangeCheck - { - public: - NearestGameObjectEntryInObjectRangeCheck(WorldObject const& obj,uint32 entry, float range) : i_obj(obj), i_entry(entry), i_range(range) {} - bool operator()(GameObject* go) - { - if(go->GetEntry() == i_entry && i_obj.IsWithinDistInMap(go, i_range)) - { - i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check - return true; - } - return false; - } - float GetLastRange() const { return i_range; } - private: - WorldObject const& i_obj; - uint32 i_entry; - float i_range; - - // prevent clone this object - NearestGameObjectEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&); - }; - - class GameObjectWithDbGUIDCheck - { - public: - GameObjectWithDbGUIDCheck(WorldObject const& obj,uint32 db_guid) : i_obj(obj), i_db_guid(db_guid) {} - bool operator()(GameObject const* go) const - { - return go->GetDBTableGUIDLow() == i_db_guid; - } - private: - WorldObject const& i_obj; - uint32 i_db_guid; - }; - - // Unit checks - - class AnyUnfriendlyUnitInObjectRangeCheck - { - public: - AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} - bool operator()(Unit* u) - { - if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u)) - return true; - else - return false; - } - private: - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - }; - - class AnyFriendlyUnitInObjectRangeCheck - { - public: - AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} - bool operator()(Unit* u) - { - if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u)) - return true; - else - return false; - } - private: - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - }; - - class AnyUnitInObjectRangeCheck - { - public: - AnyUnitInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(Unit* u) - { - if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range)) - return true; - - return false; - } - private: - WorldObject const* i_obj; - float i_range; - }; - - // Success at unit in range, range update for next check (this can be use with UnitLastSearcher to find nearest unit) - class NearestAttackableUnitInObjectRangeCheck - { - public: - NearestAttackableUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} - bool operator()(Unit* u) - { - if( u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) && - !i_funit->IsFriendlyTo(u) && u->isVisibleForOrDetect(i_funit,false) ) - { - i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check - return true; - } - - return false; - } - private: - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - - // prevent clone this object - NearestAttackableUnitInObjectRangeCheck(NearestAttackableUnitInObjectRangeCheck const&); - }; - - class AnyAoETargetUnitInObjectRangeCheck - { - public: - AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) - : i_obj(obj), i_funit(funit), i_range(range) - { - Unit const* check = i_funit; - Unit const* owner = i_funit->GetOwner(); - if(owner) - check = owner; - i_targetForPlayer = ( check->GetTypeId()==TYPEID_PLAYER ); - } - bool operator()(Unit* u) - { - // Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems - if (!u->isTargetableForAttack()) - return false; - if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isTotem()) - return false; - - if(( i_targetForPlayer ? !i_funit->IsFriendlyTo(u) : i_funit->IsHostileTo(u) )&& i_obj->IsWithinDistInMap(u, i_range)) - return true; - - return false; - } - private: - bool i_targetForPlayer; - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - }; - - struct AnyDeadUnitCheck - { - bool operator()(Unit* u) { return !u->isAlive(); } - }; - - struct AnyStealthedCheck - { - bool operator()(Unit* u) { return u->GetVisibility()==VISIBILITY_GROUP_STEALTH; } - }; - - // Creature checks - - class InAttackDistanceFromAnyHostileCreatureCheck - { - public: - explicit InAttackDistanceFromAnyHostileCreatureCheck(Unit* funit) : i_funit(funit) {} - bool operator()(Creature* u) - { - if(u->isAlive() && u->IsHostileTo(i_funit) && i_funit->IsWithinDistInMap(u, u->GetAttackDistance(i_funit))) - return true; - - return false; - } - private: - Unit* const i_funit; - }; - - class AnyAssistCreatureInRangeCheck - { - public: - AnyAssistCreatureInRangeCheck(Unit* funit, Unit* enemy, float range) - : i_funit(funit), i_enemy(enemy), i_range(range) - { - } - bool operator()(Creature* u) - { - if(u == i_funit) - return false; - - // we don't need help from zombies :) - if( !u->isAlive() ) - return false; - - // skip fighting creature - if( u->isInCombat() ) - return false; - - // only from same creature faction - if(u->getFaction() != i_funit->getFaction() ) - return false; - - // only free creature - if( u->GetCharmerOrOwnerGUID() ) - return false; - - // too far - if( !i_funit->IsWithinDistInMap(u, i_range) ) - return false; - - // skip non hostile to caster enemy creatures - if( !u->IsHostileTo(i_enemy) ) - return false; - - // only if see assisted creature - if(!u->IsWithinLOSInMap(i_funit) ) - return false; - - return true; - } - private: - Unit* const i_funit; - Unit* const i_enemy; - float i_range; - }; - - // Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature) - class NearestCreatureEntryWithLiveStateInObjectRangeCheck - { - public: - NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject const& obj,uint32 entry, bool alive, float range) - : i_obj(obj), i_entry(entry), i_alive(alive), i_range(range) {} - - bool operator()(Creature* u) - { - if(u->GetEntry() == i_entry && u->isAlive()==i_alive && i_obj.IsWithinDistInMap(u, i_range)) - { - i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check - return true; - } - return false; - } - float GetLastRange() const { return i_range; } - private: - WorldObject const& i_obj; - uint32 i_entry; - bool i_alive; - float i_range; - - // prevent clone this object - NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&); - }; - - class AnyPlayerInObjectRangeCheck - { - public: - AnyPlayerInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(Player* u) - { - if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range)) - return true; - - return false; - } - private: - WorldObject const* i_obj; - float i_range; - }; - - #ifndef WIN32 - template<> void PlayerRelocationNotifier::Visit(CreatureMapType &); - template<> void PlayerRelocationNotifier::Visit(PlayerMapType &); - template<> void CreatureRelocationNotifier::Visit(PlayerMapType &); - template<> void CreatureRelocationNotifier::Visit(CreatureMapType &); - template<> inline void DynamicObjectUpdater::Visit(CreatureMapType &); - template<> inline void DynamicObjectUpdater::Visit(PlayerMapType &); - #endif -} -#endif +/* + * Copyright (C) 2005-2008 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 MANGOS_GRIDNOTIFIERS_H +#define MANGOS_GRIDNOTIFIERS_H + +#include "ObjectGridLoader.h" +#include "ByteBuffer.h" +#include "UpdateData.h" +#include + +#include "Corpse.h" +#include "Object.h" +#include "DynamicObject.h" +#include "GameObject.h" +#include "Player.h" +#include "Unit.h" + +class Player; +//class Map; + +namespace MaNGOS +{ + + struct MANGOS_DLL_DECL PlayerNotifier + { + explicit PlayerNotifier(Player &pl) : i_player(pl) {} + void Visit(PlayerMapType &); + template void Visit(GridRefManager &) {} + Player &i_player; + }; + + struct MANGOS_DLL_DECL VisibleNotifier + { + Player &i_player; + UpdateData i_data; + UpdateDataMapType i_data_updates; + Player::ClientGUIDs i_clientGUIDs; + std::set i_visibleNow; + + explicit VisibleNotifier(Player &player) : i_player(player),i_clientGUIDs(player.m_clientGUIDs) {} + template void Visit(GridRefManager &m); + void Visit(PlayerMapType &); + void Notify(void); + }; + + struct MANGOS_DLL_DECL VisibleChangesNotifier + { + WorldObject &i_object; + + explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {} + template void Visit(GridRefManager &) {} + void Visit(PlayerMapType &); + }; + + struct MANGOS_DLL_DECL GridUpdater + { + GridType &i_grid; + uint32 i_timeDiff; + GridUpdater(GridType &grid, uint32 diff) : i_grid(grid), i_timeDiff(diff) {} + + template void updateObjects(GridRefManager &m) + { + for(typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) + iter->getSource()->Update(i_timeDiff); + } + + void Visit(PlayerMapType &m) { updateObjects(m); } + void Visit(CreatureMapType &m){ updateObjects(m); } + void Visit(GameObjectMapType &m) { updateObjects(m); } + void Visit(DynamicObjectMapType &m) { updateObjects(m); } + void Visit(CorpseMapType &m) { updateObjects(m); } + }; + + struct MANGOS_DLL_DECL MessageDeliverer + { + Player &i_player; + WorldPacket *i_message; + bool i_toSelf; + MessageDeliverer(Player &pl, WorldPacket *msg, bool to_self) : i_player(pl), i_message(msg), i_toSelf(to_self) {} + void Visit(PlayerMapType &m); + template void Visit(GridRefManager &) {} + }; + + struct MANGOS_DLL_DECL ObjectMessageDeliverer + { + WorldPacket *i_message; + explicit ObjectMessageDeliverer(WorldPacket *msg) : i_message(msg) {} + void Visit(PlayerMapType &m); + template void Visit(GridRefManager &) {} + }; + + struct MANGOS_DLL_DECL MessageDistDeliverer + { + Player &i_player; + WorldPacket *i_message; + bool i_toSelf; + bool i_ownTeamOnly; + float i_dist; + MessageDistDeliverer(Player &pl, WorldPacket *msg, float dist, bool to_self, bool ownTeamOnly) : i_player(pl), i_message(msg), i_dist(dist), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly) {} + void Visit(PlayerMapType &m); + template void Visit(GridRefManager &) {} + }; + + struct MANGOS_DLL_DECL ObjectMessageDistDeliverer + { + WorldObject &i_object; + WorldPacket *i_message; + float i_dist; + ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {} + void Visit(PlayerMapType &m); + template void Visit(GridRefManager &) {} + }; + + struct MANGOS_DLL_DECL ObjectUpdater + { + uint32 i_timeDiff; + explicit ObjectUpdater(const uint32 &diff) : i_timeDiff(diff) {} + template void Visit(GridRefManager &m); + void Visit(PlayerMapType &) {} + void Visit(CorpseMapType &) {} + void Visit(CreatureMapType &); + }; + + template + struct MANGOS_DLL_DECL ObjectAccessorNotifier + { + T *& i_object; + + uint64 i_id; + ObjectAccessorNotifier(T * &obj, uint64 id) : i_object(obj), i_id(id) + { + i_object = NULL; + } + + void Visit(GridRefManager &m ) + { + if( i_object == NULL ) + { + GridRefManager *iter = m.find(i_id); + if( iter != m.end() ) + { + assert( iter->second != NULL ); + i_object = iter->second; + } + } + } + + template void Visit(GridRefManager &) {} + }; + + struct MANGOS_DLL_DECL PlayerRelocationNotifier + { + Player &i_player; + PlayerRelocationNotifier(Player &pl) : i_player(pl) {} + template void Visit(GridRefManager &) {} + void Visit(PlayerMapType &); + void Visit(CreatureMapType &); + }; + + struct MANGOS_DLL_DECL CreatureRelocationNotifier + { + Creature &i_creature; + CreatureRelocationNotifier(Creature &c) : i_creature(c) {} + template void Visit(GridRefManager &) {} + #ifdef WIN32 + template<> void Visit(PlayerMapType &); + #endif + }; + + struct MANGOS_DLL_DECL DynamicObjectUpdater + { + DynamicObject &i_dynobject; + Unit* i_check; + DynamicObjectUpdater(DynamicObject &dynobject, Unit* caster) : i_dynobject(dynobject) + { + i_check = caster; + Unit* owner = i_check->GetOwner(); + if(owner) + i_check = owner; + } + + template inline void Visit(GridRefManager &) {} + #ifdef WIN32 + template<> inline void Visit(PlayerMapType &); + template<> inline void Visit(CreatureMapType &); + #endif + + void VisitHelper(Unit* target); + }; + + // SEARCHERS & LIST SEARCHERS & WORKERS + + // WorldObject searchers & workers + + template + struct MANGOS_DLL_DECL WorldObjectSearcher + { + WorldObject* &i_object; + Check &i_check; + + WorldObjectSearcher(WorldObject* & result, Check& check) : i_object(result),i_check(check) {} + + void Visit(GameObjectMapType &m); + void Visit(PlayerMapType &m); + void Visit(CreatureMapType &m); + void Visit(CorpseMapType &m); + void Visit(DynamicObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct MANGOS_DLL_DECL WorldObjectListSearcher + { + std::list &i_objects; + Check& i_check; + + WorldObjectListSearcher(std::list &objects, Check & check) : i_objects(objects),i_check(check) {} + + void Visit(PlayerMapType &m); + void Visit(CreatureMapType &m); + void Visit(CorpseMapType &m); + void Visit(GameObjectMapType &m); + void Visit(DynamicObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct MANGOS_DLL_DECL WorldObjectWorker + { + Do const& i_do; + + explicit WorldObjectWorker(Do const& _do) : i_do(_do) {} + + void Visit(GameObjectMapType &m) + { + for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + i_do(itr->getSource()); + } + + void Visit(PlayerMapType &m) + { + for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + i_do(itr->getSource()); + } + void Visit(CreatureMapType &m) + { + for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + i_do(itr->getSource()); + } + + void Visit(CorpseMapType &m) + { + for(CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + i_do(itr->getSource()); + } + + void Visit(DynamicObjectMapType &m) + { + for(DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + i_do(itr->getSource()); + } + + template void Visit(GridRefManager &) {} + }; + + // Gameobject searchers + + template + struct MANGOS_DLL_DECL GameObjectSearcher + { + GameObject* &i_object; + Check &i_check; + + GameObjectSearcher(GameObject* & result, Check& check) : i_object(result),i_check(check) {} + + void Visit(GameObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Last accepted by Check GO if any (Check can change requirements at each call) + template + struct MANGOS_DLL_DECL GameObjectLastSearcher + { + GameObject* &i_object; + Check& i_check; + + GameObjectLastSearcher(GameObject* & result, Check& check) : i_object(result),i_check(check) {} + + void Visit(GameObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct MANGOS_DLL_DECL GameObjectListSearcher + { + std::list &i_objects; + Check& i_check; + + GameObjectListSearcher(std::list &objects, Check & check) : i_objects(objects),i_check(check) {} + + void Visit(GameObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Unit searchers + + // First accepted by Check Unit if any + template + struct MANGOS_DLL_DECL UnitSearcher + { + Unit* &i_object; + Check & i_check; + + UnitSearcher(Unit* & result, Check & check) : i_object(result),i_check(check) {} + + void Visit(CreatureMapType &m); + void Visit(PlayerMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Last accepted by Check Unit if any (Check can change requirements at each call) + template + struct MANGOS_DLL_DECL UnitLastSearcher + { + Unit* &i_object; + Check & i_check; + + UnitLastSearcher(Unit* & result, Check & check) : i_object(result),i_check(check) {} + + void Visit(CreatureMapType &m); + void Visit(PlayerMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // All accepted by Check units if any + template + struct MANGOS_DLL_DECL UnitListSearcher + { + std::list &i_objects; + Check& i_check; + + UnitListSearcher(std::list &objects, Check & check) : i_objects(objects),i_check(check) {} + + void Visit(PlayerMapType &m); + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Creature searchers + + template + struct MANGOS_DLL_DECL CreatureSearcher + { + Creature* &i_object; + Check & i_check; + + CreatureSearcher(Creature* & result, Check & check) : i_object(result),i_check(check) {} + + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Last accepted by Check Creature if any (Check can change requirements at each call) + template + struct MANGOS_DLL_DECL CreatureLastSearcher + { + Creature* &i_object; + Check & i_check; + + CreatureLastSearcher(Creature* & result, Check & check) : i_object(result),i_check(check) {} + + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct MANGOS_DLL_DECL CreatureListSearcher + { + std::list &i_objects; + Check& i_check; + + CreatureListSearcher(std::list &objects, Check & check) : i_objects(objects),i_check(check) {} + + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Player searchers + + template + struct MANGOS_DLL_DECL PlayerSearcher + { + Player* &i_object; + Check & i_check; + + PlayerSearcher(Player* & result, Check & check) : i_object(result),i_check(check) {} + + void Visit(PlayerMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct MANGOS_DLL_DECL PlayerWorker + { + Do& i_do; + + explicit PlayerWorker(Do& _do) : i_do(_do) {} + + void Visit(PlayerMapType &m) + { + for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + i_do(itr->getSource()); + } + + template void Visit(GridRefManager &) {} + }; + + // CHECKS && DO classes + + // WorldObject check classes + class CannibalizeObjectCheck + { + public: + CannibalizeObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} + bool operator()(Player* u) + { + if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() ) + return false; + + if(i_funit->IsWithinDistInMap(u, i_range) ) + return true; + + return false; + } + bool operator()(Corpse* u); + bool operator()(Creature* u) + { + if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() || + (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD)==0) + return false; + + if(i_funit->IsWithinDistInMap(u, i_range) ) + return true; + + return false; + } + template bool operator()(NOT_INTERESTED* u) { return false; } + private: + Unit* const i_funit; + float i_range; + }; + + // WorldObject do classes + + class RespawnDo + { + public: + RespawnDo() {} + void operator()(Creature* u) const { u->Respawn(); } + void operator()(GameObject* u) const { u->Respawn(); } + void operator()(WorldObject*) const {} + void operator()(Corpse*) const {} + }; + + // GameObject checks + + class GameObjectFocusCheck + { + public: + GameObjectFocusCheck(Unit const* unit,uint32 focusId) : i_unit(unit), i_focusId(focusId) {} + bool operator()(GameObject* go) const + { + if(go->GetGOInfo()->type != GAMEOBJECT_TYPE_SPELL_FOCUS) + return false; + + if(go->GetGOInfo()->spellFocus.focusId != i_focusId) + return false; + + float dist = go->GetGOInfo()->spellFocus.dist; + + return go->IsWithinDistInMap(i_unit, dist); + } + private: + Unit const* i_unit; + uint32 i_focusId; + }; + + // Find the nearest Fishing hole and return true only if source object is in range of hole + class NearestGameObjectFishingHole + { + public: + NearestGameObjectFishingHole(WorldObject const& obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(GameObject* go) + { + if(go->GetGOInfo()->type == GAMEOBJECT_TYPE_FISHINGHOLE && go->isSpawned() && i_obj.IsWithinDistInMap(go, i_range) && i_obj.IsWithinDistInMap(go, go->GetGOInfo()->fishinghole.radius)) + { + i_range = i_obj.GetDistance(go); + return true; + } + return false; + } + float GetLastRange() const { return i_range; } + private: + WorldObject const& i_obj; + float i_range; + + // prevent clone + NearestGameObjectFishingHole(NearestGameObjectFishingHole const&); + }; + + // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO) + class NearestGameObjectEntryInObjectRangeCheck + { + public: + NearestGameObjectEntryInObjectRangeCheck(WorldObject const& obj,uint32 entry, float range) : i_obj(obj), i_entry(entry), i_range(range) {} + bool operator()(GameObject* go) + { + if(go->GetEntry() == i_entry && i_obj.IsWithinDistInMap(go, i_range)) + { + i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check + return true; + } + return false; + } + float GetLastRange() const { return i_range; } + private: + WorldObject const& i_obj; + uint32 i_entry; + float i_range; + + // prevent clone this object + NearestGameObjectEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&); + }; + + class GameObjectWithDbGUIDCheck + { + public: + GameObjectWithDbGUIDCheck(WorldObject const& obj,uint32 db_guid) : i_obj(obj), i_db_guid(db_guid) {} + bool operator()(GameObject const* go) const + { + return go->GetDBTableGUIDLow() == i_db_guid; + } + private: + WorldObject const& i_obj; + uint32 i_db_guid; + }; + + // Unit checks + + class AnyUnfriendlyUnitInObjectRangeCheck + { + public: + AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} + bool operator()(Unit* u) + { + if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u)) + return true; + else + return false; + } + private: + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + }; + + class AnyFriendlyUnitInObjectRangeCheck + { + public: + AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} + bool operator()(Unit* u) + { + if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u)) + return true; + else + return false; + } + private: + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + }; + + class AnyUnitInObjectRangeCheck + { + public: + AnyUnitInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(Unit* u) + { + if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range)) + return true; + + return false; + } + private: + WorldObject const* i_obj; + float i_range; + }; + + // Success at unit in range, range update for next check (this can be use with UnitLastSearcher to find nearest unit) + class NearestAttackableUnitInObjectRangeCheck + { + public: + NearestAttackableUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} + bool operator()(Unit* u) + { + if( u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) && + !i_funit->IsFriendlyTo(u) && u->isVisibleForOrDetect(i_funit,false) ) + { + i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check + return true; + } + + return false; + } + private: + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + + // prevent clone this object + NearestAttackableUnitInObjectRangeCheck(NearestAttackableUnitInObjectRangeCheck const&); + }; + + class AnyAoETargetUnitInObjectRangeCheck + { + public: + AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) + : i_obj(obj), i_funit(funit), i_range(range) + { + Unit const* check = i_funit; + Unit const* owner = i_funit->GetOwner(); + if(owner) + check = owner; + i_targetForPlayer = ( check->GetTypeId()==TYPEID_PLAYER ); + } + bool operator()(Unit* u) + { + // Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems + if (!u->isTargetableForAttack()) + return false; + if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isTotem()) + return false; + + if(( i_targetForPlayer ? !i_funit->IsFriendlyTo(u) : i_funit->IsHostileTo(u) )&& i_obj->IsWithinDistInMap(u, i_range)) + return true; + + return false; + } + private: + bool i_targetForPlayer; + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + }; + + struct AnyDeadUnitCheck + { + bool operator()(Unit* u) { return !u->isAlive(); } + }; + + struct AnyStealthedCheck + { + bool operator()(Unit* u) { return u->GetVisibility()==VISIBILITY_GROUP_STEALTH; } + }; + + // Creature checks + + class InAttackDistanceFromAnyHostileCreatureCheck + { + public: + explicit InAttackDistanceFromAnyHostileCreatureCheck(Unit* funit) : i_funit(funit) {} + bool operator()(Creature* u) + { + if(u->isAlive() && u->IsHostileTo(i_funit) && i_funit->IsWithinDistInMap(u, u->GetAttackDistance(i_funit))) + return true; + + return false; + } + private: + Unit* const i_funit; + }; + + class AnyAssistCreatureInRangeCheck + { + public: + AnyAssistCreatureInRangeCheck(Unit* funit, Unit* enemy, float range) + : i_funit(funit), i_enemy(enemy), i_range(range) + { + } + bool operator()(Creature* u) + { + if(u == i_funit) + return false; + + // we don't need help from zombies :) + if( !u->isAlive() ) + return false; + + // skip fighting creature + if( u->isInCombat() ) + return false; + + // only from same creature faction + if(u->getFaction() != i_funit->getFaction() ) + return false; + + // only free creature + if( u->GetCharmerOrOwnerGUID() ) + return false; + + // too far + if( !i_funit->IsWithinDistInMap(u, i_range) ) + return false; + + // skip non hostile to caster enemy creatures + if( !u->IsHostileTo(i_enemy) ) + return false; + + // only if see assisted creature + if(!u->IsWithinLOSInMap(i_funit) ) + return false; + + return true; + } + private: + Unit* const i_funit; + Unit* const i_enemy; + float i_range; + }; + + // Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature) + class NearestCreatureEntryWithLiveStateInObjectRangeCheck + { + public: + NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject const& obj,uint32 entry, bool alive, float range) + : i_obj(obj), i_entry(entry), i_alive(alive), i_range(range) {} + + bool operator()(Creature* u) + { + if(u->GetEntry() == i_entry && u->isAlive()==i_alive && i_obj.IsWithinDistInMap(u, i_range)) + { + i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check + return true; + } + return false; + } + float GetLastRange() const { return i_range; } + private: + WorldObject const& i_obj; + uint32 i_entry; + bool i_alive; + float i_range; + + // prevent clone this object + NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&); + }; + + class AnyPlayerInObjectRangeCheck + { + public: + AnyPlayerInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(Player* u) + { + if(u->isAlive() && i_obj->IsWithinDistInMap(u, i_range)) + return true; + + return false; + } + private: + WorldObject const* i_obj; + float i_range; + }; + + #ifndef WIN32 + template<> void PlayerRelocationNotifier::Visit(CreatureMapType &); + template<> void PlayerRelocationNotifier::Visit(PlayerMapType &); + template<> void CreatureRelocationNotifier::Visit(PlayerMapType &); + template<> void CreatureRelocationNotifier::Visit(CreatureMapType &); + template<> inline void DynamicObjectUpdater::Visit(CreatureMapType &); + template<> inline void DynamicObjectUpdater::Visit(PlayerMapType &); + #endif +} +#endif diff --git a/src/game/GuardAI.cpp b/src/game/GuardAI.cpp index fffbb7d4000..32598e8a3d3 100644 --- a/src/game/GuardAI.cpp +++ b/src/game/GuardAI.cpp @@ -1,150 +1,154 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "GuardAI.h" -#include "Errors.h" -#include "Creature.h" -#include "Player.h" -#include "ObjectAccessor.h" -#include "World.h" - -int GuardAI::Permissible(const Creature *creature) -{ - if( creature->isGuard()) - return PERMIT_BASE_SPECIAL; - - return PERMIT_BASE_NO; -} - -GuardAI::GuardAI(Creature &c) : i_creature(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK) -{ -} - -void GuardAI::MoveInLineOfSight(Unit *u) -{ - if( !i_creature.getVictim() && u->isTargetableForAttack() && - ( u->IsHostileToPlayers() || i_creature.IsHostileTo(u) /*|| u->getVictim() && i_creature.IsFriendlyTo(u->getVictim())*/ ) && - u->isInAccessablePlaceFor(&i_creature)) - { - float attackRadius = i_creature.GetAttackDistance(u); - if(i_creature.IsWithinDistInMap(u,attackRadius) && i_creature.GetDistanceZ(u) <= CREATURE_Z_ATTACK_RANGE) - { - //Need add code to let guard support player - AttackStart(u); - u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - } - } -} - -void GuardAI::EnterEvadeMode() -{ - if( !i_creature.isAlive() ) - { - DEBUG_LOG("Creature stopped attacking because he's dead [guid=%u]", i_creature.GetGUIDLow()); - i_creature.StopMoving(); - i_creature.GetMotionMaster()->MoveIdle(); - - i_state = STATE_NORMAL; - - i_victimGuid = 0; - i_creature.CombatStop(); - i_creature.DeleteThreatList(); - return; - } - - Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid ); - - if( !victim ) - { - DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow()); - } - else if( !victim ->isAlive() ) - { - DEBUG_LOG("Creature stopped attacking because victim is dead [guid=%u]", i_creature.GetGUIDLow()); - } - else if( victim ->HasStealthAura() ) - { - DEBUG_LOG("Creature stopped attacking because victim is using stealth [guid=%u]", i_creature.GetGUIDLow()); - } - else if( victim ->isInFlight() ) - { - DEBUG_LOG("Creature stopped attacking because victim is flying away [guid=%u]", i_creature.GetGUIDLow()); - } - else - { - DEBUG_LOG("Creature stopped attacking because victim outran him [guid=%u]", i_creature.GetGUIDLow()); - } - - i_creature.RemoveAllAuras(); - i_creature.DeleteThreatList(); - i_victimGuid = 0; - i_creature.CombatStop(); - i_state = STATE_NORMAL; - - // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead - if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE ) - i_creature.GetMotionMaster()->MoveTargetedHome(); -} - -void GuardAI::UpdateAI(const uint32 /*diff*/) -{ - // update i_victimGuid if i_creature.getVictim() !=0 and changed - if(!i_creature.SelectHostilTarget() || !i_creature.getVictim()) - return; - - i_victimGuid = i_creature.getVictim()->GetGUID(); - - if( i_creature.isAttackReady() ) - { - if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DISTANCE)) - { - i_creature.AttackerStateUpdate(i_creature.getVictim()); - i_creature.resetAttackTimer(); - } - } -} - -bool GuardAI::IsVisible(Unit *pl) const -{ - return i_creature.GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_GUARDER) - && pl->isVisibleForOrDetect(&i_creature,true); -} - -void GuardAI::AttackStart(Unit *u) -{ - if( !u ) - return; - - // DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", i_creature.GetName(), u->GetGUIDLow()); - if(i_creature.Attack(u,true)) - { - i_creature.SetInCombatWith(u); - u->SetInCombatWith(&i_creature); - - i_creature.AddThreat(u, 0.0f); - i_victimGuid = u->GetGUID(); - i_creature.GetMotionMaster()->MoveChase(u); - } -} - -void GuardAI::JustDied(Unit *killer) -{ - if(Player* pkiller = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) - i_creature.SendZoneUnderAttackMessage(pkiller); -} - +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "GuardAI.h" +#include "Errors.h" +#include "Creature.h" +#include "Player.h" +#include "ObjectAccessor.h" +#include "World.h" + +int GuardAI::Permissible(const Creature *creature) +{ + if( creature->isGuard()) + return PERMIT_BASE_SPECIAL; + + return PERMIT_BASE_NO; +} + +GuardAI::GuardAI(Creature &c) : i_creature(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK) +{ +} + +void GuardAI::MoveInLineOfSight(Unit *u) +{ + // Ignore Z for flying creatures + if ( !i_creature.canFly() && i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE ) + return; + + if( !i_creature.getVictim() && u->isTargetableForAttack() && + ( u->IsHostileToPlayers() || i_creature.IsHostileTo(u) /*|| u->getVictim() && i_creature.IsFriendlyTo(u->getVictim())*/ ) && + u->isInAccessablePlaceFor(&i_creature)) + { + float attackRadius = i_creature.GetAttackDistance(u); + if(i_creature.IsWithinDistInMap(u,attackRadius)) + { + //Need add code to let guard support player + AttackStart(u); + u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + } +} + +void GuardAI::EnterEvadeMode() +{ + if( !i_creature.isAlive() ) + { + DEBUG_LOG("Creature stopped attacking because he's dead [guid=%u]", i_creature.GetGUIDLow()); + i_creature.StopMoving(); + i_creature.GetMotionMaster()->MoveIdle(); + + i_state = STATE_NORMAL; + + i_victimGuid = 0; + i_creature.CombatStop(); + i_creature.DeleteThreatList(); + return; + } + + Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid ); + + if( !victim ) + { + DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow()); + } + else if( !victim ->isAlive() ) + { + DEBUG_LOG("Creature stopped attacking because victim is dead [guid=%u]", i_creature.GetGUIDLow()); + } + else if( victim ->HasStealthAura() ) + { + DEBUG_LOG("Creature stopped attacking because victim is using stealth [guid=%u]", i_creature.GetGUIDLow()); + } + else if( victim ->isInFlight() ) + { + DEBUG_LOG("Creature stopped attacking because victim is flying away [guid=%u]", i_creature.GetGUIDLow()); + } + else + { + DEBUG_LOG("Creature stopped attacking because victim outran him [guid=%u]", i_creature.GetGUIDLow()); + } + + i_creature.RemoveAllAuras(); + i_creature.DeleteThreatList(); + i_victimGuid = 0; + i_creature.CombatStop(); + i_state = STATE_NORMAL; + + // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead + if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE ) + i_creature.GetMotionMaster()->MoveTargetedHome(); +} + +void GuardAI::UpdateAI(const uint32 /*diff*/) +{ + // update i_victimGuid if i_creature.getVictim() !=0 and changed + if(!i_creature.SelectHostilTarget() || !i_creature.getVictim()) + return; + + i_victimGuid = i_creature.getVictim()->GetGUID(); + + if( i_creature.isAttackReady() ) + { + if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DISTANCE)) + { + i_creature.AttackerStateUpdate(i_creature.getVictim()); + i_creature.resetAttackTimer(); + } + } +} + +bool GuardAI::IsVisible(Unit *pl) const +{ + return i_creature.GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_GUARDER) + && pl->isVisibleForOrDetect(&i_creature,true); +} + +void GuardAI::AttackStart(Unit *u) +{ + if( !u ) + return; + + // DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", i_creature.GetName(), u->GetGUIDLow()); + if(i_creature.Attack(u,true)) + { + i_creature.SetInCombatWith(u); + u->SetInCombatWith(&i_creature); + + i_creature.AddThreat(u, 0.0f); + i_victimGuid = u->GetGUID(); + i_creature.GetMotionMaster()->MoveChase(u); + } +} + +void GuardAI::JustDied(Unit *killer) +{ + if(Player* pkiller = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) + i_creature.SendZoneUnderAttackMessage(pkiller); +} + diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp index bce616be394..07b9346312d 100644 --- a/src/game/Guild.cpp +++ b/src/game/Guild.cpp @@ -1,1940 +1,1963 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "MapManager.h" -#include "Player.h" -#include "Opcodes.h" -#include "ObjectMgr.h" -#include "Guild.h" -#include "Chat.h" -#include "SocialMgr.h" -#include "Util.h" - -Guild::Guild() -{ - Id = 0; - name = ""; - leaderGuid = 0; - GINFO = MOTD = ""; - EmblemStyle = 0; - EmblemColor = 0; - BorderStyle = 0; - BorderColor = 0; - BackgroundColor = 0; - - CreatedYear = 0; - CreatedMonth = 0; - CreatedDay = 0; -} - -Guild::~Guild() -{ - -} - -bool Guild::create(uint64 lGuid, std::string gname) -{ - std::string rname; - std::string lName; - - if(!objmgr.GetPlayerNameByGUID(lGuid, lName)) - return false; - if(objmgr.GetGuildByName(gname)) - return false; - - sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(lGuid)); - - leaderGuid = lGuid; - name = gname; - GINFO = ""; - MOTD = "No message set."; - guildbank_money = 0; - purchased_tabs = 0; - - QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guildid) FROM guild" ); - if( result ) - { - Id = (*result)[0].GetUInt32()+1; - delete result; - } - else Id = 1; - - // gname already assigned to Guild::name, use it to encode string for DB - CharacterDatabase.escape_string(gname); - - std::string dbGINFO = GINFO; - std::string dbMOTD = MOTD; - CharacterDatabase.escape_string(dbGINFO); - CharacterDatabase.escape_string(dbMOTD); - - CharacterDatabase.BeginTransaction(); - // CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid='%u'", Id); - MAX(guildid)+1 not exist - CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", Id); - CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid='%u'", Id); - CharacterDatabase.PExecute("INSERT INTO guild (guildid,name,leaderguid,info,motd,createdate,EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor,BankMoney) " - "VALUES('%u','%s','%u', '%s', '%s', NOW(),'%u','%u','%u','%u','%u','" I64FMTD "')", - Id, gname.c_str(), GUID_LOPART(leaderGuid), dbGINFO.c_str(), dbMOTD.c_str(), EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, guildbank_money); - CharacterDatabase.CommitTransaction(); - - rname = "Guild Master"; - CreateRank(rname,GR_RIGHT_ALL); - rname = "Officer"; - CreateRank(rname,GR_RIGHT_ALL); - rname = "Veteran"; - CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - rname = "Member"; - CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - rname = "Initiate"; - CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - - return AddMember(lGuid, (uint32)GR_GUILDMASTER); -} - -bool Guild::AddMember(uint64 plGuid, uint32 plRank) -{ - if(Player::GetGuildIdFromDB(plGuid) != 0) // player already in guild - return false; - - // remove all player signs from another petitions - // this will be prevent attempt joining player to many guilds and corrupt guild data integrity - Player::RemovePetitionsAndSigns(plGuid, 9); - - // fill player data - MemberSlot newmember; - - if(!FillPlayerData(plGuid, &newmember)) // problems with player data collection - return false; - - newmember.RankId = plRank; - newmember.OFFnote = (std::string)""; - newmember.Pnote = (std::string)""; - newmember.logout_time = time(NULL); - newmember.BankResetTimeMoney = 0; // this will force update at first query - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - newmember.BankResetTimeTab[i] = 0; - members[GUID_LOPART(plGuid)] = newmember; - - std::string dbPnote = newmember.Pnote; - std::string dbOFFnote = newmember.OFFnote; - CharacterDatabase.escape_string(dbPnote); - CharacterDatabase.escape_string(dbOFFnote); - - CharacterDatabase.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')", - Id, GUID_LOPART(plGuid), newmember.RankId, dbPnote.c_str(), dbOFFnote.c_str()); - - Player* pl = objmgr.GetPlayer(plGuid); - if(pl) - { - pl->SetInGuild(Id); - pl->SetRank(newmember.RankId); - pl->SetGuildIdInvited(0); - } - else - { - Player::SetUInt32ValueInDB(PLAYER_GUILDID, Id, plGuid); - Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, newmember.RankId, plGuid); - } - return true; -} - -void Guild::SetMOTD(std::string motd) -{ - MOTD = motd; - - // motd now can be used for encoding to DB - CharacterDatabase.escape_string(motd); - CharacterDatabase.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd.c_str(), Id); -} - -void Guild::SetGINFO(std::string ginfo) -{ - GINFO = ginfo; - - // ginfo now can be used for encoding to DB - CharacterDatabase.escape_string(ginfo); - CharacterDatabase.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo.c_str(), Id); -} - -bool Guild::LoadGuildFromDB(uint32 GuildId) -{ - if(!LoadRanksFromDB(GuildId)) - return false; - - if(!LoadMembersFromDB(GuildId)) - return false; - - QueryResult *result = CharacterDatabase.PQuery("SELECT MAX(TabId) FROM guild_bank_tab WHERE guildid='%u'", GuildId); - if(result) - { - Field *fields = result->Fetch(); - purchased_tabs = fields[0].GetUInt8()+1; // Because TabId begins at 0 - delete result; - } - else - purchased_tabs = 0; - - LoadBankRightsFromDB(GuildId); // Must be after LoadRanksFromDB because it populates rank struct - - // 0 1 2 3 4 5 6 - result = CharacterDatabase.PQuery("SELECT guildid, name, leaderguid, EmblemStyle, EmblemColor, BorderStyle, BorderColor," - // 7 8 9 10 11 - "BackgroundColor, info, motd, createdate, BankMoney FROM guild WHERE guildid = '%u'", GuildId); - - if(!result) - return false; - - Field *fields = result->Fetch(); - - Id = fields[0].GetUInt32(); - name = fields[1].GetCppString(); - leaderGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); - - EmblemStyle = fields[3].GetUInt32(); - EmblemColor = fields[4].GetUInt32(); - BorderStyle = fields[5].GetUInt32(); - BorderColor = fields[6].GetUInt32(); - BackgroundColor = fields[7].GetUInt32(); - GINFO = fields[8].GetCppString(); - MOTD = fields[9].GetCppString(); - uint64 time = fields[10].GetUInt64(); //datetime is uint64 type ... YYYYmmdd:hh:mm:ss - guildbank_money = fields[11].GetUInt64(); - - delete result; - - uint64 dTime = time /1000000; - CreatedDay = dTime%100; - CreatedMonth = (dTime/100)%100; - CreatedYear = (dTime/10000)%10000; - - // If the leader does not exist attempt to promote another member - if(!objmgr.GetPlayerAccountIdByGUID(leaderGuid )) - { - DelMember(leaderGuid); - - // check no members case (disbanded) - if(members.empty()) - return false; - } - - sLog.outDebug("Guild %u Creation time Loaded day: %u, month: %u, year: %u", GuildId, CreatedDay, CreatedMonth, CreatedYear); - m_bankloaded = false; - m_eventlogloaded = false; - m_onlinemembers = 0; - RenumBankLogs(); - RenumGuildEventlog(); - return true; -} - -bool Guild::LoadRanksFromDB(uint32 GuildId) -{ - Field *fields; - QueryResult *result = CharacterDatabase.PQuery("SELECT rname,rights,BankMoneyPerDay,rid FROM guild_rank WHERE guildid = '%u' ORDER BY rid ASC", GuildId); - - if(!result) - return false; - - bool broken_ranks = false; - - do - { - fields = result->Fetch(); - - std::string rankName = fields[0].GetCppString(); - uint32 rankRights = fields[1].GetUInt32(); - uint32 rankMoney = fields[2].GetUInt32(); - uint32 rankRID = fields[3].GetUInt32(); - - if(rankRID != m_ranks.size()+1) // guild_rank.rid always store rank+1 - broken_ranks = true; - - if(m_ranks.size()==GR_GUILDMASTER) // prevent loss leader rights - rankRights |= GR_RIGHT_ALL; - - AddRank(rankName,rankRights,rankMoney); - }while( result->NextRow() ); - delete result; - - if(m_ranks.size()==0) // empty rank table? - { - AddRank("Guild Master",GR_RIGHT_ALL,0); - broken_ranks = true; - } - - // guild_rank have wrong numbered ranks, repair - if(broken_ranks) - { - sLog.outError("Guild %u have broken `guild_rank` data, repairing...",GuildId); - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", GuildId); - for(size_t i =0; i < m_ranks.size(); ++i) - { - // guild_rank.rid always store rank+1 - std::string name = m_ranks[i].name; - uint32 rights = m_ranks[i].rights; - CharacterDatabase.escape_string(name); - CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, i+1, name.c_str(), rights); - } - CharacterDatabase.CommitTransaction(); - } - - return true; -} - -bool Guild::LoadMembersFromDB(uint32 GuildId) -{ - // 0 1 2 3 4 5 - QueryResult *result = CharacterDatabase.PQuery("SELECT guild_member.guid,rank, pnote, offnote, BankResetTimeMoney,BankRemMoney," - // 6 7 8 9 10 11 - "BankResetTimeTab0, BankRemSlotsTab0, BankResetTimeTab1, BankRemSlotsTab1, BankResetTimeTab2, BankRemSlotsTab2," - // 12 13 14 15 16 17 - "BankResetTimeTab3, BankRemSlotsTab3, BankResetTimeTab4, BankRemSlotsTab4, BankResetTimeTab5, BankRemSlotsTab5," - // 18 - "logout_time FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid WHERE guildid = '%u'", GuildId); - - if(!result) - return false; - - do - { - Field *fields = result->Fetch(); - MemberSlot newmember; - newmember.RankId = fields[1].GetUInt32(); - uint64 guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - - // Player does not exist - if(!FillPlayerData(guid, &newmember)) - continue; - - newmember.Pnote = fields[2].GetCppString(); - newmember.OFFnote = fields[3].GetCppString(); - newmember.BankResetTimeMoney = fields[4].GetUInt32(); - newmember.BankRemMoney = fields[5].GetUInt32(); - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - newmember.BankResetTimeTab[i] = fields[6+(2*i)].GetUInt32(); - newmember.BankRemSlotsTab[i] = fields[7+(2*i)].GetUInt32(); - } - newmember.logout_time = fields[18].GetUInt64(); - members[GUID_LOPART(guid)] = newmember; - - }while( result->NextRow() ); - delete result; - - if(members.empty()) - return false; - - return true; -} - -bool Guild::FillPlayerData(uint64 guid, MemberSlot* memslot) -{ - std::string plName; - uint32 plLevel; - uint32 plClass; - uint32 plZone; - - Player* pl = objmgr.GetPlayer(guid); - if(pl) - { - plName = pl->GetName(); - plLevel = pl->getLevel(); - plClass = pl->getClass(); - plZone = pl->GetZoneId(); - } - else - { - if(!objmgr.GetPlayerNameByGUID(guid, plName)) // player doesn't exist - return false; - - plLevel = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL, guid); - if(plLevel<1||plLevel>255) // can be at broken `data` field - { - sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`data`.",GUID_LOPART(guid)); - return false; - } - plZone = Player::GetZoneIdFromDB(guid); - - QueryResult *result = CharacterDatabase.PQuery("SELECT class FROM characters WHERE guid='%u'", GUID_LOPART(guid)); - if(!result) - return false; - plClass = (*result)[0].GetUInt32(); - if(plClass=MAX_CLASSES) // can be at broken `class` field - { - sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`.",GUID_LOPART(guid)); - return false; - } - - delete result; - } - - memslot->name = plName; - memslot->level = plLevel; - memslot->Class = plClass; - memslot->zoneId = plZone; - - return(true); -} - -void Guild::LoadPlayerStatsByGuid(uint64 guid) -{ - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if (itr == members.end() ) - return; - - Player *pl = ObjectAccessor::FindPlayer(guid); - if(!pl) - return; - itr->second.name = pl->GetName(); - itr->second.level = pl->getLevel(); - itr->second.Class = pl->getClass(); -} - -void Guild::SetLeader(uint64 guid) -{ - leaderGuid = guid; - this->ChangeRank(guid, GR_GUILDMASTER); - - CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid), Id); -} - -void Guild::DelMember(uint64 guid, bool isDisbanding) -{ - if(this->leaderGuid == guid && !isDisbanding) - { - std::ostringstream ss; - ss<<"SELECT guid FROM guild_member WHERE guildid='"<SetLeader(newLeaderGUID); - - newLeader = objmgr.GetPlayer(newLeaderGUID); - if(newLeader) - { - newLeader->SetRank(GR_GUILDMASTER); - newLeaderName = newLeader->GetName(); - } - else - { - Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, GR_GUILDMASTER, newLeaderGUID); - objmgr.GetPlayerNameByGUID(newLeaderGUID, newLeaderName); - } - - // when leader non-exist (at guild load with deleted leader only) not send broadcasts - if(objmgr.GetPlayerNameByGUID(guid, oldLeaderName)) - { - WorldPacket data(SMSG_GUILD_EVENT, (1+1+oldLeaderName.size()+1+newLeaderName.size()+1)); - data << (uint8)GE_LEADER_CHANGED; - data << (uint8)2; - data << oldLeaderName; - data << newLeaderName; - this->BroadcastPacket(&data); - - data.Initialize(SMSG_GUILD_EVENT, (1+1+oldLeaderName.size()+1)); - data << (uint8)GE_LEFT; - data << (uint8)1; - data << oldLeaderName; - this->BroadcastPacket(&data); - } - - sLog.outDebug( "WORLD: Sent (SMSG_GUILD_EVENT)" ); - } - else - { - this->Disband(); - return; - } - } - - members.erase(GUID_LOPART(guid)); - - Player *player = objmgr.GetPlayer(guid); - if(player) - { - player->SetInGuild(0); - player->SetRank(0); - } - else - { - Player::SetUInt32ValueInDB(PLAYER_GUILDID, 0, guid); - Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, GR_GUILDMASTER, guid); - } - - CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid)); -} - -void Guild::ChangeRank(uint64 guid, uint32 newRank) -{ - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if( itr != members.end() ) - itr->second.RankId = newRank; - - Player *player = objmgr.GetPlayer(guid); - if(player) - player->SetRank(newRank); - else - Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, newRank, guid); - - CharacterDatabase.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank, GUID_LOPART(guid) ); -} - -void Guild::SetPNOTE(uint64 guid,std::string pnote) -{ - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if( itr == members.end() ) - return; - - itr->second.Pnote = pnote; - - // pnote now can be used for encoding to DB - CharacterDatabase.escape_string(pnote); - CharacterDatabase.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote.c_str(), itr->first); -} - -void Guild::SetOFFNOTE(uint64 guid,std::string offnote) -{ - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if( itr == members.end() ) - return; - itr->second.OFFnote = offnote; - // offnote now can be used for encoding to DB - CharacterDatabase.escape_string(offnote); - CharacterDatabase.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote.c_str(), itr->first); -} - -void Guild::BroadcastToGuild(WorldSession *session, std::string msg, uint32 language) -{ - if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK)) - { - WorldPacket data; - ChatHandler(session).FillMessageData(&data, CHAT_MSG_GUILD, language, 0, msg.c_str()); - - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - { - Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - - if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_GCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()) ) - pl->GetSession()->SendPacket(&data); - } - } -} - -void Guild::BroadcastToOfficers(WorldSession *session, std::string msg, uint32 language) -{ - if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_OFFCHATSPEAK)) - { - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - { - WorldPacket data; - ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, NULL, 0, msg.c_str(),NULL); - - Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - - if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow())) - pl->GetSession()->SendPacket(&data); - } - } -} - -void Guild::BroadcastPacket(WorldPacket *packet) -{ - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - { - Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - if(player) - player->GetSession()->SendPacket(packet); - } -} - -void Guild::BroadcastPacketToRank(WorldPacket *packet, uint32 rankId) -{ - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - { - if (itr->second.RankId == rankId) - { - Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - if(player) - player->GetSession()->SendPacket(packet); - } - } -} - -void Guild::CreateRank(std::string name_,uint32 rights) -{ - if(m_ranks.size() >= GUILD_MAX_RANKS) - return; - - AddRank(name_,rights,0); - - for (int i = 0; i < purchased_tabs; ++i) - { - CreateBankRightForTab(m_ranks.size()-1, uint8(i)); - } - - // guild_rank.rid always store rank+1 value - - // name now can be used for encoding to DB - CharacterDatabase.escape_string(name_); - CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", Id, m_ranks.size(), name_.c_str(), rights ); -} - -void Guild::AddRank(std::string name_,uint32 rights, uint32 money) -{ - m_ranks.push_back(RankInfo(name_,rights,money)); -} - -void Guild::DelRank() -{ - if(m_ranks.empty()) - return; - - // guild_rank.rid always store rank+1 value - uint32 rank = m_ranks.size()-1; - CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE rid>='%u' AND guildid='%u'", (rank+1), Id); - - m_ranks.pop_back(); -} - -std::string Guild::GetRankName(uint32 rankId) -{ - if(rankId >= m_ranks.size()) - return ""; - - return m_ranks[rankId].name; -} - -uint32 Guild::GetRankRights(uint32 rankId) -{ - if(rankId >= m_ranks.size()) - return 0; - - return m_ranks[rankId].rights; -} - -void Guild::SetRankName(uint32 rankId, std::string name_) -{ - if(rankId >= m_ranks.size()) - return; - - m_ranks[rankId].name = name_; - - // name now can be used for encoding to DB - CharacterDatabase.escape_string(name_); - CharacterDatabase.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_.c_str(), (rankId+1), Id); -} - -void Guild::SetRankRights(uint32 rankId, uint32 rights) -{ - if(rankId >= m_ranks.size()) - return; - - m_ranks[rankId].rights = rights; - - CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, (rankId+1), Id); -} - -void Guild::Disband() -{ - WorldPacket data(SMSG_GUILD_EVENT, 1); - data << (uint8)GE_DISBANDED; - this->BroadcastPacket(&data); - - while (!members.empty()) - { - MemberList::iterator itr = members.begin(); - DelMember(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER), true); - } - - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid = '%u'",Id); - CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'",Id); - CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid = '%u'",Id); - CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u'",Id); - CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'",Id); - CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'",Id); - CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid = '%u'",Id); - CharacterDatabase.CommitTransaction(); - objmgr.RemoveGuild(this); -} - -void Guild::Roster(WorldSession *session) -{ - // we can only guess size - WorldPacket data(SMSG_GUILD_ROSTER, (4+MOTD.length()+1+GINFO.length()+1+4+m_ranks.size()*(4+4+GUILD_BANK_MAX_TABS*(4+4))+members.size()*50)); - data << (uint32)members.size(); - data << MOTD; - data << GINFO; - - data << (uint32)m_ranks.size(); - for (RankList::iterator ritr = m_ranks.begin(); ritr != m_ranks.end();++ritr) - { - data << (uint32)ritr->rights; - data << (uint32)ritr->BankMoneyPerDay; // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze. - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - data << (uint32)ritr->TabRight[i]; // for TAB_i rights: view tabs = 0x01, deposit items =0x02 - data << (uint32)ritr->TabSlotPerDay[i]; // for TAB_i count of: withdraw items(stack/day) - } - } - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - { - if (Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER))) - { - data << (uint64)pl->GetGUID(); - data << (uint8)1; - data << (std::string)pl->GetName(); - data << (uint32)itr->second.RankId; - data << (uint8)pl->getLevel(); - data << (uint8)pl->getClass(); - data << (uint8)0; // new 2.4.0 - data << (uint32)pl->GetZoneId(); - data << itr->second.Pnote; - data << itr->second.OFFnote; - } - else - { - data << uint64(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - data << (uint8)0; - data << itr->second.name; - data << (uint32)itr->second.RankId; - data << (uint8)itr->second.level; - data << (uint8)itr->second.Class; - data << (uint8)0; // new 2.4.0 - data << (uint32)itr->second.zoneId; - data << (float(time(NULL)-itr->second.logout_time) / DAY); - data << itr->second.Pnote; - data << itr->second.OFFnote; - } - } - session->SendPacket(&data);; - sLog.outDebug( "WORLD: Sent (SMSG_GUILD_ROSTER)" ); -} - -void Guild::Query(WorldSession *session) -{ - WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, (8*32+200));// we can only guess size - - data << Id; - data << name; - RankList::iterator itr; - for (size_t i = 0 ; i < 10; ++i) // show always 10 ranks - { - if(i < m_ranks.size()) - data << m_ranks[i].name; - else - data << (uint8)0; // null string - } - - data << uint32(EmblemStyle); - data << uint32(EmblemColor); - data << uint32(BorderStyle); - data << uint32(BorderColor); - data << uint32(BackgroundColor); - - session->SendPacket( &data ); - sLog.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" ); -} - -void Guild::SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor) -{ - this->EmblemStyle = emblemStyle; - this->EmblemColor = emblemColor; - this->BorderStyle = borderStyle; - this->BorderColor = borderColor; - this->BackgroundColor = backgroundColor; - - CharacterDatabase.PExecute("UPDATE guild SET EmblemStyle=%u, EmblemColor=%u, BorderStyle=%u, BorderColor=%u, BackgroundColor=%u WHERE guildid = %u", EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, Id); -} - -void Guild::UpdateLogoutTime(uint64 guid) -{ - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if (itr == members.end() ) - return; - - itr->second.logout_time = time(NULL); - - if (m_onlinemembers > 0) - --m_onlinemembers; - else - { - UnloadGuildBank(); - UnloadGuildEventlog(); - } -} - -// ************************************************* -// Guild Eventlog part -// ************************************************* -// Display guild eventlog -void Guild::DisplayGuildEventlog(WorldSession *session) -{ - // Load guild eventlog, if not already done - if (!m_eventlogloaded) - LoadGuildEventLogFromDB(); - - // Sending result - WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 0); - // count, max count == 100 - data << uint8(m_GuildEventlog.size()); - for (GuildEventlog::const_iterator itr = m_GuildEventlog.begin(); itr != m_GuildEventlog.end(); ++itr) - { - // Event type - data << uint8((*itr)->EventType); - // Player 1 - data << uint64((*itr)->PlayerGuid1); - // Player 2 not for left/join guild events - if( (*itr)->EventType != GUILD_EVENT_LOG_JOIN_GUILD && (*itr)->EventType != GUILD_EVENT_LOG_LEAVE_GUILD ) - data << uint64((*itr)->PlayerGuid2); - // New Rank - only for promote/demote guild events - if( (*itr)->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || (*itr)->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER ) - data << uint8((*itr)->NewRank); - // Event timestamp - data << uint32(time(NULL)-(*itr)->TimeStamp); - } - session->SendPacket(&data); - sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)"); -} - -// Load guild eventlog from DB -void Guild::LoadGuildEventLogFromDB() -{ - // Return if already loaded - if (m_eventlogloaded) - return; - - QueryResult *result = CharacterDatabase.PQuery("SELECT LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp FROM guild_eventlog WHERE guildid=%u ORDER BY LogGuid DESC LIMIT %u", Id, GUILD_EVENTLOG_MAX_ENTRIES); - if(!result) - return; - do - { - Field *fields = result->Fetch(); - GuildEventlogEntry *NewEvent = new GuildEventlogEntry; - // Fill entry - NewEvent->LogGuid = fields[0].GetUInt32(); - NewEvent->EventType = fields[1].GetUInt8(); - NewEvent->PlayerGuid1 = fields[2].GetUInt32(); - NewEvent->PlayerGuid2 = fields[3].GetUInt32(); - NewEvent->NewRank = fields[4].GetUInt8(); - NewEvent->TimeStamp = fields[5].GetUInt64(); - // Add entry to map - m_GuildEventlog.push_front(NewEvent); - - } while( result->NextRow() ); - delete result; - - // Check lists size in case to many event entries in db - // This cases can happen only if a crash occured somewhere and table has too many log entries - if (!m_GuildEventlog.empty()) - { - CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id, m_GuildEventlog.front()->LogGuid); - } - m_eventlogloaded = true; -} - -// Unload guild eventlog -void Guild::UnloadGuildEventlog() -{ - if (!m_eventlogloaded) - return; - GuildEventlogEntry *EventLogEntry; - if( !m_GuildEventlog.empty() ) - { - do - { - EventLogEntry = *(m_GuildEventlog.begin()); - m_GuildEventlog.pop_front(); - delete EventLogEntry; - }while( !m_GuildEventlog.empty() ); - } - m_eventlogloaded = false; -} - -// This will renum guids used at load to prevent always going up until infinit -void Guild::RenumGuildEventlog() -{ - QueryResult *result = CharacterDatabase.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_eventlog WHERE guildid = %u", Id); - if(!result) - return; - - Field *fields = result->Fetch(); - CharacterDatabase.PExecute("UPDATE guild_eventlog SET LogGuid=LogGuid-%u+1 WHERE guildid=%u ORDER BY LogGuid %s",fields[0].GetUInt32(), Id, fields[0].GetUInt32()?"ASC":"DESC"); - GuildEventlogMaxGuid = fields[1].GetUInt32()+1; - delete result; -} - -// Add entry to guild eventlog -void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank) -{ - GuildEventlogEntry *NewEvent = new GuildEventlogEntry; - // Fill entry - NewEvent->LogGuid = GuildEventlogMaxGuid++; - NewEvent->EventType = EventType; - NewEvent->PlayerGuid1 = PlayerGuid1; - NewEvent->PlayerGuid2 = PlayerGuid2; - NewEvent->NewRank = NewRank; - NewEvent->TimeStamp = uint32(time(NULL)); - // Check max entry limit and delete from db if needed - if (m_GuildEventlog.size() > GUILD_EVENTLOG_MAX_ENTRIES) - { - GuildEventlogEntry *OldEvent = *(m_GuildEventlog.begin()); - m_GuildEventlog.pop_front(); - CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); - delete OldEvent; - } - // Add entry to map - m_GuildEventlog.push_back(NewEvent); - // Add new eventlog entry into DB - CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" I64FMTD "')", - Id, NewEvent->LogGuid, uint32(NewEvent->EventType), NewEvent->PlayerGuid1, NewEvent->PlayerGuid2, uint32(NewEvent->NewRank), NewEvent->TimeStamp); -} - -// ************************************************* -// Guild Bank part -// ************************************************* -// Bank content related -void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId) -{ - WorldPacket data(SMSG_GUILD_BANK_LIST,1200); - - GuildBankTab const* tab = GetBankTab(TabId); - if (!tab) - return; - - if(!IsMemberHaveRights(session->GetPlayer()->GetGUIDLow(),TabId,GUILD_BANK_RIGHT_VIEW_TAB)) - return; - - data << uint64(GetGuildBankMoney()); - data << uint8(TabId); - // remaining slots for today - data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), TabId)); - data << uint8(0); // Tell client this is a tab content packet - - data << uint8(GUILD_BANK_MAX_SLOTS); - - for (int i=0; iSendPacket(&data); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); -} - -void Guild::DisplayGuildBankMoneyUpdate() -{ - WorldPacket data(SMSG_GUILD_BANK_LIST, 8+1+4+1+1); - - data << uint64(GetGuildBankMoney()); - data << uint8(0); - // remaining slots for today - - size_t rempos = data.wpos(); - data << uint32(0); // will be filled later - data << uint8(0); // Tell client this is a tab content packet - - data << uint8(0); // not send items - - BroadcastPacket(&data); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); -} - -void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2) -{ - GuildBankTab const* tab = GetBankTab(TabId); - if (!tab) - return; - - WorldPacket data(SMSG_GUILD_BANK_LIST,1200); - - data << uint64(GetGuildBankMoney()); - data << uint8(TabId); - // remaining slots for today - - size_t rempos = data.wpos(); - data << uint32(0); // will be filled later - data << uint8(0); // Tell client this is a tab content packet - - if(slot2==-1) // single item in slot1 - { - data << uint8(1); - - AppendDisplayGuildBankSlot(data, tab, slot1); - } - else // 2 items (in slot1 and slot2) - { - data << uint8(2); - - if(slot1 > slot2) - std::swap(slot1,slot2); - - AppendDisplayGuildBankSlot(data, tab, slot1); - AppendDisplayGuildBankSlot(data, tab, slot2); - } - - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - { - Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - if(!player) - continue; - - if(!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB)) - continue; - - data.put(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId))); - - player->GetSession()->SendPacket(&data); - } - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); -} - -void Guild::DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots) -{ - GuildBankTab const* tab = GetBankTab(TabId); - if (!tab) - return; - - WorldPacket data(SMSG_GUILD_BANK_LIST,1200); - - data << uint64(GetGuildBankMoney()); - data << uint8(TabId); - // remaining slots for today - - size_t rempos = data.wpos(); - data << uint32(0); // will be filled later - data << uint8(0); // Tell client this is a tab content packet - - data << uint8(slots.size()); // updates count - - for(GuildItemPosCountVec::const_iterator itr = slots.begin(); itr != slots.end(); ++itr) - AppendDisplayGuildBankSlot(data, tab, itr->slot); - - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - { - Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - if(!player) - continue; - - if(!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB)) - continue; - - data.put(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId))); - - player->GetSession()->SendPacket(&data); - } - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); -} - -Item* Guild::GetItem(uint8 TabId, uint8 SlotId) -{ - if (TabId >= m_TabListMap.size() || SlotId >= GUILD_BANK_MAX_SLOTS) - return NULL; - return m_TabListMap[TabId]->Slots[SlotId]; -} - -// ************************************************* -// Tab related - -void Guild::DisplayGuildBankTabsInfo(WorldSession *session) -{ - // Time to load bank if not already done - if (!m_bankloaded) - LoadGuildBankFromDB(); - - WorldPacket data(SMSG_GUILD_BANK_LIST, 500); - - data << uint64(GetGuildBankMoney()); - data << uint8(0); // TabInfo packet must be for TabId 0 - data << uint32(0xFFFFFFFF); // bit 9 must be set for this packet to work - data << uint8(1); // Tell Client this is a TabInfo packet - - data << uint8(purchased_tabs); // here is the number of tabs - - for(int i = 0; i < purchased_tabs; ++i) - { - data << m_TabListMap[i]->Name.c_str(); - data << m_TabListMap[i]->Icon.c_str(); - } - data << uint8(0); // Do not send tab content - session->SendPacket(&data); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); -} - -void Guild::CreateNewBankTab() -{ - if (purchased_tabs >= GUILD_BANK_MAX_TABS) - return; - - ++purchased_tabs; - - GuildBankTab* AnotherTab = new GuildBankTab; - memset(AnotherTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*)); - m_TabListMap.resize(purchased_tabs); - m_TabListMap[purchased_tabs-1] = AnotherTab; - - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", Id, uint32(purchased_tabs-1)); - CharacterDatabase.PExecute("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", Id, uint32(purchased_tabs-1)); - CharacterDatabase.CommitTransaction(); -} - -void Guild::SetGuildBankTabInfo(uint8 TabId, std::string Name, std::string Icon) -{ - if (TabId >= GUILD_BANK_MAX_TABS) - return; - if (TabId >= m_TabListMap.size()) - return; - - if (!m_TabListMap[TabId]) - return; - - if(m_TabListMap[TabId]->Name == Name && m_TabListMap[TabId]->Icon == Icon) - return; - - m_TabListMap[TabId]->Name = Name; - m_TabListMap[TabId]->Icon = Icon; - - CharacterDatabase.escape_string(Name); - CharacterDatabase.escape_string(Icon); - CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabName='%s',TabIcon='%s' WHERE guildid='%u' AND TabId='%u'", Name.c_str(), Icon.c_str(), Id, uint32(TabId)); -} - -void Guild::CreateBankRightForTab(uint32 rankId, uint8 TabId) -{ - sLog.outDebug("CreateBankRightForTab. rank: %u, TabId: %u", rankId, uint32(TabId)); - if (rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS) - return; - - m_ranks[rankId].TabRight[TabId]=0; - m_ranks[rankId].TabSlotPerDay[TabId]=0; - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u' AND TabId = '%u' AND rid = '%u'", Id, uint32(TabId), rankId); - CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", Id, uint32(TabId), rankId); - CharacterDatabase.CommitTransaction(); -} - -uint32 Guild::GetBankRights(uint32 rankId, uint8 TabId) const -{ - if(rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS) - return 0; - - return m_ranks[rankId].TabRight[TabId]; -} - -// ************************************************* -// Guild bank loading/unloading related - -// This load should be called when the bank is first accessed by a guild member -void Guild::LoadGuildBankFromDB() -{ - if (m_bankloaded) - return; - - m_bankloaded = true; - LoadGuildBankEventLogFromDB(); - - // 0 1 2 3 - QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", Id); - if(!result) - { - purchased_tabs = 0; - return; - } - - m_TabListMap.resize(purchased_tabs); - do - { - Field *fields = result->Fetch(); - uint8 TabId = fields[0].GetUInt8(); - - GuildBankTab *NewTab = new GuildBankTab; - memset(NewTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*)); - - NewTab->Name = fields[1].GetCppString(); - NewTab->Icon = fields[2].GetCppString(); - NewTab->Text = fields[3].GetCppString(); - - m_TabListMap[TabId] = NewTab; - }while( result->NextRow() ); - - delete result; - - // 0 1 2 3 - result = CharacterDatabase.PQuery("SELECT TabId, SlotId, item_guid, item_entry FROM guild_bank_item WHERE guildid='%u' ORDER BY TabId", Id); - if(!result) - return; - - do - { - Field *fields = result->Fetch(); - uint8 TabId = fields[0].GetUInt8(); - uint8 SlotId = fields[1].GetUInt8(); - uint32 ItemGuid = fields[2].GetUInt32(); - uint32 ItemEntry = fields[3].GetUInt32(); - - if (TabId >= purchased_tabs || TabId >= GUILD_BANK_MAX_TABS) - { - sLog.outError( "Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry); - continue; - } - - if (SlotId >= GUILD_BANK_MAX_SLOTS) - { - sLog.outError( "Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry); - continue; - } - - ItemPrototype const *proto = objmgr.GetItemPrototype(ItemEntry); - - if(!proto) - { - sLog.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry); - continue; - } - - Item *pItem = NewItemOrBag(proto); - if(!pItem->LoadFromDB(ItemGuid, 0)) - { - CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", Id, uint32(TabId), uint32(SlotId)); - sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid); - delete pItem; - continue; - } - - pItem->AddToWorld(); - m_TabListMap[TabId]->Slots[SlotId] = pItem; - }while( result->NextRow() ); - - delete result; -} - -// This unload should be called when the last member of the guild gets offline -void Guild::UnloadGuildBank() -{ - if (!m_bankloaded) - return; - for (uint8 i = 0 ; i < purchased_tabs ; ++i ) - { - for (uint8 j = 0 ; j < GUILD_BANK_MAX_SLOTS ; ++j) - { - if (m_TabListMap[i]->Slots[j]) - { - m_TabListMap[i]->Slots[j]->RemoveFromWorld(); - delete m_TabListMap[i]->Slots[j]; - } - } - delete m_TabListMap[i]; - } - m_TabListMap.clear(); - - UnloadGuildBankEventLog(); - m_bankloaded = false; -} - -// ************************************************* -// Money deposit/withdraw related - -void Guild::SendMoneyInfo(WorldSession *session, uint32 LowGuid) -{ - WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4); - data << uint32(GetMemberMoneyWithdrawRem(LowGuid)); - session->SendPacket(&data); - sLog.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN"); -} - -bool Guild::MemberMoneyWithdraw(uint32 amount, uint32 LowGuid) -{ - uint32 MoneyWithDrawRight = GetMemberMoneyWithdrawRem(LowGuid); - - if (MoneyWithDrawRight < amount || GetGuildBankMoney() < amount) - return false; - - SetBankMoney(GetGuildBankMoney()-amount); - - if (MoneyWithDrawRight < WITHDRAW_MONEY_UNLIMITED) - { - MemberList::iterator itr = members.find(LowGuid); - if (itr == members.end() ) - return false; - itr->second.BankRemMoney -= amount; - CharacterDatabase.PExecute("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'", - itr->second.BankRemMoney, Id, LowGuid); - } - return true; -} - -void Guild::SetBankMoney(int64 money) -{ - if (money < 0) // I don't know how this happens, it does!! - money = 0; - guildbank_money = money; - - CharacterDatabase.PExecute("UPDATE guild SET BankMoney='" I64FMTD "' WHERE guildid='%u'", money, Id); -} - -// ************************************************* -// Item per day and money per day related - -bool Guild::MemberItemWithdraw(uint8 TabId, uint32 LowGuid) -{ - uint32 SlotsWithDrawRight = GetMemberSlotWithdrawRem(LowGuid, TabId); - - if (SlotsWithDrawRight == 0) - return false; - - if (SlotsWithDrawRight < WITHDRAW_SLOT_UNLIMITED) - { - MemberList::iterator itr = members.find(LowGuid); - if (itr == members.end() ) - return false; - --itr->second.BankRemSlotsTab[TabId]; - CharacterDatabase.PExecute("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'", - uint32(TabId), itr->second.BankRemSlotsTab[TabId], Id, LowGuid); - } - return true; -} - -bool Guild::IsMemberHaveRights(uint32 LowGuid, uint8 TabId, uint32 rights) const -{ - MemberList::const_iterator itr = members.find(LowGuid); - if (itr == members.end() ) - return false; - - if (itr->second.RankId == GR_GUILDMASTER) - return true; - - return (GetBankRights(itr->second.RankId,TabId) & rights)==rights; -} - -uint32 Guild::GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId) -{ - MemberList::iterator itr = members.find(LowGuid); - if (itr == members.end() ) - return 0; - - if (itr->second.RankId == GR_GUILDMASTER) - return WITHDRAW_SLOT_UNLIMITED; - - if((GetBankRights(itr->second.RankId,TabId) & GUILD_BANK_RIGHT_VIEW_TAB)!=GUILD_BANK_RIGHT_VIEW_TAB) - return 0; - - uint32 curTime = uint32(time(NULL)/MINUTE); - if (curTime - itr->second.BankResetTimeTab[TabId] >= 24*HOUR/MINUTE) - { - itr->second.BankResetTimeTab[TabId] = curTime; - itr->second.BankRemSlotsTab[TabId] = GetBankSlotPerDay(itr->second.RankId, TabId); - CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u',BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'", - uint32(TabId), itr->second.BankResetTimeTab[TabId], uint32(TabId), itr->second.BankRemSlotsTab[TabId], Id, LowGuid); - } - return itr->second.BankRemSlotsTab[TabId]; -} - -uint32 Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid) -{ - MemberList::iterator itr = members.find(LowGuid); - if (itr == members.end() ) - return 0; - - if (itr->second.RankId == GR_GUILDMASTER) - return WITHDRAW_MONEY_UNLIMITED; - - uint32 curTime = uint32(time(NULL)/MINUTE); // minutes - // 24 hours - if (curTime > itr->second.BankResetTimeMoney + 24*HOUR/MINUTE) - { - itr->second.BankResetTimeMoney = curTime; - itr->second.BankRemMoney = GetBankMoneyPerDay(itr->second.RankId); - CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u',BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'", - itr->second.BankResetTimeMoney, itr->second.BankRemMoney, Id, LowGuid); - } - return itr->second.BankRemMoney; -} - -void Guild::SetBankMoneyPerDay(uint32 rankId, uint32 money) -{ - if (rankId >= m_ranks.size()) - return; - - if (rankId == GR_GUILDMASTER) - money = WITHDRAW_MONEY_UNLIMITED; - - m_ranks[rankId].BankMoneyPerDay = money; - - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - if (itr->second.RankId == rankId) - itr->second.BankResetTimeMoney = 0; - - CharacterDatabase.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money, (rankId+1), Id); - CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", Id, rankId); -} - -void Guild::SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 nbSlots, bool db) -{ - if(rankId >= m_ranks.size() || - TabId >= GUILD_BANK_MAX_TABS || - TabId >= purchased_tabs) - return; - - if (rankId == GR_GUILDMASTER) - { - nbSlots = WITHDRAW_SLOT_UNLIMITED; - right = GUILD_BANK_RIGHT_FULL; - } - - m_ranks[rankId].TabSlotPerDay[TabId]=nbSlots; - m_ranks[rankId].TabRight[TabId]=right; - - if (db) - { - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - if (itr->second.RankId == rankId) - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - itr->second.BankResetTimeTab[i] = 0; - - CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", Id, uint32(TabId), rankId); - CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES " - "('%u','%u','%u','%u','%u')", Id, uint32(TabId), rankId, m_ranks[rankId].TabRight[TabId], m_ranks[rankId].TabSlotPerDay[TabId]); - CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId), Id, rankId); - } -} - -uint32 Guild::GetBankMoneyPerDay(uint32 rankId) -{ - if(rankId >= m_ranks.size()) - return 0; - - if (rankId == GR_GUILDMASTER) - return WITHDRAW_MONEY_UNLIMITED; - return m_ranks[rankId].BankMoneyPerDay; -} - -uint32 Guild::GetBankSlotPerDay(uint32 rankId, uint8 TabId) -{ - if(rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS) - return 0; - - if (rankId == GR_GUILDMASTER) - return WITHDRAW_SLOT_UNLIMITED; - return m_ranks[rankId].TabSlotPerDay[TabId]; -} - -// ************************************************* -// Rights per day related - -void Guild::LoadBankRightsFromDB(uint32 GuildId) -{ - // 0 1 2 3 - QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, rid, gbright, SlotPerDay FROM guild_bank_right WHERE guildid = '%u' ORDER BY TabId", GuildId); - - if(!result) - return; - - do - { - Field *fields = result->Fetch(); - uint8 TabId = fields[0].GetUInt8(); - uint32 rankId = fields[1].GetUInt32(); - uint16 right = fields[2].GetUInt16(); - uint16 SlotPerDay = fields[3].GetUInt16(); - - SetBankRightsAndSlots(rankId, TabId, right, SlotPerDay, false); - - }while( result->NextRow() ); - delete result; - - return; -} - -// ************************************************* -// Bank log related - -void Guild::LoadGuildBankEventLogFromDB() -{ - // We can't add a limit as in Guild::LoadGuildEventLogFromDB since we fetch both money and bank log and know nothing about the composition - // 0 1 2 3 4 5 6 7 - QueryResult *result = CharacterDatabase.PQuery("SELECT LogGuid, LogEntry, TabId, PlayerGuid, ItemOrMoney, ItemStackCount, DestTabId, TimeStamp FROM guild_bank_eventlog WHERE guildid='%u' ORDER BY TimeStamp DESC", Id); - if(!result) - return; - - do - { - Field *fields = result->Fetch(); - GuildBankEvent *NewEvent = new GuildBankEvent; - - NewEvent->LogGuid = fields[0].GetUInt32(); - NewEvent->LogEntry = fields[1].GetUInt8(); - uint8 TabId = fields[2].GetUInt8(); - NewEvent->PlayerGuid = fields[3].GetUInt32(); - NewEvent->ItemOrMoney = fields[4].GetUInt32(); - NewEvent->ItemStackCount = fields[5].GetUInt8(); - NewEvent->DestTabId = fields[6].GetUInt8(); - NewEvent->TimeStamp = fields[7].GetUInt64(); - - if (TabId >= GUILD_BANK_MAX_TABS) - { - sLog.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId, GetName().c_str(), NewEvent->LogGuid); - delete NewEvent; - continue; - } - if (NewEvent->isMoneyEvent() && m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS - || m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS) - { - delete NewEvent; - continue; - } - if (NewEvent->isMoneyEvent()) - m_GuildBankEventLog_Money.push_front(NewEvent); - else - m_GuildBankEventLog_Item[TabId].push_front(NewEvent); - - }while( result->NextRow() ); - delete result; - - // Check lists size in case to many event entries in db for a tab or for money - // This cases can happen only if a crash occured somewhere and table has too many log entries - if (!m_GuildBankEventLog_Money.empty()) - { - CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u", - Id, m_GuildBankEventLog_Money.front()->LogGuid); - } - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - if (!m_GuildBankEventLog_Item[i].empty()) - { - CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u", - Id, m_GuildBankEventLog_Item[i].front()->LogGuid); - } - } -} - -void Guild::UnloadGuildBankEventLog() -{ - GuildBankEvent *EventLogEntry; - if( !m_GuildBankEventLog_Money.empty() ) - { - do - { - EventLogEntry = *(m_GuildBankEventLog_Money.begin()); - m_GuildBankEventLog_Money.pop_front(); - delete EventLogEntry; - }while( !m_GuildBankEventLog_Money.empty() ); - } - - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - if( !m_GuildBankEventLog_Item[i].empty() ) - { - do - { - EventLogEntry = *(m_GuildBankEventLog_Item[i].begin()); - m_GuildBankEventLog_Item[i].pop_front(); - delete EventLogEntry; - }while( !m_GuildBankEventLog_Item[i].empty() ); - } - } -} - -void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId) -{ - if (TabId > GUILD_BANK_MAX_TABS) - return; - - if (TabId == GUILD_BANK_MAX_TABS) - { - // Here we display money logs - WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Money.size()*(4*4+1)+1+1); - data << uint8(TabId); // Here GUILD_BANK_MAX_TABS - data << uint8(m_GuildBankEventLog_Money.size()); // number of log entries - for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr) - { - data << uint8((*itr)->LogEntry); - data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER)); - data << uint32((*itr)->ItemOrMoney); - data << uint32(time(NULL)-(*itr)->TimeStamp); - } - session->SendPacket(&data); - } - else - { - // here we display current tab logs - WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Item[TabId].size()*(4*4+1+1)+1+1); - data << uint8(TabId); // Here a real Tab Id - // number of log entries - data << uint8(m_GuildBankEventLog_Item[TabId].size()); - for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr) - { - data << uint8((*itr)->LogEntry); - data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER)); - data << uint32((*itr)->ItemOrMoney); - data << uint8((*itr)->ItemStackCount); - if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2) - data << uint8((*itr)->DestTabId); // moved tab - data << uint32(time(NULL)-(*itr)->TimeStamp); - } - session->SendPacket(&data); - } - sLog.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)"); -} - -void Guild::LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount, uint8 DestTabId) -{ - GuildBankEvent *NewEvent = new GuildBankEvent; - - NewEvent->LogGuid = LogMaxGuid++; - NewEvent->LogEntry = LogEntry; - NewEvent->PlayerGuid = PlayerGuidLow; - NewEvent->ItemOrMoney = ItemOrMoney; - NewEvent->ItemStackCount = ItemStackCount; - NewEvent->DestTabId = DestTabId; - NewEvent->TimeStamp = uint32(time(NULL)); - - if (NewEvent->isMoneyEvent()) - { - if (m_GuildBankEventLog_Money.size() > GUILD_BANK_MAX_LOGS) - { - GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Money.begin()); - m_GuildBankEventLog_Money.pop_front(); - CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); - delete OldEvent; - } - m_GuildBankEventLog_Money.push_back(NewEvent); - } - else - { - if (m_GuildBankEventLog_Item[TabId].size() > GUILD_BANK_MAX_LOGS) - { - GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Item[TabId].begin()); - m_GuildBankEventLog_Item[TabId].pop_front(); - CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); - delete OldEvent; - } - m_GuildBankEventLog_Item[TabId].push_back(NewEvent); - } - CharacterDatabase.PExecute("INSERT INTO guild_bank_eventlog (guildid,LogGuid,LogEntry,TabId,PlayerGuid,ItemOrMoney,ItemStackCount,DestTabId,TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','%u','%u','" I64FMTD "')", - Id, NewEvent->LogGuid, uint32(NewEvent->LogEntry), uint32(TabId), NewEvent->PlayerGuid, NewEvent->ItemOrMoney, uint32(NewEvent->ItemStackCount), uint32(NewEvent->DestTabId), NewEvent->TimeStamp); -} - -// This will renum guids used at load to prevent always going up until infinit -void Guild::RenumBankLogs() -{ - QueryResult *result = CharacterDatabase.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_bank_eventlog WHERE guildid = %u", Id); - if(!result) - return; - - Field *fields = result->Fetch(); - CharacterDatabase.PExecute("UPDATE guild_bank_eventlog SET LogGuid=LogGuid-%u+1 WHERE guildid=%u ORDER BY LogGuid %s",fields[0].GetUInt32(), Id, fields[0].GetUInt32()?"ASC":"DESC"); - LogMaxGuid = fields[1].GetUInt32()+1; - delete result; -} - -bool Guild::AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry ) -{ - CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId, BankTab, BankTabSlot); - CharacterDatabase.PExecute("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) " - "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId, BankTab, BankTabSlot, GUIDLow, Entry); - return true; -} - -void Guild::AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int slot ) -{ - Item *pItem = tab->Slots[slot]; - uint32 entry = pItem ? pItem->GetEntry() : 0; - - data << uint8(slot); - data << uint32(entry); - if (entry) - { - // random item property id +8 - data << (uint32) pItem->GetItemRandomPropertyId(); - if (pItem->GetItemRandomPropertyId()) - // SuffixFactor +4 - data << (uint32) pItem->GetItemSuffixFactor(); - // +12 // ITEM_FIELD_STACK_COUNT - data << uint8(pItem->GetCount()); - data << uint32(0); // +16 // Unknown value - data << uint8(0); // unknown 2.4.2 - if (uint32 Enchant0 = pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)) - { - data << uint8(1); // number of enchantments (max 3) why max 3? - data << uint8(PERM_ENCHANTMENT_SLOT); // enchantment slot (range: 0:2) - data << uint32(Enchant0); // enchantment id - } - else - data << uint8(0); // no enchantments (0) - } -} - -Item* Guild::StoreItem(uint8 tabId, GuildItemPosCountVec const& dest, Item* pItem ) -{ - if( !pItem ) - return NULL; - - Item* lastItem = pItem; - - for(GuildItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ) - { - uint8 slot = itr->slot; - uint32 count = itr->count; - - ++itr; - - if(itr == dest.end()) - { - lastItem = _StoreItem(tabId,slot,pItem,count,false); - break; - } - - lastItem = _StoreItem(tabId,slot,pItem,count,true); - } - - return lastItem; -} - -// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. -Item* Guild::_StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone ) -{ - if( !pItem ) - return NULL; - - sLog.outDebug( "GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count); - - Item* pItem2 = m_TabListMap[tab]->Slots[slot]; - - if( !pItem2 ) - { - if(clone) - pItem = pItem->CloneItem(count); - else - pItem->SetCount(count); - - if(!pItem) - return NULL; - - m_TabListMap[tab]->Slots[slot] = pItem; - - pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0); - pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); - AddGBankItemToDB(GetId(), tab, slot, pItem->GetGUIDLow(), pItem->GetEntry()); - pItem->FSetState(ITEM_NEW); - pItem->SaveToDB(); // not in onventory and can be save standalone - - return pItem; - } - else - { - pItem2->SetCount( pItem2->GetCount() + count ); - pItem2->FSetState(ITEM_CHANGED); - pItem2->SaveToDB(); // not in onventory and can be save standalone - - if(!clone) - { - pItem->RemoveFromWorld(); - pItem->DeleteFromDB(); - delete pItem; - } - - return pItem2; - } -} - -void Guild::RemoveItem(uint8 tab, uint8 slot ) -{ - m_TabListMap[tab]->Slots[slot] = NULL; - CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", - GetId(), uint32(tab), uint32(slot)); -} - -uint8 Guild::_CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32& count, bool swap, Item* pSrcItem ) const -{ - Item* pItem2 = m_TabListMap[tab]->Slots[slot]; - - // ignore move item (this slot will be empty at move) - if(pItem2==pSrcItem) - pItem2 = NULL; - - uint32 need_space; - - // empty specific slot - check item fit to slot - if( !pItem2 || swap ) - { - // non empty stack with space - need_space = pSrcItem->GetMaxStackCount(); - } - // non empty slot, check item type - else - { - // check item type - if(pItem2->GetEntry() != pSrcItem->GetEntry()) - return EQUIP_ERR_ITEM_CANT_STACK; - - // check free space - if(pItem2->GetCount() >= pSrcItem->GetMaxStackCount()) - return EQUIP_ERR_ITEM_CANT_STACK; - - need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount(); - } - - if(need_space > count) - need_space = count; - - dest.push_back(GuildItemPosCount(slot,need_space)); - count -= need_space; - return EQUIP_ERR_OK; -} - -uint8 Guild::_CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec &dest, uint32& count, bool merge, Item* pSrcItem, uint8 skip_slot ) const -{ - for(uint32 j = 0; j < GUILD_BANK_MAX_SLOTS; j++) - { - // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot - if(j==skip_slot) - continue; - - Item* pItem2 = m_TabListMap[tab]->Slots[j]; - - // ignore move item (this slot will be empty at move) - if(pItem2==pSrcItem) - pItem2 = NULL; - - // if merge skip empty, if !merge skip non-empty - if((pItem2!=NULL)!=merge) - continue; - - if( pItem2 ) - { - if(pItem2->GetEntry() == pSrcItem->GetEntry() && pItem2->GetCount() < pSrcItem->GetMaxStackCount() ) - { - uint32 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount(); - if(need_space > count) - need_space = count; - - dest.push_back(GuildItemPosCount(j,need_space)); - count -= need_space; - - if(count==0) - return EQUIP_ERR_OK; - } - } - else - { - uint32 need_space = pSrcItem->GetMaxStackCount(); - if(need_space > count) - need_space = count; - - dest.push_back(GuildItemPosCount(j,need_space)); - count -= need_space; - - if(count==0) - return EQUIP_ERR_OK; - } - } - return EQUIP_ERR_OK; -} - -uint8 Guild::CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32 count, Item *pItem, bool swap ) const -{ - sLog.outDebug( "GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count); - - if(count > pItem->GetCount()) - return EQUIP_ERR_COULDNT_SPLIT_ITEMS; - - if(pItem->IsSoulBound()) - return EQUIP_ERR_CANT_DROP_SOULBOUND; - - // in specific slot - if( slot != NULL_SLOT ) - { - uint8 res = _CanStoreItem_InSpecificSlot(tab,slot,dest,count,swap,pItem); - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - } - - // not specific slot or have spece for partly store only in specific slot - - // search stack in tab for merge to - if( pItem->GetMaxStackCount() > 1 ) - { - uint8 res = _CanStoreItem_InTab(tab,dest,count,true,pItem,slot); - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - } - - // search free slot in bag for place to - uint8 res = _CanStoreItem_InTab(tab,dest,count,false,pItem,slot); - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - - return EQUIP_ERR_BANK_FULL; -} - -void Guild::SetGuildBankTabText(uint8 TabId, std::string text) -{ - if (TabId >= GUILD_BANK_MAX_TABS) - return; - if (TabId >= m_TabListMap.size()) - return; - if (!m_TabListMap[TabId]) - return; - - if(m_TabListMap[TabId]->Text==text) - return; - - utf8truncate(text,500); // DB and client size limitation - - m_TabListMap[TabId]->Text = text; - - CharacterDatabase.escape_string(text); - CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text.c_str(), Id, uint32(TabId)); -} - -void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId) -{ - if (TabId > GUILD_BANK_MAX_TABS) - return; - - GuildBankTab const *tab = GetBankTab(TabId); - if (!tab) - return; - - WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1); - data << uint8(TabId); - data << tab->Text; - session->SendPacket(&data); -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "MapManager.h" +#include "Player.h" +#include "Opcodes.h" +#include "ObjectMgr.h" +#include "Guild.h" +#include "Chat.h" +#include "SocialMgr.h" +#include "Util.h" + +Guild::Guild() +{ + Id = 0; + name = ""; + leaderGuid = 0; + GINFO = MOTD = ""; + EmblemStyle = 0; + EmblemColor = 0; + BorderStyle = 0; + BorderColor = 0; + BackgroundColor = 0; + + CreatedYear = 0; + CreatedMonth = 0; + CreatedDay = 0; +} + +Guild::~Guild() +{ + +} + +bool Guild::create(uint64 lGuid, std::string gname) +{ + std::string rname; + std::string lName; + + if(!objmgr.GetPlayerNameByGUID(lGuid, lName)) + return false; + if(objmgr.GetGuildByName(gname)) + return false; + + sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(lGuid)); + + leaderGuid = lGuid; + name = gname; + GINFO = ""; + MOTD = "No message set."; + guildbank_money = 0; + purchased_tabs = 0; + + QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guildid) FROM guild" ); + if( result ) + { + Id = (*result)[0].GetUInt32()+1; + delete result; + } + else Id = 1; + + // gname already assigned to Guild::name, use it to encode string for DB + CharacterDatabase.escape_string(gname); + + std::string dbGINFO = GINFO; + std::string dbMOTD = MOTD; + CharacterDatabase.escape_string(dbGINFO); + CharacterDatabase.escape_string(dbMOTD); + + CharacterDatabase.BeginTransaction(); + // CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid='%u'", Id); - MAX(guildid)+1 not exist + CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", Id); + CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid='%u'", Id); + CharacterDatabase.PExecute("INSERT INTO guild (guildid,name,leaderguid,info,motd,createdate,EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor,BankMoney) " + "VALUES('%u','%s','%u', '%s', '%s', NOW(),'%u','%u','%u','%u','%u','" I64FMTD "')", + Id, gname.c_str(), GUID_LOPART(leaderGuid), dbGINFO.c_str(), dbMOTD.c_str(), EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, guildbank_money); + CharacterDatabase.CommitTransaction(); + + rname = "Guild Master"; + CreateRank(rname,GR_RIGHT_ALL); + rname = "Officer"; + CreateRank(rname,GR_RIGHT_ALL); + rname = "Veteran"; + CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + rname = "Member"; + CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + rname = "Initiate"; + CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + + return AddMember(lGuid, (uint32)GR_GUILDMASTER); +} + +bool Guild::AddMember(uint64 plGuid, uint32 plRank) +{ + if(Player::GetGuildIdFromDB(plGuid) != 0) // player already in guild + return false; + + // remove all player signs from another petitions + // this will be prevent attempt joining player to many guilds and corrupt guild data integrity + Player::RemovePetitionsAndSigns(plGuid, 9); + + // fill player data + MemberSlot newmember; + + if(!FillPlayerData(plGuid, &newmember)) // problems with player data collection + return false; + + newmember.RankId = plRank; + newmember.OFFnote = (std::string)""; + newmember.Pnote = (std::string)""; + newmember.logout_time = time(NULL); + newmember.BankResetTimeMoney = 0; // this will force update at first query + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + newmember.BankResetTimeTab[i] = 0; + members[GUID_LOPART(plGuid)] = newmember; + + std::string dbPnote = newmember.Pnote; + std::string dbOFFnote = newmember.OFFnote; + CharacterDatabase.escape_string(dbPnote); + CharacterDatabase.escape_string(dbOFFnote); + + CharacterDatabase.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')", + Id, GUID_LOPART(plGuid), newmember.RankId, dbPnote.c_str(), dbOFFnote.c_str()); + + Player* pl = objmgr.GetPlayer(plGuid); + if(pl) + { + pl->SetInGuild(Id); + pl->SetRank(newmember.RankId); + pl->SetGuildIdInvited(0); + } + else + { + Player::SetUInt32ValueInDB(PLAYER_GUILDID, Id, plGuid); + Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, newmember.RankId, plGuid); + } + return true; +} + +void Guild::SetMOTD(std::string motd) +{ + MOTD = motd; + + // motd now can be used for encoding to DB + CharacterDatabase.escape_string(motd); + CharacterDatabase.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd.c_str(), Id); +} + +void Guild::SetGINFO(std::string ginfo) +{ + GINFO = ginfo; + + // ginfo now can be used for encoding to DB + CharacterDatabase.escape_string(ginfo); + CharacterDatabase.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo.c_str(), Id); +} + +bool Guild::LoadGuildFromDB(uint32 GuildId) +{ + if(!LoadRanksFromDB(GuildId)) + return false; + + if(!LoadMembersFromDB(GuildId)) + return false; + + QueryResult *result = CharacterDatabase.PQuery("SELECT MAX(TabId) FROM guild_bank_tab WHERE guildid='%u'", GuildId); + if(result) + { + Field *fields = result->Fetch(); + purchased_tabs = fields[0].GetUInt8()+1; // Because TabId begins at 0 + delete result; + } + else + purchased_tabs = 0; + + LoadBankRightsFromDB(GuildId); // Must be after LoadRanksFromDB because it populates rank struct + + // 0 1 2 3 4 5 6 + result = CharacterDatabase.PQuery("SELECT guildid, name, leaderguid, EmblemStyle, EmblemColor, BorderStyle, BorderColor," + // 7 8 9 10 11 + "BackgroundColor, info, motd, createdate, BankMoney FROM guild WHERE guildid = '%u'", GuildId); + + if(!result) + return false; + + Field *fields = result->Fetch(); + + Id = fields[0].GetUInt32(); + name = fields[1].GetCppString(); + leaderGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); + + EmblemStyle = fields[3].GetUInt32(); + EmblemColor = fields[4].GetUInt32(); + BorderStyle = fields[5].GetUInt32(); + BorderColor = fields[6].GetUInt32(); + BackgroundColor = fields[7].GetUInt32(); + GINFO = fields[8].GetCppString(); + MOTD = fields[9].GetCppString(); + uint64 time = fields[10].GetUInt64(); //datetime is uint64 type ... YYYYmmdd:hh:mm:ss + guildbank_money = fields[11].GetUInt64(); + + delete result; + + uint64 dTime = time /1000000; + CreatedDay = dTime%100; + CreatedMonth = (dTime/100)%100; + CreatedYear = (dTime/10000)%10000; + + // If the leader does not exist attempt to promote another member + if(!objmgr.GetPlayerAccountIdByGUID(leaderGuid )) + { + DelMember(leaderGuid); + + // check no members case (disbanded) + if(members.empty()) + return false; + } + + sLog.outDebug("Guild %u Creation time Loaded day: %u, month: %u, year: %u", GuildId, CreatedDay, CreatedMonth, CreatedYear); + m_bankloaded = false; + m_eventlogloaded = false; + m_onlinemembers = 0; + RenumBankLogs(); + RenumGuildEventlog(); + return true; +} + +bool Guild::LoadRanksFromDB(uint32 GuildId) +{ + Field *fields; + QueryResult *result = CharacterDatabase.PQuery("SELECT rname,rights,BankMoneyPerDay,rid FROM guild_rank WHERE guildid = '%u' ORDER BY rid ASC", GuildId); + + if(!result) + return false; + + bool broken_ranks = false; + + do + { + fields = result->Fetch(); + + std::string rankName = fields[0].GetCppString(); + uint32 rankRights = fields[1].GetUInt32(); + uint32 rankMoney = fields[2].GetUInt32(); + uint32 rankRID = fields[3].GetUInt32(); + + if(rankRID != m_ranks.size()+1) // guild_rank.rid always store rank+1 + broken_ranks = true; + + if(m_ranks.size()==GR_GUILDMASTER) // prevent loss leader rights + rankRights |= GR_RIGHT_ALL; + + AddRank(rankName,rankRights,rankMoney); + }while( result->NextRow() ); + delete result; + + if(m_ranks.size()==0) // empty rank table? + { + AddRank("Guild Master",GR_RIGHT_ALL,0); + broken_ranks = true; + } + + // guild_rank have wrong numbered ranks, repair + if(broken_ranks) + { + sLog.outError("Guild %u have broken `guild_rank` data, repairing...",GuildId); + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", GuildId); + for(size_t i =0; i < m_ranks.size(); ++i) + { + // guild_rank.rid always store rank+1 + std::string name = m_ranks[i].name; + uint32 rights = m_ranks[i].rights; + CharacterDatabase.escape_string(name); + CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, i+1, name.c_str(), rights); + } + CharacterDatabase.CommitTransaction(); + } + + return true; +} + +bool Guild::LoadMembersFromDB(uint32 GuildId) +{ + // 0 1 2 3 4 5 + QueryResult *result = CharacterDatabase.PQuery("SELECT guild_member.guid,rank, pnote, offnote, BankResetTimeMoney,BankRemMoney," + // 6 7 8 9 10 11 + "BankResetTimeTab0, BankRemSlotsTab0, BankResetTimeTab1, BankRemSlotsTab1, BankResetTimeTab2, BankRemSlotsTab2," + // 12 13 14 15 16 17 + "BankResetTimeTab3, BankRemSlotsTab3, BankResetTimeTab4, BankRemSlotsTab4, BankResetTimeTab5, BankRemSlotsTab5," + // 18 + "logout_time FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid WHERE guildid = '%u'", GuildId); + + if(!result) + return false; + + do + { + Field *fields = result->Fetch(); + MemberSlot newmember; + newmember.RankId = fields[1].GetUInt32(); + uint64 guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + + // Player does not exist + if(!FillPlayerData(guid, &newmember)) + continue; + + newmember.Pnote = fields[2].GetCppString(); + newmember.OFFnote = fields[3].GetCppString(); + newmember.BankResetTimeMoney = fields[4].GetUInt32(); + newmember.BankRemMoney = fields[5].GetUInt32(); + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + newmember.BankResetTimeTab[i] = fields[6+(2*i)].GetUInt32(); + newmember.BankRemSlotsTab[i] = fields[7+(2*i)].GetUInt32(); + } + newmember.logout_time = fields[18].GetUInt64(); + members[GUID_LOPART(guid)] = newmember; + + }while( result->NextRow() ); + delete result; + + if(members.empty()) + return false; + + return true; +} + +bool Guild::FillPlayerData(uint64 guid, MemberSlot* memslot) +{ + std::string plName; + uint32 plLevel; + uint32 plClass; + uint32 plZone; + + Player* pl = objmgr.GetPlayer(guid); + if(pl) + { + plName = pl->GetName(); + plLevel = pl->getLevel(); + plClass = pl->getClass(); + plZone = pl->GetZoneId(); + } + else + { + if(!objmgr.GetPlayerNameByGUID(guid, plName)) // player doesn't exist + return false; + + plLevel = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL, guid); + if(plLevel<1||plLevel>255) // can be at broken `data` field + { + sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`data`.",GUID_LOPART(guid)); + return false; + } + plZone = Player::GetZoneIdFromDB(guid); + + QueryResult *result = CharacterDatabase.PQuery("SELECT class FROM characters WHERE guid='%u'", GUID_LOPART(guid)); + if(!result) + return false; + plClass = (*result)[0].GetUInt32(); + if(plClass=MAX_CLASSES) // can be at broken `class` field + { + sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`.",GUID_LOPART(guid)); + return false; + } + + delete result; + } + + memslot->name = plName; + memslot->level = plLevel; + memslot->Class = plClass; + memslot->zoneId = plZone; + + return(true); +} + +void Guild::LoadPlayerStatsByGuid(uint64 guid) +{ + MemberList::iterator itr = members.find(GUID_LOPART(guid)); + if (itr == members.end() ) + return; + + Player *pl = ObjectAccessor::FindPlayer(guid); + if(!pl) + return; + itr->second.name = pl->GetName(); + itr->second.level = pl->getLevel(); + itr->second.Class = pl->getClass(); +} + +void Guild::SetLeader(uint64 guid) +{ + leaderGuid = guid; + this->ChangeRank(guid, GR_GUILDMASTER); + + CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid), Id); +} + +void Guild::DelMember(uint64 guid, bool isDisbanding) +{ + if(this->leaderGuid == guid && !isDisbanding) + { + std::ostringstream ss; + ss<<"SELECT guid FROM guild_member WHERE guildid='"<SetLeader(newLeaderGUID); + + newLeader = objmgr.GetPlayer(newLeaderGUID); + if(newLeader) + { + newLeader->SetRank(GR_GUILDMASTER); + newLeaderName = newLeader->GetName(); + } + else + { + Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, GR_GUILDMASTER, newLeaderGUID); + objmgr.GetPlayerNameByGUID(newLeaderGUID, newLeaderName); + } + + // when leader non-exist (at guild load with deleted leader only) not send broadcasts + if(objmgr.GetPlayerNameByGUID(guid, oldLeaderName)) + { + WorldPacket data(SMSG_GUILD_EVENT, (1+1+oldLeaderName.size()+1+newLeaderName.size()+1)); + data << (uint8)GE_LEADER_CHANGED; + data << (uint8)2; + data << oldLeaderName; + data << newLeaderName; + this->BroadcastPacket(&data); + + data.Initialize(SMSG_GUILD_EVENT, (1+1+oldLeaderName.size()+1)); + data << (uint8)GE_LEFT; + data << (uint8)1; + data << oldLeaderName; + this->BroadcastPacket(&data); + } + + sLog.outDebug( "WORLD: Sent (SMSG_GUILD_EVENT)" ); + } + else + { + this->Disband(); + return; + } + } + + members.erase(GUID_LOPART(guid)); + + Player *player = objmgr.GetPlayer(guid); + if(player) + { + player->SetInGuild(0); + player->SetRank(0); + } + else + { + Player::SetUInt32ValueInDB(PLAYER_GUILDID, 0, guid); + Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, GR_GUILDMASTER, guid); + } + + CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid)); +} + +void Guild::ChangeRank(uint64 guid, uint32 newRank) +{ + MemberList::iterator itr = members.find(GUID_LOPART(guid)); + if( itr != members.end() ) + itr->second.RankId = newRank; + + Player *player = objmgr.GetPlayer(guid); + if(player) + player->SetRank(newRank); + else + Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, newRank, guid); + + CharacterDatabase.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank, GUID_LOPART(guid) ); +} + +void Guild::SetPNOTE(uint64 guid,std::string pnote) +{ + MemberList::iterator itr = members.find(GUID_LOPART(guid)); + if( itr == members.end() ) + return; + + itr->second.Pnote = pnote; + + // pnote now can be used for encoding to DB + CharacterDatabase.escape_string(pnote); + CharacterDatabase.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote.c_str(), itr->first); +} + +void Guild::SetOFFNOTE(uint64 guid,std::string offnote) +{ + MemberList::iterator itr = members.find(GUID_LOPART(guid)); + if( itr == members.end() ) + return; + itr->second.OFFnote = offnote; + // offnote now can be used for encoding to DB + CharacterDatabase.escape_string(offnote); + CharacterDatabase.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote.c_str(), itr->first); +} + +void Guild::BroadcastToGuild(WorldSession *session, std::string msg, uint32 language) +{ + if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK)) + { + WorldPacket data; + ChatHandler(session).FillMessageData(&data, CHAT_MSG_GUILD, language, 0, msg.c_str()); + + for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + { + Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + + if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_GCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()) ) + pl->GetSession()->SendPacket(&data); + } + } +} + +void Guild::BroadcastToOfficers(WorldSession *session, std::string msg, uint32 language) +{ + if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_OFFCHATSPEAK)) + { + for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + { + WorldPacket data; + ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, NULL, 0, msg.c_str(),NULL); + + Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + + if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow())) + pl->GetSession()->SendPacket(&data); + } + } +} + +void Guild::BroadcastPacket(WorldPacket *packet) +{ + for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + { + Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + if(player) + player->GetSession()->SendPacket(packet); + } +} + +void Guild::BroadcastPacketToRank(WorldPacket *packet, uint32 rankId) +{ + for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + { + if (itr->second.RankId == rankId) + { + Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + if(player) + player->GetSession()->SendPacket(packet); + } + } +} + +void Guild::CreateRank(std::string name_,uint32 rights) +{ + if(m_ranks.size() >= GUILD_MAX_RANKS) + return; + + AddRank(name_,rights,0); + + for (int i = 0; i < purchased_tabs; ++i) + { + CreateBankRightForTab(m_ranks.size()-1, uint8(i)); + } + + // guild_rank.rid always store rank+1 value + + // name now can be used for encoding to DB + CharacterDatabase.escape_string(name_); + CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", Id, m_ranks.size(), name_.c_str(), rights ); +} + +void Guild::AddRank(std::string name_,uint32 rights, uint32 money) +{ + m_ranks.push_back(RankInfo(name_,rights,money)); +} + +void Guild::DelRank() +{ + if(m_ranks.empty()) + return; + + // guild_rank.rid always store rank+1 value + uint32 rank = m_ranks.size()-1; + CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE rid>='%u' AND guildid='%u'", (rank+1), Id); + + m_ranks.pop_back(); +} + +std::string Guild::GetRankName(uint32 rankId) +{ + if(rankId >= m_ranks.size()) + return ""; + + return m_ranks[rankId].name; +} + +uint32 Guild::GetRankRights(uint32 rankId) +{ + if(rankId >= m_ranks.size()) + return 0; + + return m_ranks[rankId].rights; +} + +void Guild::SetRankName(uint32 rankId, std::string name_) +{ + if(rankId >= m_ranks.size()) + return; + + m_ranks[rankId].name = name_; + + // name now can be used for encoding to DB + CharacterDatabase.escape_string(name_); + CharacterDatabase.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_.c_str(), (rankId+1), Id); +} + +void Guild::SetRankRights(uint32 rankId, uint32 rights) +{ + if(rankId >= m_ranks.size()) + return; + + m_ranks[rankId].rights = rights; + + CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, (rankId+1), Id); +} + +void Guild::Disband() +{ + WorldPacket data(SMSG_GUILD_EVENT, 1); + data << (uint8)GE_DISBANDED; + this->BroadcastPacket(&data); + + while (!members.empty()) + { + MemberList::iterator itr = members.begin(); + DelMember(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER), true); + } + + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid = '%u'",Id); + CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'",Id); + CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid = '%u'",Id); + CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u'",Id); + CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'",Id); + CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'",Id); + CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid = '%u'",Id); + CharacterDatabase.CommitTransaction(); + objmgr.RemoveGuild(this); +} + +void Guild::Roster(WorldSession *session) +{ + // we can only guess size + WorldPacket data(SMSG_GUILD_ROSTER, (4+MOTD.length()+1+GINFO.length()+1+4+m_ranks.size()*(4+4+GUILD_BANK_MAX_TABS*(4+4))+members.size()*50)); + data << (uint32)members.size(); + data << MOTD; + data << GINFO; + + data << (uint32)m_ranks.size(); + for (RankList::iterator ritr = m_ranks.begin(); ritr != m_ranks.end();++ritr) + { + data << (uint32)ritr->rights; + data << (uint32)ritr->BankMoneyPerDay; // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze. + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + data << (uint32)ritr->TabRight[i]; // for TAB_i rights: view tabs = 0x01, deposit items =0x02 + data << (uint32)ritr->TabSlotPerDay[i]; // for TAB_i count of: withdraw items(stack/day) + } + } + for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + { + if (Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER))) + { + data << (uint64)pl->GetGUID(); + data << (uint8)1; + data << (std::string)pl->GetName(); + data << (uint32)itr->second.RankId; + data << (uint8)pl->getLevel(); + data << (uint8)pl->getClass(); + data << (uint8)0; // new 2.4.0 + data << (uint32)pl->GetZoneId(); + data << itr->second.Pnote; + data << itr->second.OFFnote; + } + else + { + data << uint64(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + data << (uint8)0; + data << itr->second.name; + data << (uint32)itr->second.RankId; + data << (uint8)itr->second.level; + data << (uint8)itr->second.Class; + data << (uint8)0; // new 2.4.0 + data << (uint32)itr->second.zoneId; + data << (float(time(NULL)-itr->second.logout_time) / DAY); + data << itr->second.Pnote; + data << itr->second.OFFnote; + } + } + session->SendPacket(&data);; + sLog.outDebug( "WORLD: Sent (SMSG_GUILD_ROSTER)" ); +} + +void Guild::Query(WorldSession *session) +{ + WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, (8*32+200));// we can only guess size + + data << Id; + data << name; + RankList::iterator itr; + for (size_t i = 0 ; i < 10; ++i) // show always 10 ranks + { + if(i < m_ranks.size()) + data << m_ranks[i].name; + else + data << (uint8)0; // null string + } + + data << uint32(EmblemStyle); + data << uint32(EmblemColor); + data << uint32(BorderStyle); + data << uint32(BorderColor); + data << uint32(BackgroundColor); + + session->SendPacket( &data ); + sLog.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" ); +} + +void Guild::SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor) +{ + this->EmblemStyle = emblemStyle; + this->EmblemColor = emblemColor; + this->BorderStyle = borderStyle; + this->BorderColor = borderColor; + this->BackgroundColor = backgroundColor; + + CharacterDatabase.PExecute("UPDATE guild SET EmblemStyle=%u, EmblemColor=%u, BorderStyle=%u, BorderColor=%u, BackgroundColor=%u WHERE guildid = %u", EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, Id); +} + +void Guild::UpdateLogoutTime(uint64 guid) +{ + MemberList::iterator itr = members.find(GUID_LOPART(guid)); + if (itr == members.end() ) + return; + + itr->second.logout_time = time(NULL); + + if (m_onlinemembers > 0) + --m_onlinemembers; + else + { + UnloadGuildBank(); + UnloadGuildEventlog(); + } +} + +// ************************************************* +// Guild Eventlog part +// ************************************************* +// Display guild eventlog +void Guild::DisplayGuildEventlog(WorldSession *session) +{ + // Load guild eventlog, if not already done + if (!m_eventlogloaded) + LoadGuildEventLogFromDB(); + + // Sending result + WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 0); + // count, max count == 100 + data << uint8(m_GuildEventlog.size()); + for (GuildEventlog::const_iterator itr = m_GuildEventlog.begin(); itr != m_GuildEventlog.end(); ++itr) + { + // Event type + data << uint8((*itr)->EventType); + // Player 1 + data << uint64((*itr)->PlayerGuid1); + // Player 2 not for left/join guild events + if( (*itr)->EventType != GUILD_EVENT_LOG_JOIN_GUILD && (*itr)->EventType != GUILD_EVENT_LOG_LEAVE_GUILD ) + data << uint64((*itr)->PlayerGuid2); + // New Rank - only for promote/demote guild events + if( (*itr)->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || (*itr)->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER ) + data << uint8((*itr)->NewRank); + // Event timestamp + data << uint32(time(NULL)-(*itr)->TimeStamp); + } + session->SendPacket(&data); + sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)"); +} + +// Load guild eventlog from DB +void Guild::LoadGuildEventLogFromDB() +{ + // Return if already loaded + if (m_eventlogloaded) + return; + + QueryResult *result = CharacterDatabase.PQuery("SELECT LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp FROM guild_eventlog WHERE guildid=%u ORDER BY LogGuid DESC LIMIT %u", Id, GUILD_EVENTLOG_MAX_ENTRIES); + if(!result) + return; + do + { + Field *fields = result->Fetch(); + GuildEventlogEntry *NewEvent = new GuildEventlogEntry; + // Fill entry + NewEvent->LogGuid = fields[0].GetUInt32(); + NewEvent->EventType = fields[1].GetUInt8(); + NewEvent->PlayerGuid1 = fields[2].GetUInt32(); + NewEvent->PlayerGuid2 = fields[3].GetUInt32(); + NewEvent->NewRank = fields[4].GetUInt8(); + NewEvent->TimeStamp = fields[5].GetUInt64(); + // Add entry to map + m_GuildEventlog.push_front(NewEvent); + + } while( result->NextRow() ); + delete result; + + // Check lists size in case to many event entries in db + // This cases can happen only if a crash occured somewhere and table has too many log entries + if (!m_GuildEventlog.empty()) + { + CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id, m_GuildEventlog.front()->LogGuid); + } + m_eventlogloaded = true; +} + +// Unload guild eventlog +void Guild::UnloadGuildEventlog() +{ + if (!m_eventlogloaded) + return; + GuildEventlogEntry *EventLogEntry; + if( !m_GuildEventlog.empty() ) + { + do + { + EventLogEntry = *(m_GuildEventlog.begin()); + m_GuildEventlog.pop_front(); + delete EventLogEntry; + }while( !m_GuildEventlog.empty() ); + } + m_eventlogloaded = false; +} + +// This will renum guids used at load to prevent always going up until infinit +void Guild::RenumGuildEventlog() +{ + QueryResult *result = CharacterDatabase.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_eventlog WHERE guildid = %u", Id); + if(!result) + return; + + Field *fields = result->Fetch(); + CharacterDatabase.PExecute("UPDATE guild_eventlog SET LogGuid=LogGuid-%u+1 WHERE guildid=%u ORDER BY LogGuid %s",fields[0].GetUInt32(), Id, fields[0].GetUInt32()?"ASC":"DESC"); + GuildEventlogMaxGuid = fields[1].GetUInt32()+1; + delete result; +} + +// Add entry to guild eventlog +void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank) +{ + GuildEventlogEntry *NewEvent = new GuildEventlogEntry; + // Fill entry + NewEvent->LogGuid = GuildEventlogMaxGuid++; + NewEvent->EventType = EventType; + NewEvent->PlayerGuid1 = PlayerGuid1; + NewEvent->PlayerGuid2 = PlayerGuid2; + NewEvent->NewRank = NewRank; + NewEvent->TimeStamp = uint32(time(NULL)); + // Check max entry limit and delete from db if needed + if (m_GuildEventlog.size() > GUILD_EVENTLOG_MAX_ENTRIES) + { + GuildEventlogEntry *OldEvent = *(m_GuildEventlog.begin()); + m_GuildEventlog.pop_front(); + CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); + delete OldEvent; + } + // Add entry to map + m_GuildEventlog.push_back(NewEvent); + // Add new eventlog entry into DB + CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" I64FMTD "')", + Id, NewEvent->LogGuid, uint32(NewEvent->EventType), NewEvent->PlayerGuid1, NewEvent->PlayerGuid2, uint32(NewEvent->NewRank), NewEvent->TimeStamp); +} + +// ************************************************* +// Guild Bank part +// ************************************************* +// Bank content related +void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId) +{ + WorldPacket data(SMSG_GUILD_BANK_LIST,1200); + + GuildBankTab const* tab = GetBankTab(TabId); + if (!tab) + return; + + if(!IsMemberHaveRights(session->GetPlayer()->GetGUIDLow(),TabId,GUILD_BANK_RIGHT_VIEW_TAB)) + return; + + data << uint64(GetGuildBankMoney()); + data << uint8(TabId); + // remaining slots for today + data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), TabId)); + data << uint8(0); // Tell client this is a tab content packet + + data << uint8(GUILD_BANK_MAX_SLOTS); + + for (int i=0; iSendPacket(&data); + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); +} + +void Guild::DisplayGuildBankMoneyUpdate() +{ + WorldPacket data(SMSG_GUILD_BANK_LIST, 8+1+4+1+1); + + data << uint64(GetGuildBankMoney()); + data << uint8(0); + // remaining slots for today + + size_t rempos = data.wpos(); + data << uint32(0); // will be filled later + data << uint8(0); // Tell client this is a tab content packet + + data << uint8(0); // not send items + + BroadcastPacket(&data); + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); +} + +void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2) +{ + GuildBankTab const* tab = GetBankTab(TabId); + if (!tab) + return; + + WorldPacket data(SMSG_GUILD_BANK_LIST,1200); + + data << uint64(GetGuildBankMoney()); + data << uint8(TabId); + // remaining slots for today + + size_t rempos = data.wpos(); + data << uint32(0); // will be filled later + data << uint8(0); // Tell client this is a tab content packet + + if(slot2==-1) // single item in slot1 + { + data << uint8(1); + + AppendDisplayGuildBankSlot(data, tab, slot1); + } + else // 2 items (in slot1 and slot2) + { + data << uint8(2); + + if(slot1 > slot2) + std::swap(slot1,slot2); + + AppendDisplayGuildBankSlot(data, tab, slot1); + AppendDisplayGuildBankSlot(data, tab, slot2); + } + + for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + { + Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + if(!player) + continue; + + if(!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB)) + continue; + + data.put(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId))); + + player->GetSession()->SendPacket(&data); + } + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); +} + +void Guild::DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots) +{ + GuildBankTab const* tab = GetBankTab(TabId); + if (!tab) + return; + + WorldPacket data(SMSG_GUILD_BANK_LIST,1200); + + data << uint64(GetGuildBankMoney()); + data << uint8(TabId); + // remaining slots for today + + size_t rempos = data.wpos(); + data << uint32(0); // will be filled later + data << uint8(0); // Tell client this is a tab content packet + + data << uint8(slots.size()); // updates count + + for(GuildItemPosCountVec::const_iterator itr = slots.begin(); itr != slots.end(); ++itr) + AppendDisplayGuildBankSlot(data, tab, itr->slot); + + for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + { + Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + if(!player) + continue; + + if(!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB)) + continue; + + data.put(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId))); + + player->GetSession()->SendPacket(&data); + } + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); +} + +Item* Guild::GetItem(uint8 TabId, uint8 SlotId) +{ + if (TabId >= m_TabListMap.size() || SlotId >= GUILD_BANK_MAX_SLOTS) + return NULL; + return m_TabListMap[TabId]->Slots[SlotId]; +} + +// ************************************************* +// Tab related + +void Guild::DisplayGuildBankTabsInfo(WorldSession *session) +{ + // Time to load bank if not already done + if (!m_bankloaded) + LoadGuildBankFromDB(); + + WorldPacket data(SMSG_GUILD_BANK_LIST, 500); + + data << uint64(GetGuildBankMoney()); + data << uint8(0); // TabInfo packet must be for TabId 0 + data << uint32(0xFFFFFFFF); // bit 9 must be set for this packet to work + data << uint8(1); // Tell Client this is a TabInfo packet + + data << uint8(purchased_tabs); // here is the number of tabs + + for(int i = 0; i < purchased_tabs; ++i) + { + data << m_TabListMap[i]->Name.c_str(); + data << m_TabListMap[i]->Icon.c_str(); + } + data << uint8(0); // Do not send tab content + session->SendPacket(&data); + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); +} + +void Guild::CreateNewBankTab() +{ + if (purchased_tabs >= GUILD_BANK_MAX_TABS) + return; + + ++purchased_tabs; + + GuildBankTab* AnotherTab = new GuildBankTab; + memset(AnotherTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*)); + m_TabListMap.resize(purchased_tabs); + m_TabListMap[purchased_tabs-1] = AnotherTab; + + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", Id, uint32(purchased_tabs-1)); + CharacterDatabase.PExecute("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", Id, uint32(purchased_tabs-1)); + CharacterDatabase.CommitTransaction(); +} + +void Guild::SetGuildBankTabInfo(uint8 TabId, std::string Name, std::string Icon) +{ + if (TabId >= GUILD_BANK_MAX_TABS) + return; + if (TabId >= m_TabListMap.size()) + return; + + if (!m_TabListMap[TabId]) + return; + + if(m_TabListMap[TabId]->Name == Name && m_TabListMap[TabId]->Icon == Icon) + return; + + m_TabListMap[TabId]->Name = Name; + m_TabListMap[TabId]->Icon = Icon; + + CharacterDatabase.escape_string(Name); + CharacterDatabase.escape_string(Icon); + CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabName='%s',TabIcon='%s' WHERE guildid='%u' AND TabId='%u'", Name.c_str(), Icon.c_str(), Id, uint32(TabId)); +} + +void Guild::CreateBankRightForTab(uint32 rankId, uint8 TabId) +{ + sLog.outDebug("CreateBankRightForTab. rank: %u, TabId: %u", rankId, uint32(TabId)); + if (rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS) + return; + + m_ranks[rankId].TabRight[TabId]=0; + m_ranks[rankId].TabSlotPerDay[TabId]=0; + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u' AND TabId = '%u' AND rid = '%u'", Id, uint32(TabId), rankId); + CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", Id, uint32(TabId), rankId); + CharacterDatabase.CommitTransaction(); +} + +uint32 Guild::GetBankRights(uint32 rankId, uint8 TabId) const +{ + if(rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS) + return 0; + + return m_ranks[rankId].TabRight[TabId]; +} + +// ************************************************* +// Guild bank loading/unloading related + +// This load should be called when the bank is first accessed by a guild member +void Guild::LoadGuildBankFromDB() +{ + if (m_bankloaded) + return; + + m_bankloaded = true; + LoadGuildBankEventLogFromDB(); + + // 0 1 2 3 + QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", Id); + if(!result) + { + purchased_tabs = 0; + return; + } + + m_TabListMap.resize(purchased_tabs); + do + { + Field *fields = result->Fetch(); + uint8 TabId = fields[0].GetUInt8(); + + GuildBankTab *NewTab = new GuildBankTab; + memset(NewTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*)); + + NewTab->Name = fields[1].GetCppString(); + NewTab->Icon = fields[2].GetCppString(); + NewTab->Text = fields[3].GetCppString(); + + m_TabListMap[TabId] = NewTab; + }while( result->NextRow() ); + + delete result; + + // 0 1 2 3 + result = CharacterDatabase.PQuery("SELECT TabId, SlotId, item_guid, item_entry FROM guild_bank_item WHERE guildid='%u' ORDER BY TabId", Id); + if(!result) + return; + + do + { + Field *fields = result->Fetch(); + uint8 TabId = fields[0].GetUInt8(); + uint8 SlotId = fields[1].GetUInt8(); + uint32 ItemGuid = fields[2].GetUInt32(); + uint32 ItemEntry = fields[3].GetUInt32(); + + if (TabId >= purchased_tabs || TabId >= GUILD_BANK_MAX_TABS) + { + sLog.outError( "Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry); + continue; + } + + if (SlotId >= GUILD_BANK_MAX_SLOTS) + { + sLog.outError( "Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry); + continue; + } + + ItemPrototype const *proto = objmgr.GetItemPrototype(ItemEntry); + + if(!proto) + { + sLog.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry); + continue; + } + + Item *pItem = NewItemOrBag(proto); + if(!pItem->LoadFromDB(ItemGuid, 0)) + { + CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", Id, uint32(TabId), uint32(SlotId)); + sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid); + delete pItem; + continue; + } + + pItem->AddToWorld(); + m_TabListMap[TabId]->Slots[SlotId] = pItem; + }while( result->NextRow() ); + + delete result; +} + +// This unload should be called when the last member of the guild gets offline +void Guild::UnloadGuildBank() +{ + if (!m_bankloaded) + return; + for (uint8 i = 0 ; i < purchased_tabs ; ++i ) + { + for (uint8 j = 0 ; j < GUILD_BANK_MAX_SLOTS ; ++j) + { + if (m_TabListMap[i]->Slots[j]) + { + m_TabListMap[i]->Slots[j]->RemoveFromWorld(); + delete m_TabListMap[i]->Slots[j]; + } + } + delete m_TabListMap[i]; + } + m_TabListMap.clear(); + + UnloadGuildBankEventLog(); + m_bankloaded = false; +} + +// ************************************************* +// Money deposit/withdraw related + +void Guild::SendMoneyInfo(WorldSession *session, uint32 LowGuid) +{ + WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4); + data << uint32(GetMemberMoneyWithdrawRem(LowGuid)); + session->SendPacket(&data); + sLog.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN"); +} + +bool Guild::MemberMoneyWithdraw(uint32 amount, uint32 LowGuid) +{ + uint32 MoneyWithDrawRight = GetMemberMoneyWithdrawRem(LowGuid); + + if (MoneyWithDrawRight < amount || GetGuildBankMoney() < amount) + return false; + + SetBankMoney(GetGuildBankMoney()-amount); + + if (MoneyWithDrawRight < WITHDRAW_MONEY_UNLIMITED) + { + MemberList::iterator itr = members.find(LowGuid); + if (itr == members.end() ) + return false; + itr->second.BankRemMoney -= amount; + CharacterDatabase.PExecute("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'", + itr->second.BankRemMoney, Id, LowGuid); + } + return true; +} + +void Guild::SetBankMoney(int64 money) +{ + if (money < 0) // I don't know how this happens, it does!! + money = 0; + guildbank_money = money; + + CharacterDatabase.PExecute("UPDATE guild SET BankMoney='" I64FMTD "' WHERE guildid='%u'", money, Id); +} + +// ************************************************* +// Item per day and money per day related + +bool Guild::MemberItemWithdraw(uint8 TabId, uint32 LowGuid) +{ + uint32 SlotsWithDrawRight = GetMemberSlotWithdrawRem(LowGuid, TabId); + + if (SlotsWithDrawRight == 0) + return false; + + if (SlotsWithDrawRight < WITHDRAW_SLOT_UNLIMITED) + { + MemberList::iterator itr = members.find(LowGuid); + if (itr == members.end() ) + return false; + --itr->second.BankRemSlotsTab[TabId]; + CharacterDatabase.PExecute("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'", + uint32(TabId), itr->second.BankRemSlotsTab[TabId], Id, LowGuid); + } + return true; +} + +bool Guild::IsMemberHaveRights(uint32 LowGuid, uint8 TabId, uint32 rights) const +{ + MemberList::const_iterator itr = members.find(LowGuid); + if (itr == members.end() ) + return false; + + if (itr->second.RankId == GR_GUILDMASTER) + return true; + + return (GetBankRights(itr->second.RankId,TabId) & rights)==rights; +} + +uint32 Guild::GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId) +{ + MemberList::iterator itr = members.find(LowGuid); + if (itr == members.end() ) + return 0; + + if (itr->second.RankId == GR_GUILDMASTER) + return WITHDRAW_SLOT_UNLIMITED; + + if((GetBankRights(itr->second.RankId,TabId) & GUILD_BANK_RIGHT_VIEW_TAB)!=GUILD_BANK_RIGHT_VIEW_TAB) + return 0; + + uint32 curTime = uint32(time(NULL)/MINUTE); + if (curTime - itr->second.BankResetTimeTab[TabId] >= 24*HOUR/MINUTE) + { + itr->second.BankResetTimeTab[TabId] = curTime; + itr->second.BankRemSlotsTab[TabId] = GetBankSlotPerDay(itr->second.RankId, TabId); + CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u',BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'", + uint32(TabId), itr->second.BankResetTimeTab[TabId], uint32(TabId), itr->second.BankRemSlotsTab[TabId], Id, LowGuid); + } + return itr->second.BankRemSlotsTab[TabId]; +} + +uint32 Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid) +{ + MemberList::iterator itr = members.find(LowGuid); + if (itr == members.end() ) + return 0; + + if (itr->second.RankId == GR_GUILDMASTER) + return WITHDRAW_MONEY_UNLIMITED; + + uint32 curTime = uint32(time(NULL)/MINUTE); // minutes + // 24 hours + if (curTime > itr->second.BankResetTimeMoney + 24*HOUR/MINUTE) + { + itr->second.BankResetTimeMoney = curTime; + itr->second.BankRemMoney = GetBankMoneyPerDay(itr->second.RankId); + CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u',BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'", + itr->second.BankResetTimeMoney, itr->second.BankRemMoney, Id, LowGuid); + } + return itr->second.BankRemMoney; +} + +void Guild::SetBankMoneyPerDay(uint32 rankId, uint32 money) +{ + if (rankId >= m_ranks.size()) + return; + + if (rankId == GR_GUILDMASTER) + money = WITHDRAW_MONEY_UNLIMITED; + + m_ranks[rankId].BankMoneyPerDay = money; + + for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + if (itr->second.RankId == rankId) + itr->second.BankResetTimeMoney = 0; + + CharacterDatabase.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money, (rankId+1), Id); + CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", Id, rankId); +} + +void Guild::SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 nbSlots, bool db) +{ + if(rankId >= m_ranks.size() || + TabId >= GUILD_BANK_MAX_TABS || + TabId >= purchased_tabs) + return; + + if (rankId == GR_GUILDMASTER) + { + nbSlots = WITHDRAW_SLOT_UNLIMITED; + right = GUILD_BANK_RIGHT_FULL; + } + + m_ranks[rankId].TabSlotPerDay[TabId]=nbSlots; + m_ranks[rankId].TabRight[TabId]=right; + + if (db) + { + for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + if (itr->second.RankId == rankId) + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + itr->second.BankResetTimeTab[i] = 0; + + CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", Id, uint32(TabId), rankId); + CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES " + "('%u','%u','%u','%u','%u')", Id, uint32(TabId), rankId, m_ranks[rankId].TabRight[TabId], m_ranks[rankId].TabSlotPerDay[TabId]); + CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId), Id, rankId); + } +} + +uint32 Guild::GetBankMoneyPerDay(uint32 rankId) +{ + if(rankId >= m_ranks.size()) + return 0; + + if (rankId == GR_GUILDMASTER) + return WITHDRAW_MONEY_UNLIMITED; + return m_ranks[rankId].BankMoneyPerDay; +} + +uint32 Guild::GetBankSlotPerDay(uint32 rankId, uint8 TabId) +{ + if(rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS) + return 0; + + if (rankId == GR_GUILDMASTER) + return WITHDRAW_SLOT_UNLIMITED; + return m_ranks[rankId].TabSlotPerDay[TabId]; +} + +// ************************************************* +// Rights per day related + +void Guild::LoadBankRightsFromDB(uint32 GuildId) +{ + // 0 1 2 3 + QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, rid, gbright, SlotPerDay FROM guild_bank_right WHERE guildid = '%u' ORDER BY TabId", GuildId); + + if(!result) + return; + + do + { + Field *fields = result->Fetch(); + uint8 TabId = fields[0].GetUInt8(); + uint32 rankId = fields[1].GetUInt32(); + uint16 right = fields[2].GetUInt16(); + uint16 SlotPerDay = fields[3].GetUInt16(); + + SetBankRightsAndSlots(rankId, TabId, right, SlotPerDay, false); + + }while( result->NextRow() ); + delete result; + + return; +} + +// ************************************************* +// Bank log related + +void Guild::LoadGuildBankEventLogFromDB() +{ + // We can't add a limit as in Guild::LoadGuildEventLogFromDB since we fetch both money and bank log and know nothing about the composition + // 0 1 2 3 4 5 6 7 + QueryResult *result = CharacterDatabase.PQuery("SELECT LogGuid, LogEntry, TabId, PlayerGuid, ItemOrMoney, ItemStackCount, DestTabId, TimeStamp FROM guild_bank_eventlog WHERE guildid='%u' ORDER BY TimeStamp DESC", Id); + if(!result) + return; + + do + { + Field *fields = result->Fetch(); + GuildBankEvent *NewEvent = new GuildBankEvent; + + NewEvent->LogGuid = fields[0].GetUInt32(); + NewEvent->LogEntry = fields[1].GetUInt8(); + uint8 TabId = fields[2].GetUInt8(); + NewEvent->PlayerGuid = fields[3].GetUInt32(); + NewEvent->ItemOrMoney = fields[4].GetUInt32(); + NewEvent->ItemStackCount = fields[5].GetUInt8(); + NewEvent->DestTabId = fields[6].GetUInt8(); + NewEvent->TimeStamp = fields[7].GetUInt64(); + + if (TabId >= GUILD_BANK_MAX_TABS) + { + sLog.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId, GetName().c_str(), NewEvent->LogGuid); + delete NewEvent; + continue; + } + if (NewEvent->isMoneyEvent() && m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS + || m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS) + { + delete NewEvent; + continue; + } + if (NewEvent->isMoneyEvent()) + m_GuildBankEventLog_Money.push_front(NewEvent); + else + m_GuildBankEventLog_Item[TabId].push_front(NewEvent); + + }while( result->NextRow() ); + delete result; + + // Check lists size in case to many event entries in db for a tab or for money + // This cases can happen only if a crash occured somewhere and table has too many log entries + if (!m_GuildBankEventLog_Money.empty()) + { + CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u", + Id, m_GuildBankEventLog_Money.front()->LogGuid); + } + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + if (!m_GuildBankEventLog_Item[i].empty()) + { + CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u", + Id, m_GuildBankEventLog_Item[i].front()->LogGuid); + } + } +} + +void Guild::UnloadGuildBankEventLog() +{ + GuildBankEvent *EventLogEntry; + if( !m_GuildBankEventLog_Money.empty() ) + { + do + { + EventLogEntry = *(m_GuildBankEventLog_Money.begin()); + m_GuildBankEventLog_Money.pop_front(); + delete EventLogEntry; + }while( !m_GuildBankEventLog_Money.empty() ); + } + + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + if( !m_GuildBankEventLog_Item[i].empty() ) + { + do + { + EventLogEntry = *(m_GuildBankEventLog_Item[i].begin()); + m_GuildBankEventLog_Item[i].pop_front(); + delete EventLogEntry; + }while( !m_GuildBankEventLog_Item[i].empty() ); + } + } +} + +void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId) +{ + if (TabId > GUILD_BANK_MAX_TABS) + return; + + if (TabId == GUILD_BANK_MAX_TABS) + { + // Here we display money logs + WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Money.size()*(4*4+1)+1+1); + data << uint8(TabId); // Here GUILD_BANK_MAX_TABS + data << uint8(m_GuildBankEventLog_Money.size()); // number of log entries + for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr) + { + data << uint8((*itr)->LogEntry); + data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER)); + data << uint32((*itr)->ItemOrMoney); + data << uint32(time(NULL)-(*itr)->TimeStamp); + } + session->SendPacket(&data); + } + else + { + // here we display current tab logs + WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Item[TabId].size()*(4*4+1+1)+1+1); + data << uint8(TabId); // Here a real Tab Id + // number of log entries + data << uint8(m_GuildBankEventLog_Item[TabId].size()); + for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr) + { + data << uint8((*itr)->LogEntry); + data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER)); + data << uint32((*itr)->ItemOrMoney); + data << uint8((*itr)->ItemStackCount); + if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2) + data << uint8((*itr)->DestTabId); // moved tab + data << uint32(time(NULL)-(*itr)->TimeStamp); + } + session->SendPacket(&data); + } + sLog.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)"); +} + +void Guild::LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount, uint8 DestTabId) +{ + GuildBankEvent *NewEvent = new GuildBankEvent; + + NewEvent->LogGuid = LogMaxGuid++; + NewEvent->LogEntry = LogEntry; + NewEvent->PlayerGuid = PlayerGuidLow; + NewEvent->ItemOrMoney = ItemOrMoney; + NewEvent->ItemStackCount = ItemStackCount; + NewEvent->DestTabId = DestTabId; + NewEvent->TimeStamp = uint32(time(NULL)); + + if (NewEvent->isMoneyEvent()) + { + if (m_GuildBankEventLog_Money.size() > GUILD_BANK_MAX_LOGS) + { + GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Money.begin()); + m_GuildBankEventLog_Money.pop_front(); + CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); + delete OldEvent; + } + m_GuildBankEventLog_Money.push_back(NewEvent); + } + else + { + if (m_GuildBankEventLog_Item[TabId].size() > GUILD_BANK_MAX_LOGS) + { + GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Item[TabId].begin()); + m_GuildBankEventLog_Item[TabId].pop_front(); + CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); + delete OldEvent; + } + m_GuildBankEventLog_Item[TabId].push_back(NewEvent); + } + CharacterDatabase.PExecute("INSERT INTO guild_bank_eventlog (guildid,LogGuid,LogEntry,TabId,PlayerGuid,ItemOrMoney,ItemStackCount,DestTabId,TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','%u','%u','" I64FMTD "')", + Id, NewEvent->LogGuid, uint32(NewEvent->LogEntry), uint32(TabId), NewEvent->PlayerGuid, NewEvent->ItemOrMoney, uint32(NewEvent->ItemStackCount), uint32(NewEvent->DestTabId), NewEvent->TimeStamp); +} + +// This will renum guids used at load to prevent always going up until infinit +void Guild::RenumBankLogs() +{ + QueryResult *result = CharacterDatabase.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_bank_eventlog WHERE guildid = %u", Id); + if(!result) + return; + + Field *fields = result->Fetch(); + CharacterDatabase.PExecute("UPDATE guild_bank_eventlog SET LogGuid=LogGuid-%u+1 WHERE guildid=%u ORDER BY LogGuid %s",fields[0].GetUInt32(), Id, fields[0].GetUInt32()?"ASC":"DESC"); + LogMaxGuid = fields[1].GetUInt32()+1; + delete result; +} + +bool Guild::AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry ) +{ + CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId, BankTab, BankTabSlot); + CharacterDatabase.PExecute("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) " + "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId, BankTab, BankTabSlot, GUIDLow, Entry); + return true; +} + +void Guild::AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int slot ) +{ + Item *pItem = tab->Slots[slot]; + uint32 entry = pItem ? pItem->GetEntry() : 0; + + data << uint8(slot); + data << uint32(entry); + if (entry) + { + // random item property id +8 + data << (uint32) pItem->GetItemRandomPropertyId(); + if (pItem->GetItemRandomPropertyId()) + // SuffixFactor +4 + data << (uint32) pItem->GetItemSuffixFactor(); + // +12 // ITEM_FIELD_STACK_COUNT + data << uint8(pItem->GetCount()); + data << uint32(0); // +16 // Unknown value + data << uint8(0); // unknown 2.4.2 + if (uint32 Enchant0 = pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)) + { + data << uint8(1); // number of enchantments (max 3) why max 3? + data << uint8(PERM_ENCHANTMENT_SLOT); // enchantment slot (range: 0:2) + data << uint32(Enchant0); // enchantment id + } + else + data << uint8(0); // no enchantments (0) + } +} + +Item* Guild::StoreItem(uint8 tabId, GuildItemPosCountVec const& dest, Item* pItem ) +{ + if( !pItem ) + return NULL; + + Item* lastItem = pItem; + + for(GuildItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ) + { + uint8 slot = itr->slot; + uint32 count = itr->count; + + ++itr; + + if(itr == dest.end()) + { + lastItem = _StoreItem(tabId,slot,pItem,count,false); + break; + } + + lastItem = _StoreItem(tabId,slot,pItem,count,true); + } + + return lastItem; +} + +// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. +Item* Guild::_StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone ) +{ + if( !pItem ) + return NULL; + + sLog.outDebug( "GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count); + + Item* pItem2 = m_TabListMap[tab]->Slots[slot]; + + if( !pItem2 ) + { + if(clone) + pItem = pItem->CloneItem(count); + else + pItem->SetCount(count); + + if(!pItem) + return NULL; + + m_TabListMap[tab]->Slots[slot] = pItem; + + pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0); + pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); + AddGBankItemToDB(GetId(), tab, slot, pItem->GetGUIDLow(), pItem->GetEntry()); + pItem->FSetState(ITEM_NEW); + pItem->SaveToDB(); // not in onventory and can be save standalone + + return pItem; + } + else + { + pItem2->SetCount( pItem2->GetCount() + count ); + pItem2->FSetState(ITEM_CHANGED); + pItem2->SaveToDB(); // not in onventory and can be save standalone + + if(!clone) + { + pItem->RemoveFromWorld(); + pItem->DeleteFromDB(); + delete pItem; + } + + return pItem2; + } +} + +void Guild::RemoveItem(uint8 tab, uint8 slot ) +{ + m_TabListMap[tab]->Slots[slot] = NULL; + CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", + GetId(), uint32(tab), uint32(slot)); +} + +uint8 Guild::_CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32& count, bool swap, Item* pSrcItem ) const +{ + Item* pItem2 = m_TabListMap[tab]->Slots[slot]; + + // ignore move item (this slot will be empty at move) + if(pItem2==pSrcItem) + pItem2 = NULL; + + uint32 need_space; + + // empty specific slot - check item fit to slot + if( !pItem2 || swap ) + { + // non empty stack with space + need_space = pSrcItem->GetMaxStackCount(); + } + // non empty slot, check item type + else + { + // check item type + if(pItem2->GetEntry() != pSrcItem->GetEntry()) + return EQUIP_ERR_ITEM_CANT_STACK; + + // check free space + if(pItem2->GetCount() >= pSrcItem->GetMaxStackCount()) + return EQUIP_ERR_ITEM_CANT_STACK; + + need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount(); + } + + if(need_space > count) + need_space = count; + + GuildItemPosCount newPosition = GuildItemPosCount(slot,need_space); + if(!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + } + + return EQUIP_ERR_OK; +} + +uint8 Guild::_CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec &dest, uint32& count, bool merge, Item* pSrcItem, uint8 skip_slot ) const +{ + for(uint32 j = 0; j < GUILD_BANK_MAX_SLOTS; j++) + { + // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot + if(j==skip_slot) + continue; + + Item* pItem2 = m_TabListMap[tab]->Slots[j]; + + // ignore move item (this slot will be empty at move) + if(pItem2==pSrcItem) + pItem2 = NULL; + + // if merge skip empty, if !merge skip non-empty + if((pItem2!=NULL)!=merge) + continue; + + if( pItem2 ) + { + if(pItem2->GetEntry() == pSrcItem->GetEntry() && pItem2->GetCount() < pSrcItem->GetMaxStackCount() ) + { + uint32 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount(); + if(need_space > count) + need_space = count; + + GuildItemPosCount newPosition = GuildItemPosCount(j,need_space); + if(!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + + if(count==0) + return EQUIP_ERR_OK; + } + } + } + else + { + uint32 need_space = pSrcItem->GetMaxStackCount(); + if(need_space > count) + need_space = count; + + GuildItemPosCount newPosition = GuildItemPosCount(j,need_space); + if(!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + + if(count==0) + return EQUIP_ERR_OK; + } + } + } + return EQUIP_ERR_OK; +} + +uint8 Guild::CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32 count, Item *pItem, bool swap ) const +{ + sLog.outDebug( "GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count); + + if(count > pItem->GetCount()) + return EQUIP_ERR_COULDNT_SPLIT_ITEMS; + + if(pItem->IsSoulBound()) + return EQUIP_ERR_CANT_DROP_SOULBOUND; + + // in specific slot + if( slot != NULL_SLOT ) + { + uint8 res = _CanStoreItem_InSpecificSlot(tab,slot,dest,count,swap,pItem); + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + } + + // not specific slot or have spece for partly store only in specific slot + + // search stack in tab for merge to + if( pItem->GetMaxStackCount() > 1 ) + { + uint8 res = _CanStoreItem_InTab(tab,dest,count,true,pItem,slot); + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + } + + // search free slot in bag for place to + uint8 res = _CanStoreItem_InTab(tab,dest,count,false,pItem,slot); + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + + return EQUIP_ERR_BANK_FULL; +} + +void Guild::SetGuildBankTabText(uint8 TabId, std::string text) +{ + if (TabId >= GUILD_BANK_MAX_TABS) + return; + if (TabId >= m_TabListMap.size()) + return; + if (!m_TabListMap[TabId]) + return; + + if(m_TabListMap[TabId]->Text==text) + return; + + utf8truncate(text,500); // DB and client size limitation + + m_TabListMap[TabId]->Text = text; + + CharacterDatabase.escape_string(text); + CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text.c_str(), Id, uint32(TabId)); +} + +void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId) +{ + if (TabId > GUILD_BANK_MAX_TABS) + return; + + GuildBankTab const *tab = GetBankTab(TabId); + if (!tab) + return; + + WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1); + data << uint8(TabId); + data << tab->Text; + session->SendPacket(&data); +} + +bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const +{ + for(GuildItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr) + if(itr->slot == this->slot) + return true; + + return false; +} + diff --git a/src/game/Guild.h b/src/game/Guild.h index 3f16d80987d..6ec58efb196 100644 --- a/src/game/Guild.h +++ b/src/game/Guild.h @@ -1,435 +1,437 @@ -/* - * Copyright (C) 2005-2008 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 MANGOSSERVER_GUILD_H -#define MANGOSSERVER_GUILD_H - -#define WITHDRAW_MONEY_UNLIMITED 0xFFFFFFFF -#define WITHDRAW_SLOT_UNLIMITED 0xFFFFFFFF - -#include "Item.h" - -class Item; - -enum GuildDefaultRanks -{ - GR_GUILDMASTER = 0, - GR_OFFICER = 1, - //GR_VETERAN = 2, -- not used anywhere and possible incorrect in modified rank list - //GR_MEMBER = 3, - //GR_INITIATE = 4, -- use Guild::GetLowestRank() instead for lowest rank -}; - -enum GuildRankRights -{ - GR_RIGHT_EMPTY = 0x00000040, - GR_RIGHT_GCHATLISTEN = 0x00000041, - GR_RIGHT_GCHATSPEAK = 0x00000042, - GR_RIGHT_OFFCHATLISTEN = 0x00000044, - GR_RIGHT_OFFCHATSPEAK = 0x00000048, - GR_RIGHT_PROMOTE = 0x000000C0, - GR_RIGHT_DEMOTE = 0x00000140, - GR_RIGHT_INVITE = 0x00000050, - GR_RIGHT_REMOVE = 0x00000060, - GR_RIGHT_SETMOTD = 0x00001040, - GR_RIGHT_EPNOTE = 0x00002040, - GR_RIGHT_VIEWOFFNOTE = 0x00004040, - GR_RIGHT_EOFFNOTE = 0x00008040, - GR_RIGHT_MODIFY_GUILD_INFO = 0x00010040, - GR_RIGHT_REPAIR_FROM_GUILD = 0x00020000, // unused in 2.4.x?, Remove money withdraw capacity - GR_RIGHT_WITHDRAW_REPAIR = 0x00040000, // withdraw for repair - GR_RIGHT_WITHDRAW_GOLD = 0x00080000, // withdraw gold - GR_RIGHT_ALL = 0x000FF1FF -}; - -enum Typecommand -{ - GUILD_CREATE_S = 0x00, - GUILD_INVITE_S = 0x01, - GUILD_QUIT_S = 0x03, - GUILD_FOUNDER_S = 0x0E, - GUILD_UNK1 = 0x10, - GUILD_BANK_S = 0x15, - GUILD_UNK3 = 0x16 -}; - -enum CommandErrors -{ - GUILD_PLAYER_NO_MORE_IN_GUILD = 0x00, - GUILD_INTERNAL = 0x01, - GUILD_ALREADY_IN_GUILD = 0x02, - ALREADY_IN_GUILD = 0x03, - INVITED_TO_GUILD = 0x04, - ALREADY_INVITED_TO_GUILD = 0x05, - GUILD_NAME_INVALID = 0x06, - GUILD_NAME_EXISTS = 0x07, - GUILD_LEADER_LEAVE = 0x08, - GUILD_PERMISSIONS = 0x08, - GUILD_PLAYER_NOT_IN_GUILD = 0x09, - GUILD_PLAYER_NOT_IN_GUILD_S = 0x0A, - GUILD_PLAYER_NOT_FOUND = 0x0B, - GUILD_NOT_ALLIED = 0x0C, - GUILD_RANK_TOO_HIGH_S = 0x0D, - GUILD_ALREADY_LOWEST_RANK_S = 0x0E, - GUILD_TEMP_ERROR = 0x11, - GUILD_RANK_IN_USE = 0x12, - GUILD_IGNORE = 0x13, - GUILD_ERR_UNK1 = 0x17, - GUILD_WITHDRAW_TOO_MUCH = 0x18, - GUILD_BANK_NO_MONEY = 0x19, - GUILD_BANK_TAB_IS_FULL = 0x1B, - GUILD_BANK_ITEM_NOT_FOUND = 0x1C -}; - -enum GuildEvents -{ - GE_PROMOTION = 0x00, - GE_DEMOTION = 0x01, - GE_MOTD = 0x02, - GE_JOINED = 0x03, - GE_LEFT = 0x04, - GE_REMOVED = 0x05, - GE_LEADER_IS = 0x06, - GE_LEADER_CHANGED = 0x07, - GE_DISBANDED = 0x08, - GE_TABARDCHANGE = 0x09, - GE_UNK1 = 0x0A, // string, string - GE_UNK2 = 0x0B, - GE_SIGNED_ON = 0x0C, - GE_SIGNED_OFF = 0x0D, - GE_UNK3 = 0x0E, - GE_BANKTAB_PURCHASED= 0x0F, - GE_UNK5 = 0x10, - GE_UNK6 = 0x11, // string 0000000000002710 is 1 gold - GE_UNK7 = 0x12 -}; - -enum PetitionTurns -{ - PETITION_TURN_OK = 0, - PETITION_TURN_ALREADY_IN_GUILD = 2, - PETITION_TURN_NEED_MORE_SIGNATURES = 4, -}; - -enum PetitionSigns -{ - PETITION_SIGN_OK = 0, - PETITION_SIGN_ALREADY_SIGNED = 1, - PETITION_SIGN_ALREADY_IN_GUILD = 2, - PETITION_SIGN_CANT_SIGN_OWN = 3, - PETITION_SIGN_NOT_SERVER = 4, -}; - -enum GuildBankRights -{ - GUILD_BANK_RIGHT_VIEW_TAB = 0x01, - GUILD_BANK_RIGHT_PUT_ITEM = 0x02, - GUILD_BANK_RIGHT_UPDATE_TEXT = 0x04, - - GUILD_BANK_RIGHT_DEPOSIT_ITEM = GUILD_BANK_RIGHT_VIEW_TAB | GUILD_BANK_RIGHT_PUT_ITEM, - GUILD_BANK_RIGHT_FULL = 0xFF, -}; - -enum GuildBankLogEntries -{ - GUILD_BANK_LOG_DEPOSIT_ITEM = 1, - GUILD_BANK_LOG_WITHDRAW_ITEM = 2, - GUILD_BANK_LOG_MOVE_ITEM = 3, - GUILD_BANK_LOG_DEPOSIT_MONEY = 4, - GUILD_BANK_LOG_WITHDRAW_MONEY = 5, - GUILD_BANK_LOG_REPAIR_MONEY = 6, - GUILD_BANK_LOG_MOVE_ITEM2 = 7, -}; - -enum GuildEventLogEntryTypes -{ - GUILD_EVENT_LOG_INVITE_PLAYER = 1, - GUILD_EVENT_LOG_JOIN_GUILD = 2, - GUILD_EVENT_LOG_PROMOTE_PLAYER = 3, - GUILD_EVENT_LOG_DEMOTE_PLAYER = 4, - GUILD_EVENT_LOG_UNINVITE_PLAYER = 5, - GUILD_EVENT_LOG_LEAVE_GUILD = 6, -}; - -struct GuildEventlogEntry -{ - uint32 LogGuid; - uint8 EventType; - uint32 PlayerGuid1; - uint32 PlayerGuid2; - uint8 NewRank; - uint64 TimeStamp; -}; - -enum GuildEmblem -{ - ERR_GUILDEMBLEM_SUCCESS = 0, - ERR_GUILDEMBLEM_INVALID_TABARD_COLORS = 1, - ERR_GUILDEMBLEM_NOGUILD = 2, - ERR_GUILDEMBLEM_NOTGUILDMASTER = 3, - ERR_GUILDEMBLEM_NOTENOUGHMONEY = 4, - ERR_GUILDEMBLEM_INVALIDVENDOR = 5 -}; - -struct GuildBankEvent -{ - uint32 LogGuid; - uint8 LogEntry; - uint8 TabId; - uint32 PlayerGuid; - uint32 ItemOrMoney; - uint8 ItemStackCount; - uint8 DestTabId; - uint64 TimeStamp; - - const bool isMoneyEvent() - { - return LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY || - LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY || - LogEntry == GUILD_BANK_LOG_REPAIR_MONEY; - } -}; - -struct GuildBankTab -{ - Item* Slots[GUILD_BANK_MAX_SLOTS]; - std::string Name; - std::string Icon; - std::string Text; -}; - -struct GuildItemPosCount -{ - GuildItemPosCount(uint8 _slot, uint8 _count) : slot(_slot), count(_count) {} - - uint8 slot; - uint8 count; -}; -typedef std::vector GuildItemPosCountVec; - -struct MemberSlot -{ - uint64 logout_time; - std::string name; - std::string Pnote; - std::string OFFnote; - uint32 RankId; - uint32 zoneId; - uint8 level; - uint8 Class; - uint32 BankResetTimeMoney; - uint32 BankRemMoney; - uint32 BankResetTimeTab[GUILD_BANK_MAX_TABS]; - uint32 BankRemSlotsTab[GUILD_BANK_MAX_TABS]; -}; - -struct RankInfo -{ - RankInfo(std::string _name, uint32 _rights, uint32 _money) : name(_name), rights(_rights), BankMoneyPerDay(_money) - { - for(uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - TabRight[i] = 0; - TabSlotPerDay[i] = 0; - } - } - - std::string name; - uint32 rights; - uint32 BankMoneyPerDay; - uint32 TabRight[GUILD_BANK_MAX_TABS]; - uint32 TabSlotPerDay[GUILD_BANK_MAX_TABS]; -}; - -class Guild -{ - public: - Guild(); - ~Guild(); - - bool create(uint64 lGuid, std::string gname); - void Disband(); - - typedef std::map MemberList; - typedef std::vector RankList; - - uint32 GetId(){ return Id; } - const uint64& GetLeader(){ return leaderGuid; } - std::string GetName(){ return name; } - std::string GetMOTD(){ return MOTD; } - std::string GetGINFO(){ return GINFO; } - - uint32 GetCreatedYear(){ return CreatedYear; } - uint32 GetCreatedMonth(){ return CreatedMonth; } - uint32 GetCreatedDay(){ return CreatedDay; } - - uint32 GetEmblemStyle(){ return EmblemStyle; } - uint32 GetEmblemColor(){ return EmblemColor; } - uint32 GetBorderStyle(){ return BorderStyle; } - uint32 GetBorderColor(){ return BorderColor; } - uint32 GetBackgroundColor(){ return BackgroundColor; } - - void SetLeader(uint64 guid); - bool AddMember(uint64 plGuid, uint32 plRank); - void ChangeRank(uint64 guid, uint32 newRank); - void DelMember(uint64 guid, bool isDisbanding=false); - uint32 GetLowestRank() const { return GetNrRanks()-1; } - - void SetMOTD(std::string motd); - void SetGINFO(std::string ginfo); - void SetPNOTE(uint64 guid,std::string pnote); - void SetOFFNOTE(uint64 guid,std::string offnote); - void SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor); - - uint32 GetMemberSize() const { return members.size(); } - - bool LoadGuildFromDB(uint32 GuildId); - bool LoadRanksFromDB(uint32 GuildId); - bool LoadMembersFromDB(uint32 GuildId); - - bool FillPlayerData(uint64 guid, MemberSlot* memslot); - void LoadPlayerStatsByGuid(uint64 guid); - - void BroadcastToGuild(WorldSession *session, std::string msg, uint32 language = LANG_UNIVERSAL); - void BroadcastToOfficers(WorldSession *session, std::string msg, uint32 language = LANG_UNIVERSAL); - void BroadcastPacketToRank(WorldPacket *packet, uint32 rankId); - void BroadcastPacket(WorldPacket *packet); - - void CreateRank(std::string name,uint32 rights); - void DelRank(); - std::string GetRankName(uint32 rankId); - uint32 GetRankRights(uint32 rankId); - uint32 GetNrRanks() const { return m_ranks.size(); } - - void SetRankName(uint32 rankId, std::string name); - void SetRankRights(uint32 rankId, uint32 rights); - bool HasRankRight(uint32 rankId, uint32 right) - { - return ((GetRankRights(rankId) & right) != GR_RIGHT_EMPTY) ? true : false; - } - - void Roster(WorldSession *session); - void Query(WorldSession *session); - - void UpdateLogoutTime(uint64 guid); - // Guild eventlog - void LoadGuildEventLogFromDB(); - void UnloadGuildEventlog(); - void DisplayGuildEventlog(WorldSession *session); - void LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank); - void RenumGuildEventlog(); - - // ** Guild bank ** - // Content & item deposit/withdraw - void DisplayGuildBankContent(WorldSession *session, uint8 TabId); - void DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2 = -1); - void DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots); - void DisplayGuildBankMoneyUpdate(); - - Item* GetItem(uint8 TabId, uint8 SlotId); - uint8 CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec& dest, uint32 count, Item *pItem, bool swap = false) const; - Item* StoreItem( uint8 tab, GuildItemPosCountVec const& pos, Item *pItem ); - void RemoveItem(uint8 tab, uint8 slot ); - - // Tabs - void DisplayGuildBankTabsInfo(WorldSession *session); - void CreateNewBankTab(); - void SetGuildBankTabText(uint8 TabId, std::string text); - void SendGuildBankTabText(WorldSession *session, uint8 TabId); - void SetGuildBankTabInfo(uint8 TabId, std::string name, std::string icon); - void CreateBankRightForTab(uint32 rankid, uint8 TabId); - const GuildBankTab *GetBankTab(uint8 index) { if(index >= m_TabListMap.size()) return NULL; return m_TabListMap[index]; } - const uint8 GetPurchasedTabs() const { return purchased_tabs; } - uint32 GetBankRights(uint32 rankId, uint8 TabId) const; - bool IsMemberHaveRights(uint32 LowGuid, uint8 TabId,uint32 rights) const; - bool CanMemberViewTab(uint32 LowGuid, uint8 TabId) const; - // Load/unload - void LoadGuildBankFromDB(); - void UnloadGuildBank(); - void IncOnlineMemberCount() { ++m_onlinemembers; } - // Money deposit/withdraw - void SendMoneyInfo(WorldSession *session, uint32 LowGuid); - bool MemberMoneyWithdraw(uint32 amount, uint32 LowGuid); - uint64 GetGuildBankMoney() { return guildbank_money; } - void SetBankMoney(int64 money); - // per days - bool MemberItemWithdraw(uint8 TabId, uint32 LowGuid); - uint32 GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId); - uint32 GetMemberMoneyWithdrawRem(uint32 LowGuid); - void SetBankMoneyPerDay(uint32 rankId, uint32 money); - void SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 SlotPerDay, bool db); - uint32 GetBankMoneyPerDay(uint32 rankId); - uint32 GetBankSlotPerDay(uint32 rankId, uint8 TabId); - // rights per day - void LoadBankRightsFromDB(uint32 GuildId); - // logs - void LoadGuildBankEventLogFromDB(); - void UnloadGuildBankEventLog(); - void DisplayGuildBankLogs(WorldSession *session, uint8 TabId); - void LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount=0, uint8 DestTabId=0); - void RenumBankLogs(); - bool AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry ); - - protected: - void AddRank(std::string name,uint32 rights,uint32 money); - - uint32 Id; - std::string name; - uint64 leaderGuid; - std::string MOTD; - std::string GINFO; - uint32 CreatedYear; - uint32 CreatedMonth; - uint32 CreatedDay; - - uint32 EmblemStyle; - uint32 EmblemColor; - uint32 BorderStyle; - uint32 BorderColor; - uint32 BackgroundColor; - - RankList m_ranks; - - MemberList members; - - typedef std::vector TabListMap; - TabListMap m_TabListMap; - - /** These are actually ordered lists. The first element is the oldest entry.*/ - typedef std::list GuildEventlog; - typedef std::list GuildBankEventLog; - GuildEventlog m_GuildEventlog; - GuildBankEventLog m_GuildBankEventLog_Money; - GuildBankEventLog m_GuildBankEventLog_Item[GUILD_BANK_MAX_TABS]; - - bool m_bankloaded; - bool m_eventlogloaded; - uint32 m_onlinemembers; - uint64 guildbank_money; - uint8 purchased_tabs; - - uint32 LogMaxGuid; - uint32 GuildEventlogMaxGuid; - private: - // internal common parts for CanStore/StoreItem functions - void AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int32 slot ); - uint8 _CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec& dest, uint32& count, bool swap, Item *pSrcItem ) const; - uint8 _CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec& dest, uint32& count, bool merge, Item *pSrcItem, uint8 skip_slot ) const; - Item* _StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone ); -}; -#endif +/* + * Copyright (C) 2005-2008 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 MANGOSSERVER_GUILD_H +#define MANGOSSERVER_GUILD_H + +#define WITHDRAW_MONEY_UNLIMITED 0xFFFFFFFF +#define WITHDRAW_SLOT_UNLIMITED 0xFFFFFFFF + +#include "Item.h" + +class Item; + +enum GuildDefaultRanks +{ + GR_GUILDMASTER = 0, + GR_OFFICER = 1, + //GR_VETERAN = 2, -- not used anywhere and possible incorrect in modified rank list + //GR_MEMBER = 3, + //GR_INITIATE = 4, -- use Guild::GetLowestRank() instead for lowest rank +}; + +enum GuildRankRights +{ + GR_RIGHT_EMPTY = 0x00000040, + GR_RIGHT_GCHATLISTEN = 0x00000041, + GR_RIGHT_GCHATSPEAK = 0x00000042, + GR_RIGHT_OFFCHATLISTEN = 0x00000044, + GR_RIGHT_OFFCHATSPEAK = 0x00000048, + GR_RIGHT_PROMOTE = 0x000000C0, + GR_RIGHT_DEMOTE = 0x00000140, + GR_RIGHT_INVITE = 0x00000050, + GR_RIGHT_REMOVE = 0x00000060, + GR_RIGHT_SETMOTD = 0x00001040, + GR_RIGHT_EPNOTE = 0x00002040, + GR_RIGHT_VIEWOFFNOTE = 0x00004040, + GR_RIGHT_EOFFNOTE = 0x00008040, + GR_RIGHT_MODIFY_GUILD_INFO = 0x00010040, + GR_RIGHT_REPAIR_FROM_GUILD = 0x00020000, // unused in 2.4.x?, Remove money withdraw capacity + GR_RIGHT_WITHDRAW_REPAIR = 0x00040000, // withdraw for repair + GR_RIGHT_WITHDRAW_GOLD = 0x00080000, // withdraw gold + GR_RIGHT_ALL = 0x000FF1FF +}; + +enum Typecommand +{ + GUILD_CREATE_S = 0x00, + GUILD_INVITE_S = 0x01, + GUILD_QUIT_S = 0x03, + GUILD_FOUNDER_S = 0x0E, + GUILD_UNK1 = 0x10, + GUILD_BANK_S = 0x15, + GUILD_UNK3 = 0x16 +}; + +enum CommandErrors +{ + GUILD_PLAYER_NO_MORE_IN_GUILD = 0x00, + GUILD_INTERNAL = 0x01, + GUILD_ALREADY_IN_GUILD = 0x02, + ALREADY_IN_GUILD = 0x03, + INVITED_TO_GUILD = 0x04, + ALREADY_INVITED_TO_GUILD = 0x05, + GUILD_NAME_INVALID = 0x06, + GUILD_NAME_EXISTS = 0x07, + GUILD_LEADER_LEAVE = 0x08, + GUILD_PERMISSIONS = 0x08, + GUILD_PLAYER_NOT_IN_GUILD = 0x09, + GUILD_PLAYER_NOT_IN_GUILD_S = 0x0A, + GUILD_PLAYER_NOT_FOUND = 0x0B, + GUILD_NOT_ALLIED = 0x0C, + GUILD_RANK_TOO_HIGH_S = 0x0D, + GUILD_ALREADY_LOWEST_RANK_S = 0x0E, + GUILD_TEMP_ERROR = 0x11, + GUILD_RANK_IN_USE = 0x12, + GUILD_IGNORE = 0x13, + GUILD_ERR_UNK1 = 0x17, + GUILD_WITHDRAW_TOO_MUCH = 0x18, + GUILD_BANK_NO_MONEY = 0x19, + GUILD_BANK_TAB_IS_FULL = 0x1B, + GUILD_BANK_ITEM_NOT_FOUND = 0x1C +}; + +enum GuildEvents +{ + GE_PROMOTION = 0x00, + GE_DEMOTION = 0x01, + GE_MOTD = 0x02, + GE_JOINED = 0x03, + GE_LEFT = 0x04, + GE_REMOVED = 0x05, + GE_LEADER_IS = 0x06, + GE_LEADER_CHANGED = 0x07, + GE_DISBANDED = 0x08, + GE_TABARDCHANGE = 0x09, + GE_UNK1 = 0x0A, // string, string + GE_UNK2 = 0x0B, + GE_SIGNED_ON = 0x0C, + GE_SIGNED_OFF = 0x0D, + GE_UNK3 = 0x0E, + GE_BANKTAB_PURCHASED= 0x0F, + GE_UNK5 = 0x10, + GE_UNK6 = 0x11, // string 0000000000002710 is 1 gold + GE_UNK7 = 0x12 +}; + +enum PetitionTurns +{ + PETITION_TURN_OK = 0, + PETITION_TURN_ALREADY_IN_GUILD = 2, + PETITION_TURN_NEED_MORE_SIGNATURES = 4, +}; + +enum PetitionSigns +{ + PETITION_SIGN_OK = 0, + PETITION_SIGN_ALREADY_SIGNED = 1, + PETITION_SIGN_ALREADY_IN_GUILD = 2, + PETITION_SIGN_CANT_SIGN_OWN = 3, + PETITION_SIGN_NOT_SERVER = 4, +}; + +enum GuildBankRights +{ + GUILD_BANK_RIGHT_VIEW_TAB = 0x01, + GUILD_BANK_RIGHT_PUT_ITEM = 0x02, + GUILD_BANK_RIGHT_UPDATE_TEXT = 0x04, + + GUILD_BANK_RIGHT_DEPOSIT_ITEM = GUILD_BANK_RIGHT_VIEW_TAB | GUILD_BANK_RIGHT_PUT_ITEM, + GUILD_BANK_RIGHT_FULL = 0xFF, +}; + +enum GuildBankLogEntries +{ + GUILD_BANK_LOG_DEPOSIT_ITEM = 1, + GUILD_BANK_LOG_WITHDRAW_ITEM = 2, + GUILD_BANK_LOG_MOVE_ITEM = 3, + GUILD_BANK_LOG_DEPOSIT_MONEY = 4, + GUILD_BANK_LOG_WITHDRAW_MONEY = 5, + GUILD_BANK_LOG_REPAIR_MONEY = 6, + GUILD_BANK_LOG_MOVE_ITEM2 = 7, +}; + +enum GuildEventLogEntryTypes +{ + GUILD_EVENT_LOG_INVITE_PLAYER = 1, + GUILD_EVENT_LOG_JOIN_GUILD = 2, + GUILD_EVENT_LOG_PROMOTE_PLAYER = 3, + GUILD_EVENT_LOG_DEMOTE_PLAYER = 4, + GUILD_EVENT_LOG_UNINVITE_PLAYER = 5, + GUILD_EVENT_LOG_LEAVE_GUILD = 6, +}; + +struct GuildEventlogEntry +{ + uint32 LogGuid; + uint8 EventType; + uint32 PlayerGuid1; + uint32 PlayerGuid2; + uint8 NewRank; + uint64 TimeStamp; +}; + +enum GuildEmblem +{ + ERR_GUILDEMBLEM_SUCCESS = 0, + ERR_GUILDEMBLEM_INVALID_TABARD_COLORS = 1, + ERR_GUILDEMBLEM_NOGUILD = 2, + ERR_GUILDEMBLEM_NOTGUILDMASTER = 3, + ERR_GUILDEMBLEM_NOTENOUGHMONEY = 4, + ERR_GUILDEMBLEM_INVALIDVENDOR = 5 +}; + +struct GuildBankEvent +{ + uint32 LogGuid; + uint8 LogEntry; + uint8 TabId; + uint32 PlayerGuid; + uint32 ItemOrMoney; + uint8 ItemStackCount; + uint8 DestTabId; + uint64 TimeStamp; + + const bool isMoneyEvent() + { + return LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY || + LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY || + LogEntry == GUILD_BANK_LOG_REPAIR_MONEY; + } +}; + +struct GuildBankTab +{ + Item* Slots[GUILD_BANK_MAX_SLOTS]; + std::string Name; + std::string Icon; + std::string Text; +}; + +struct GuildItemPosCount +{ + GuildItemPosCount(uint8 _slot, uint8 _count) : slot(_slot), count(_count) {} + + bool isContainedIn(std::vector const& vec) const; + + uint8 slot; + uint8 count; +}; +typedef std::vector GuildItemPosCountVec; + +struct MemberSlot +{ + uint64 logout_time; + std::string name; + std::string Pnote; + std::string OFFnote; + uint32 RankId; + uint32 zoneId; + uint8 level; + uint8 Class; + uint32 BankResetTimeMoney; + uint32 BankRemMoney; + uint32 BankResetTimeTab[GUILD_BANK_MAX_TABS]; + uint32 BankRemSlotsTab[GUILD_BANK_MAX_TABS]; +}; + +struct RankInfo +{ + RankInfo(std::string _name, uint32 _rights, uint32 _money) : name(_name), rights(_rights), BankMoneyPerDay(_money) + { + for(uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + TabRight[i] = 0; + TabSlotPerDay[i] = 0; + } + } + + std::string name; + uint32 rights; + uint32 BankMoneyPerDay; + uint32 TabRight[GUILD_BANK_MAX_TABS]; + uint32 TabSlotPerDay[GUILD_BANK_MAX_TABS]; +}; + +class Guild +{ + public: + Guild(); + ~Guild(); + + bool create(uint64 lGuid, std::string gname); + void Disband(); + + typedef std::map MemberList; + typedef std::vector RankList; + + uint32 GetId(){ return Id; } + const uint64& GetLeader(){ return leaderGuid; } + std::string GetName(){ return name; } + std::string GetMOTD(){ return MOTD; } + std::string GetGINFO(){ return GINFO; } + + uint32 GetCreatedYear(){ return CreatedYear; } + uint32 GetCreatedMonth(){ return CreatedMonth; } + uint32 GetCreatedDay(){ return CreatedDay; } + + uint32 GetEmblemStyle(){ return EmblemStyle; } + uint32 GetEmblemColor(){ return EmblemColor; } + uint32 GetBorderStyle(){ return BorderStyle; } + uint32 GetBorderColor(){ return BorderColor; } + uint32 GetBackgroundColor(){ return BackgroundColor; } + + void SetLeader(uint64 guid); + bool AddMember(uint64 plGuid, uint32 plRank); + void ChangeRank(uint64 guid, uint32 newRank); + void DelMember(uint64 guid, bool isDisbanding=false); + uint32 GetLowestRank() const { return GetNrRanks()-1; } + + void SetMOTD(std::string motd); + void SetGINFO(std::string ginfo); + void SetPNOTE(uint64 guid,std::string pnote); + void SetOFFNOTE(uint64 guid,std::string offnote); + void SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor); + + uint32 GetMemberSize() const { return members.size(); } + + bool LoadGuildFromDB(uint32 GuildId); + bool LoadRanksFromDB(uint32 GuildId); + bool LoadMembersFromDB(uint32 GuildId); + + bool FillPlayerData(uint64 guid, MemberSlot* memslot); + void LoadPlayerStatsByGuid(uint64 guid); + + void BroadcastToGuild(WorldSession *session, std::string msg, uint32 language = LANG_UNIVERSAL); + void BroadcastToOfficers(WorldSession *session, std::string msg, uint32 language = LANG_UNIVERSAL); + void BroadcastPacketToRank(WorldPacket *packet, uint32 rankId); + void BroadcastPacket(WorldPacket *packet); + + void CreateRank(std::string name,uint32 rights); + void DelRank(); + std::string GetRankName(uint32 rankId); + uint32 GetRankRights(uint32 rankId); + uint32 GetNrRanks() const { return m_ranks.size(); } + + void SetRankName(uint32 rankId, std::string name); + void SetRankRights(uint32 rankId, uint32 rights); + bool HasRankRight(uint32 rankId, uint32 right) + { + return ((GetRankRights(rankId) & right) != GR_RIGHT_EMPTY) ? true : false; + } + + void Roster(WorldSession *session); + void Query(WorldSession *session); + + void UpdateLogoutTime(uint64 guid); + // Guild eventlog + void LoadGuildEventLogFromDB(); + void UnloadGuildEventlog(); + void DisplayGuildEventlog(WorldSession *session); + void LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank); + void RenumGuildEventlog(); + + // ** Guild bank ** + // Content & item deposit/withdraw + void DisplayGuildBankContent(WorldSession *session, uint8 TabId); + void DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2 = -1); + void DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots); + void DisplayGuildBankMoneyUpdate(); + + Item* GetItem(uint8 TabId, uint8 SlotId); + uint8 CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec& dest, uint32 count, Item *pItem, bool swap = false) const; + Item* StoreItem( uint8 tab, GuildItemPosCountVec const& pos, Item *pItem ); + void RemoveItem(uint8 tab, uint8 slot ); + + // Tabs + void DisplayGuildBankTabsInfo(WorldSession *session); + void CreateNewBankTab(); + void SetGuildBankTabText(uint8 TabId, std::string text); + void SendGuildBankTabText(WorldSession *session, uint8 TabId); + void SetGuildBankTabInfo(uint8 TabId, std::string name, std::string icon); + void CreateBankRightForTab(uint32 rankid, uint8 TabId); + const GuildBankTab *GetBankTab(uint8 index) { if(index >= m_TabListMap.size()) return NULL; return m_TabListMap[index]; } + const uint8 GetPurchasedTabs() const { return purchased_tabs; } + uint32 GetBankRights(uint32 rankId, uint8 TabId) const; + bool IsMemberHaveRights(uint32 LowGuid, uint8 TabId,uint32 rights) const; + bool CanMemberViewTab(uint32 LowGuid, uint8 TabId) const; + // Load/unload + void LoadGuildBankFromDB(); + void UnloadGuildBank(); + void IncOnlineMemberCount() { ++m_onlinemembers; } + // Money deposit/withdraw + void SendMoneyInfo(WorldSession *session, uint32 LowGuid); + bool MemberMoneyWithdraw(uint32 amount, uint32 LowGuid); + uint64 GetGuildBankMoney() { return guildbank_money; } + void SetBankMoney(int64 money); + // per days + bool MemberItemWithdraw(uint8 TabId, uint32 LowGuid); + uint32 GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId); + uint32 GetMemberMoneyWithdrawRem(uint32 LowGuid); + void SetBankMoneyPerDay(uint32 rankId, uint32 money); + void SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 SlotPerDay, bool db); + uint32 GetBankMoneyPerDay(uint32 rankId); + uint32 GetBankSlotPerDay(uint32 rankId, uint8 TabId); + // rights per day + void LoadBankRightsFromDB(uint32 GuildId); + // logs + void LoadGuildBankEventLogFromDB(); + void UnloadGuildBankEventLog(); + void DisplayGuildBankLogs(WorldSession *session, uint8 TabId); + void LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount=0, uint8 DestTabId=0); + void RenumBankLogs(); + bool AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry ); + + protected: + void AddRank(std::string name,uint32 rights,uint32 money); + + uint32 Id; + std::string name; + uint64 leaderGuid; + std::string MOTD; + std::string GINFO; + uint32 CreatedYear; + uint32 CreatedMonth; + uint32 CreatedDay; + + uint32 EmblemStyle; + uint32 EmblemColor; + uint32 BorderStyle; + uint32 BorderColor; + uint32 BackgroundColor; + + RankList m_ranks; + + MemberList members; + + typedef std::vector TabListMap; + TabListMap m_TabListMap; + + /** These are actually ordered lists. The first element is the oldest entry.*/ + typedef std::list GuildEventlog; + typedef std::list GuildBankEventLog; + GuildEventlog m_GuildEventlog; + GuildBankEventLog m_GuildBankEventLog_Money; + GuildBankEventLog m_GuildBankEventLog_Item[GUILD_BANK_MAX_TABS]; + + bool m_bankloaded; + bool m_eventlogloaded; + uint32 m_onlinemembers; + uint64 guildbank_money; + uint8 purchased_tabs; + + uint32 LogMaxGuid; + uint32 GuildEventlogMaxGuid; + private: + // internal common parts for CanStore/StoreItem functions + void AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int32 slot ); + uint8 _CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec& dest, uint32& count, bool swap, Item *pSrcItem ) const; + uint8 _CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec& dest, uint32& count, bool merge, Item *pSrcItem, uint8 skip_slot ) const; + Item* _StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone ); +}; +#endif diff --git a/src/game/Language.h b/src/game/Language.h index bb36bffcee6..5fe11e44c57 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -1,665 +1,668 @@ -/* - * Copyright (C) 2005-2008 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 __MANGOS_LANGUAGE_H -#define __MANGOS_LANGUAGE_H - -enum MangosStrings -{ - // for chat commands - LANG_SELECT_CHAR_OR_CREATURE = 1, - LANG_SELECT_CREATURE = 2, - - // level 0 chat - LANG_SYSTEMMESSAGE = 3, - LANG_EVENTMESSAGE = 4, - LANG_NO_HELP_CMD = 5, - LANG_NO_CMD = 6, - LANG_NO_SUBCMD = 7, - LANG_SUBCMDS_LIST = 8, - LANG_AVIABLE_CMD = 9, - LANG_CMD_SYNTAX = 10, - LANG_ACCOUNT_LEVEL = 11, - LANG_CONNECTED_USERS = 12, - LANG_UPTIME = 13, - LANG_PLAYER_SAVED = 14, - LANG_PLAYERS_SAVED = 15, - LANG_GMS_ON_SRV = 16, - LANG_GMS_NOT_LOGGED = 17, - LANG_YOU_IN_FLIGHT = 18, - //LANG_YOU_IN_BATTLEGROUND = 19, not used - //LANG_TARGET_IN_FLIGHT = 20, not used - LANG_CHAR_IN_FLIGHT = 21, - LANG_CHAR_NON_MOUNTED = 22, - LANG_YOU_IN_COMBAT = 23, - LANG_YOU_USED_IT_RECENTLY = 24, - LANG_COMMAND_NOTCHANGEPASSWORD = 25, - LANG_COMMAND_PASSWORD = 26, - LANG_COMMAND_WRONGOLDPASSWORD = 27, - LANG_COMMAND_ACCLOCKLOCKED = 28, - LANG_COMMAND_ACCLOCKUNLOCKED = 29, - LANG_SPELL_RANK = 30, - LANG_KNOWN = 31, - LANG_LEARN = 32, - LANG_PASSIVE = 33, - LANG_TALENT = 34, - LANG_ACTIVE = 35, - LANG_COMPLETE = 36, - LANG_OFFLINE = 37, - LANG_ON = 38, - LANG_OFF = 39, - LANG_YOU_ARE = 40, - LANG_VISIBLE = 41, - LANG_INVISIBLE = 42, - LANG_DONE = 43, - LANG_YOU = 44, - LANG_UNKNOWN = 45, - LANG_ERROR = 46, - LANG_NON_EXIST_CHARACTER = 47, - LANG_FRIEND_IGNORE_UNKNOWN = 48, - LANG_LEVEL_MINREQUIRED = 49, - LANG_LEVEL_MINREQUIRED_AND_ITEM = 50, - LANG_NPC_TAINER_HELLO = 51, - // Room for more level 0 - - // level 1 chat - LANG_GLOBAL_NOTIFY = 100, - LANG_MAP_POSITION = 101, - LANG_IS_TELEPORTED = 102, - LANG_CANNOT_SUMMON_TO_INST = 103, - LANG_CANNOT_GO_TO_INST_PARTY = 104, - LANG_CANNOT_GO_TO_INST_GM = 105, - LANG_CANNOT_GO_INST_INST = 106, - LANG_CANNOT_SUMMON_INST_INST = 107, - - LANG_SUMMONING = 108, - LANG_SUMMONED_BY = 109, - LANG_TELEPORTING_TO = 110, - LANG_TELEPORTED_TO_BY = 111, - LANG_NO_PLAYER = 112, - LANG_APPEARING_AT = 113, - LANG_APPEARING_TO = 114, - - LANG_BAD_VALUE = 115, - LANG_NO_CHAR_SELECTED = 116, - LANG_NOT_IN_GROUP = 117, - - LANG_YOU_CHANGE_HP = 118, - LANG_YOURS_HP_CHANGED = 119, - LANG_YOU_CHANGE_MANA = 120, - LANG_YOURS_MANA_CHANGED = 121, - LANG_YOU_CHANGE_ENERGY = 122, - LANG_YOURS_ENERGY_CHANGED = 123, - - LANG_CURRENT_ENERGY = 124, //log - LANG_YOU_CHANGE_RAGE = 125, - LANG_YOURS_RAGE_CHANGED = 126, - LANG_YOU_CHANGE_LVL = 127, - LANG_CURRENT_FACTION = 128, - LANG_WRONG_FACTION = 129, - LANG_YOU_CHANGE_FACTION = 130, - LANG_YOU_CHANGE_SPELLFLATID = 131, - LANG_YOURS_SPELLFLATID_CHANGED = 132, - LANG_YOU_GIVE_TAXIS = 133, - LANG_YOU_REMOVE_TAXIS = 134, - LANG_YOURS_TAXIS_ADDED = 135, - LANG_YOURS_TAXIS_REMOVED = 136, - - LANG_YOU_CHANGE_ASPEED = 137, - LANG_YOURS_ASPEED_CHANGED = 138, - LANG_YOU_CHANGE_SPEED = 139, - LANG_YOURS_SPEED_CHANGED = 140, - LANG_YOU_CHANGE_SWIM_SPEED = 141, - LANG_YOURS_SWIM_SPEED_CHANGED = 142, - LANG_YOU_CHANGE_BACK_SPEED = 143, - LANG_YOURS_BACK_SPEED_CHANGED = 144, - LANG_YOU_CHANGE_FLY_SPEED = 145, - LANG_YOURS_FLY_SPEED_CHANGED = 146, - - LANG_YOU_CHANGE_SIZE = 147, - LANG_YOURS_SIZE_CHANGED = 148, - LANG_NO_MOUNT = 149, - LANG_YOU_GIVE_MOUNT = 150, - LANG_MOUNT_GIVED = 151, - - LANG_CURRENT_MONEY = 152, - LANG_YOU_TAKE_ALL_MONEY = 153, - LANG_YOURS_ALL_MONEY_GONE = 154, - LANG_YOU_TAKE_MONEY = 155, - LANG_YOURS_MONEY_TAKEN = 156, - LANG_YOU_GIVE_MONEY = 157, - LANG_YOURS_MONEY_GIVEN = 158, - LANG_YOU_HEAR_SOUND = 159, - - LANG_NEW_MONEY = 160, // Log - - LANG_REMOVE_BIT = 161, - LANG_SET_BIT = 162, - LANG_COMMAND_TELE_TABLEEMPTY = 163, - LANG_COMMAND_TELE_NOTFOUND = 164, - LANG_COMMAND_TELE_PARAMETER = 165, - LANG_COMMAND_TELE_NOREQUEST = 166, - LANG_COMMAND_TELE_NOLOCATION = 167, - LANG_COMMAND_TELE_LOCATION = 168, - - LANG_MAIL_SENT = 169, - LANG_SOUND_NOT_EXIST = 170, - // Room for more level 1 - - // level 2 chat - LANG_NO_SELECTION = 200, - LANG_OBJECT_GUID = 201, - LANG_TOO_LONG_NAME = 202, - LANG_CHARS_ONLY = 203, - LANG_TOO_LONG_SUBNAME = 204, - LANG_NOT_IMPLEMENTED = 205, - - LANG_ITEM_ADDED_TO_LIST = 206, - LANG_ITEM_NOT_FOUND = 207, - LANG_ITEM_DELETED_FROM_LIST = 208, - LANG_ITEM_NOT_IN_LIST = 209, - LANG_ITEM_ALREADY_IN_LIST = 210, - - LANG_RESET_SPELLS_ONLINE = 211, - LANG_RESET_SPELLS_OFFLINE = 212, - LANG_RESET_TALENTS_ONLINE = 213, - LANG_RESET_TALENTS_OFFLINE = 214, - LANG_RESET_SPELLS = 215, - LANG_RESET_TALENTS = 216, - - LANG_RESETALL_UNKNOWN_CASE = 217, - LANG_RESETALL_SPELLS = 218, - LANG_RESETALL_TALENTS = 219, - - LANG_WAYPOINT_NOTFOUND = 220, - LANG_WAYPOINT_NOTFOUNDLAST = 221, - LANG_WAYPOINT_NOTFOUNDSEARCH = 222, - LANG_WAYPOINT_NOTFOUNDDBPROBLEM = 223, - LANG_WAYPOINT_CREATSELECTED = 224, - LANG_WAYPOINT_CREATNOTFOUND = 225, - LANG_WAYPOINT_VP_SELECT = 226, - LANG_WAYPOINT_VP_NOTFOUND = 227, - LANG_WAYPOINT_VP_NOTCREATED = 228, - LANG_WAYPOINT_VP_ALLREMOVED = 229, - LANG_WAYPOINT_NOTCREATED = 230, - LANG_WAYPOINT_NOGUID = 231, - LANG_WAYPOINT_NOWAYPOINTGIVEN = 232, - LANG_WAYPOINT_ARGUMENTREQ = 233, - LANG_WAYPOINT_ADDED = 234, - LANG_WAYPOINT_ADDED_NO = 235, - LANG_WAYPOINT_CHANGED = 236, - LANG_WAYPOINT_CHANGED_NO = 237, - LANG_WAYPOINT_EXPORTED = 238, - LANG_WAYPOINT_NOTHINGTOEXPORT = 239, - LANG_WAYPOINT_IMPORTED = 240, - LANG_WAYPOINT_REMOVED = 241, - LANG_WAYPOINT_NOTREMOVED = 242, - LANG_WAYPOINT_TOOFAR1 = 243, - LANG_WAYPOINT_TOOFAR2 = 244, - LANG_WAYPOINT_TOOFAR3 = 245, - LANG_WAYPOINT_INFO_TITLE = 246, - LANG_WAYPOINT_INFO_WAITTIME = 247, - LANG_WAYPOINT_INFO_MODEL = 248, - LANG_WAYPOINT_INFO_EMOTE = 249, - LANG_WAYPOINT_INFO_SPELL = 250, - LANG_WAYPOINT_INFO_TEXT = 251, - LANG_WAYPOINT_INFO_AISCRIPT = 252, - - LANG_RENAME_PLAYER = 253, - LANG_RENAME_PLAYER_GUID = 254, - - LANG_WAYPOINT_WPCREATNOTFOUND = 255, - LANG_WAYPOINT_NPCNOTFOUND = 256, - - LANG_MOVE_TYPE_SET = 257, - LANG_MOVE_TYPE_SET_NODEL = 258, - LANG_USE_BOL = 259, - LANG_VALUE_SAVED = 260, - LANG_VALUE_SAVED_REJOIN = 261, - - LANG_COMMAND_GOAREATRNOTFOUND = 262, - LANG_INVALID_TARGET_COORD = 263, - LANG_INVALID_ZONE_COORD = 264, - LANG_INVALID_ZONE_MAP = 265, - LANG_COMMAND_TARGETOBJNOTFOUND = 266, - LANG_COMMAND_GOOBJNOTFOUND = 267, - LANG_COMMAND_GOCREATNOTFOUND = 268, - LANG_COMMAND_GOCREATMULTIPLE = 269, - LANG_COMMAND_DELCREATMESSAGE = 270, - LANG_COMMAND_CREATUREMOVED = 271, - LANG_COMMAND_CREATUREATSAMEMAP = 272, - LANG_COMMAND_OBJNOTFOUND = 273, - LANG_COMMAND_DELOBJREFERCREATURE = 274, - LANG_COMMAND_DELOBJMESSAGE = 275, - LANG_COMMAND_TURNOBJMESSAGE = 276, - LANG_COMMAND_MOVEOBJMESSAGE = 277, - LANG_COMMAND_VENDORSELECTION = 278, - LANG_COMMAND_NEEDITEMSEND = 279, - LANG_COMMAND_ADDVENDORITEMITEMS = 280, - LANG_COMMAND_KICKSELF = 281, - LANG_COMMAND_KICKMESSAGE = 282, - LANG_COMMAND_KICKNOTFOUNDPLAYER = 283, - LANG_COMMAND_WHISPERACCEPTING = 284, - LANG_COMMAND_WHISPERON = 285, - LANG_COMMAND_WHISPEROFF = 286, - LANG_COMMAND_CREATGUIDNOTFOUND = 287, - LANG_COMMAND_TICKETCOUNT = 288, - LANG_COMMAND_TICKETNEW = 289, - LANG_COMMAND_TICKETVIEW = 290, - LANG_COMMAND_TICKETON = 291, - LANG_COMMAND_TICKETOFF = 292, - LANG_COMMAND_TICKENOTEXIST = 293, - LANG_COMMAND_ALLTICKETDELETED = 294, - LANG_COMMAND_TICKETPLAYERDEL = 295, - LANG_COMMAND_TICKETDEL = 296, - LANG_COMMAND_SPAWNDIST = 297, - LANG_COMMAND_SPAWNTIME = 298, - LANG_COMMAND_MODIFY_HONOR = 299, - - LANG_YOUR_CHAT_DISABLED = 300, - LANG_YOU_DISABLE_CHAT = 301, - LANG_CHAT_ALREADY_ENABLED = 302, - LANG_YOUR_CHAT_ENABLED = 303, - LANG_YOU_ENABLE_CHAT = 304, - - LANG_COMMAND_MODIFY_REP = 305, - LANG_COMMAND_MODIFY_ARENA = 306, - LANG_COMMAND_FACTION_NOTFOUND = 307, - LANG_COMMAND_FACTION_UNKNOWN = 308, - LANG_COMMAND_FACTION_INVPARAM = 309, - LANG_COMMAND_FACTION_DELTA = 310, - LANG_FACTION_LIST = 311, - LANG_FACTION_VISIBLE = 312, - LANG_FACTION_ATWAR = 313, - LANG_FACTION_PEACE_FORCED = 314, - LANG_FACTION_HIDDEN = 315, - LANG_FACTION_INVISIBLE_FORCED = 316, - LANG_FACTION_INACTIVE = 317, - LANG_REP_HATED = 318, - LANG_REP_HOSTILE = 319, - LANG_REP_UNFRIENDLY = 320, - LANG_REP_NEUTRAL = 321, - LANG_REP_FRIENDLY = 322, - LANG_REP_HONORED = 323, - LANG_REP_REVERED = 324, - LANG_REP_EXALTED = 325, - LANG_COMMAND_FACTION_NOREP_ERROR = 326, - LANG_FACTION_NOREPUTATION = 327, - - // Room for more level 2 - - // level 3 chat - LANG_SCRIPTS_RELOADED = 400, - LANG_YOU_CHANGE_SECURITY = 401, - LANG_YOURS_SECURITY_CHANGED = 402, - LANG_YOURS_SECURITY_IS_LOW = 403, - LANG_CREATURE_MOVE_DISABLED = 404, - LANG_CREATURE_MOVE_ENABLED = 405, - LANG_NO_WEATHER = 406, - LANG_WEATHER_DISABLED = 407, - - LANG_BAN_YOUBANNED = 408, - LANG_BAN_YOUPERMBANNED = 409, - LANG_BAN_NOTFOUND = 410, - - LANG_UNBAN_UNBANNED = 411, - LANG_UNBAN_ERROR = 412, - - LANG_BANINFO_NOACCOUNT = 413, - LANG_BANINFO_NOCHARACTER = 414, - LANG_BANINFO_NOIP = 415, - LANG_BANINFO_NOACCOUNTBAN = 416, - LANG_BANINFO_BANHISTORY = 417, - LANG_BANINFO_HISTORYENTRY = 418, - LANG_BANINFO_INFINITE = 419, - LANG_BANINFO_NEVER = 420, - LANG_BANINFO_YES = 421, - LANG_BANINFO_NO = 422, - LANG_BANINFO_IPENTRY = 423, - - LANG_BANLIST_NOIP = 424, - LANG_BANLIST_NOACCOUNT = 425, - LANG_BANLIST_NOCHARACTER = 426, - LANG_BANLIST_MATCHINGIP = 427, - LANG_BANLIST_MATCHINGACCOUNT = 428, - - LANG_COMMAND_LEARN_MANY_SPELLS = 429, - LANG_COMMAND_LEARN_CLASS_SPELLS = 430, - LANG_COMMAND_LEARN_CLASS_TALENTS = 431, - LANG_COMMAND_LEARN_ALL_LANG = 432, - LANG_COMMAND_LEARN_ALL_CRAFT = 433, - LANG_COMMAND_COULDNOTFIND = 434, - LANG_COMMAND_ITEMIDINVALID = 435, - LANG_COMMAND_NOITEMFOUND = 436, - LANG_COMMAND_LISTOBJINVALIDID = 437, - LANG_COMMAND_LISTITEMMESSAGE = 438, - LANG_COMMAND_LISTOBJMESSAGE = 439, - LANG_COMMAND_INVALIDCREATUREID = 440, - LANG_COMMAND_LISTCREATUREMESSAGE = 441, - LANG_COMMAND_NOAREAFOUND = 442, - LANG_COMMAND_NOITEMSETFOUND = 443, - LANG_COMMAND_NOSKILLFOUND = 444, - LANG_COMMAND_NOSPELLFOUND = 445, - LANG_COMMAND_NOQUESTFOUND = 446, - LANG_COMMAND_NOCREATUREFOUND = 447, - LANG_COMMAND_NOGAMEOBJECTFOUND = 448, - LANG_COMMAND_GRAVEYARDNOEXIST = 449, - LANG_COMMAND_GRAVEYARDALRLINKED = 450, - LANG_COMMAND_GRAVEYARDLINKED = 451, - LANG_COMMAND_GRAVEYARDWRONGZONE = 452, - LANG_COMMAND_GRAVEYARDWRONGTEAM = 453, - LANG_COMMAND_GRAVEYARDERROR = 454, - LANG_COMMAND_GRAVEYARD_NOTEAM = 455, - LANG_COMMAND_GRAVEYARD_ANY = 456, - LANG_COMMAND_GRAVEYARD_ALLIANCE = 457, - LANG_COMMAND_GRAVEYARD_HORDE = 458, - LANG_COMMAND_GRAVEYARDNEAREST = 459, - LANG_COMMAND_ZONENOGRAVEYARDS = 460, - LANG_COMMAND_ZONENOGRAFACTION = 461, - LANG_COMMAND_TP_ALREADYEXIST = 462, - LANG_COMMAND_TP_ADDED = 463, - LANG_COMMAND_TP_ADDEDERR = 464, - LANG_COMMAND_TP_DELETED = 465, - LANG_COMMAND_TP_DELETEERR = 466, - - LANG_COMMAND_TARGET_LISTAURAS = 467, - LANG_COMMAND_TARGET_AURADETAIL = 468, - LANG_COMMAND_TARGET_LISTAURATYPE = 469, - LANG_COMMAND_TARGET_AURASIMPLE = 470, - - LANG_COMMAND_QUEST_NOTFOUND = 471, - LANG_COMMAND_QUEST_STARTFROMITEM = 472, - LANG_COMMAND_QUEST_REMOVED = 473, - LANG_COMMAND_QUEST_REWARDED = 474, - LANG_COMMAND_QUEST_COMPLETE = 475, - LANG_COMMAND_QUEST_ACTIVE = 476, - - LANG_COMMAND_FLYMODE_STATUS = 477, - - LANG_COMMAND_OPCODESENT = 478, - - LANG_COMMAND_IMPORT_SUCCESS = 479, - LANG_COMMAND_IMPORT_FAILED = 480, - LANG_COMMAND_EXPORT_SUCCESS = 481, - LANG_COMMAND_EXPORT_FAILED = 482, - - LANG_COMMAND_SPELL_BROKEN = 483, - - LANG_SET_SKILL = 484, - LANG_SET_SKILL_ERROR = 485, - - LANG_INVALID_SKILL_ID = 486, - LANG_LEARNING_GM_SKILLS = 487, - LANG_YOU_KNOWN_SPELL = 488, - LANG_TARGET_KNOWN_SPELL = 489, - LANG_UNKNOWN_SPELL = 490, - LANG_FORGET_SPELL = 491, - LANG_REMOVEALL_COOLDOWN = 492, - LANG_REMOVE_COOLDOWN = 493, - - LANG_ADDITEM = 494, //log - LANG_ADDITEMSET = 495, //log - LANG_REMOVEITEM = 496, - LANG_ITEM_CANNOT_CREATE = 497, - LANG_INSERT_GUILD_NAME = 498, - LANG_PLAYER_NOT_FOUND = 499, - LANG_PLAYER_IN_GUILD = 500, - LANG_GUILD_NOT_CREATED = 501, - LANG_NO_ITEMS_FROM_ITEMSET_FOUND = 502, - - LANG_DISTANCE = 503, - - LANG_ITEM_SLOT = 504, - LANG_ITEM_SLOT_NOT_EXIST = 505, - LANG_ITEM_ADDED_TO_SLOT = 506, - LANG_ITEM_SAVE_FAILED = 507, - LANG_ITEMLIST_SLOT = 508, - LANG_ITEMLIST_MAIL = 509, - LANG_ITEMLIST_AUCTION = 510, - - LANG_WRONG_LINK_TYPE = 511, - LANG_ITEM_LIST = 512, - LANG_QUEST_LIST = 513, - LANG_CREATURE_ENTRY_LIST = 514, - LANG_CREATURE_LIST = 515, - LANG_GO_ENTRY_LIST = 516, - LANG_GO_LIST = 517, - LANG_ITEMSET_LIST = 518, - LANG_TELE_LIST = 519, - LANG_SPELL_LIST = 520, - LANG_SKILL_LIST = 521, - - LANG_GAMEOBJECT_NOT_EXIST = 522, - - LANG_GAMEOBJECT_CURRENT = 523, //log - LANG_GAMEOBJECT_DETAIL = 524, - LANG_GAMEOBJECT_ADD = 525, - - LANG_MOVEGENS_LIST = 526, - LANG_MOVEGENS_IDLE = 527, - LANG_MOVEGENS_RANDOM = 528, - LANG_MOVEGENS_WAYPOINT = 529, - LANG_MOVEGENS_ANIMAL_RANDOM = 530, - LANG_MOVEGENS_CONFUSED = 531, - LANG_MOVEGENS_TARGETED_PLAYER = 532, - LANG_MOVEGENS_TARGETED_CREATURE = 533, - LANG_MOVEGENS_TARGETED_NULL = 534, - LANG_MOVEGENS_HOME_CREATURE = 535, - LANG_MOVEGENS_HOME_PLAYER = 536, - LANG_MOVEGENS_FLIGHT = 537, - LANG_MOVEGENS_UNKNOWN = 538, - - LANG_NPCINFO_CHAR = 539, - LANG_NPCINFO_LEVEL = 540, - LANG_NPCINFO_HEALTH = 541, - LANG_NPCINFO_FLAGS = 542, - LANG_NPCINFO_LOOT = 543, - LANG_NPCINFO_POSITION = 544, - LANG_NPCINFO_VENDOR = 545, - LANG_NPCINFO_TRAINER = 546, - LANG_NPCINFO_DUNGEON_ID = 547, - - LANG_PINFO_ACCOUNT = 548, - LANG_PINFO_LEVEL = 549, - LANG_PINFO_NO_REP = 550, - - LANG_YOU_SET_EXPLORE_ALL = 551, - LANG_YOU_SET_EXPLORE_NOTHING = 552, - LANG_YOURS_EXPLORE_SET_ALL = 553, - LANG_YOURS_EXPLORE_SET_NOTHING = 554, - - LANG_HOVER_ENABLED = 555, - LANG_HOVER_DISABLED = 556, - LANG_YOURS_LEVEL_UP = 557, - LANG_YOURS_LEVEL_DOWN = 558, - LANG_YOURS_LEVEL_PROGRESS_RESET = 559, - LANG_EXPLORE_AREA = 560, - LANG_UNEXPLORE_AREA = 561, - - LANG_UPDATE = 562, - LANG_UPDATE_CHANGE = 563, - LANG_TOO_BIG_INDEX = 564, - LANG_SET_UINT = 565, //log - LANG_SET_UINT_FIELD = 566, - LANG_SET_FLOAT = 567, //log - LANG_SET_FLOAT_FIELD = 568, - LANG_GET_UINT = 569, //log - LANG_GET_UINT_FIELD = 570, - LANG_GET_FLOAT = 571, //log - LANG_GET_FLOAT_FIELD = 572, - LANG_SET_32BIT = 573, //log - LANG_SET_32BIT_FIELD = 574, - LANG_CHANGE_32BIT = 575, //log - LANG_CHANGE_32BIT_FIELD = 576, - - LANG_INVISIBLE_INVISIBLE = 577, - LANG_INVISIBLE_VISIBLE = 578, - LANG_SELECTED_TARGET_NOT_HAVE_VICTIM = 579, - - LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST = 580, - LANG_COMMAND_NEAROBJMESSAGE = 581, - LANG_COMMAND_RAWPAWNTIMES = 582, - - LANG_EVENT_ENTRY_LIST = 583, - LANG_NOEVENTFOUND = 584, - LANG_EVENT_NOT_EXIST = 585, - LANG_EVENT_INFO = 586, - LANG_EVENT_ALREADY_ACTIVE = 587, - LANG_EVENT_NOT_ACTIVE = 588, - - LANG_MOVEGENS_POINT = 589, - LANG_MOVEGENS_FEAR = 590, - LANG_MOVEGENS_DISTRACT = 591, - - LANG_COMMAND_LEARN_ALL_RECIPES = 592, - - // Battleground - LANG_BG_A_WINS = 600, - LANG_BG_H_WINS = 601, - LANG_BG_WS_ONE_MINUTE = 602, - LANG_BG_WS_HALF_MINUTE = 603, - LANG_BG_WS_BEGIN = 604, - - LANG_BG_WS_CAPTURED_HF = 605, - LANG_BG_WS_CAPTURED_AF = 606, - LANG_BG_WS_DROPPED_HF = 607, - LANG_BG_WS_DROPPED_AF = 608, - LANG_BG_WS_RETURNED_AF = 609, - LANG_BG_WS_RETURNED_HF = 610, - LANG_BG_WS_PICKEDUP_HF = 611, - LANG_BG_WS_PICKEDUP_AF = 612, - LANG_BG_WS_F_PLACED = 613, - LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED = 614, - LANG_BG_WS_HORDE_FLAG_RESPAWNED = 615, - - LANG_BG_EY_ONE_MINUTE = 636, - LANG_BG_EY_HALF_MINUTE = 637, - LANG_BG_EY_BEGIN = 638, - - LANG_BG_AB_ALLY = 650, - LANG_BG_AB_HORDE = 651, - LANG_BG_AB_NODE_STABLES = 652, - LANG_BG_AB_NODE_BLACKSMITH = 653, - LANG_BG_AB_NODE_FARM = 654, - LANG_BG_AB_NODE_LUMBER_MILL = 655, - LANG_BG_AB_NODE_GOLD_MINE = 656, - LANG_BG_AB_NODE_TAKEN = 657, - LANG_BG_AB_NODE_DEFENDED = 658, - LANG_BG_AB_NODE_ASSAULTED = 659, - LANG_BG_AB_NODE_CLAIMED = 660, - LANG_BG_AB_ONEMINTOSTART = 661, - LANG_BG_AB_HALFMINTOSTART = 662, - LANG_BG_AB_STARTED = 663, - LANG_BG_AB_A_NEAR_VICTORY = 664, - LANG_BG_AB_H_NEAR_VICTORY = 665, - LANG_BG_MARK_BY_MAIL = 666, - - LANG_BG_EY_HAS_TAKEN_A_M_TOWER = 667, - LANG_BG_EY_HAS_TAKEN_H_M_TOWER = 668, - LANG_BG_EY_HAS_TAKEN_A_D_RUINS = 669, - LANG_BG_EY_HAS_TAKEN_H_D_RUINS = 670, - LANG_BG_EY_HAS_TAKEN_A_B_TOWER = 671, - LANG_BG_EY_HAS_TAKEN_H_B_TOWER = 672, - LANG_BG_EY_HAS_TAKEN_A_F_RUINS = 673, - LANG_BG_EY_HAS_TAKEN_H_F_RUINS = 674, - LANG_BG_EY_HAS_LOST_A_M_TOWER = 675, - LANG_BG_EY_HAS_LOST_H_M_TOWER = 676, - LANG_BG_EY_HAS_LOST_A_D_RUINS = 677, - LANG_BG_EY_HAS_LOST_H_D_RUINS = 678, - LANG_BG_EY_HAS_LOST_A_B_TOWER = 679, - LANG_BG_EY_HAS_LOST_H_B_TOWER = 680, - LANG_BG_EY_HAS_LOST_A_F_RUINS = 681, - LANG_BG_EY_HAS_LOST_H_F_RUINS = 682, - LANG_BG_EY_HAS_TAKEN_FLAG = 683, - LANG_BG_EY_CAPTURED_FLAG_A = 684, - LANG_BG_EY_CAPTURED_FLAG_H = 685, - LANG_BG_EY_DROPPED_FLAG = 686, - LANG_BG_EY_RESETED_FLAG = 687, - - LANG_ARENA_ONE_TOOLOW = 700, - LANG_ARENA_ONE_MINUTE = 701, - LANG_ARENA_THIRTY_SECONDS = 702, - LANG_ARENA_FIFTEEN_SECONDS = 703, - LANG_ARENA_BEGUN = 704, - - LANG_WAIT_BEFORE_SPEAKING = 705, - LANG_NOT_EQUIPPED_ITEM = 706, - LANG_PLAYER_DND = 707, - LANG_PLAYER_AFK = 708, - LANG_PLAYER_DND_DEFAULT = 709, - LANG_PLAYER_AFK_DEFAULT = 710, - - LANG_BG_QUEUE_ANNOUNCE_SELF = 711, - LANG_BG_QUEUE_ANNOUNCE_WORLD = 712, -}; -#endif - -/* NOT USED VALUES -// alliance ranks -#define LANG_ALI_PRIVATE "Private " -#define LANG_ALI_CORPORAL "Corporal " -#define LANG_ALI_SERGEANT "Sergeant " -#define LANG_ALI_MASTER_SERGEANT "Master Sergeant " -#define LANG_ALI_SERGEANT_MAJOR "Sergeant Major " -#define LANG_ALI_KNIGHT "Knight " -#define LANG_ALI_KNIGHT_LIEUTENANT "Knight-Lieutenant " -#define LANG_ALI_KNIGHT_CAPTAIN "Knight-Captain " -#define LANG_ALI_KNIGHT_CHAMPION "Knight-Champion " -#define LANG_ALI_LIEUTENANT_COMMANDER "Lieutenant Commander " -#define LANG_ALI_COMMANDER "Commander " -#define LANG_ALI_MARSHAL "Marshal " -#define LANG_ALI_FIELD_MARSHAL "Field Marshal " -#define LANG_ALI_GRAND_MARSHAL "Grand Marshal " -#define LANG_ALI_GAME_MASTER "Game Master " - -// horde ranks -#define LANG_HRD_SCOUT "Scout " -#define LANG_HRD_GRUNT "Grunt " -#define LANG_HRD_SERGEANT "Sergeant " -#define LANG_HRD_SENIOR_SERGEANT "Senior Sergeant " -#define LANG_HRD_FIRST_SERGEANT "First Sergeant " -#define LANG_HRD_STONE_GUARD "Stone Guard " -#define LANG_HRD_BLOOD_GUARD "Blood Guard " -#define LANG_HRD_LEGIONNARE "Legionnaire " -#define LANG_HRD_CENTURION "Centurion " -#define LANG_HRD_CHAMPION "Champion " -#define LANG_HRD_LIEUTENANT_GENERAL "Lieutenant General " -#define LANG_HRD_GENERAL "General " -#define LANG_HRD_WARLORD "Warlord " -#define LANG_HRD_HIGH_WARLORD "High Warlord " -#define LANG_HRD_GAME_MASTER "Game Master " - -#define LANG_NO_RANK "No rank " -#define LANG_RANK "%s (Rank %u)" -#define LANG_HONOR_TODAY "Today: [Honorable kills: |c0000ff00%u|r] [Dishonorable kills: |c00ff0000%u|r]" -#define LANG_HONOR_YESTERDAY "Yesterday: [Kills: |c0000ff00%u|r] [Honor: %u]" -#define LANG_HONOR_THIS_WEEK "This week: [Kills: |c0000ff00%u|r] [Honor: %u]" -#define LANG_HONOR_LAST_WEEK "Last week: [Kills: |c0000ff00%u|r] [Honor: %u] [Standing: %u]" -#define LANG_HONOR_LIFE "Lifetime: [Honorable kills: |c0000ff00%u|r] [Dishonorable kills: |c00ff0000%u|r] [Highest rank %u: %s]" - -// level 2 -#define LANG_ADD_OBJ "AddObject at Chat.cpp" //log -#define LANG_DEMORPHED "Demorphed %s" //log - -// level 3 -#define LANG_SPAWNING_SPIRIT_HEAL "Spawning spirit healers\n" -#define LANG_NO_SPIRIT_HEAL_DB "No spirit healers in database, exiting." - -#define LANG_ADD_OBJ_LV3 "AddObject at Level3.cpp line 1176" - -*/ +/* + * Copyright (C) 2005-2008 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 __MANGOS_LANGUAGE_H +#define __MANGOS_LANGUAGE_H + +enum MangosStrings +{ + // for chat commands + LANG_SELECT_CHAR_OR_CREATURE = 1, + LANG_SELECT_CREATURE = 2, + + // level 0 chat + LANG_SYSTEMMESSAGE = 3, + LANG_EVENTMESSAGE = 4, + LANG_NO_HELP_CMD = 5, + LANG_NO_CMD = 6, + LANG_NO_SUBCMD = 7, + LANG_SUBCMDS_LIST = 8, + LANG_AVIABLE_CMD = 9, + LANG_CMD_SYNTAX = 10, + LANG_ACCOUNT_LEVEL = 11, + LANG_CONNECTED_USERS = 12, + LANG_UPTIME = 13, + LANG_PLAYER_SAVED = 14, + LANG_PLAYERS_SAVED = 15, + LANG_GMS_ON_SRV = 16, + LANG_GMS_NOT_LOGGED = 17, + LANG_YOU_IN_FLIGHT = 18, + //LANG_YOU_IN_BATTLEGROUND = 19, not used + //LANG_TARGET_IN_FLIGHT = 20, not used + LANG_CHAR_IN_FLIGHT = 21, + LANG_CHAR_NON_MOUNTED = 22, + LANG_YOU_IN_COMBAT = 23, + LANG_YOU_USED_IT_RECENTLY = 24, + LANG_COMMAND_NOTCHANGEPASSWORD = 25, + LANG_COMMAND_PASSWORD = 26, + LANG_COMMAND_WRONGOLDPASSWORD = 27, + LANG_COMMAND_ACCLOCKLOCKED = 28, + LANG_COMMAND_ACCLOCKUNLOCKED = 29, + LANG_SPELL_RANK = 30, + LANG_KNOWN = 31, + LANG_LEARN = 32, + LANG_PASSIVE = 33, + LANG_TALENT = 34, + LANG_ACTIVE = 35, + LANG_COMPLETE = 36, + LANG_OFFLINE = 37, + LANG_ON = 38, + LANG_OFF = 39, + LANG_YOU_ARE = 40, + LANG_VISIBLE = 41, + LANG_INVISIBLE = 42, + LANG_DONE = 43, + LANG_YOU = 44, + LANG_UNKNOWN = 45, + LANG_ERROR = 46, + LANG_NON_EXIST_CHARACTER = 47, + LANG_FRIEND_IGNORE_UNKNOWN = 48, + LANG_LEVEL_MINREQUIRED = 49, + LANG_LEVEL_MINREQUIRED_AND_ITEM = 50, + LANG_NPC_TAINER_HELLO = 51, + // Room for more level 0 + + // level 1 chat + LANG_GLOBAL_NOTIFY = 100, + LANG_MAP_POSITION = 101, + LANG_IS_TELEPORTED = 102, + LANG_CANNOT_SUMMON_TO_INST = 103, + LANG_CANNOT_GO_TO_INST_PARTY = 104, + LANG_CANNOT_GO_TO_INST_GM = 105, + LANG_CANNOT_GO_INST_INST = 106, + LANG_CANNOT_SUMMON_INST_INST = 107, + + LANG_SUMMONING = 108, + LANG_SUMMONED_BY = 109, + LANG_TELEPORTING_TO = 110, + LANG_TELEPORTED_TO_BY = 111, + LANG_NO_PLAYER = 112, + LANG_APPEARING_AT = 113, + LANG_APPEARING_TO = 114, + + LANG_BAD_VALUE = 115, + LANG_NO_CHAR_SELECTED = 116, + LANG_NOT_IN_GROUP = 117, + + LANG_YOU_CHANGE_HP = 118, + LANG_YOURS_HP_CHANGED = 119, + LANG_YOU_CHANGE_MANA = 120, + LANG_YOURS_MANA_CHANGED = 121, + LANG_YOU_CHANGE_ENERGY = 122, + LANG_YOURS_ENERGY_CHANGED = 123, + + LANG_CURRENT_ENERGY = 124, //log + LANG_YOU_CHANGE_RAGE = 125, + LANG_YOURS_RAGE_CHANGED = 126, + LANG_YOU_CHANGE_LVL = 127, + LANG_CURRENT_FACTION = 128, + LANG_WRONG_FACTION = 129, + LANG_YOU_CHANGE_FACTION = 130, + LANG_YOU_CHANGE_SPELLFLATID = 131, + LANG_YOURS_SPELLFLATID_CHANGED = 132, + LANG_YOU_GIVE_TAXIS = 133, + LANG_YOU_REMOVE_TAXIS = 134, + LANG_YOURS_TAXIS_ADDED = 135, + LANG_YOURS_TAXIS_REMOVED = 136, + + LANG_YOU_CHANGE_ASPEED = 137, + LANG_YOURS_ASPEED_CHANGED = 138, + LANG_YOU_CHANGE_SPEED = 139, + LANG_YOURS_SPEED_CHANGED = 140, + LANG_YOU_CHANGE_SWIM_SPEED = 141, + LANG_YOURS_SWIM_SPEED_CHANGED = 142, + LANG_YOU_CHANGE_BACK_SPEED = 143, + LANG_YOURS_BACK_SPEED_CHANGED = 144, + LANG_YOU_CHANGE_FLY_SPEED = 145, + LANG_YOURS_FLY_SPEED_CHANGED = 146, + + LANG_YOU_CHANGE_SIZE = 147, + LANG_YOURS_SIZE_CHANGED = 148, + LANG_NO_MOUNT = 149, + LANG_YOU_GIVE_MOUNT = 150, + LANG_MOUNT_GIVED = 151, + + LANG_CURRENT_MONEY = 152, + LANG_YOU_TAKE_ALL_MONEY = 153, + LANG_YOURS_ALL_MONEY_GONE = 154, + LANG_YOU_TAKE_MONEY = 155, + LANG_YOURS_MONEY_TAKEN = 156, + LANG_YOU_GIVE_MONEY = 157, + LANG_YOURS_MONEY_GIVEN = 158, + LANG_YOU_HEAR_SOUND = 159, + + LANG_NEW_MONEY = 160, // Log + + LANG_REMOVE_BIT = 161, + LANG_SET_BIT = 162, + LANG_COMMAND_TELE_TABLEEMPTY = 163, + LANG_COMMAND_TELE_NOTFOUND = 164, + LANG_COMMAND_TELE_PARAMETER = 165, + LANG_COMMAND_TELE_NOLOCATION = 166, + // 167 // not used + LANG_COMMAND_TELE_LOCATION = 168, + + LANG_MAIL_SENT = 169, + LANG_SOUND_NOT_EXIST = 170, + // Room for more level 1 + + // level 2 chat + LANG_NO_SELECTION = 200, + LANG_OBJECT_GUID = 201, + LANG_TOO_LONG_NAME = 202, + LANG_CHARS_ONLY = 203, + LANG_TOO_LONG_SUBNAME = 204, + LANG_NOT_IMPLEMENTED = 205, + + LANG_ITEM_ADDED_TO_LIST = 206, + LANG_ITEM_NOT_FOUND = 207, + LANG_ITEM_DELETED_FROM_LIST = 208, + LANG_ITEM_NOT_IN_LIST = 209, + LANG_ITEM_ALREADY_IN_LIST = 210, + + LANG_RESET_SPELLS_ONLINE = 211, + LANG_RESET_SPELLS_OFFLINE = 212, + LANG_RESET_TALENTS_ONLINE = 213, + LANG_RESET_TALENTS_OFFLINE = 214, + LANG_RESET_SPELLS = 215, + LANG_RESET_TALENTS = 216, + + LANG_RESETALL_UNKNOWN_CASE = 217, + LANG_RESETALL_SPELLS = 218, + LANG_RESETALL_TALENTS = 219, + + LANG_WAYPOINT_NOTFOUND = 220, + LANG_WAYPOINT_NOTFOUNDLAST = 221, + LANG_WAYPOINT_NOTFOUNDSEARCH = 222, + LANG_WAYPOINT_NOTFOUNDDBPROBLEM = 223, + LANG_WAYPOINT_CREATSELECTED = 224, + LANG_WAYPOINT_CREATNOTFOUND = 225, + LANG_WAYPOINT_VP_SELECT = 226, + LANG_WAYPOINT_VP_NOTFOUND = 227, + LANG_WAYPOINT_VP_NOTCREATED = 228, + LANG_WAYPOINT_VP_ALLREMOVED = 229, + LANG_WAYPOINT_NOTCREATED = 230, + LANG_WAYPOINT_NOGUID = 231, + LANG_WAYPOINT_NOWAYPOINTGIVEN = 232, + LANG_WAYPOINT_ARGUMENTREQ = 233, + LANG_WAYPOINT_ADDED = 234, + LANG_WAYPOINT_ADDED_NO = 235, + LANG_WAYPOINT_CHANGED = 236, + LANG_WAYPOINT_CHANGED_NO = 237, + LANG_WAYPOINT_EXPORTED = 238, + LANG_WAYPOINT_NOTHINGTOEXPORT = 239, + LANG_WAYPOINT_IMPORTED = 240, + LANG_WAYPOINT_REMOVED = 241, + LANG_WAYPOINT_NOTREMOVED = 242, + LANG_WAYPOINT_TOOFAR1 = 243, + LANG_WAYPOINT_TOOFAR2 = 244, + LANG_WAYPOINT_TOOFAR3 = 245, + LANG_WAYPOINT_INFO_TITLE = 246, + LANG_WAYPOINT_INFO_WAITTIME = 247, + LANG_WAYPOINT_INFO_MODEL = 248, + LANG_WAYPOINT_INFO_EMOTE = 249, + LANG_WAYPOINT_INFO_SPELL = 250, + LANG_WAYPOINT_INFO_TEXT = 251, + LANG_WAYPOINT_INFO_AISCRIPT = 252, + + LANG_RENAME_PLAYER = 253, + LANG_RENAME_PLAYER_GUID = 254, + + LANG_WAYPOINT_WPCREATNOTFOUND = 255, + LANG_WAYPOINT_NPCNOTFOUND = 256, + + LANG_MOVE_TYPE_SET = 257, + LANG_MOVE_TYPE_SET_NODEL = 258, + LANG_USE_BOL = 259, + LANG_VALUE_SAVED = 260, + LANG_VALUE_SAVED_REJOIN = 261, + + LANG_COMMAND_GOAREATRNOTFOUND = 262, + LANG_INVALID_TARGET_COORD = 263, + LANG_INVALID_ZONE_COORD = 264, + LANG_INVALID_ZONE_MAP = 265, + LANG_COMMAND_TARGETOBJNOTFOUND = 266, + LANG_COMMAND_GOOBJNOTFOUND = 267, + LANG_COMMAND_GOCREATNOTFOUND = 268, + LANG_COMMAND_GOCREATMULTIPLE = 269, + LANG_COMMAND_DELCREATMESSAGE = 270, + LANG_COMMAND_CREATUREMOVED = 271, + LANG_COMMAND_CREATUREATSAMEMAP = 272, + LANG_COMMAND_OBJNOTFOUND = 273, + LANG_COMMAND_DELOBJREFERCREATURE = 274, + LANG_COMMAND_DELOBJMESSAGE = 275, + LANG_COMMAND_TURNOBJMESSAGE = 276, + LANG_COMMAND_MOVEOBJMESSAGE = 277, + LANG_COMMAND_VENDORSELECTION = 278, + LANG_COMMAND_NEEDITEMSEND = 279, + LANG_COMMAND_ADDVENDORITEMITEMS = 280, + LANG_COMMAND_KICKSELF = 281, + LANG_COMMAND_KICKMESSAGE = 282, + LANG_COMMAND_KICKNOTFOUNDPLAYER = 283, + LANG_COMMAND_WHISPERACCEPTING = 284, + LANG_COMMAND_WHISPERON = 285, + LANG_COMMAND_WHISPEROFF = 286, + LANG_COMMAND_CREATGUIDNOTFOUND = 287, + LANG_COMMAND_TICKETCOUNT = 288, + LANG_COMMAND_TICKETNEW = 289, + LANG_COMMAND_TICKETVIEW = 290, + LANG_COMMAND_TICKETON = 291, + LANG_COMMAND_TICKETOFF = 292, + LANG_COMMAND_TICKENOTEXIST = 293, + LANG_COMMAND_ALLTICKETDELETED = 294, + LANG_COMMAND_TICKETPLAYERDEL = 295, + LANG_COMMAND_TICKETDEL = 296, + LANG_COMMAND_SPAWNDIST = 297, + LANG_COMMAND_SPAWNTIME = 298, + LANG_COMMAND_MODIFY_HONOR = 299, + + LANG_YOUR_CHAT_DISABLED = 300, + LANG_YOU_DISABLE_CHAT = 301, + LANG_CHAT_ALREADY_ENABLED = 302, + LANG_YOUR_CHAT_ENABLED = 303, + LANG_YOU_ENABLE_CHAT = 304, + + LANG_COMMAND_MODIFY_REP = 305, + LANG_COMMAND_MODIFY_ARENA = 306, + LANG_COMMAND_FACTION_NOTFOUND = 307, + LANG_COMMAND_FACTION_UNKNOWN = 308, + LANG_COMMAND_FACTION_INVPARAM = 309, + LANG_COMMAND_FACTION_DELTA = 310, + LANG_FACTION_LIST = 311, + LANG_FACTION_VISIBLE = 312, + LANG_FACTION_ATWAR = 313, + LANG_FACTION_PEACE_FORCED = 314, + LANG_FACTION_HIDDEN = 315, + LANG_FACTION_INVISIBLE_FORCED = 316, + LANG_FACTION_INACTIVE = 317, + LANG_REP_HATED = 318, + LANG_REP_HOSTILE = 319, + LANG_REP_UNFRIENDLY = 320, + LANG_REP_NEUTRAL = 321, + LANG_REP_FRIENDLY = 322, + LANG_REP_HONORED = 323, + LANG_REP_REVERED = 324, + LANG_REP_EXALTED = 325, + LANG_COMMAND_FACTION_NOREP_ERROR = 326, + LANG_FACTION_NOREPUTATION = 327, + LANG_LOOKUP_PLAYER_ACCOUNT = 328, + LANG_LOOKUP_PLAYER_CHARACTER = 329, + LANG_NO_PLAYERS_FOUND = 330, + + // Room for more level 2 + + // level 3 chat + LANG_SCRIPTS_RELOADED = 400, + LANG_YOU_CHANGE_SECURITY = 401, + LANG_YOURS_SECURITY_CHANGED = 402, + LANG_YOURS_SECURITY_IS_LOW = 403, + LANG_CREATURE_MOVE_DISABLED = 404, + LANG_CREATURE_MOVE_ENABLED = 405, + LANG_NO_WEATHER = 406, + LANG_WEATHER_DISABLED = 407, + + LANG_BAN_YOUBANNED = 408, + LANG_BAN_YOUPERMBANNED = 409, + LANG_BAN_NOTFOUND = 410, + + LANG_UNBAN_UNBANNED = 411, + LANG_UNBAN_ERROR = 412, + + LANG_BANINFO_NOACCOUNT = 413, + LANG_BANINFO_NOCHARACTER = 414, + LANG_BANINFO_NOIP = 415, + LANG_BANINFO_NOACCOUNTBAN = 416, + LANG_BANINFO_BANHISTORY = 417, + LANG_BANINFO_HISTORYENTRY = 418, + LANG_BANINFO_INFINITE = 419, + LANG_BANINFO_NEVER = 420, + LANG_BANINFO_YES = 421, + LANG_BANINFO_NO = 422, + LANG_BANINFO_IPENTRY = 423, + + LANG_BANLIST_NOIP = 424, + LANG_BANLIST_NOACCOUNT = 425, + LANG_BANLIST_NOCHARACTER = 426, + LANG_BANLIST_MATCHINGIP = 427, + LANG_BANLIST_MATCHINGACCOUNT = 428, + + LANG_COMMAND_LEARN_MANY_SPELLS = 429, + LANG_COMMAND_LEARN_CLASS_SPELLS = 430, + LANG_COMMAND_LEARN_CLASS_TALENTS = 431, + LANG_COMMAND_LEARN_ALL_LANG = 432, + LANG_COMMAND_LEARN_ALL_CRAFT = 433, + LANG_COMMAND_COULDNOTFIND = 434, + LANG_COMMAND_ITEMIDINVALID = 435, + LANG_COMMAND_NOITEMFOUND = 436, + LANG_COMMAND_LISTOBJINVALIDID = 437, + LANG_COMMAND_LISTITEMMESSAGE = 438, + LANG_COMMAND_LISTOBJMESSAGE = 439, + LANG_COMMAND_INVALIDCREATUREID = 440, + LANG_COMMAND_LISTCREATUREMESSAGE = 441, + LANG_COMMAND_NOAREAFOUND = 442, + LANG_COMMAND_NOITEMSETFOUND = 443, + LANG_COMMAND_NOSKILLFOUND = 444, + LANG_COMMAND_NOSPELLFOUND = 445, + LANG_COMMAND_NOQUESTFOUND = 446, + LANG_COMMAND_NOCREATUREFOUND = 447, + LANG_COMMAND_NOGAMEOBJECTFOUND = 448, + LANG_COMMAND_GRAVEYARDNOEXIST = 449, + LANG_COMMAND_GRAVEYARDALRLINKED = 450, + LANG_COMMAND_GRAVEYARDLINKED = 451, + LANG_COMMAND_GRAVEYARDWRONGZONE = 452, + LANG_COMMAND_GRAVEYARDWRONGTEAM = 453, + LANG_COMMAND_GRAVEYARDERROR = 454, + LANG_COMMAND_GRAVEYARD_NOTEAM = 455, + LANG_COMMAND_GRAVEYARD_ANY = 456, + LANG_COMMAND_GRAVEYARD_ALLIANCE = 457, + LANG_COMMAND_GRAVEYARD_HORDE = 458, + LANG_COMMAND_GRAVEYARDNEAREST = 459, + LANG_COMMAND_ZONENOGRAVEYARDS = 460, + LANG_COMMAND_ZONENOGRAFACTION = 461, + LANG_COMMAND_TP_ALREADYEXIST = 462, + LANG_COMMAND_TP_ADDED = 463, + LANG_COMMAND_TP_ADDEDERR = 464, + LANG_COMMAND_TP_DELETED = 465, + // 466, // not used + + LANG_COMMAND_TARGET_LISTAURAS = 467, + LANG_COMMAND_TARGET_AURADETAIL = 468, + LANG_COMMAND_TARGET_LISTAURATYPE = 469, + LANG_COMMAND_TARGET_AURASIMPLE = 470, + + LANG_COMMAND_QUEST_NOTFOUND = 471, + LANG_COMMAND_QUEST_STARTFROMITEM = 472, + LANG_COMMAND_QUEST_REMOVED = 473, + LANG_COMMAND_QUEST_REWARDED = 474, + LANG_COMMAND_QUEST_COMPLETE = 475, + LANG_COMMAND_QUEST_ACTIVE = 476, + + LANG_COMMAND_FLYMODE_STATUS = 477, + + LANG_COMMAND_OPCODESENT = 478, + + LANG_COMMAND_IMPORT_SUCCESS = 479, + LANG_COMMAND_IMPORT_FAILED = 480, + LANG_COMMAND_EXPORT_SUCCESS = 481, + LANG_COMMAND_EXPORT_FAILED = 482, + + LANG_COMMAND_SPELL_BROKEN = 483, + + LANG_SET_SKILL = 484, + LANG_SET_SKILL_ERROR = 485, + + LANG_INVALID_SKILL_ID = 486, + LANG_LEARNING_GM_SKILLS = 487, + LANG_YOU_KNOWN_SPELL = 488, + LANG_TARGET_KNOWN_SPELL = 489, + LANG_UNKNOWN_SPELL = 490, + LANG_FORGET_SPELL = 491, + LANG_REMOVEALL_COOLDOWN = 492, + LANG_REMOVE_COOLDOWN = 493, + + LANG_ADDITEM = 494, //log + LANG_ADDITEMSET = 495, //log + LANG_REMOVEITEM = 496, + LANG_ITEM_CANNOT_CREATE = 497, + LANG_INSERT_GUILD_NAME = 498, + LANG_PLAYER_NOT_FOUND = 499, + LANG_PLAYER_IN_GUILD = 500, + LANG_GUILD_NOT_CREATED = 501, + LANG_NO_ITEMS_FROM_ITEMSET_FOUND = 502, + + LANG_DISTANCE = 503, + + LANG_ITEM_SLOT = 504, + LANG_ITEM_SLOT_NOT_EXIST = 505, + LANG_ITEM_ADDED_TO_SLOT = 506, + LANG_ITEM_SAVE_FAILED = 507, + LANG_ITEMLIST_SLOT = 508, + LANG_ITEMLIST_MAIL = 509, + LANG_ITEMLIST_AUCTION = 510, + + LANG_WRONG_LINK_TYPE = 511, + LANG_ITEM_LIST = 512, + LANG_QUEST_LIST = 513, + LANG_CREATURE_ENTRY_LIST = 514, + LANG_CREATURE_LIST = 515, + LANG_GO_ENTRY_LIST = 516, + LANG_GO_LIST = 517, + LANG_ITEMSET_LIST = 518, + LANG_TELE_LIST = 519, + LANG_SPELL_LIST = 520, + LANG_SKILL_LIST = 521, + + LANG_GAMEOBJECT_NOT_EXIST = 522, + + LANG_GAMEOBJECT_CURRENT = 523, //log + LANG_GAMEOBJECT_DETAIL = 524, + LANG_GAMEOBJECT_ADD = 525, + + LANG_MOVEGENS_LIST = 526, + LANG_MOVEGENS_IDLE = 527, + LANG_MOVEGENS_RANDOM = 528, + LANG_MOVEGENS_WAYPOINT = 529, + LANG_MOVEGENS_ANIMAL_RANDOM = 530, + LANG_MOVEGENS_CONFUSED = 531, + LANG_MOVEGENS_TARGETED_PLAYER = 532, + LANG_MOVEGENS_TARGETED_CREATURE = 533, + LANG_MOVEGENS_TARGETED_NULL = 534, + LANG_MOVEGENS_HOME_CREATURE = 535, + LANG_MOVEGENS_HOME_PLAYER = 536, + LANG_MOVEGENS_FLIGHT = 537, + LANG_MOVEGENS_UNKNOWN = 538, + + LANG_NPCINFO_CHAR = 539, + LANG_NPCINFO_LEVEL = 540, + LANG_NPCINFO_HEALTH = 541, + LANG_NPCINFO_FLAGS = 542, + LANG_NPCINFO_LOOT = 543, + LANG_NPCINFO_POSITION = 544, + LANG_NPCINFO_VENDOR = 545, + LANG_NPCINFO_TRAINER = 546, + LANG_NPCINFO_DUNGEON_ID = 547, + + LANG_PINFO_ACCOUNT = 548, + LANG_PINFO_LEVEL = 549, + LANG_PINFO_NO_REP = 550, + + LANG_YOU_SET_EXPLORE_ALL = 551, + LANG_YOU_SET_EXPLORE_NOTHING = 552, + LANG_YOURS_EXPLORE_SET_ALL = 553, + LANG_YOURS_EXPLORE_SET_NOTHING = 554, + + LANG_HOVER_ENABLED = 555, + LANG_HOVER_DISABLED = 556, + LANG_YOURS_LEVEL_UP = 557, + LANG_YOURS_LEVEL_DOWN = 558, + LANG_YOURS_LEVEL_PROGRESS_RESET = 559, + LANG_EXPLORE_AREA = 560, + LANG_UNEXPLORE_AREA = 561, + + LANG_UPDATE = 562, + LANG_UPDATE_CHANGE = 563, + LANG_TOO_BIG_INDEX = 564, + LANG_SET_UINT = 565, //log + LANG_SET_UINT_FIELD = 566, + LANG_SET_FLOAT = 567, //log + LANG_SET_FLOAT_FIELD = 568, + LANG_GET_UINT = 569, //log + LANG_GET_UINT_FIELD = 570, + LANG_GET_FLOAT = 571, //log + LANG_GET_FLOAT_FIELD = 572, + LANG_SET_32BIT = 573, //log + LANG_SET_32BIT_FIELD = 574, + LANG_CHANGE_32BIT = 575, //log + LANG_CHANGE_32BIT_FIELD = 576, + + LANG_INVISIBLE_INVISIBLE = 577, + LANG_INVISIBLE_VISIBLE = 578, + LANG_SELECTED_TARGET_NOT_HAVE_VICTIM = 579, + + LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST = 580, + LANG_COMMAND_NEAROBJMESSAGE = 581, + LANG_COMMAND_RAWPAWNTIMES = 582, + + LANG_EVENT_ENTRY_LIST = 583, + LANG_NOEVENTFOUND = 584, + LANG_EVENT_NOT_EXIST = 585, + LANG_EVENT_INFO = 586, + LANG_EVENT_ALREADY_ACTIVE = 587, + LANG_EVENT_NOT_ACTIVE = 588, + + LANG_MOVEGENS_POINT = 589, + LANG_MOVEGENS_FEAR = 590, + LANG_MOVEGENS_DISTRACT = 591, + + LANG_COMMAND_LEARN_ALL_RECIPES = 592, + + // Battleground + LANG_BG_A_WINS = 600, + LANG_BG_H_WINS = 601, + LANG_BG_WS_ONE_MINUTE = 602, + LANG_BG_WS_HALF_MINUTE = 603, + LANG_BG_WS_BEGIN = 604, + + LANG_BG_WS_CAPTURED_HF = 605, + LANG_BG_WS_CAPTURED_AF = 606, + LANG_BG_WS_DROPPED_HF = 607, + LANG_BG_WS_DROPPED_AF = 608, + LANG_BG_WS_RETURNED_AF = 609, + LANG_BG_WS_RETURNED_HF = 610, + LANG_BG_WS_PICKEDUP_HF = 611, + LANG_BG_WS_PICKEDUP_AF = 612, + LANG_BG_WS_F_PLACED = 613, + LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED = 614, + LANG_BG_WS_HORDE_FLAG_RESPAWNED = 615, + + LANG_BG_EY_ONE_MINUTE = 636, + LANG_BG_EY_HALF_MINUTE = 637, + LANG_BG_EY_BEGIN = 638, + + LANG_BG_AB_ALLY = 650, + LANG_BG_AB_HORDE = 651, + LANG_BG_AB_NODE_STABLES = 652, + LANG_BG_AB_NODE_BLACKSMITH = 653, + LANG_BG_AB_NODE_FARM = 654, + LANG_BG_AB_NODE_LUMBER_MILL = 655, + LANG_BG_AB_NODE_GOLD_MINE = 656, + LANG_BG_AB_NODE_TAKEN = 657, + LANG_BG_AB_NODE_DEFENDED = 658, + LANG_BG_AB_NODE_ASSAULTED = 659, + LANG_BG_AB_NODE_CLAIMED = 660, + LANG_BG_AB_ONEMINTOSTART = 661, + LANG_BG_AB_HALFMINTOSTART = 662, + LANG_BG_AB_STARTED = 663, + LANG_BG_AB_A_NEAR_VICTORY = 664, + LANG_BG_AB_H_NEAR_VICTORY = 665, + LANG_BG_MARK_BY_MAIL = 666, + + LANG_BG_EY_HAS_TAKEN_A_M_TOWER = 667, + LANG_BG_EY_HAS_TAKEN_H_M_TOWER = 668, + LANG_BG_EY_HAS_TAKEN_A_D_RUINS = 669, + LANG_BG_EY_HAS_TAKEN_H_D_RUINS = 670, + LANG_BG_EY_HAS_TAKEN_A_B_TOWER = 671, + LANG_BG_EY_HAS_TAKEN_H_B_TOWER = 672, + LANG_BG_EY_HAS_TAKEN_A_F_RUINS = 673, + LANG_BG_EY_HAS_TAKEN_H_F_RUINS = 674, + LANG_BG_EY_HAS_LOST_A_M_TOWER = 675, + LANG_BG_EY_HAS_LOST_H_M_TOWER = 676, + LANG_BG_EY_HAS_LOST_A_D_RUINS = 677, + LANG_BG_EY_HAS_LOST_H_D_RUINS = 678, + LANG_BG_EY_HAS_LOST_A_B_TOWER = 679, + LANG_BG_EY_HAS_LOST_H_B_TOWER = 680, + LANG_BG_EY_HAS_LOST_A_F_RUINS = 681, + LANG_BG_EY_HAS_LOST_H_F_RUINS = 682, + LANG_BG_EY_HAS_TAKEN_FLAG = 683, + LANG_BG_EY_CAPTURED_FLAG_A = 684, + LANG_BG_EY_CAPTURED_FLAG_H = 685, + LANG_BG_EY_DROPPED_FLAG = 686, + LANG_BG_EY_RESETED_FLAG = 687, + + LANG_ARENA_ONE_TOOLOW = 700, + LANG_ARENA_ONE_MINUTE = 701, + LANG_ARENA_THIRTY_SECONDS = 702, + LANG_ARENA_FIFTEEN_SECONDS = 703, + LANG_ARENA_BEGUN = 704, + + LANG_WAIT_BEFORE_SPEAKING = 705, + LANG_NOT_EQUIPPED_ITEM = 706, + LANG_PLAYER_DND = 707, + LANG_PLAYER_AFK = 708, + LANG_PLAYER_DND_DEFAULT = 709, + LANG_PLAYER_AFK_DEFAULT = 710, + + LANG_BG_QUEUE_ANNOUNCE_SELF = 711, + LANG_BG_QUEUE_ANNOUNCE_WORLD = 712, +}; +#endif + +/* NOT USED VALUES +// alliance ranks +#define LANG_ALI_PRIVATE "Private " +#define LANG_ALI_CORPORAL "Corporal " +#define LANG_ALI_SERGEANT "Sergeant " +#define LANG_ALI_MASTER_SERGEANT "Master Sergeant " +#define LANG_ALI_SERGEANT_MAJOR "Sergeant Major " +#define LANG_ALI_KNIGHT "Knight " +#define LANG_ALI_KNIGHT_LIEUTENANT "Knight-Lieutenant " +#define LANG_ALI_KNIGHT_CAPTAIN "Knight-Captain " +#define LANG_ALI_KNIGHT_CHAMPION "Knight-Champion " +#define LANG_ALI_LIEUTENANT_COMMANDER "Lieutenant Commander " +#define LANG_ALI_COMMANDER "Commander " +#define LANG_ALI_MARSHAL "Marshal " +#define LANG_ALI_FIELD_MARSHAL "Field Marshal " +#define LANG_ALI_GRAND_MARSHAL "Grand Marshal " +#define LANG_ALI_GAME_MASTER "Game Master " + +// horde ranks +#define LANG_HRD_SCOUT "Scout " +#define LANG_HRD_GRUNT "Grunt " +#define LANG_HRD_SERGEANT "Sergeant " +#define LANG_HRD_SENIOR_SERGEANT "Senior Sergeant " +#define LANG_HRD_FIRST_SERGEANT "First Sergeant " +#define LANG_HRD_STONE_GUARD "Stone Guard " +#define LANG_HRD_BLOOD_GUARD "Blood Guard " +#define LANG_HRD_LEGIONNARE "Legionnaire " +#define LANG_HRD_CENTURION "Centurion " +#define LANG_HRD_CHAMPION "Champion " +#define LANG_HRD_LIEUTENANT_GENERAL "Lieutenant General " +#define LANG_HRD_GENERAL "General " +#define LANG_HRD_WARLORD "Warlord " +#define LANG_HRD_HIGH_WARLORD "High Warlord " +#define LANG_HRD_GAME_MASTER "Game Master " + +#define LANG_NO_RANK "No rank " +#define LANG_RANK "%s (Rank %u)" +#define LANG_HONOR_TODAY "Today: [Honorable kills: |c0000ff00%u|r] [Dishonorable kills: |c00ff0000%u|r]" +#define LANG_HONOR_YESTERDAY "Yesterday: [Kills: |c0000ff00%u|r] [Honor: %u]" +#define LANG_HONOR_THIS_WEEK "This week: [Kills: |c0000ff00%u|r] [Honor: %u]" +#define LANG_HONOR_LAST_WEEK "Last week: [Kills: |c0000ff00%u|r] [Honor: %u] [Standing: %u]" +#define LANG_HONOR_LIFE "Lifetime: [Honorable kills: |c0000ff00%u|r] [Dishonorable kills: |c00ff0000%u|r] [Highest rank %u: %s]" + +// level 2 +#define LANG_ADD_OBJ "AddObject at Chat.cpp" //log +#define LANG_DEMORPHED "Demorphed %s" //log + +// level 3 +#define LANG_SPAWNING_SPIRIT_HEAL "Spawning spirit healers\n" +#define LANG_NO_SPIRIT_HEAL_DB "No spirit healers in database, exiting." + +#define LANG_ADD_OBJ_LV3 "AddObject at Level3.cpp line 1176" + +*/ diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 21c1eec9f16..93e44cd9802 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -1,2351 +1,2291 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "Opcodes.h" -#include "Chat.h" -#include "Log.h" -#include "MapManager.h" -#include "ObjectAccessor.h" -#include "Language.h" -#include "CellImpl.h" -#include "InstanceSaveMgr.h" -#include "Util.h" -#ifdef _DEBUG_VMAPS -#include "VMapFactory.h" -#endif - -bool ChatHandler::HandleSayCommand(const char* args) -{ - if(!*args) - return false; - - Creature* pCreature = getSelectedCreature(); - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->Say(args, LANG_UNIVERSAL, 0); - - return true; -} - -bool ChatHandler::HandleYellCommand(const char* args) -{ - if(!*args) - return false; - - Creature* pCreature = getSelectedCreature(); - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->Yell(args, LANG_UNIVERSAL, 0); - - return true; -} - -//show text emote by creature in chat -bool ChatHandler::HandleTextEmoteCommand(const char* args) -{ - if(!*args) - return false; - - Creature* pCreature = getSelectedCreature(); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->TextEmote(args, 0); - - return true; -} - -// make npc whisper to player -bool ChatHandler::HandleNpcWhisperCommand(const char* args) -{ - if(!*args) - return false; - - char* receiver_str = strtok((char*)args, " "); - char* text = strtok(NULL, ""); - - uint64 guid = m_session->GetPlayer()->GetSelection(); - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature || !receiver_str || !text) - { - return false; - } - - uint64 receiver_guid= atol(receiver_str); - - pCreature->Whisper(text,receiver_guid); - - return true; -} - -// global announce -bool ChatHandler::HandleAnnounceCommand(const char* args) -{ - if(!*args) - return false; - - sWorld.SendWorldText(LANG_SYSTEMMESSAGE,args); - return true; -} - -//notification player at the screen -bool ChatHandler::HandleNotifyCommand(const char* args) -{ - if(!*args) - return false; - - std::string str = GetMangosString(LANG_GLOBAL_NOTIFY); - str += args; - - WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); - data << str; - sWorld.SendGlobalMessage(&data); - - return true; -} - -//Enable\Dissable GM Mode -bool ChatHandler::HandleGMmodeCommand(const char* args) -{ - if(!*args) - { - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; - } - - std::string argstr = (char*)args; - - if (argstr == "on") - { - m_session->GetPlayer()->SetGameMaster(true); - m_session->SendNotification("GM mode is ON"); - #ifdef _DEBUG_VMAPS - VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); - vMapManager->processCommand("stoplog"); - #endif - return true; - } - - if (argstr == "off") - { - m_session->GetPlayer()->SetGameMaster(false); - m_session->SendNotification("GM mode is OFF"); - #ifdef _DEBUG_VMAPS - VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); - vMapManager->processCommand("startlog"); - #endif - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -//Enable\Dissable Invisible mode -bool ChatHandler::HandleVisibleCommand(const char* args) -{ - if (!*args) - { - PSendSysMessage(LANG_YOU_ARE, m_session->GetPlayer()->isGMVisible() ? GetMangosString(LANG_VISIBLE) : GetMangosString(LANG_INVISIBLE)); - return true; - } - - std::string argstr = (char*)args; - - if (argstr == "on") - { - m_session->GetPlayer()->SetGMVisible(true); - m_session->SendNotification(GetMangosString(LANG_INVISIBLE_VISIBLE)); - return true; - } - - if (argstr == "off") - { - m_session->SendNotification(GetMangosString(LANG_INVISIBLE_INVISIBLE)); - m_session->GetPlayer()->SetGMVisible(false); - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -bool ChatHandler::HandleGPSCommand(const char* args) -{ - WorldObject *obj = NULL; - if (*args) - { - std::string name = args; - if(normalizePlayerName(name)) - obj = objmgr.GetPlayer(name.c_str()); - - if(!obj) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - } - else - { - obj = getSelectedUnit(); - - if(!obj) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - } - CellPair cell_val = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - Cell cell(cell_val); - - uint32 zone_id = obj->GetZoneId(); - uint32 area_id = obj->GetAreaId(); - - MapEntry const* mapEntry = sMapStore.LookupEntry(obj->GetMapId()); - AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zone_id); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(area_id); - - float zone_x = obj->GetPositionX(); - float zone_y = obj->GetPositionY(); - - Map2ZoneCoordinates(zone_x,zone_y,zone_id); - - Map const *map = MapManager::Instance().GetMap(obj->GetMapId(), obj); - float ground_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), MAX_HEIGHT); - float floor_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ()); - - GridPair p = MaNGOS::ComputeGridPair(obj->GetPositionX(), obj->GetPositionY()); - - int gx=63-p.x_coord; - int gy=63-p.y_coord; - - uint32 have_map = Map::ExistMap(obj->GetMapId(),gx,gy) ? 1 : 0; - uint32 have_vmap = Map::ExistVMap(obj->GetMapId(),gx,gy) ? 1 : 0; - - PSendSysMessage(LANG_MAP_POSITION, - obj->GetMapId(), (mapEntry ? mapEntry->name[m_session->GetSessionDbcLocale()] : "" ), - zone_id, (zoneEntry ? zoneEntry->area_name[m_session->GetSessionDbcLocale()] : "" ), - area_id, (areaEntry ? areaEntry->area_name[m_session->GetSessionDbcLocale()] : "" ), - obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), - cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), - zone_x, zone_y, ground_z, floor_z, have_map, have_vmap ); - - sLog.outDebug("Player %s GPS call for %s '%s' (%s: %u):", - m_session->GetPlayer()->GetName(), - (obj->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), obj->GetName(), - (obj->GetTypeId() == TYPEID_PLAYER ? "GUID" : "Entry"), (obj->GetTypeId() == TYPEID_PLAYER ? obj->GetGUIDLow(): obj->GetEntry()) ); - sLog.outDebug(GetMangosString(LANG_MAP_POSITION), - obj->GetMapId(), (mapEntry ? mapEntry->name[sWorld.GetDefaultDbcLocale()] : "" ), - zone_id, (zoneEntry ? zoneEntry->area_name[sWorld.GetDefaultDbcLocale()] : "" ), - area_id, (areaEntry ? areaEntry->area_name[sWorld.GetDefaultDbcLocale()] : "" ), - obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), - cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), - zone_x, zone_y, ground_z, floor_z, have_map, have_vmap ); - - return true; -} - -//Summon Player -bool ChatHandler::HandleNamegoCommand(const char* args) -{ - if(!*args) - return false; - - std::string name = args; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - Player *chr = objmgr.GetPlayer(name.c_str()); - if (chr) - { - if(chr->IsBeingTeleported()==true) - { - PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName()); - SetSentErrorMessage(true); - return false; - } - - Map* pMap = MapManager::Instance().GetMap(m_session->GetPlayer()->GetMapId(),m_session->GetPlayer()); - - if(pMap->Instanceable()) - { - Map* cMap = MapManager::Instance().GetMap(chr->GetMapId(),chr); - if( cMap->Instanceable() && cMap->GetInstanceId() != pMap->GetInstanceId() ) - { - // cannot summon from instance to instance - PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,chr->GetName()); - SetSentErrorMessage(true); - return false; - } - - // we are in instance, and can summon only player in our group with us as lead - if ( !m_session->GetPlayer()->GetGroup() || !chr->GetGroup() || - (chr->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) || - (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) ) - // the last check is a bit excessive, but let it be, just in case - { - PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,chr->GetName()); - SetSentErrorMessage(true); - return false; - } - } - - PSendSysMessage(LANG_SUMMONING, chr->GetName(),""); - - if (m_session->GetPlayer()->IsVisibleGloballyFor(chr)) - ChatHandler(chr).PSendSysMessage(LANG_SUMMONED_BY, m_session->GetPlayer()->GetName()); - - // stop flight if need - if(chr->isInFlight()) - { - chr->GetMotionMaster()->MovementExpired(); - chr->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - chr->SaveRecallPosition(); - - // before GM - float x,y,z; - m_session->GetPlayer()->GetClosePoint(x,y,z,chr->GetObjectSize()); - chr->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,chr->GetOrientation()); - } - else if (uint64 guid = objmgr.GetPlayerGUIDByName(name)) - { - PSendSysMessage(LANG_SUMMONING, name.c_str(),GetMangosString(LANG_OFFLINE)); - - // in point where GM stay - Player::SavePositionInDB(m_session->GetPlayer()->GetMapId(), - m_session->GetPlayer()->GetPositionX(), - m_session->GetPlayer()->GetPositionY(), - m_session->GetPlayer()->GetPositionZ(), - m_session->GetPlayer()->GetOrientation(), - m_session->GetPlayer()->GetZoneId(), - guid); - } - else - { - PSendSysMessage(LANG_NO_PLAYER, args); - SetSentErrorMessage(true); - } - - return true; -} - -//Teleport to Player -bool ChatHandler::HandleGonameCommand(const char* args) -{ - if(!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - std::string name = args; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - Player *chr = objmgr.GetPlayer(name.c_str()); - if (chr) - { - Map* cMap = MapManager::Instance().GetMap(chr->GetMapId(),chr); - if(cMap->Instanceable()) - { - Map* pMap = MapManager::Instance().GetMap(_player->GetMapId(),_player); - - // we have to go to instance, and can go to player only if: - // 1) we are in his group (either as leader or as member) - // 2) we are not bound to any group and have GM mode on - if (_player->GetGroup()) - { - // we are in group, we can go only if we are in the player group - if (_player->GetGroup() != chr->GetGroup()) - { - PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY,chr->GetName()); - SetSentErrorMessage(true); - return false; - } - } - else - { - // we are not in group, let's verify our GM mode - if (!_player->isGameMaster()) - { - PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM,chr->GetName()); - SetSentErrorMessage(true); - return false; - } - } - - // if the player or the player's group is bound to another instance - // the player will not be bound to another one - InstancePlayerBind *pBind = _player->GetBoundInstance(chr->GetMapId(), chr->GetDifficulty()); - if(!pBind) - { - Group *group = _player->GetGroup(); - InstanceGroupBind *gBind = group ? group->GetBoundInstance(chr->GetMapId(), chr->GetDifficulty()) : NULL; - if(!gBind) - { - // if no bind exists, create a solo bind - InstanceSave *save = sInstanceSaveManager.GetInstanceSave(chr->GetInstanceId()); - if(save) _player->BindToInstance(save, !save->CanReset()); - } - } - - _player->SetDifficulty(chr->GetDifficulty()); - } - - PSendSysMessage(LANG_APPEARING_AT, chr->GetName()); - - if (_player->IsVisibleGloballyFor(chr)) - ChatHandler(chr).PSendSysMessage(LANG_APPEARING_TO, _player->GetName()); - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - // to point to see at target with same orientation - float x,y,z; - chr->GetContactPoint(m_session->GetPlayer(),x,y,z); - - _player->TeleportTo(chr->GetMapId(), x, y, z, _player->GetAngle( chr ), TELE_TO_GM_MODE); - - return true; - } - - if (uint64 guid = objmgr.GetPlayerGUIDByName(name)) - { - PSendSysMessage(LANG_APPEARING_AT, name.c_str()); - - // to point where player stay (if loaded) - float x,y,z,o; - uint32 map; - bool in_flight; - if(Player::LoadPositionFromDB(map,x,y,z,o,in_flight,guid)) - { - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(map, x, y, z,_player->GetOrientation()); - return true; - } - } - - PSendSysMessage(LANG_NO_PLAYER, args); - - SetSentErrorMessage(true); - return false; -} - -// Teleport player to last position -bool ChatHandler::HandleRecallCommand(const char* args) -{ - Player* chr = NULL; - - if(!*args) - { - chr = getSelectedPlayer(); - if(!chr) - chr = m_session->GetPlayer(); - } - else - { - std::string name = args; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - chr = objmgr.GetPlayer(name.c_str()); - - if(!chr) - { - PSendSysMessage(LANG_NO_PLAYER, args); - SetSentErrorMessage(true); - return false; - } - } - - if(chr->IsBeingTeleported()) - { - PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName()); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(chr->isInFlight()) - { - chr->GetMotionMaster()->MovementExpired(); - chr->m_taxi.ClearTaxiDestinations(); - } - - chr->TeleportTo(chr->m_recallMap, chr->m_recallX, chr->m_recallY, chr->m_recallZ, chr->m_recallO); - return true; -} - -//Edit Player KnownTitles -bool ChatHandler::HandleModifyKnownTitlesCommand(const char* args) -{ - if(!*args) - return false; - - uint64 titles = 0; - - sscanf((char*)args, I64FMTD, &titles); - - Player *chr = getSelectedPlayer(); - if (!chr) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - uint64 titles2 = titles; - - for(int i=1; i < sCharTitlesStore.GetNumRows(); ++i) - if(CharTitlesEntry const* tEntry = sCharTitlesStore.LookupEntry(i)) - titles2 &= ~(uint64(1) << tEntry->bit_index); - - titles &= ~titles2; // remove not existed titles - - chr->SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES, titles); - SendSysMessage(LANG_DONE); - - return true; -} - -//Edit Player HP -bool ChatHandler::HandleModifyHPCommand(const char* args) -{ - if(!*args) - return false; - - // char* pHp = strtok((char*)args, " "); - // if (!pHp) - // return false; - - // char* pHpMax = strtok(NULL, " "); - // if (!pHpMax) - // return false; - - // int32 hpm = atoi(pHpMax); - // int32 hp = atoi(pHp); - - int32 hp = atoi((char*)args); - int32 hpm = atoi((char*)args); - - if (hp <= 0 || hpm <= 0 || hpm < hp) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_HP, chr->GetName(), hp, hpm); - ChatHandler(chr).PSendSysMessage(LANG_YOURS_HP_CHANGED, m_session->GetPlayer()->GetName(), hp, hpm); - - chr->SetMaxHealth( hpm ); - chr->SetHealth( hp ); - - return true; -} - -//Edit Player Mana -bool ChatHandler::HandleModifyManaCommand(const char* args) -{ - if(!*args) - return false; - - // char* pmana = strtok((char*)args, " "); - // if (!pmana) - // return false; - - // char* pmanaMax = strtok(NULL, " "); - // if (!pmanaMax) - // return false; - - // int32 manam = atoi(pmanaMax); - // int32 mana = atoi(pmana); - int32 mana = atoi((char*)args); - int32 manam = atoi((char*)args); - - if (mana <= 0 || manam <= 0 || manam < mana) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_MANA, chr->GetName(), mana, manam); - ChatHandler(chr).PSendSysMessage(LANG_YOURS_MANA_CHANGED, m_session->GetPlayer()->GetName(), mana, manam); - - chr->SetMaxPower(POWER_MANA,manam ); - chr->SetPower(POWER_MANA, mana ); - - return true; -} - -//Edit Player Energy -bool ChatHandler::HandleModifyEnergyCommand(const char* args) -{ - if(!*args) - return false; - - // char* pmana = strtok((char*)args, " "); - // if (!pmana) - // return false; - - // char* pmanaMax = strtok(NULL, " "); - // if (!pmanaMax) - // return false; - - // int32 manam = atoi(pmanaMax); - // int32 mana = atoi(pmana); - - int32 energy = atoi((char*)args)*10; - int32 energym = atoi((char*)args)*10; - - if (energy <= 0 || energym <= 0 || energym < energy) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (!chr) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_ENERGY, chr->GetName(), energy/10, energym/10); - ChatHandler(chr).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, m_session->GetPlayer()->GetName(), energy/10, energym/10); - - chr->SetMaxPower(POWER_ENERGY,energym ); - chr->SetPower(POWER_ENERGY, energy ); - - sLog.outDetail(GetMangosString(LANG_CURRENT_ENERGY),chr->GetMaxPower(POWER_ENERGY)); - - return true; -} - -//Edit Player Rage -bool ChatHandler::HandleModifyRageCommand(const char* args) -{ - if(!*args) - return false; - - // char* pmana = strtok((char*)args, " "); - // if (!pmana) - // return false; - - // char* pmanaMax = strtok(NULL, " "); - // if (!pmanaMax) - // return false; - - // int32 manam = atoi(pmanaMax); - // int32 mana = atoi(pmana); - - int32 rage = atoi((char*)args)*10; - int32 ragem = atoi((char*)args)*10; - - if (rage <= 0 || ragem <= 0 || ragem < rage) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_RAGE, chr->GetName(), rage/10, ragem/10); - // Special case: I use GetMangosString here to get local of destination char ;) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_RAGE_CHANGED), m_session->GetPlayer()->GetName(), rage/10, ragem/10); - - chr->SetMaxPower(POWER_RAGE,ragem ); - chr->SetPower(POWER_RAGE, rage ); - - return true; -} - -//Edit Player Faction -bool ChatHandler::HandleModifyFactionCommand(const char* args) -{ - if(!*args) - return false; - - char* pfactionid = extractKeyFromLink((char*)args,"Hfaction"); - - Creature* chr = getSelectedCreature(); - if(!chr) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if(!pfactionid) - { - if(chr) - { - uint32 factionid = chr->getFaction(); - uint32 flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); - uint32 npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); - uint32 dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); - PSendSysMessage(LANG_CURRENT_FACTION,chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); - } - return true; - } - - if( !chr ) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - uint32 factionid = atoi(pfactionid); - uint32 flag; - - char *pflag = strtok(NULL, " "); - if (!pflag) - flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); - else - flag = atoi(pflag); - - char* pnpcflag = strtok(NULL, " "); - - uint32 npcflag; - if(!pnpcflag) - npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); - else - npcflag = atoi(pnpcflag); - - char* pdyflag = strtok(NULL, " "); - - uint32 dyflag; - if(!pdyflag) - dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); - else - dyflag = atoi(pdyflag); - - if(!sFactionTemplateStore.LookupEntry(factionid)) - { - PSendSysMessage(LANG_WRONG_FACTION, factionid); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); - - //sprintf((char*)buf,"%s changed your Faction to %i.", m_session->GetPlayer()->GetName(), factionid); - //FillSystemMessageData(&data, m_session, buf); - - //chr->GetSession()->SendPacket(&data); - - chr->setFaction(factionid); - chr->SetUInt32Value(UNIT_FIELD_FLAGS,flag); - chr->SetUInt32Value(UNIT_NPC_FLAGS,npcflag); - chr->SetUInt32Value(UNIT_DYNAMIC_FLAGS,dyflag); - - return true; -} - -//Edit Player Spell -bool ChatHandler::HandleModifySpellCommand(const char* args) -{ - if(!*args) return false; - char* pspellflatid = strtok((char*)args, " "); - if (!pspellflatid) - return false; - - char* pop = strtok(NULL, " "); - if (!pop) - return false; - - char* pval = strtok(NULL, " "); - if (!pval) - return false; - - uint16 mark; - - char* pmark = strtok(NULL, " "); - - uint8 spellflatid = atoi(pspellflatid); - uint8 op = atoi(pop); - uint16 val = atoi(pval); - if(!pmark) - mark = 65535; - else - mark = atoi(pmark); - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_SPELLFLATID, spellflatid, val, mark, chr->GetName()); - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPELLFLATID_CHANGED, m_session->GetPlayer()->GetName(), spellflatid, val, mark); - - WorldPacket data(SMSG_SET_FLAT_SPELL_MODIFIER, (1+1+2+2)); - data << uint8(spellflatid); - data << uint8(op); - data << uint16(val); - data << uint16(mark); - chr->GetSession()->SendPacket(&data); - - return true; -} - -//Edit Player TP -bool ChatHandler::HandleModifyTalentCommand (const char* args) -{ - if (!*args) - return false; - - int tp = atoi((char*)args); - if (tp>0) - { - Player* player = getSelectedPlayer(); - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - player->SetFreeTalentPoints(tp); - return true; - } - return false; -} - -//Enable On\OFF all taxi paths -bool ChatHandler::HandleTaxiCheatCommand(const char* args) -{ - if (!*args) - { - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; - } - - std::string argstr = (char*)args; - - Player *chr = getSelectedPlayer(); - if (!chr) - { - chr=m_session->GetPlayer(); - } - - if (argstr == "on") - { - chr->SetTaxiCheater(true); - PSendSysMessage(LANG_YOU_GIVE_TAXIS, chr->GetName()); - - if(chr != m_session->GetPlayer()) - // to send localized data to target - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_TAXIS_ADDED), m_session->GetPlayer()->GetName()); - return true; - } - - if (argstr == "off") - { - chr->SetTaxiCheater(false); - PSendSysMessage(LANG_YOU_REMOVE_TAXIS, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_TAXIS_REMOVED), m_session->GetPlayer()->GetName()); - - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -//Edit Player Aspeed -bool ChatHandler::HandleModifyASpeedCommand(const char* args) -{ - if (!*args) - return false; - - float ASpeed = (float)atof((char*)args); - - if (ASpeed > 10 || ASpeed < 0.1) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(chr->isInFlight()) - { - PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_ASPEED_CHANGED), m_session->GetPlayer()->GetName(), ASpeed); - - chr->SetSpeed(MOVE_WALK, ASpeed,true); - chr->SetSpeed(MOVE_RUN, ASpeed,true); - chr->SetSpeed(MOVE_SWIM, ASpeed,true); - //chr->SetSpeed(MOVE_TURN, ASpeed,true); - chr->SetSpeed(MOVE_FLY, ASpeed,true); - return true; -} - -//Edit Player Speed -bool ChatHandler::HandleModifySpeedCommand(const char* args) -{ - if (!*args) - return false; - - float Speed = (float)atof((char*)args); - - if (Speed > 10 || Speed < 0.1) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(chr->isInFlight()) - { - PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SPEED_CHANGED), m_session->GetPlayer()->GetName(), Speed); - - chr->SetSpeed(MOVE_RUN,Speed,true); - - return true; -} - -//Edit Player Swim Speed -bool ChatHandler::HandleModifySwimCommand(const char* args) -{ - if (!*args) - return false; - - float Swim = (float)atof((char*)args); - - if (Swim > 10.0f || Swim < 0.01f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(chr->isInFlight()) - { - PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SWIM_SPEED_CHANGED), m_session->GetPlayer()->GetName(), Swim); - - chr->SetSpeed(MOVE_SWIM,Swim,true); - - return true; -} - -//Edit Player Walk Speed -bool ChatHandler::HandleModifyBWalkCommand(const char* args) -{ - if (!*args) - return false; - - float BSpeed = (float)atof((char*)args); - - if (BSpeed > 10.0f || BSpeed < 0.1f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(chr->isInFlight()) - { - PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_BACK_SPEED_CHANGED), m_session->GetPlayer()->GetName(), BSpeed); - - chr->SetSpeed(MOVE_WALKBACK,BSpeed,true); - - return true; -} - -//Edit Player Fly -bool ChatHandler::HandleModifyFlyCommand(const char* args) -{ - if (!*args) - return false; - - float FSpeed = (float)atof((char*)args); - - if (FSpeed > 10.0f || FSpeed < 0.1f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_FLY_SPEED_CHANGED), m_session->GetPlayer()->GetName(), FSpeed); - - chr->SetSpeed(MOVE_FLY,FSpeed,true); - - return true; -} - -//Edit Player Scale -bool ChatHandler::HandleModifyScaleCommand(const char* args) -{ - if (!*args) - return false; - - float Scale = (float)atof((char*)args); - if (Scale > 3.0f || Scale <= 0.0f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SIZE_CHANGED), m_session->GetPlayer()->GetName(), Scale); - - chr->SetFloatValue(OBJECT_FIELD_SCALE_X, Scale); - - return true; -} - -//Enable Player mount -bool ChatHandler::HandleModifyMountCommand(const char* args) -{ - if(!*args) - return false; - - uint16 mId = 1147; - float speed = (float)15; - uint32 num = 0; - - num = atoi((char*)args); - switch(num) - { - case 1: - mId=14340; - break; - case 2: - mId=4806; - break; - case 3: - mId=6471; - break; - case 4: - mId=12345; - break; - case 5: - mId=6472; - break; - case 6: - mId=6473; - break; - case 7: - mId=10670; - break; - case 8: - mId=10719; - break; - case 9: - mId=10671; - break; - case 10: - mId=10672; - break; - case 11: - mId=10720; - break; - case 12: - mId=14349; - break; - case 13: - mId=11641; - break; - case 14: - mId=12244; - break; - case 15: - mId=12242; - break; - case 16: - mId=14578; - break; - case 17: - mId=14579; - break; - case 18: - mId=14349; - break; - case 19: - mId=12245; - break; - case 20: - mId=14335; - break; - case 21: - mId=207; - break; - case 22: - mId=2328; - break; - case 23: - mId=2327; - break; - case 24: - mId=2326; - break; - case 25: - mId=14573; - break; - case 26: - mId=14574; - break; - case 27: - mId=14575; - break; - case 28: - mId=604; - break; - case 29: - mId=1166; - break; - case 30: - mId=2402; - break; - case 31: - mId=2410; - break; - case 32: - mId=2409; - break; - case 33: - mId=2408; - break; - case 34: - mId=2405; - break; - case 35: - mId=14337; - break; - case 36: - mId=6569; - break; - case 37: - mId=10661; - break; - case 38: - mId=10666; - break; - case 39: - mId=9473; - break; - case 40: - mId=9476; - break; - case 41: - mId=9474; - break; - case 42: - mId=14374; - break; - case 43: - mId=14376; - break; - case 44: - mId=14377; - break; - case 45: - mId=2404; - break; - case 46: - mId=2784; - break; - case 47: - mId=2787; - break; - case 48: - mId=2785; - break; - case 49: - mId=2736; - break; - case 50: - mId=2786; - break; - case 51: - mId=14347; - break; - case 52: - mId=14346; - break; - case 53: - mId=14576; - break; - case 54: - mId=9695; - break; - case 55: - mId=9991; - break; - case 56: - mId=6448; - break; - case 57: - mId=6444; - break; - case 58: - mId=6080; - break; - case 59: - mId=6447; - break; - case 60: - mId=4805; - break; - case 61: - mId=9714; - break; - case 62: - mId=6448; - break; - case 63: - mId=6442; - break; - case 64: - mId=14632; - break; - case 65: - mId=14332; - break; - case 66: - mId=14331; - break; - case 67: - mId=8469; - break; - case 68: - mId=2830; - break; - case 69: - mId=2346; - break; - default: - SendSysMessage(LANG_NO_MOUNT); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_GIVE_MOUNT, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_MOUNT_GIVED), m_session->GetPlayer()->GetName()); - - chr->SetUInt32Value( UNIT_FIELD_FLAGS , 0x001000 ); - chr->Mount(mId); - - WorldPacket data( SMSG_FORCE_RUN_SPEED_CHANGE, (8+4+1+4) ); - data.append(chr->GetPackGUID()); - data << (uint32)0; - data << (uint8)0; //new 2.1.0 - data << float(speed); - chr->SendMessageToSet( &data, true ); - - data.Initialize( SMSG_FORCE_SWIM_SPEED_CHANGE, (8+4+4) ); - data.append(chr->GetPackGUID()); - data << (uint32)0; - data << float(speed); - chr->SendMessageToSet( &data, true ); - - return true; -} - -//Edit Player money -bool ChatHandler::HandleModifyMoneyCommand(const char* args) -{ - if (!*args) - return false; - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - int32 addmoney = atoi((char*)args); - - uint32 moneyuser = chr->GetMoney(); - - if(addmoney < 0) - { - int32 newmoney = moneyuser + addmoney; - - sLog.outDetail(GetMangosString(LANG_CURRENT_MONEY), moneyuser, addmoney, newmoney); - if(newmoney <= 0 ) - { - PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, chr->GetName()); - - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_ALL_MONEY_GONE), m_session->GetPlayer()->GetName()); - - chr->SetMoney(0); - } - else - { - PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), chr->GetName()); - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_MONEY_TAKEN), m_session->GetPlayer()->GetName(), abs(addmoney)); - chr->SetMoney( newmoney ); - } - } - else - { - PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, chr->GetName()); - if(chr != m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_MONEY_GIVEN), m_session->GetPlayer()->GetName(), addmoney); - chr->ModifyMoney( addmoney ); - } - - sLog.outDetail(GetMangosString(LANG_NEW_MONEY), moneyuser, addmoney, chr->GetMoney() ); - - return true; -} - -//Edit Player field -bool ChatHandler::HandleModifyBitCommand(const char* args) -{ - if( !*args ) - return false; - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - char* pField = strtok((char*)args, " "); - if (!pField) - return false; - - char* pBit = strtok(NULL, " "); - if (!pBit) - return false; - - uint16 field = atoi(pField); - uint32 bit = atoi(pBit); - - if (field < 1 || field >= PLAYER_END) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - if (bit < 1 || bit > 32) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - if ( chr->HasFlag( field, (1<<(bit-1)) ) ) - { - chr->RemoveFlag( field, (1<<(bit-1)) ); - PSendSysMessage(LANG_REMOVE_BIT, bit, field); - } - else - { - chr->SetFlag( field, (1<<(bit-1)) ); - PSendSysMessage(LANG_SET_BIT, bit, field); - } - - return true; -} - -//Teleport by game_tele entry -bool ChatHandler::HandleModifyHonorCommand (const char* args) -{ - if (!*args) - return false; - - Player *target = getSelectedPlayer(); - if(!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - int32 amount = (uint32)atoi(args); - - target->ModifyHonorPoints(amount); - - PSendSysMessage(LANG_COMMAND_MODIFY_HONOR, target->GetName(), target->GetHonorPoints()); - - return true; -} - -bool ChatHandler::HandleTeleCommand(const char * args) -{ - if(!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - char* cId = extractKeyFromLink((char*)args,"Htele"); // string or [name] Shift-click form |color|Htele:name|h[name]|h|r - if(!cId) - return false; - - std::string name = cId; - WorldDatabase.escape_string(name); - - QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",name.c_str()); - if (!result) - { - SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - float ort = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - delete result; - - if(!MapManager::IsValidMapCoord(mapid,x,y,x,ort)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, ort); - return true; -} - -bool ChatHandler::HandleLookupAreaCommand(const char* args) -{ - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - uint32 counter = 0; // Counter for figure out that we found smth. - - // converting string that we try to find to lower case - wstrToLower( wnamepart ); - - // Search in AreaTable.dbc - for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows(); ++areaflag) - { - AreaTableEntry const *areaEntry = sAreaStore.LookupEntry(areaflag); - if(areaEntry) - { - int loc = m_session->GetSessionDbcLocale(); - std::string name = areaEntry->area_name[loc]; - if(name.empty()) - continue; - - if(!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for(; loc < MAX_LOCALE; ++loc) - { - if(loc==m_session->GetSessionDbcLocale()) - continue; - - name = areaEntry->area_name[loc]; - if(name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if(loc < MAX_LOCALE) - { - // send area in "id - [name]" format - std::ostringstream ss; - ss << areaEntry->ID << " - |cffffffff|Harea:" << areaEntry->ID << "|h[" << name << " " << localeNames[loc]<< "]|h|r"; - - SendSysMessage(ss.str().c_str()); - - ++counter; - } - } - } - if (counter == 0) // if counter == 0 then we found nth - SendSysMessage(LANG_COMMAND_NOAREAFOUND); - return true; -} - -//Find tele in game_tele order by name -bool ChatHandler::HandleLookupTeleCommand(const char * args) -{ - if(!*args) - { - SendSysMessage(LANG_COMMAND_TELE_PARAMETER); - SetSentErrorMessage(true); - return false; - } - char const* str = strtok((char*)args, " "); - if(!str) - return false; - - std::string namepart = str; - WorldDatabase.escape_string(namepart); - QueryResult *result = WorldDatabase.PQuery("SELECT name FROM game_tele WHERE name "_LIKE_" '""%%%s%%""'",namepart.c_str()); - if (!result) - { - SendSysMessage(LANG_COMMAND_TELE_NOREQUEST); - SetSentErrorMessage(true); - return false; - } - std::string reply; - for (uint64 i=0; i < result->GetRowCount(); i++) - { - Field *fields = result->Fetch(); - reply += " |cffffffff|Htele:"; - reply += fields[0].GetCppString(); - reply += "|h["; - reply += fields[0].GetCppString(); - reply += "]|h|r\n"; - result->NextRow(); - } - delete result; - - if(reply.empty()) - SendSysMessage(LANG_COMMAND_TELE_NOLOCATION); - else - { - reply = GetMangosString(LANG_COMMAND_TELE_LOCATION) + reply; - SendSysMessage(reply.c_str()); - } - return true; -} - -//Enable\Dissable accept whispers (for GM) -bool ChatHandler::HandleWhispersCommand(const char* args) -{ - if(!*args) - { - PSendSysMessage(LANG_COMMAND_WHISPERACCEPTING, m_session->GetPlayer()->isAcceptWhispers() ? GetMangosString(LANG_ON) : GetMangosString(LANG_OFF)); - return true; - } - - std::string argstr = (char*)args; - // whisper on - if (argstr == "on") - { - m_session->GetPlayer()->SetAcceptWhispers(true); - SendSysMessage(LANG_COMMAND_WHISPERON); - return true; - } - - // whisper off - if (argstr == "off") - { - m_session->GetPlayer()->SetAcceptWhispers(false); - SendSysMessage(LANG_COMMAND_WHISPEROFF); - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -//Play sound -bool ChatHandler::HandlePlaySoundCommand(const char* args) -{ - // USAGE: .debug playsound #soundid - // #soundid - ID decimal number from SoundEntries.dbc (1st column) - // this file have about 5000 sounds. - // In this realization only caller can hear this sound. - if( *args ) - { - uint32 dwSoundId = atoi((char*)args); - - if( !sSoundEntriesStore.LookupEntry(dwSoundId) ) - { - PSendSysMessage(LANG_SOUND_NOT_EXIST, dwSoundId); - SetSentErrorMessage(true); - return false; - } - - WorldPacket data(SMSG_PLAY_OBJECT_SOUND,4+8); - data << uint32(dwSoundId) << m_session->GetPlayer()->GetGUID(); - m_session->SendPacket(&data); - - PSendSysMessage(LANG_YOU_HEAR_SOUND, dwSoundId); - return true; - } - - return false; -} - -//Save all players in the world -bool ChatHandler::HandleSaveAllCommand(const char* /*args*/) -{ - ObjectAccessor::Instance().SaveAllPlayers(); - SendSysMessage(LANG_PLAYERS_SAVED); - return true; -} - -//Send mail by command -bool ChatHandler::HandleSendMailCommand(const char* args) -{ - if(!*args) - return false; - - char* pName = strtok((char*)args, " "); - char* msgSubject = strtok(NULL, " "); - char* msgText = strtok(NULL, ""); - - if (!msgText) - return false; - - // pName, msgSubject, msgText isn't NUL after prev. check - - std::string name = pName; - std::string subject = msgSubject; - std::string text = msgText; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 receiver_guid = objmgr.GetPlayerGUIDByName(name); - - if(!receiver_guid) - return false; - - uint32 mailId = objmgr.GenerateMailID(); - uint32 sender_guidlo = m_session->GetPlayer()->GetGUIDLow(); - uint32 messagetype = MAIL_NORMAL; - uint32 stationery = MAIL_STATIONERY_GM; - uint32 itemTextId = 0; - if (!text.empty()) - { - itemTextId = objmgr.CreateItemText( text ); - } - - Player *receiver = objmgr.GetPlayer(receiver_guid); - - WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_NONE); - - PSendSysMessage(LANG_MAIL_SENT, name.c_str()); - return true; -} - -// teleport player to given game_tele.entry -bool ChatHandler::HandleNameTeleCommand(const char * args) -{ - if(!*args) - return false; - - char* pName = strtok((char*)args, " "); - - if(!pName) - return false; - - char* tail = strtok(NULL, ""); - if(!tail) - return false; - - char* cId = extractKeyFromLink((char*)tail,"Htele"); // string or [name] Shift-click form |color|Htele:name|h[name]|h|r - if(!cId) - return false; - - std::string location = cId; - - std::string name = pName; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - WorldDatabase.escape_string(location); - QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",location.c_str()); - if (!result) - { - SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - float ort = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - delete result; - - if(!MapManager::IsValidMapCoord(mapid,x,y,x,ort)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - Player *chr = objmgr.GetPlayer(name.c_str()); - if (chr) - { - - if(chr->IsBeingTeleported()==true) - { - PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_TELEPORTING_TO, chr->GetName(),"", location.c_str()); - - if (m_session->GetPlayer()->IsVisibleGloballyFor(chr)) - ChatHandler(chr).PSendSysMessage(LANG_TELEPORTED_TO_BY, m_session->GetPlayer()->GetName()); - - // stop flight if need - if(chr->isInFlight()) - { - chr->GetMotionMaster()->MovementExpired(); - chr->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - chr->SaveRecallPosition(); - - chr->TeleportTo(mapid,x,y,z,chr->GetOrientation()); - } - else if (uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str())) - { - PSendSysMessage(LANG_TELEPORTING_TO, name.c_str(), GetMangosString(LANG_OFFLINE), location.c_str()); - Player::SavePositionInDB(mapid,x,y,z,ort,MapManager::Instance().GetZoneId(mapid,x,y),guid); - } - else - PSendSysMessage(LANG_NO_PLAYER, name.c_str()); - - return true; -} - -//Teleport group to given game_tele.entry -bool ChatHandler::HandleGroupTeleCommand(const char * args) -{ - if(!*args) - return false; - - Player *player = getSelectedPlayer(); - if (!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - char* cId = extractKeyFromLink((char*)args,"Htele"); // string or [name] Shift-click form |color|Htele:name|h[name]|h|r - if(!cId) - return false; - - std::string location = cId; - - WorldDatabase.escape_string(location); - QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",location.c_str()); - if (!result) - { - SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - float ort = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - delete result; - - if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - Group *grp = player->GetGroup(); - - if(!grp) - { - PSendSysMessage(LANG_NOT_IN_GROUP,player->GetName()); - SetSentErrorMessage(true); - return false; - } - - for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *pl = itr->getSource(); - - if(!pl || !pl->GetSession() ) - continue; - - if(pl->IsBeingTeleported()) - { - PSendSysMessage(LANG_IS_TELEPORTED, pl->GetName()); - continue; - } - - PSendSysMessage(LANG_TELEPORTING_TO, pl->GetName(),"", location.c_str()); - - if (m_session->GetPlayer() != pl && m_session->GetPlayer()->IsVisibleGloballyFor(pl)) - ChatHandler(pl).PSendSysMessage(LANG_TELEPORTED_TO_BY, m_session->GetPlayer()->GetName()); - - // stop flight if need - if(pl->isInFlight()) - { - pl->GetMotionMaster()->MovementExpired(); - pl->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - pl->SaveRecallPosition(); - - pl->TeleportTo(mapid, x, y, z, ort); - } - - return true; -} - -//Summon group of player -bool ChatHandler::HandleGroupgoCommand(const char* args) -{ - if(!*args) - return false; - - std::string name = args; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - Player *player = objmgr.GetPlayer(name.c_str()); - if (!player) - { - PSendSysMessage(LANG_NO_PLAYER, args); - SetSentErrorMessage(true); - return false; - } - - Group *grp = player->GetGroup(); - - if(!grp) - { - PSendSysMessage(LANG_NOT_IN_GROUP,player->GetName()); - SetSentErrorMessage(true); - return false; - } - - Map* gmMap = MapManager::Instance().GetMap(m_session->GetPlayer()->GetMapId(),m_session->GetPlayer()); - bool to_instance = gmMap->Instanceable(); - - // we are in instance, and can summon only player in our group with us as lead - if ( to_instance && ( - !m_session->GetPlayer()->GetGroup() || (grp->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) || - (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) ) ) - // the last check is a bit excessive, but let it be, just in case - { - SendSysMessage(LANG_CANNOT_SUMMON_TO_INST); - SetSentErrorMessage(true); - return false; - } - - for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *pl = itr->getSource(); - - if(!pl || pl==m_session->GetPlayer() || !pl->GetSession() ) - continue; - - if(pl->IsBeingTeleported()==true) - { - PSendSysMessage(LANG_IS_TELEPORTED, pl->GetName()); - SetSentErrorMessage(true); - return false; - } - - if (to_instance) - { - Map* plMap = MapManager::Instance().GetMap(pl->GetMapId(),pl); - - if ( plMap->Instanceable() && plMap->GetInstanceId() != gmMap->GetInstanceId() ) - { - // cannot summon from instance to instance - PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,pl->GetName()); - SetSentErrorMessage(true); - return false; - } - } - - PSendSysMessage(LANG_SUMMONING, pl->GetName(),""); - - if (m_session->GetPlayer()->IsVisibleGloballyFor(pl)) - ChatHandler(pl).PSendSysMessage(LANG_SUMMONED_BY, m_session->GetPlayer()->GetName()); - - // stop flight if need - if(pl->isInFlight()) - { - pl->GetMotionMaster()->MovementExpired(); - pl->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - pl->SaveRecallPosition(); - - // before GM - float x,y,z; - m_session->GetPlayer()->GetClosePoint(x,y,z,pl->GetObjectSize()); - pl->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,pl->GetOrientation()); - } - - return true; -} - -//teleport at coordinates -bool ChatHandler::HandleGoXYCommand(const char* args) -{ - if(!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pmapid = strtok(NULL, " "); - - if (!px || !py) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - uint32 mapid; - if (pmapid) - mapid = (uint32)atoi(pmapid); - else mapid = _player->GetMapId(); - - if(!MapManager::IsValidMapCoord(mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - Map const *map = MapManager::Instance().GetBaseMap(mapid); - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; -} - -//teleport at coordinates, including Z -bool ChatHandler::HandleGoXYZCommand(const char* args) -{ - if(!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - char* pmapid = strtok(NULL, " "); - - if (!px || !py || !pz) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - float z = (float)atof(pz); - uint32 mapid; - if (pmapid) - mapid = (uint32)atoi(pmapid); - else - mapid = _player->GetMapId(); - - if(!MapManager::IsValidMapCoord(mapid,x,y,z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; -} - -//teleport at coordinates -bool ChatHandler::HandleGoZoneXYCommand(const char* args) -{ - if(!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* tail = strtok(NULL,""); - - char* cAreaId = extractKeyFromLink(tail,"Harea"); // string or [name] Shift-click form |color|Harea:area_id|h[name]|h|r - - if (!px || !py) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - uint32 areaid = cAreaId ? (uint32)atoi(cAreaId) : _player->GetZoneId(); - - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaid); - - if( x<0 || x>100 || y<0 || y>100 || !areaEntry ) - { - PSendSysMessage(LANG_INVALID_ZONE_COORD,x,y,areaid); - SetSentErrorMessage(true); - return false; - } - - // update to parent zone if exist (client map show only zones without parents) - AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry; - - Map const *map = MapManager::Instance().GetBaseMap(zoneEntry->mapid); - - if(map->Instanceable()) - { - PSendSysMessage(LANG_INVALID_ZONE_MAP,areaEntry->ID,areaEntry->area_name[m_session->GetSessionDbcLocale()],map->GetId(),map->GetMapName()); - SetSentErrorMessage(true); - return false; - } - - Zone2MapCoordinates(x,y,zoneEntry->ID); - - if(!MapManager::IsValidMapCoord(zoneEntry->mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,zoneEntry->mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - _player->TeleportTo(zoneEntry->mapid, x, y, z, _player->GetOrientation()); - - return true; -} - -//teleport to grid -bool ChatHandler::HandleGoGridCommand(const char* args) -{ - if(!*args) return false; - Player* _player = m_session->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pmapid = strtok(NULL, " "); - - if (!px || !py) - return false; - - float grid_x = (float)atof(px); - float grid_y = (float)atof(py); - uint32 mapid; - if (pmapid) - mapid = (uint32)atoi(pmapid); - else mapid = _player->GetMapId(); - - // center of grid - float x = (grid_x-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; - float y = (grid_y-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; - - if(!MapManager::IsValidMapCoord(mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - Map const *map = MapManager::Instance().GetBaseMap(mapid); - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; -} - -bool ChatHandler::HandleDrunkCommand(const char* args) -{ - if(!*args) return false; - - uint32 drunklevel = (uint32)atoi(args); - if(drunklevel > 100) - drunklevel = 100; - - uint16 drunkMod = drunklevel * 0xFFFF / 100; - - m_session->GetPlayer()->SetDrunkValue(drunkMod); - - return true; -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Opcodes.h" +#include "Chat.h" +#include "Log.h" +#include "MapManager.h" +#include "ObjectAccessor.h" +#include "Language.h" +#include "CellImpl.h" +#include "InstanceSaveMgr.h" +#include "Util.h" +#ifdef _DEBUG_VMAPS +#include "VMapFactory.h" +#endif + +bool ChatHandler::HandleSayCommand(const char* args) +{ + if(!*args) + return false; + + Creature* pCreature = getSelectedCreature(); + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->Say(args, LANG_UNIVERSAL, 0); + + return true; +} + +bool ChatHandler::HandleYellCommand(const char* args) +{ + if(!*args) + return false; + + Creature* pCreature = getSelectedCreature(); + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->Yell(args, LANG_UNIVERSAL, 0); + + return true; +} + +//show text emote by creature in chat +bool ChatHandler::HandleTextEmoteCommand(const char* args) +{ + if(!*args) + return false; + + Creature* pCreature = getSelectedCreature(); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->TextEmote(args, 0); + + return true; +} + +// make npc whisper to player +bool ChatHandler::HandleNpcWhisperCommand(const char* args) +{ + if(!*args) + return false; + + char* receiver_str = strtok((char*)args, " "); + char* text = strtok(NULL, ""); + + uint64 guid = m_session->GetPlayer()->GetSelection(); + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if(!pCreature || !receiver_str || !text) + { + return false; + } + + uint64 receiver_guid= atol(receiver_str); + + pCreature->Whisper(text,receiver_guid); + + return true; +} + +// global announce +bool ChatHandler::HandleAnnounceCommand(const char* args) +{ + if(!*args) + return false; + + sWorld.SendWorldText(LANG_SYSTEMMESSAGE,args); + return true; +} + +//notification player at the screen +bool ChatHandler::HandleNotifyCommand(const char* args) +{ + if(!*args) + return false; + + std::string str = GetMangosString(LANG_GLOBAL_NOTIFY); + str += args; + + WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); + data << str; + sWorld.SendGlobalMessage(&data); + + return true; +} + +//Enable\Dissable GM Mode +bool ChatHandler::HandleGMmodeCommand(const char* args) +{ + if(!*args) + { + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; + } + + std::string argstr = (char*)args; + + if (argstr == "on") + { + m_session->GetPlayer()->SetGameMaster(true); + m_session->SendNotification("GM mode is ON"); + #ifdef _DEBUG_VMAPS + VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); + vMapManager->processCommand("stoplog"); + #endif + return true; + } + + if (argstr == "off") + { + m_session->GetPlayer()->SetGameMaster(false); + m_session->SendNotification("GM mode is OFF"); + #ifdef _DEBUG_VMAPS + VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); + vMapManager->processCommand("startlog"); + #endif + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +//Enable\Dissable Invisible mode +bool ChatHandler::HandleVisibleCommand(const char* args) +{ + if (!*args) + { + PSendSysMessage(LANG_YOU_ARE, m_session->GetPlayer()->isGMVisible() ? GetMangosString(LANG_VISIBLE) : GetMangosString(LANG_INVISIBLE)); + return true; + } + + std::string argstr = (char*)args; + + if (argstr == "on") + { + m_session->GetPlayer()->SetGMVisible(true); + m_session->SendNotification(GetMangosString(LANG_INVISIBLE_VISIBLE)); + return true; + } + + if (argstr == "off") + { + m_session->SendNotification(GetMangosString(LANG_INVISIBLE_INVISIBLE)); + m_session->GetPlayer()->SetGMVisible(false); + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +bool ChatHandler::HandleGPSCommand(const char* args) +{ + WorldObject *obj = NULL; + if (*args) + { + std::string name = args; + if(normalizePlayerName(name)) + obj = objmgr.GetPlayer(name.c_str()); + + if(!obj) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + } + else + { + obj = getSelectedUnit(); + + if(!obj) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + } + CellPair cell_val = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + Cell cell(cell_val); + + uint32 zone_id = obj->GetZoneId(); + uint32 area_id = obj->GetAreaId(); + + MapEntry const* mapEntry = sMapStore.LookupEntry(obj->GetMapId()); + AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zone_id); + AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(area_id); + + float zone_x = obj->GetPositionX(); + float zone_y = obj->GetPositionY(); + + Map2ZoneCoordinates(zone_x,zone_y,zone_id); + + Map const *map = MapManager::Instance().GetMap(obj->GetMapId(), obj); + float ground_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), MAX_HEIGHT); + float floor_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ()); + + GridPair p = MaNGOS::ComputeGridPair(obj->GetPositionX(), obj->GetPositionY()); + + int gx=63-p.x_coord; + int gy=63-p.y_coord; + + uint32 have_map = Map::ExistMap(obj->GetMapId(),gx,gy) ? 1 : 0; + uint32 have_vmap = Map::ExistVMap(obj->GetMapId(),gx,gy) ? 1 : 0; + + PSendSysMessage(LANG_MAP_POSITION, + obj->GetMapId(), (mapEntry ? mapEntry->name[m_session->GetSessionDbcLocale()] : "" ), + zone_id, (zoneEntry ? zoneEntry->area_name[m_session->GetSessionDbcLocale()] : "" ), + area_id, (areaEntry ? areaEntry->area_name[m_session->GetSessionDbcLocale()] : "" ), + obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), + cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), + zone_x, zone_y, ground_z, floor_z, have_map, have_vmap ); + + sLog.outDebug("Player %s GPS call for %s '%s' (%s: %u):", + m_session->GetPlayer()->GetName(), + (obj->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), obj->GetName(), + (obj->GetTypeId() == TYPEID_PLAYER ? "GUID" : "Entry"), (obj->GetTypeId() == TYPEID_PLAYER ? obj->GetGUIDLow(): obj->GetEntry()) ); + sLog.outDebug(GetMangosString(LANG_MAP_POSITION), + obj->GetMapId(), (mapEntry ? mapEntry->name[sWorld.GetDefaultDbcLocale()] : "" ), + zone_id, (zoneEntry ? zoneEntry->area_name[sWorld.GetDefaultDbcLocale()] : "" ), + area_id, (areaEntry ? areaEntry->area_name[sWorld.GetDefaultDbcLocale()] : "" ), + obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), + cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), + zone_x, zone_y, ground_z, floor_z, have_map, have_vmap ); + + return true; +} + +//Summon Player +bool ChatHandler::HandleNamegoCommand(const char* args) +{ + if(!*args) + return false; + + std::string name = args; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + Player *chr = objmgr.GetPlayer(name.c_str()); + if (chr) + { + if(chr->IsBeingTeleported()==true) + { + PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName()); + SetSentErrorMessage(true); + return false; + } + + Map* pMap = MapManager::Instance().GetMap(m_session->GetPlayer()->GetMapId(),m_session->GetPlayer()); + + if(pMap->Instanceable()) + { + Map* cMap = MapManager::Instance().GetMap(chr->GetMapId(),chr); + if( cMap->Instanceable() && cMap->GetInstanceId() != pMap->GetInstanceId() ) + { + // cannot summon from instance to instance + PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,chr->GetName()); + SetSentErrorMessage(true); + return false; + } + + // we are in instance, and can summon only player in our group with us as lead + if ( !m_session->GetPlayer()->GetGroup() || !chr->GetGroup() || + (chr->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) || + (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) ) + // the last check is a bit excessive, but let it be, just in case + { + PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,chr->GetName()); + SetSentErrorMessage(true); + return false; + } + } + + PSendSysMessage(LANG_SUMMONING, chr->GetName(),""); + + if (m_session->GetPlayer()->IsVisibleGloballyFor(chr)) + ChatHandler(chr).PSendSysMessage(LANG_SUMMONED_BY, m_session->GetPlayer()->GetName()); + + // stop flight if need + if(chr->isInFlight()) + { + chr->GetMotionMaster()->MovementExpired(); + chr->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + chr->SaveRecallPosition(); + + // before GM + float x,y,z; + m_session->GetPlayer()->GetClosePoint(x,y,z,chr->GetObjectSize()); + chr->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,chr->GetOrientation()); + } + else if (uint64 guid = objmgr.GetPlayerGUIDByName(name)) + { + PSendSysMessage(LANG_SUMMONING, name.c_str(),GetMangosString(LANG_OFFLINE)); + + // in point where GM stay + Player::SavePositionInDB(m_session->GetPlayer()->GetMapId(), + m_session->GetPlayer()->GetPositionX(), + m_session->GetPlayer()->GetPositionY(), + m_session->GetPlayer()->GetPositionZ(), + m_session->GetPlayer()->GetOrientation(), + m_session->GetPlayer()->GetZoneId(), + guid); + } + else + { + PSendSysMessage(LANG_NO_PLAYER, args); + SetSentErrorMessage(true); + } + + return true; +} + +//Teleport to Player +bool ChatHandler::HandleGonameCommand(const char* args) +{ + if(!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + std::string name = args; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + Player *chr = objmgr.GetPlayer(name.c_str()); + if (chr) + { + Map* cMap = MapManager::Instance().GetMap(chr->GetMapId(),chr); + if(cMap->Instanceable()) + { + Map* pMap = MapManager::Instance().GetMap(_player->GetMapId(),_player); + + // we have to go to instance, and can go to player only if: + // 1) we are in his group (either as leader or as member) + // 2) we are not bound to any group and have GM mode on + if (_player->GetGroup()) + { + // we are in group, we can go only if we are in the player group + if (_player->GetGroup() != chr->GetGroup()) + { + PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY,chr->GetName()); + SetSentErrorMessage(true); + return false; + } + } + else + { + // we are not in group, let's verify our GM mode + if (!_player->isGameMaster()) + { + PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM,chr->GetName()); + SetSentErrorMessage(true); + return false; + } + } + + // if the player or the player's group is bound to another instance + // the player will not be bound to another one + InstancePlayerBind *pBind = _player->GetBoundInstance(chr->GetMapId(), chr->GetDifficulty()); + if(!pBind) + { + Group *group = _player->GetGroup(); + InstanceGroupBind *gBind = group ? group->GetBoundInstance(chr->GetMapId(), chr->GetDifficulty()) : NULL; + if(!gBind) + { + // if no bind exists, create a solo bind + InstanceSave *save = sInstanceSaveManager.GetInstanceSave(chr->GetInstanceId()); + if(save) _player->BindToInstance(save, !save->CanReset()); + } + } + + _player->SetDifficulty(chr->GetDifficulty()); + } + + PSendSysMessage(LANG_APPEARING_AT, chr->GetName()); + + if (_player->IsVisibleGloballyFor(chr)) + ChatHandler(chr).PSendSysMessage(LANG_APPEARING_TO, _player->GetName()); + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + // to point to see at target with same orientation + float x,y,z; + chr->GetContactPoint(m_session->GetPlayer(),x,y,z); + + _player->TeleportTo(chr->GetMapId(), x, y, z, _player->GetAngle( chr ), TELE_TO_GM_MODE); + + return true; + } + + if (uint64 guid = objmgr.GetPlayerGUIDByName(name)) + { + PSendSysMessage(LANG_APPEARING_AT, name.c_str()); + + // to point where player stay (if loaded) + float x,y,z,o; + uint32 map; + bool in_flight; + if(Player::LoadPositionFromDB(map,x,y,z,o,in_flight,guid)) + { + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(map, x, y, z,_player->GetOrientation()); + return true; + } + } + + PSendSysMessage(LANG_NO_PLAYER, args); + + SetSentErrorMessage(true); + return false; +} + +// Teleport player to last position +bool ChatHandler::HandleRecallCommand(const char* args) +{ + Player* chr = NULL; + + if(!*args) + { + chr = getSelectedPlayer(); + if(!chr) + chr = m_session->GetPlayer(); + } + else + { + std::string name = args; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + chr = objmgr.GetPlayer(name.c_str()); + + if(!chr) + { + PSendSysMessage(LANG_NO_PLAYER, args); + SetSentErrorMessage(true); + return false; + } + } + + if(chr->IsBeingTeleported()) + { + PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName()); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(chr->isInFlight()) + { + chr->GetMotionMaster()->MovementExpired(); + chr->m_taxi.ClearTaxiDestinations(); + } + + chr->TeleportTo(chr->m_recallMap, chr->m_recallX, chr->m_recallY, chr->m_recallZ, chr->m_recallO); + return true; +} + +//Edit Player KnownTitles +bool ChatHandler::HandleModifyKnownTitlesCommand(const char* args) +{ + if(!*args) + return false; + + uint64 titles = 0; + + sscanf((char*)args, I64FMTD, &titles); + + Player *chr = getSelectedPlayer(); + if (!chr) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + uint64 titles2 = titles; + + for(int i=1; i < sCharTitlesStore.GetNumRows(); ++i) + if(CharTitlesEntry const* tEntry = sCharTitlesStore.LookupEntry(i)) + titles2 &= ~(uint64(1) << tEntry->bit_index); + + titles &= ~titles2; // remove not existed titles + + chr->SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES, titles); + SendSysMessage(LANG_DONE); + + return true; +} + +//Edit Player HP +bool ChatHandler::HandleModifyHPCommand(const char* args) +{ + if(!*args) + return false; + + // char* pHp = strtok((char*)args, " "); + // if (!pHp) + // return false; + + // char* pHpMax = strtok(NULL, " "); + // if (!pHpMax) + // return false; + + // int32 hpm = atoi(pHpMax); + // int32 hp = atoi(pHp); + + int32 hp = atoi((char*)args); + int32 hpm = atoi((char*)args); + + if (hp <= 0 || hpm <= 0 || hpm < hp) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_HP, chr->GetName(), hp, hpm); + ChatHandler(chr).PSendSysMessage(LANG_YOURS_HP_CHANGED, m_session->GetPlayer()->GetName(), hp, hpm); + + chr->SetMaxHealth( hpm ); + chr->SetHealth( hp ); + + return true; +} + +//Edit Player Mana +bool ChatHandler::HandleModifyManaCommand(const char* args) +{ + if(!*args) + return false; + + // char* pmana = strtok((char*)args, " "); + // if (!pmana) + // return false; + + // char* pmanaMax = strtok(NULL, " "); + // if (!pmanaMax) + // return false; + + // int32 manam = atoi(pmanaMax); + // int32 mana = atoi(pmana); + int32 mana = atoi((char*)args); + int32 manam = atoi((char*)args); + + if (mana <= 0 || manam <= 0 || manam < mana) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_MANA, chr->GetName(), mana, manam); + ChatHandler(chr).PSendSysMessage(LANG_YOURS_MANA_CHANGED, m_session->GetPlayer()->GetName(), mana, manam); + + chr->SetMaxPower(POWER_MANA,manam ); + chr->SetPower(POWER_MANA, mana ); + + return true; +} + +//Edit Player Energy +bool ChatHandler::HandleModifyEnergyCommand(const char* args) +{ + if(!*args) + return false; + + // char* pmana = strtok((char*)args, " "); + // if (!pmana) + // return false; + + // char* pmanaMax = strtok(NULL, " "); + // if (!pmanaMax) + // return false; + + // int32 manam = atoi(pmanaMax); + // int32 mana = atoi(pmana); + + int32 energy = atoi((char*)args)*10; + int32 energym = atoi((char*)args)*10; + + if (energy <= 0 || energym <= 0 || energym < energy) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (!chr) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_ENERGY, chr->GetName(), energy/10, energym/10); + ChatHandler(chr).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, m_session->GetPlayer()->GetName(), energy/10, energym/10); + + chr->SetMaxPower(POWER_ENERGY,energym ); + chr->SetPower(POWER_ENERGY, energy ); + + sLog.outDetail(GetMangosString(LANG_CURRENT_ENERGY),chr->GetMaxPower(POWER_ENERGY)); + + return true; +} + +//Edit Player Rage +bool ChatHandler::HandleModifyRageCommand(const char* args) +{ + if(!*args) + return false; + + // char* pmana = strtok((char*)args, " "); + // if (!pmana) + // return false; + + // char* pmanaMax = strtok(NULL, " "); + // if (!pmanaMax) + // return false; + + // int32 manam = atoi(pmanaMax); + // int32 mana = atoi(pmana); + + int32 rage = atoi((char*)args)*10; + int32 ragem = atoi((char*)args)*10; + + if (rage <= 0 || ragem <= 0 || ragem < rage) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_RAGE, chr->GetName(), rage/10, ragem/10); + // Special case: I use GetMangosString here to get local of destination char ;) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_RAGE_CHANGED), m_session->GetPlayer()->GetName(), rage/10, ragem/10); + + chr->SetMaxPower(POWER_RAGE,ragem ); + chr->SetPower(POWER_RAGE, rage ); + + return true; +} + +//Edit Player Faction +bool ChatHandler::HandleModifyFactionCommand(const char* args) +{ + if(!*args) + return false; + + char* pfactionid = extractKeyFromLink((char*)args,"Hfaction"); + + Creature* chr = getSelectedCreature(); + if(!chr) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if(!pfactionid) + { + if(chr) + { + uint32 factionid = chr->getFaction(); + uint32 flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); + uint32 npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); + uint32 dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); + PSendSysMessage(LANG_CURRENT_FACTION,chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); + } + return true; + } + + if( !chr ) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + uint32 factionid = atoi(pfactionid); + uint32 flag; + + char *pflag = strtok(NULL, " "); + if (!pflag) + flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); + else + flag = atoi(pflag); + + char* pnpcflag = strtok(NULL, " "); + + uint32 npcflag; + if(!pnpcflag) + npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); + else + npcflag = atoi(pnpcflag); + + char* pdyflag = strtok(NULL, " "); + + uint32 dyflag; + if(!pdyflag) + dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); + else + dyflag = atoi(pdyflag); + + if(!sFactionTemplateStore.LookupEntry(factionid)) + { + PSendSysMessage(LANG_WRONG_FACTION, factionid); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); + + //sprintf((char*)buf,"%s changed your Faction to %i.", m_session->GetPlayer()->GetName(), factionid); + //FillSystemMessageData(&data, m_session, buf); + + //chr->GetSession()->SendPacket(&data); + + chr->setFaction(factionid); + chr->SetUInt32Value(UNIT_FIELD_FLAGS,flag); + chr->SetUInt32Value(UNIT_NPC_FLAGS,npcflag); + chr->SetUInt32Value(UNIT_DYNAMIC_FLAGS,dyflag); + + return true; +} + +//Edit Player Spell +bool ChatHandler::HandleModifySpellCommand(const char* args) +{ + if(!*args) return false; + char* pspellflatid = strtok((char*)args, " "); + if (!pspellflatid) + return false; + + char* pop = strtok(NULL, " "); + if (!pop) + return false; + + char* pval = strtok(NULL, " "); + if (!pval) + return false; + + uint16 mark; + + char* pmark = strtok(NULL, " "); + + uint8 spellflatid = atoi(pspellflatid); + uint8 op = atoi(pop); + uint16 val = atoi(pval); + if(!pmark) + mark = 65535; + else + mark = atoi(pmark); + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_SPELLFLATID, spellflatid, val, mark, chr->GetName()); + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPELLFLATID_CHANGED, m_session->GetPlayer()->GetName(), spellflatid, val, mark); + + WorldPacket data(SMSG_SET_FLAT_SPELL_MODIFIER, (1+1+2+2)); + data << uint8(spellflatid); + data << uint8(op); + data << uint16(val); + data << uint16(mark); + chr->GetSession()->SendPacket(&data); + + return true; +} + +//Edit Player TP +bool ChatHandler::HandleModifyTalentCommand (const char* args) +{ + if (!*args) + return false; + + int tp = atoi((char*)args); + if (tp>0) + { + Player* player = getSelectedPlayer(); + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + player->SetFreeTalentPoints(tp); + return true; + } + return false; +} + +//Enable On\OFF all taxi paths +bool ChatHandler::HandleTaxiCheatCommand(const char* args) +{ + if (!*args) + { + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; + } + + std::string argstr = (char*)args; + + Player *chr = getSelectedPlayer(); + if (!chr) + { + chr=m_session->GetPlayer(); + } + + if (argstr == "on") + { + chr->SetTaxiCheater(true); + PSendSysMessage(LANG_YOU_GIVE_TAXIS, chr->GetName()); + + if(chr != m_session->GetPlayer()) + // to send localized data to target + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_TAXIS_ADDED), m_session->GetPlayer()->GetName()); + return true; + } + + if (argstr == "off") + { + chr->SetTaxiCheater(false); + PSendSysMessage(LANG_YOU_REMOVE_TAXIS, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_TAXIS_REMOVED), m_session->GetPlayer()->GetName()); + + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +//Edit Player Aspeed +bool ChatHandler::HandleModifyASpeedCommand(const char* args) +{ + if (!*args) + return false; + + float ASpeed = (float)atof((char*)args); + + if (ASpeed > 10 || ASpeed < 0.1) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(chr->isInFlight()) + { + PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_ASPEED_CHANGED), m_session->GetPlayer()->GetName(), ASpeed); + + chr->SetSpeed(MOVE_WALK, ASpeed,true); + chr->SetSpeed(MOVE_RUN, ASpeed,true); + chr->SetSpeed(MOVE_SWIM, ASpeed,true); + //chr->SetSpeed(MOVE_TURN, ASpeed,true); + chr->SetSpeed(MOVE_FLY, ASpeed,true); + return true; +} + +//Edit Player Speed +bool ChatHandler::HandleModifySpeedCommand(const char* args) +{ + if (!*args) + return false; + + float Speed = (float)atof((char*)args); + + if (Speed > 10 || Speed < 0.1) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(chr->isInFlight()) + { + PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SPEED_CHANGED), m_session->GetPlayer()->GetName(), Speed); + + chr->SetSpeed(MOVE_RUN,Speed,true); + + return true; +} + +//Edit Player Swim Speed +bool ChatHandler::HandleModifySwimCommand(const char* args) +{ + if (!*args) + return false; + + float Swim = (float)atof((char*)args); + + if (Swim > 10.0f || Swim < 0.01f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(chr->isInFlight()) + { + PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SWIM_SPEED_CHANGED), m_session->GetPlayer()->GetName(), Swim); + + chr->SetSpeed(MOVE_SWIM,Swim,true); + + return true; +} + +//Edit Player Walk Speed +bool ChatHandler::HandleModifyBWalkCommand(const char* args) +{ + if (!*args) + return false; + + float BSpeed = (float)atof((char*)args); + + if (BSpeed > 10.0f || BSpeed < 0.1f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(chr->isInFlight()) + { + PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_BACK_SPEED_CHANGED), m_session->GetPlayer()->GetName(), BSpeed); + + chr->SetSpeed(MOVE_WALKBACK,BSpeed,true); + + return true; +} + +//Edit Player Fly +bool ChatHandler::HandleModifyFlyCommand(const char* args) +{ + if (!*args) + return false; + + float FSpeed = (float)atof((char*)args); + + if (FSpeed > 10.0f || FSpeed < 0.1f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_FLY_SPEED_CHANGED), m_session->GetPlayer()->GetName(), FSpeed); + + chr->SetSpeed(MOVE_FLY,FSpeed,true); + + return true; +} + +//Edit Player Scale +bool ChatHandler::HandleModifyScaleCommand(const char* args) +{ + if (!*args) + return false; + + float Scale = (float)atof((char*)args); + if (Scale > 3.0f || Scale <= 0.0f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_SIZE_CHANGED), m_session->GetPlayer()->GetName(), Scale); + + chr->SetFloatValue(OBJECT_FIELD_SCALE_X, Scale); + + return true; +} + +//Enable Player mount +bool ChatHandler::HandleModifyMountCommand(const char* args) +{ + if(!*args) + return false; + + uint16 mId = 1147; + float speed = (float)15; + uint32 num = 0; + + num = atoi((char*)args); + switch(num) + { + case 1: + mId=14340; + break; + case 2: + mId=4806; + break; + case 3: + mId=6471; + break; + case 4: + mId=12345; + break; + case 5: + mId=6472; + break; + case 6: + mId=6473; + break; + case 7: + mId=10670; + break; + case 8: + mId=10719; + break; + case 9: + mId=10671; + break; + case 10: + mId=10672; + break; + case 11: + mId=10720; + break; + case 12: + mId=14349; + break; + case 13: + mId=11641; + break; + case 14: + mId=12244; + break; + case 15: + mId=12242; + break; + case 16: + mId=14578; + break; + case 17: + mId=14579; + break; + case 18: + mId=14349; + break; + case 19: + mId=12245; + break; + case 20: + mId=14335; + break; + case 21: + mId=207; + break; + case 22: + mId=2328; + break; + case 23: + mId=2327; + break; + case 24: + mId=2326; + break; + case 25: + mId=14573; + break; + case 26: + mId=14574; + break; + case 27: + mId=14575; + break; + case 28: + mId=604; + break; + case 29: + mId=1166; + break; + case 30: + mId=2402; + break; + case 31: + mId=2410; + break; + case 32: + mId=2409; + break; + case 33: + mId=2408; + break; + case 34: + mId=2405; + break; + case 35: + mId=14337; + break; + case 36: + mId=6569; + break; + case 37: + mId=10661; + break; + case 38: + mId=10666; + break; + case 39: + mId=9473; + break; + case 40: + mId=9476; + break; + case 41: + mId=9474; + break; + case 42: + mId=14374; + break; + case 43: + mId=14376; + break; + case 44: + mId=14377; + break; + case 45: + mId=2404; + break; + case 46: + mId=2784; + break; + case 47: + mId=2787; + break; + case 48: + mId=2785; + break; + case 49: + mId=2736; + break; + case 50: + mId=2786; + break; + case 51: + mId=14347; + break; + case 52: + mId=14346; + break; + case 53: + mId=14576; + break; + case 54: + mId=9695; + break; + case 55: + mId=9991; + break; + case 56: + mId=6448; + break; + case 57: + mId=6444; + break; + case 58: + mId=6080; + break; + case 59: + mId=6447; + break; + case 60: + mId=4805; + break; + case 61: + mId=9714; + break; + case 62: + mId=6448; + break; + case 63: + mId=6442; + break; + case 64: + mId=14632; + break; + case 65: + mId=14332; + break; + case 66: + mId=14331; + break; + case 67: + mId=8469; + break; + case 68: + mId=2830; + break; + case 69: + mId=2346; + break; + default: + SendSysMessage(LANG_NO_MOUNT); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_GIVE_MOUNT, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_MOUNT_GIVED), m_session->GetPlayer()->GetName()); + + chr->SetUInt32Value( UNIT_FIELD_FLAGS , 0x001000 ); + chr->Mount(mId); + + WorldPacket data( SMSG_FORCE_RUN_SPEED_CHANGE, (8+4+1+4) ); + data.append(chr->GetPackGUID()); + data << (uint32)0; + data << (uint8)0; //new 2.1.0 + data << float(speed); + chr->SendMessageToSet( &data, true ); + + data.Initialize( SMSG_FORCE_SWIM_SPEED_CHANGE, (8+4+4) ); + data.append(chr->GetPackGUID()); + data << (uint32)0; + data << float(speed); + chr->SendMessageToSet( &data, true ); + + return true; +} + +//Edit Player money +bool ChatHandler::HandleModifyMoneyCommand(const char* args) +{ + if (!*args) + return false; + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + int32 addmoney = atoi((char*)args); + + uint32 moneyuser = chr->GetMoney(); + + if(addmoney < 0) + { + int32 newmoney = moneyuser + addmoney; + + sLog.outDetail(GetMangosString(LANG_CURRENT_MONEY), moneyuser, addmoney, newmoney); + if(newmoney <= 0 ) + { + PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, chr->GetName()); + + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_ALL_MONEY_GONE), m_session->GetPlayer()->GetName()); + + chr->SetMoney(0); + } + else + { + PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), chr->GetName()); + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_MONEY_TAKEN), m_session->GetPlayer()->GetName(), abs(addmoney)); + chr->SetMoney( newmoney ); + } + } + else + { + PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, chr->GetName()); + if(chr != m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(ChatHandler(chr).GetMangosString(LANG_YOURS_MONEY_GIVEN), m_session->GetPlayer()->GetName(), addmoney); + chr->ModifyMoney( addmoney ); + } + + sLog.outDetail(GetMangosString(LANG_NEW_MONEY), moneyuser, addmoney, chr->GetMoney() ); + + return true; +} + +//Edit Player field +bool ChatHandler::HandleModifyBitCommand(const char* args) +{ + if( !*args ) + return false; + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + char* pField = strtok((char*)args, " "); + if (!pField) + return false; + + char* pBit = strtok(NULL, " "); + if (!pBit) + return false; + + uint16 field = atoi(pField); + uint32 bit = atoi(pBit); + + if (field < 1 || field >= PLAYER_END) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + if (bit < 1 || bit > 32) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + if ( chr->HasFlag( field, (1<<(bit-1)) ) ) + { + chr->RemoveFlag( field, (1<<(bit-1)) ); + PSendSysMessage(LANG_REMOVE_BIT, bit, field); + } + else + { + chr->SetFlag( field, (1<<(bit-1)) ); + PSendSysMessage(LANG_SET_BIT, bit, field); + } + + return true; +} + +bool ChatHandler::HandleModifyHonorCommand (const char* args) +{ + if (!*args) + return false; + + Player *target = getSelectedPlayer(); + if(!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + int32 amount = (uint32)atoi(args); + + target->ModifyHonorPoints(amount); + + PSendSysMessage(LANG_COMMAND_MODIFY_HONOR, target->GetName(), target->GetHonorPoints()); + + return true; +} + +bool ChatHandler::HandleTeleCommand(const char * args) +{ + if(!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r + GameTele const* tele = extractGameTeleFromLink((char*)args); + + if (!tele) + { + SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); + return true; +} + +bool ChatHandler::HandleLookupAreaCommand(const char* args) +{ + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + uint32 counter = 0; // Counter for figure out that we found smth. + + // converting string that we try to find to lower case + wstrToLower( wnamepart ); + + // Search in AreaTable.dbc + for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows(); ++areaflag) + { + AreaTableEntry const *areaEntry = sAreaStore.LookupEntry(areaflag); + if(areaEntry) + { + int loc = m_session->GetSessionDbcLocale(); + std::string name = areaEntry->area_name[loc]; + if(name.empty()) + continue; + + if(!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for(; loc < MAX_LOCALE; ++loc) + { + if(loc==m_session->GetSessionDbcLocale()) + continue; + + name = areaEntry->area_name[loc]; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if(loc < MAX_LOCALE) + { + // send area in "id - [name]" format + std::ostringstream ss; + ss << areaEntry->ID << " - |cffffffff|Harea:" << areaEntry->ID << "|h[" << name << " " << localeNames[loc]<< "]|h|r"; + + SendSysMessage(ss.str().c_str()); + + ++counter; + } + } + } + if (counter == 0) // if counter == 0 then we found nth + SendSysMessage(LANG_COMMAND_NOAREAFOUND); + return true; +} + +//Find tele in game_tele order by name +bool ChatHandler::HandleLookupTeleCommand(const char * args) +{ + if(!*args) + { + SendSysMessage(LANG_COMMAND_TELE_PARAMETER); + SetSentErrorMessage(true); + return false; + } + char const* str = strtok((char*)args, " "); + if(!str) + return false; + + std::string namepart = str; + std::wstring wnamepart; + + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower( wnamepart ); + + GameTeleMap const & teleMap = objmgr.GetGameTeleMap(); + + std::ostringstream reply; + for(GameTeleMap::const_iterator itr = teleMap.begin(); itr != teleMap.end(); ++itr) + { + GameTele const* tele = &itr->second; + + if(tele->wnameLow.find(wnamepart) == std::wstring::npos) + continue; + + reply << " |cffffffff|Htele:"; + reply << itr->first; + reply << "|h["; + reply << tele->name; + reply << "]|h|r\n"; + } + + if(reply.str().empty()) + SendSysMessage(LANG_COMMAND_TELE_NOLOCATION); + else + PSendSysMessage(LANG_COMMAND_TELE_LOCATION,reply.str().c_str()); + + return true; +} + +//Enable\Dissable accept whispers (for GM) +bool ChatHandler::HandleWhispersCommand(const char* args) +{ + if(!*args) + { + PSendSysMessage(LANG_COMMAND_WHISPERACCEPTING, m_session->GetPlayer()->isAcceptWhispers() ? GetMangosString(LANG_ON) : GetMangosString(LANG_OFF)); + return true; + } + + std::string argstr = (char*)args; + // whisper on + if (argstr == "on") + { + m_session->GetPlayer()->SetAcceptWhispers(true); + SendSysMessage(LANG_COMMAND_WHISPERON); + return true; + } + + // whisper off + if (argstr == "off") + { + m_session->GetPlayer()->SetAcceptWhispers(false); + SendSysMessage(LANG_COMMAND_WHISPEROFF); + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +//Play sound +bool ChatHandler::HandlePlaySoundCommand(const char* args) +{ + // USAGE: .debug playsound #soundid + // #soundid - ID decimal number from SoundEntries.dbc (1st column) + // this file have about 5000 sounds. + // In this realization only caller can hear this sound. + if( *args ) + { + uint32 dwSoundId = atoi((char*)args); + + if( !sSoundEntriesStore.LookupEntry(dwSoundId) ) + { + PSendSysMessage(LANG_SOUND_NOT_EXIST, dwSoundId); + SetSentErrorMessage(true); + return false; + } + + WorldPacket data(SMSG_PLAY_OBJECT_SOUND,4+8); + data << uint32(dwSoundId) << m_session->GetPlayer()->GetGUID(); + m_session->SendPacket(&data); + + PSendSysMessage(LANG_YOU_HEAR_SOUND, dwSoundId); + return true; + } + + return false; +} + +//Save all players in the world +bool ChatHandler::HandleSaveAllCommand(const char* /*args*/) +{ + ObjectAccessor::Instance().SaveAllPlayers(); + SendSysMessage(LANG_PLAYERS_SAVED); + return true; +} + +//Send mail by command +bool ChatHandler::HandleSendMailCommand(const char* args) +{ + if(!*args) + return false; + + char* pName = strtok((char*)args, " "); + char* msgSubject = strtok(NULL, " "); + char* msgText = strtok(NULL, ""); + + if (!msgText) + return false; + + // pName, msgSubject, msgText isn't NUL after prev. check + + std::string name = pName; + std::string subject = msgSubject; + std::string text = msgText; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 receiver_guid = objmgr.GetPlayerGUIDByName(name); + + if(!receiver_guid) + return false; + + uint32 mailId = objmgr.GenerateMailID(); + uint32 sender_guidlo = m_session->GetPlayer()->GetGUIDLow(); + uint32 messagetype = MAIL_NORMAL; + uint32 stationery = MAIL_STATIONERY_GM; + uint32 itemTextId = 0; + if (!text.empty()) + { + itemTextId = objmgr.CreateItemText( text ); + } + + Player *receiver = objmgr.GetPlayer(receiver_guid); + + WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_NONE); + + PSendSysMessage(LANG_MAIL_SENT, name.c_str()); + return true; +} + +// teleport player to given game_tele.entry +bool ChatHandler::HandleNameTeleCommand(const char * args) +{ + if(!*args) + return false; + + char* pName = strtok((char*)args, " "); + + if(!pName) + return false; + + std::string name = pName; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + char* tail = strtok(NULL, ""); + if(!tail) + return false; + + // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r + GameTele const* tele = extractGameTeleFromLink(tail); + if(!tele) + { + SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + + Player *chr = objmgr.GetPlayer(name.c_str()); + if (chr) + { + + if(chr->IsBeingTeleported()==true) + { + PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_TELEPORTING_TO, chr->GetName(),"", tele->name.c_str()); + + if (m_session->GetPlayer()->IsVisibleGloballyFor(chr)) + ChatHandler(chr).PSendSysMessage(LANG_TELEPORTED_TO_BY, m_session->GetPlayer()->GetName()); + + // stop flight if need + if(chr->isInFlight()) + { + chr->GetMotionMaster()->MovementExpired(); + chr->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + chr->SaveRecallPosition(); + + chr->TeleportTo(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation); + } + else if (uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str())) + { + PSendSysMessage(LANG_TELEPORTING_TO, name.c_str(), GetMangosString(LANG_OFFLINE), tele->name.c_str()); + Player::SavePositionInDB(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation,MapManager::Instance().GetZoneId(tele->mapId,tele->position_x,tele->position_y),guid); + } + else + PSendSysMessage(LANG_NO_PLAYER, name.c_str()); + + return true; +} + +//Teleport group to given game_tele.entry +bool ChatHandler::HandleGroupTeleCommand(const char * args) +{ + if(!*args) + return false; + + Player *player = getSelectedPlayer(); + if (!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r + GameTele const* tele = extractGameTeleFromLink((char*)args); + if(!tele) + { + SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + + Group *grp = player->GetGroup(); + if(!grp) + { + PSendSysMessage(LANG_NOT_IN_GROUP,player->GetName()); + SetSentErrorMessage(true); + return false; + } + + for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *pl = itr->getSource(); + + if(!pl || !pl->GetSession() ) + continue; + + if(pl->IsBeingTeleported()) + { + PSendSysMessage(LANG_IS_TELEPORTED, pl->GetName()); + continue; + } + + PSendSysMessage(LANG_TELEPORTING_TO, pl->GetName(),"", tele->name.c_str()); + + if (m_session->GetPlayer() != pl && m_session->GetPlayer()->IsVisibleGloballyFor(pl)) + ChatHandler(pl).PSendSysMessage(LANG_TELEPORTED_TO_BY, m_session->GetPlayer()->GetName()); + + // stop flight if need + if(pl->isInFlight()) + { + pl->GetMotionMaster()->MovementExpired(); + pl->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + pl->SaveRecallPosition(); + + pl->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); + } + + return true; +} + +//Summon group of player +bool ChatHandler::HandleGroupgoCommand(const char* args) +{ + if(!*args) + return false; + + std::string name = args; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + Player *player = objmgr.GetPlayer(name.c_str()); + if (!player) + { + PSendSysMessage(LANG_NO_PLAYER, args); + SetSentErrorMessage(true); + return false; + } + + Group *grp = player->GetGroup(); + + if(!grp) + { + PSendSysMessage(LANG_NOT_IN_GROUP,player->GetName()); + SetSentErrorMessage(true); + return false; + } + + Map* gmMap = MapManager::Instance().GetMap(m_session->GetPlayer()->GetMapId(),m_session->GetPlayer()); + bool to_instance = gmMap->Instanceable(); + + // we are in instance, and can summon only player in our group with us as lead + if ( to_instance && ( + !m_session->GetPlayer()->GetGroup() || (grp->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) || + (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) ) ) + // the last check is a bit excessive, but let it be, just in case + { + SendSysMessage(LANG_CANNOT_SUMMON_TO_INST); + SetSentErrorMessage(true); + return false; + } + + for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *pl = itr->getSource(); + + if(!pl || pl==m_session->GetPlayer() || !pl->GetSession() ) + continue; + + if(pl->IsBeingTeleported()==true) + { + PSendSysMessage(LANG_IS_TELEPORTED, pl->GetName()); + SetSentErrorMessage(true); + return false; + } + + if (to_instance) + { + Map* plMap = MapManager::Instance().GetMap(pl->GetMapId(),pl); + + if ( plMap->Instanceable() && plMap->GetInstanceId() != gmMap->GetInstanceId() ) + { + // cannot summon from instance to instance + PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,pl->GetName()); + SetSentErrorMessage(true); + return false; + } + } + + PSendSysMessage(LANG_SUMMONING, pl->GetName(),""); + + if (m_session->GetPlayer()->IsVisibleGloballyFor(pl)) + ChatHandler(pl).PSendSysMessage(LANG_SUMMONED_BY, m_session->GetPlayer()->GetName()); + + // stop flight if need + if(pl->isInFlight()) + { + pl->GetMotionMaster()->MovementExpired(); + pl->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + pl->SaveRecallPosition(); + + // before GM + float x,y,z; + m_session->GetPlayer()->GetClosePoint(x,y,z,pl->GetObjectSize()); + pl->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,pl->GetOrientation()); + } + + return true; +} + +//teleport at coordinates +bool ChatHandler::HandleGoXYCommand(const char* args) +{ + if(!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pmapid = strtok(NULL, " "); + + if (!px || !py) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + uint32 mapid; + if (pmapid) + mapid = (uint32)atoi(pmapid); + else mapid = _player->GetMapId(); + + if(!MapManager::IsValidMapCoord(mapid,x,y)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + Map const *map = MapManager::Instance().GetBaseMap(mapid); + float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + + _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); + + return true; +} + +//teleport at coordinates, including Z +bool ChatHandler::HandleGoXYZCommand(const char* args) +{ + if(!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + char* pmapid = strtok(NULL, " "); + + if (!px || !py || !pz) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + float z = (float)atof(pz); + uint32 mapid; + if (pmapid) + mapid = (uint32)atoi(pmapid); + else + mapid = _player->GetMapId(); + + if(!MapManager::IsValidMapCoord(mapid,x,y,z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); + + return true; +} + +//teleport at coordinates +bool ChatHandler::HandleGoZoneXYCommand(const char* args) +{ + if(!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* tail = strtok(NULL,""); + + char* cAreaId = extractKeyFromLink(tail,"Harea"); // string or [name] Shift-click form |color|Harea:area_id|h[name]|h|r + + if (!px || !py) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + uint32 areaid = cAreaId ? (uint32)atoi(cAreaId) : _player->GetZoneId(); + + AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaid); + + if( x<0 || x>100 || y<0 || y>100 || !areaEntry ) + { + PSendSysMessage(LANG_INVALID_ZONE_COORD,x,y,areaid); + SetSentErrorMessage(true); + return false; + } + + // update to parent zone if exist (client map show only zones without parents) + AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry; + + Map const *map = MapManager::Instance().GetBaseMap(zoneEntry->mapid); + + if(map->Instanceable()) + { + PSendSysMessage(LANG_INVALID_ZONE_MAP,areaEntry->ID,areaEntry->area_name[m_session->GetSessionDbcLocale()],map->GetId(),map->GetMapName()); + SetSentErrorMessage(true); + return false; + } + + Zone2MapCoordinates(x,y,zoneEntry->ID); + + if(!MapManager::IsValidMapCoord(zoneEntry->mapid,x,y)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,zoneEntry->mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + _player->TeleportTo(zoneEntry->mapid, x, y, z, _player->GetOrientation()); + + return true; +} + +//teleport to grid +bool ChatHandler::HandleGoGridCommand(const char* args) +{ + if(!*args) return false; + Player* _player = m_session->GetPlayer(); + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pmapid = strtok(NULL, " "); + + if (!px || !py) + return false; + + float grid_x = (float)atof(px); + float grid_y = (float)atof(py); + uint32 mapid; + if (pmapid) + mapid = (uint32)atoi(pmapid); + else mapid = _player->GetMapId(); + + // center of grid + float x = (grid_x-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; + float y = (grid_y-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; + + if(!MapManager::IsValidMapCoord(mapid,x,y)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + Map const *map = MapManager::Instance().GetBaseMap(mapid); + float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); + + return true; +} + +bool ChatHandler::HandleDrunkCommand(const char* args) +{ + if(!*args) return false; + + uint32 drunklevel = (uint32)atoi(args); + if(drunklevel > 100) + drunklevel = 100; + + uint16 drunkMod = drunklevel * 0xFFFF / 100; + + m_session->GetPlayer()->SetDrunkValue(drunkMod); + + return true; +} diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 63ad2a7a0b9..d3457d19493 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -1,3948 +1,4046 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "Item.h" -#include "GameObject.h" -#include "Opcodes.h" -#include "Chat.h" -#include "ObjectAccessor.h" -#include "MapManager.h" -#include "Language.h" -#include "World.h" -#include "GameEvent.h" -#include "SpellMgr.h" -#include "WaypointManager.h" -#include "Util.h" -#include -#include -#include -#include - -static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] = -{ - LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL, - LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED -}; - -//mute player for some times -bool ChatHandler::HandleMuteCommand(const char* args) -{ - if (!*args) - return false; - - char *charname = strtok((char*)args, " "); - if (!charname) - return false; - - std::string cname = charname; - - char *timetonotspeak = strtok(NULL, " "); - if(!timetonotspeak) - return false; - - uint32 notspeaktime = (uint32) atoi(timetonotspeak); - - if(!normalizePlayerName(cname)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str()); - if(!guid) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - Player *chr = objmgr.GetPlayer(guid); - - // check security - uint32 account_id = 0; - uint32 security = 0; - - if (chr) - { - account_id = chr->GetSession()->GetAccountId(); - security = chr->GetSession()->GetSecurity(); - } - else - { - account_id = objmgr.GetPlayerAccountIdByGUID(guid); - security = objmgr.GetSecurityByAccount(account_id); - } - - if(security >= m_session->GetSecurity()) - { - SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); - SetSentErrorMessage(true); - return false; - } - - time_t mutetime = time(NULL) + notspeaktime*60; - - if (chr) - chr->GetSession()->m_muteTime = mutetime; - - loginDatabase.PExecute("UPDATE account SET mutetime = " I64FMTD " WHERE id = '%u'",uint64(mutetime), account_id ); - - if(chr) - ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime); - - PSendSysMessage(LANG_YOU_DISABLE_CHAT, cname.c_str(), notspeaktime); - - return true; -} - -//unmute player -bool ChatHandler::HandleUnmuteCommand(const char* args) -{ - if (!*args) - return false; - - char *charname = strtok((char*)args, " "); - if (!charname) - return false; - - std::string cname = charname; - - if(!normalizePlayerName(cname)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str()); - if(!guid) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - Player *chr = objmgr.GetPlayer(guid); - - // check security - uint32 account_id = 0; - uint32 security = 0; - - if (chr) - { - account_id = chr->GetSession()->GetAccountId(); - security = chr->GetSession()->GetSecurity(); - } - else - { - account_id = objmgr.GetPlayerAccountIdByGUID(guid); - security = objmgr.GetSecurityByAccount(account_id); - } - - if(security >= m_session->GetSecurity()) - { - SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); - SetSentErrorMessage(true); - return false; - } - - if (chr) - { - if(chr->CanSpeak()) - { - SendSysMessage(LANG_CHAT_ALREADY_ENABLED); - SetSentErrorMessage(true); - return false; - } - - chr->GetSession()->m_muteTime = 0; - } - - loginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id ); - - if(chr) - ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_ENABLED); - - PSendSysMessage(LANG_YOU_ENABLE_CHAT, cname.c_str()); - return true; -} - -bool ChatHandler::HandleTargetObjectCommand(const char* args) -{ - Player* pl = m_session->GetPlayer(); - QueryResult *result; - GameEvent::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList(); - if(*args) - { - int32 id = atoi((char*)args); - if(id) - result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),id); - else - { - std::string name = args; - WorldDatabase.escape_string(name); - result = WorldDatabase.PQuery( - "SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ " - "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" '""%%%s%%""' ORDER BY order_ ASC LIMIT 1", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str()); - } - } - else - { - std::ostringstream eventFilter; - eventFilter << " AND (event IS NULL "; - bool initString = true; - - for (GameEvent::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr) - { - if (initString) - { - eventFilter << "OR event IN (" <<*itr; - initString =false; - } - else - eventFilter << "," << *itr; - } - - if (!initString) - eventFilter << "))"; - else - eventFilter << ")"; - - result = WorldDatabase.PQuery("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, " - "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject " - "LEFT OUTER JOIN game_event_gameobject on gameobject.guid=game_event_gameobject.guid WHERE map = '%i' %s ORDER BY order_ ASC LIMIT 1", - m_session->GetPlayer()->GetPositionX(), m_session->GetPlayer()->GetPositionY(), m_session->GetPlayer()->GetPositionZ(), m_session->GetPlayer()->GetMapId(),eventFilter.str().c_str()); - } - - if (!result) - { - SendSysMessage(LANG_COMMAND_TARGETOBJNOTFOUND); - return true; - } - - Field *fields = result->Fetch(); - uint32 lowguid = fields[0].GetUInt32(); - uint32 id = fields[1].GetUInt32(); - float x = fields[2].GetFloat(); - float y = fields[3].GetFloat(); - float z = fields[4].GetFloat(); - float o = fields[5].GetFloat(); - int mapid = fields[6].GetUInt16(); - delete result; - - GameObjectInfo const* goI = objmgr.GetGameObjectInfo(id); - - if (!goI) - { - PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); - return false; - } - - GameObject* target = ObjectAccessor::GetGameObject(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,id,HIGHGUID_GAMEOBJECT)); - - PSendSysMessage(LANG_GAMEOBJECT_DETAIL, lowguid, goI->name, lowguid, id, x, y, z, mapid, o); - - if(target) - { - int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL); - if(curRespawnDelay < 0) - curRespawnDelay = 0; - - std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true); - std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true); - - PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str()); - } - return true; -} - -//teleport to gameobject -bool ChatHandler::HandleGoObjectCommand(const char* args) -{ - if(!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if(!cId) - return false; - - int32 guid = atoi(cId); - if(!guid) - return false; - - float x, y, z, ort; - int mapid; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(guid)) - { - x = go_data->posX; - y = go_data->posY; - z = go_data->posZ; - ort = go_data->orientation; - mapid = go_data->mapid; - } - else - { - SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND); - SetSentErrorMessage(true); - return false; - } - - if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, ort); - return true; -} - -bool ChatHandler::HandleGoTriggerCommand(const char* args) -{ - Player* _player = m_session->GetPlayer(); - - if (!*args) - return false; - - char *atId = strtok((char*)args, " "); - if (!atId) - return false; - - int32 i_atId = atoi(atId); - - if(!i_atId) - return false; - - AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(i_atId); - if (!at) - { - PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND,i_atId); - SetSentErrorMessage(true); - return false; - } - - if(!MapManager::IsValidMapCoord(at->mapid,at->x,at->y,at->z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,at->x,at->y,at->mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(at->mapid, at->x, at->y, at->z, _player->GetOrientation()); - return true; -} - -bool ChatHandler::HandleGoGraveyardCommand(const char* args) -{ - Player* _player = m_session->GetPlayer(); - - if (!*args) - return false; - - char *gyId = strtok((char*)args, " "); - if (!gyId) - return false; - - int32 i_gyId = atoi(gyId); - - if(!i_gyId) - return false; - - WorldSafeLocsEntry const* gy = sWorldSafeLocsStore.LookupEntry(i_gyId); - if (!gy) - { - PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST,i_gyId); - SetSentErrorMessage(true); - return false; - } - - if(!MapManager::IsValidMapCoord(gy->map_id,gy->x,gy->y,gy->z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,gy->x,gy->y,gy->map_id); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(gy->map_id, gy->x, gy->y, gy->z, _player->GetOrientation()); - return true; -} - -/** \brief Teleport the GM to the specified creature - * - * .gocreature --> TP using creature.guid - * .gocreature azuregos --> TP player to the mob with this name - * Warning: If there is more than one mob with this name - * you will be teleported to the first one that is found. - * .gocreature id 6109 --> TP player to the mob, that has this creature_template.entry - * Warning: If there is more than one mob with this "id" - * you will be teleported to the first one that is found. - */ -//teleport to creature -bool ChatHandler::HandleGoCreatureCommand(const char* args) -{ - if(!*args) - return false; - Player* _player = m_session->GetPlayer(); - - // "id" or number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r - char* pParam1 = extractKeyFromLink((char*)args,"Hcreature"); - if (!pParam1) - return false; - - std::ostringstream whereClause; - - // User wants to teleport to the NPC's template entry - if( strcmp(pParam1, "id") == 0 ) - { - //sLog.outError("DEBUG: ID found"); - - // Get the "creature_template.entry" - // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r - char* tail = strtok(NULL,""); - if(!tail) - return false; - char* cId = extractKeyFromLink(tail,"Hcreature_entry"); - if(!cId) - return false; - - int32 tEntry = atoi(cId); - //sLog.outError("DEBUG: ID value: %d", tEntry); - if(!tEntry) - return false; - - whereClause << "WHERE id = '" << tEntry << "'"; - } - else - { - //sLog.outError("DEBUG: ID *not found*"); - - int32 guid = atoi(pParam1); - - // Number is invalid - maybe the user specified the mob's name - if(!guid) - { - std::string name = pParam1; - WorldDatabase.escape_string(name); - whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name "_LIKE_" '" << name << "'"; - } - else - { - whereClause << "WHERE guid = '" << guid << "'"; - } - } - //sLog.outError("DEBUG: %s", whereClause.c_str()); - - QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM creature %s", whereClause.str().c_str() ); - if (!result) - { - SendSysMessage(LANG_COMMAND_GOCREATNOTFOUND); - SetSentErrorMessage(true); - return false; - } - if( result->GetRowCount() > 1 ) - { - SendSysMessage(LANG_COMMAND_GOCREATMULTIPLE); - } - - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - float ort = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - - delete result; - - if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, ort); - return true; -} - -bool ChatHandler::HandleGUIDCommand(const char* /*args*/) -{ - uint64 guid = m_session->GetPlayer()->GetSelection(); - - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_OBJECT_GUID, GUID_LOPART(guid), GUID_HIPART(guid)); - return true; -} - -bool ChatHandler::HandleLookupFactionCommand(const char* args) -{ - if(!*args) - return false; - - Player *target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - std::string namepart = args; - std::wstring wnamepart; - - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower( wnamepart ); - - uint32 counter = 0; // Counter for figure out that we found smth. - - for (uint32 id = 0; id < sFactionStore.GetNumRows(); id++) - //for(FactionStateList::const_iterator itr = target->m_factions.begin(); itr != target->m_factions.end(); ++itr) - { - FactionEntry const *factionEntry = sFactionStore.LookupEntry(id); - //FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID); - if (factionEntry) - { - FactionStateList::const_iterator repItr = target->m_factions.find(factionEntry->reputationListID); - - int loc = m_session->GetSessionDbcLocale(); - std::string name = factionEntry->name[loc]; - if(name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for(; loc < MAX_LOCALE; ++loc) - { - if(loc==m_session->GetSessionDbcLocale()) - continue; - - name = factionEntry->name[loc]; - if(name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if(loc < MAX_LOCALE) - { - // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format - // or "id - [faction] [no reputation]" format - std::ostringstream ss; - ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r"; - - if (repItr != target->m_factions.end()) - { - ReputationRank rank = target->GetReputationRank(factionEntry); - std::string rankName = GetMangosString(ReputationRankStrIndex[rank]); - - ss << " " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")"; - - if(repItr->second.Flags & FACTION_FLAG_VISIBLE) - ss << GetMangosString(LANG_FACTION_VISIBLE); - if(repItr->second.Flags & FACTION_FLAG_AT_WAR) - ss << GetMangosString(LANG_FACTION_ATWAR); - if(repItr->second.Flags & FACTION_FLAG_PEACE_FORCED) - ss << GetMangosString(LANG_FACTION_PEACE_FORCED); - if(repItr->second.Flags & FACTION_FLAG_HIDDEN) - ss << GetMangosString(LANG_FACTION_HIDDEN); - if(repItr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED) - ss << GetMangosString(LANG_FACTION_INVISIBLE_FORCED); - if(repItr->second.Flags & FACTION_FLAG_INACTIVE) - ss << GetMangosString(LANG_FACTION_INACTIVE); - } - else - ss << GetMangosString(LANG_FACTION_NOREPUTATION); - - SendSysMessage(ss.str().c_str()); - counter++; - } - } - } - - if (counter == 0) // if counter == 0 then we found nth - SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND); - return true; -} - -bool ChatHandler::HandleModifyRepCommand(const char * args) -{ - if (!*args) return false; - - Player* target = NULL; - target = getSelectedPlayer(); - - if(!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - char* factionTxt = extractKeyFromLink((char*)args,"Hfaction"); - if(!factionTxt) - return false; - - uint32 factionId = atoi(factionTxt); - - int32 amount = 0; - char *rankTxt = strtok(NULL, " "); - if (!factionTxt || !rankTxt) - return false; - - amount = atoi(rankTxt); - if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0])) - { - std::string rankStr = rankTxt; - std::wstring wrankStr; - if(!Utf8toWStr(rankStr,wrankStr)) - return false; - wstrToLower( wrankStr ); - - int r = 0; - amount = -42000; - for (; r < MAX_REPUTATION_RANK; ++r) - { - std::string rank = GetMangosString(ReputationRankStrIndex[r]); - if(rank.empty()) - continue; - - std::wstring wrank; - if(!Utf8toWStr(rank,wrank)) - continue; - - wstrToLower(wrank); - - if(wrank.substr(0,wrankStr.size())==wrankStr) - { - char *deltaTxt = strtok(NULL, " "); - if (deltaTxt) - { - int32 delta = atoi(deltaTxt); - if ((delta < 0) || (delta > Player::ReputationRank_Length[r] -1)) - { - PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (Player::ReputationRank_Length[r]-1)); - SetSentErrorMessage(true); - return false; - } - amount += delta; - } - break; - } - amount += Player::ReputationRank_Length[r]; - } - if (r >= MAX_REPUTATION_RANK) - { - PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt); - SetSentErrorMessage(true); - return false; - } - } - - FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId); - - if (!factionEntry) - { - PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId); - SetSentErrorMessage(true); - return false; - } - - if (factionEntry->reputationListID < 0) - { - PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->name[m_session->GetSessionDbcLocale()], factionId); - SetSentErrorMessage(true); - return false; - } - - target->SetFactionReputation(factionEntry,amount); - PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[m_session->GetSessionDbcLocale()], factionId, target->GetName(), target->GetReputation(factionId)); - return true; -} - -bool ChatHandler::HandleNameCommand(const char* args) -{ - /* Temp. disabled - if(!*args) - return false; - - if(strlen((char*)args)>75) - { - PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75); - return true; - } - - for (uint8 i = 0; i < strlen(args); i++) - { - if(!isalpha(args[i]) && args[i]!=' ') - { - SendSysMessage(LANG_CHARS_ONLY); - return false; - } - } - - uint64 guid; - guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - pCreature->SetName(args); - uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName()); - pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); - - pCreature->SaveToDB(); - */ - - return true; -} - -bool ChatHandler::HandleSubNameCommand(const char* /*args*/) -{ - /* Temp. disabled - - if(!*args) - args = ""; - - if(strlen((char*)args)>75) - { - - PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75); - return true; - } - - for (uint8 i = 0; i < strlen(args); i++) - { - if(!isalpha(args[i]) && args[i]!=' ') - { - SendSysMessage(LANG_CHARS_ONLY); - return false; - } - } - uint64 guid; - guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID)); - pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); - - pCreature->SaveToDB(); - */ - return true; -} - -//move item to other slot -bool ChatHandler::HandleItemMoveCommand(const char* args) -{ - if(!*args) - return false; - uint8 srcslot, dstslot; - - char* pParam1 = strtok((char*)args, " "); - if (!pParam1) - return false; - - char* pParam2 = strtok(NULL, " "); - if (!pParam2) - return false; - - srcslot = (uint8)atoi(pParam1); - dstslot = (uint8)atoi(pParam2); - - uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); - uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); - - if(srcslot==dstslot) - return true; - - m_session->GetPlayer()->SwapItem( src, dst ); - - return true; -} - -//add spawn of creature -bool ChatHandler::HandleAddSpwCommand(const char* args) -{ - if(!*args) - return false; - char* charID = strtok((char*)args, " "); - if (!charID) - return false; - - char* team = strtok(NULL, " "); - int32 teamval = 0; - if (team) { teamval = atoi(team); } - if (teamval < 0) { teamval = 0; } - - uint32 id = atoi(charID); - - Player *chr = m_session->GetPlayer(); - float x = chr->GetPositionX(); - float y = chr->GetPositionY(); - float z = chr->GetPositionZ(); - float o = chr->GetOrientation(); - Map *map = chr->GetMap(); - - Creature* pCreature = new Creature; - if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, (uint32)teamval)) - { - delete pCreature; - return false; - } - - pCreature->Relocate(x,y,z,o); - - if(!pCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); - delete pCreature; - return false; - } - - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - - uint32 db_guid = pCreature->GetDBTableGUIDLow(); - - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - pCreature->LoadFromDB(db_guid, map); - - map->Add(pCreature); - objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid)); - return true; -} - -bool ChatHandler::HandleDelCreatureCommand(const char* args) -{ - Creature* unit = NULL; - - if(*args) - { - // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hcreature"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - if(!lowguid) - return false; - - if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid)) - unit = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT)); - } - else - unit = getSelectedCreature(); - - if(!unit || unit->isPet() || unit->isTotem()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // Delete the creature - unit->CombatStop(); - unit->DeleteFromDB(); - unit->CleanupsBeforeDelete(); - unit->AddObjectToRemoveList(); - - SendSysMessage(LANG_COMMAND_DELCREATMESSAGE); - - return true; -} - -//delete object by selection or guid -bool ChatHandler::HandleDelObjectCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - if(!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if(!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - uint64 owner_guid = obj->GetOwnerGUID(); - if(owner_guid) - { - Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid); - if(!owner && !IS_PLAYER_GUID(owner_guid)) - { - PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow()); - SetSentErrorMessage(true); - return false; - } - - owner->RemoveGameObject(obj,false); - } - - obj->SetRespawnTime(0); // not save respawn time - obj->Delete(); - obj->DeleteFromDB(); - - PSendSysMessage(LANG_COMMAND_DELOBJMESSAGE, obj->GetGUIDLow()); - - return true; -} - -//turn selected object -bool ChatHandler::HandleTurnObjectCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - if(!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if(!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - char* po = strtok(NULL, " "); - float o; - - if (po) - { - o = (float)atof(po); - } - else - { - Player *chr = m_session->GetPlayer(); - o = chr->GetOrientation(); - } - - float rot2 = sin(o/2); - float rot3 = cos(o/2); - - Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj); - map->Remove(obj,false); - - obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o); - - obj->SetFloatValue(GAMEOBJECT_FACING, o); - obj->SetFloatValue(GAMEOBJECT_ROTATION+2, rot2); - obj->SetFloatValue(GAMEOBJECT_ROTATION+3, rot3); - - map->Add(obj); - - obj->SaveToDB(); - obj->Refresh(); - - PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), o); - - return true; -} - -//move selected creature -bool ChatHandler::HandleMoveCreatureCommand(const char* args) -{ - uint32 lowguid = 0; - - Creature* pCreature = getSelectedCreature(); - - if(!pCreature) - { - // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hcreature"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - - /* FIXME: impossibel without entry - if(lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - // Attempting creature load from DB data - if(!pCreature) - { - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - uint32 map_id = data->mapid; - - if(m_session->GetPlayer()->GetMapId()!=map_id) - { - PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - lowguid = pCreature->GetDBTableGUIDLow(); - } - } - else - { - lowguid = pCreature->GetDBTableGUIDLow(); - } - - float x = m_session->GetPlayer()->GetPositionX(); - float y = m_session->GetPlayer()->GetPositionY(); - float z = m_session->GetPlayer()->GetPositionZ(); - float o = m_session->GetPlayer()->GetOrientation(); - - if (pCreature) - { - if(CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow())) - { - const_cast(data)->posX = x; - const_cast(data)->posY = y; - const_cast(data)->posZ = z; - const_cast(data)->orientation = o; - } - MapManager::Instance().GetMap(pCreature->GetMapId(),pCreature)->CreatureRelocation(pCreature,x, y, z,o); - pCreature->GetMotionMaster()->Initialize(); - if(pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - } - - WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid); - PSendSysMessage(LANG_COMMAND_CREATUREMOVED); - return true; -} - -//move selected object -bool ChatHandler::HandleMoveObjectCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - if(!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if(!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - char* px = strtok(NULL, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - - if (!px) - { - Player *chr = m_session->GetPlayer(); - - Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj); - map->Remove(obj,false); - - obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation()); - obj->SetFloatValue(GAMEOBJECT_POS_X, chr->GetPositionX()); - obj->SetFloatValue(GAMEOBJECT_POS_Y, chr->GetPositionY()); - obj->SetFloatValue(GAMEOBJECT_POS_Z, chr->GetPositionZ()); - - map->Add(obj); - } - else - { - if(!py || !pz) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - float z = (float)atof(pz); - - if(!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId()); - SetSentErrorMessage(true); - return false; - } - - Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj); - map->Remove(obj,false); - - obj->Relocate(x, y, z, obj->GetOrientation()); - obj->SetFloatValue(GAMEOBJECT_POS_X, x); - obj->SetFloatValue(GAMEOBJECT_POS_Y, y); - obj->SetFloatValue(GAMEOBJECT_POS_Z, z); - - map->Add(obj); - } - - obj->SaveToDB(); - obj->Refresh(); - - PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow()); - - return true; -} - -//demorph player or unit -bool ChatHandler::HandleDeMorphCommand(const char* /*args*/) -{ - Unit *target = getSelectedUnit(); - if(!target) - target = m_session->GetPlayer(); - - target->DeMorph(); - - return true; -} - -//add item in vendorlist -bool ChatHandler::HandleAddVendorItemCommand(const char* args) -{ - if (!*args) - return false; - - Creature* vendor = getSelectedCreature(); - if (!vendor || !vendor->isVendor()) - { - SendSysMessage(LANG_COMMAND_VENDORSELECTION); - SetSentErrorMessage(true); - return false; - } - - char* pitem = extractKeyFromLink((char*)args,"Hitem"); - if (!pitem) - { - SendSysMessage(LANG_COMMAND_NEEDITEMSEND); - SetSentErrorMessage(true); - return false; - } - uint32 itemId = atol(pitem); - - char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0 - uint32 maxcount = 0; - if (fmaxcount) - maxcount = atol(fmaxcount); - - char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0 - uint32 incrtime = 0; - if (fincrtime) - incrtime = atol(fincrtime); - - char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0 - uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0; - - ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); - if(!pProto) - { - PSendSysMessage(LANG_ITEM_NOT_FOUND, itemId); - SetSentErrorMessage(true); - return false; - } - - if(extendedcost && !sItemExtendedCostStore.LookupEntry(extendedcost)) - { - PSendSysMessage(LANG_BAD_VALUE, extendedcost); - SetSentErrorMessage(true); - return false; - } - - // load vendor items if not yet - vendor->LoadGoods(); - - if(vendor->FindItem(itemId)) - { - PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST,itemId); - SetSentErrorMessage(true); - return false; - } - - if (vendor->GetItemCount() >= MAX_VENDOR_ITEMS) - { - SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS); - SetSentErrorMessage(true); - return false; - } - - // add to DB and to current ingame vendor - WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')",vendor->GetEntry(), itemId, maxcount,incrtime,extendedcost); - vendor->AddItem(itemId,maxcount,incrtime,extendedcost); - PSendSysMessage(LANG_ITEM_ADDED_TO_LIST,itemId,pProto->Name1,maxcount,incrtime,extendedcost); - return true; -} - -//del item from vendor list -bool ChatHandler::HandleDelVendorItemCommand(const char* args) -{ - if (!*args) - return false; - - Creature* vendor = getSelectedCreature(); - if (!vendor || !vendor->isVendor()) - { - SendSysMessage(LANG_COMMAND_VENDORSELECTION); - SetSentErrorMessage(true); - return false; - } - - char* pitem = extractKeyFromLink((char*)args,"Hitem"); - if (!pitem) - { - SendSysMessage(LANG_COMMAND_NEEDITEMSEND); - SetSentErrorMessage(true); - return false; - } - uint32 itemId = atol(pitem); - - ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); - if(!pProto) - { - PSendSysMessage(LANG_ITEM_NOT_FOUND, itemId); - SetSentErrorMessage(true); - return false; - } - - // load vendor items if not yet - vendor->LoadGoods(); - - if (!vendor->RemoveItem(itemId)) - { - PSendSysMessage(LANG_ITEM_NOT_IN_LIST,itemId); - SetSentErrorMessage(true); - return false; - } - - WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",vendor->GetEntry(), itemId); - PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST,itemId,pProto->Name1); - return true; -} - -//add move for creature -bool ChatHandler::HandleAddMoveCommand(const char* args) -{ - if(!*args) - return false; - - char* guid_str = strtok((char*)args, " "); - char* wait_str = strtok((char*)NULL, " "); - - uint32 lowguid = atoi((char*)guid_str); - - Creature* pCreature = NULL; - - /* FIXME: impossible without entry - if(lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - // attempt check creature existence by DB data - if(!pCreature) - { - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - // obtain real GUID for DB operations - lowguid = pCreature->GetDBTableGUIDLow(); - } - - int wait = wait_str ? atoi(wait_str) : 0; - - if(wait < 0) - wait = 0; - - Player* player = m_session->GetPlayer(); - - WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0); - - // update movement type - WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); - if(pCreature) - { - pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - pCreature->GetMotionMaster()->Initialize(); - if(pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - pCreature->SaveToDB(); - } - - SendSysMessage(LANG_WAYPOINT_ADDED); - - return true; -} - -/** - * Set the movement type for an NPC.
- *
- * Valid movement types are: - *
    - *
  • stay - NPC wont move
  • - *
  • random - NPC will move randomly according to the spawndist
  • - *
  • way - NPC will move with given waypoints set
  • - *
- * additional parameter: NODEL - so no waypoints are deleted, if you - * change the movement type - */ -bool ChatHandler::HandleSetMoveTypeCommand(const char* args) -{ - if(!*args) - return false; - - // 3 arguments: - // GUID (optional - you can also select the creature) - // stay|random|way (determines the kind of movement) - // NODEL (optional - tells the system NOT to delete any waypoints) - // this is very handy if you want to do waypoints, that are - // later switched on/off according to special events (like escort - // quests, etc) - char* guid_str = strtok((char*)args, " "); - char* type_str = strtok((char*)NULL, " "); - char* dontdel_str = strtok((char*)NULL, " "); - - bool doNotDelete = false; - - if(!guid_str) - return false; - - uint32 lowguid = 0; - Creature* pCreature = NULL; - - if( dontdel_str ) - { - //sLog.outError("DEBUG: All 3 params are set"); - - // All 3 params are set - // GUID - // type - // doNotDEL - if( stricmp( dontdel_str, "NODEL" ) == 0 ) - { - //sLog.outError("DEBUG: doNotDelete = true;"); - doNotDelete = true; - } - } - else - { - // Only 2 params - but maybe NODEL is set - if( type_str ) - { - sLog.outError("DEBUG: Only 2 params "); - if( stricmp( type_str, "NODEL" ) == 0 ) - { - //sLog.outError("DEBUG: type_str, NODEL "); - doNotDelete = true; - type_str = NULL; - } - } - } - - if(!type_str) // case .setmovetype $move_type (with selected creature) - { - type_str = guid_str; - pCreature = getSelectedCreature(); - if(!pCreature) - return false; - lowguid = pCreature->GetDBTableGUIDLow(); - } - else // case .setmovetype #creature_guid $move_type (with selected creature) - { - lowguid = atoi((char*)guid_str); - - /* impossible without entry - if(lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - // attempt check creature existence by DB data - if(!pCreature) - { - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - lowguid = pCreature->GetDBTableGUIDLow(); - } - } - - // now lowguid is low guid really existed creature - // and pCreature point (maybe) to this creature or NULL - - MovementGeneratorType move_type; - - std::string type = type_str; - - if(type == "stay") - move_type = IDLE_MOTION_TYPE; - else if(type == "random") - move_type = RANDOM_MOTION_TYPE; - else if(type == "way") - move_type = WAYPOINT_MOTION_TYPE; - else - return false; - - // update movement type - if(doNotDelete == false) - WaypointMgr.DeletePath(lowguid); - - if(pCreature) - { - pCreature->SetDefaultMovementType(move_type); - pCreature->GetMotionMaster()->Initialize(); - if(pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - pCreature->SaveToDB(); - } - if( doNotDelete == false ) - { - PSendSysMessage(LANG_MOVE_TYPE_SET,type_str); - } - else - { - PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL,type_str); - } - - return true; -} // HandleSetMoveTypeCommand - -//change level of creature or pet -bool ChatHandler::HandleChangeLevelCommand(const char* args) -{ - if (!*args) - return false; - - uint8 lvl = (uint8) atoi((char*)args); - if ( lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Creature* pCreature = getSelectedCreature(); - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if(pCreature->isPet()) - { - ((Pet*)pCreature)->GivePetLevel(lvl); - } - else - { - pCreature->SetMaxHealth( 100 + 30*lvl); - pCreature->SetHealth( 100 + 30*lvl); - pCreature->SetLevel( lvl); - pCreature->SaveToDB(); - } - - return true; -} - -//set npcflag of creature -bool ChatHandler::HandleNPCFlagCommand(const char* args) -{ - if (!*args) - return false; - - uint32 npcFlags = (uint32) atoi((char*)args); - - Creature* pCreature = getSelectedCreature(); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); - - WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); - - SendSysMessage(LANG_VALUE_SAVED_REJOIN); - - return true; -} - -//set model of creature -bool ChatHandler::HandleSetModelCommand(const char* args) -{ - if (!*args) - return false; - - uint32 displayId = (uint32) atoi((char*)args); - - Creature *pCreature = getSelectedCreature(); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->SetDisplayId(displayId); - pCreature->SetNativeDisplayId(displayId); - - pCreature->SaveToDB(); - - return true; -} - -//morph creature or player -bool ChatHandler::HandleMorphCommand(const char* args) -{ - if (!*args) - return false; - - uint16 display_id = (uint16)atoi((char*)args); - - Unit *target = getSelectedUnit(); - if(!target) - target = m_session->GetPlayer(); - - target->SetDisplayId(display_id); - - return true; -} - -//set faction of creature or go -bool ChatHandler::HandleFactionIdCommand(const char* args) -{ - if (!*args) - return false; - - uint32 factionId = (uint32) atoi((char*)args); - - if (!sFactionTemplateStore.LookupEntry(factionId)) - { - PSendSysMessage(LANG_WRONG_FACTION, factionId); - SetSentErrorMessage(true); - return false; - } - - Creature* pCreature = getSelectedCreature(); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->setFaction(factionId); - - // faction is set in creature_template - not inside creature - - // update in memory - if(CreatureInfo const *cinfo = pCreature->GetCreatureInfo()) - { - const_cast(cinfo)->faction_A = factionId; - const_cast(cinfo)->faction_H = factionId; - } - - // and DB - WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry()); - - return true; -} - -//kick player -bool ChatHandler::HandleKickPlayerCommand(const char *args) -{ - char* kickName = strtok((char*)args, " "); - if (!kickName) - { - Player* player = getSelectedPlayer(); - - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(player==m_session->GetPlayer()) - { - SendSysMessage(LANG_COMMAND_KICKSELF); - SetSentErrorMessage(true); - return false; - } - - player->GetSession()->KickPlayer(); - } - else - { - std::string name = kickName; - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if(name==m_session->GetPlayer()->GetName()) - { - SendSysMessage(LANG_COMMAND_KICKSELF); - SetSentErrorMessage(true); - return false; - } - - if(sWorld.KickPlayer(name)) - { - PSendSysMessage(LANG_COMMAND_KICKMESSAGE,name.c_str()); - } - else - PSendSysMessage(LANG_COMMAND_KICKNOTFOUNDPLAYER,name.c_str()); - } - - return true; -} - -//show info of player -bool ChatHandler::HandlePInfoCommand(const char* args) -{ - Player* target = NULL; - uint64 targetGUID = 0; - - char* px = strtok((char*)args, " "); - char* py = NULL; - - std::string name; - - if (px) - { - name = px; - - if(name.empty()) - return false; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - target = objmgr.GetPlayer(name.c_str()); - if (target) - py = strtok(NULL, " "); - else - { - targetGUID = objmgr.GetPlayerGUIDByName(name); - if(targetGUID) - py = strtok(NULL, " "); - else - py = px; - } - } - - if(!target && !targetGUID) - { - target = getSelectedPlayer(); - } - - if(!target && !targetGUID) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint32 accId = 0; - uint32 money = 0; - uint32 total_player_time = 0; - uint32 level = 0; - uint32 latency = 0; - - // get additional information from Player object - if(target) - { - targetGUID = target->GetGUID(); - name = target->GetName(); // re-read for case getSelectedPlayer() target - accId = target->GetSession()->GetAccountId(); - money = target->GetMoney(); - total_player_time = target->GetTotalPlayedTime(); - level = target->getLevel(); - latency = target->GetSession()->GetLatency(); - } - // get additional information from DB - else - { - accId = objmgr.GetPlayerAccountIdByGUID(targetGUID); - Player plr(m_session); // use current session for temporary load - plr.MinimalLoadFromDB(NULL, targetGUID); - money = plr.GetMoney(); - total_player_time = plr.GetTotalPlayedTime(); - level = plr.getLevel(); - } - - std::string username = GetMangosString(LANG_ERROR); - std::string last_ip = GetMangosString(LANG_ERROR); - uint32 security = 0; - std::string last_login = GetMangosString(LANG_ERROR); - - QueryResult* result = loginDatabase.PQuery("SELECT username,gmlevel,last_ip,last_login FROM account WHERE id = '%u'",accId); - if(result) - { - Field* fields = result->Fetch(); - username = fields[0].GetCppString(); - security = fields[1].GetUInt32(); - if(m_session->GetSecurity() >= security) - { - last_ip = fields[2].GetCppString(); - last_login = fields[3].GetCppString(); - } - else - { - last_ip = "-"; - last_login = "-"; - } - - delete result; - } - - PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetMangosString(LANG_OFFLINE)), name.c_str(), GUID_LOPART(targetGUID), username.c_str(), accId, security, last_ip.c_str(), last_login.c_str(), latency); - - std::string timeStr = secsToTimeString(total_player_time,true,true); - uint32 gold = money /GOLD; - uint32 silv = (money % GOLD) / SILVER; - uint32 copp = (money % GOLD) % SILVER; - PSendSysMessage(LANG_PINFO_LEVEL, timeStr.c_str(), level, gold,silv,copp ); - - if ( py && strncmp(py, "rep", 3) == 0 ) - { - if(!target) - { - // rep option not implemented for offline case - SendSysMessage(LANG_PINFO_NO_REP); - SetSentErrorMessage(true); - return false; - } - - char* FactionName; - for(FactionStateList::const_iterator itr = target->m_factions.begin(); itr != target->m_factions.end(); ++itr) - { - FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID); - if (factionEntry) - FactionName = factionEntry->name[m_session->GetSessionDbcLocale()]; - else - FactionName = "#Not found#"; - ReputationRank rank = target->GetReputationRank(factionEntry); - std::string rankName = GetMangosString(ReputationRankStrIndex[rank]); - std::ostringstream ss; - ss << itr->second.ID << ": |cffffffff|Hfaction:" << itr->second.ID << "|h[" << FactionName << "]|h|r " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")"; - - if(itr->second.Flags & FACTION_FLAG_VISIBLE) - ss << GetMangosString(LANG_FACTION_VISIBLE); - if(itr->second.Flags & FACTION_FLAG_AT_WAR) - ss << GetMangosString(LANG_FACTION_ATWAR); - if(itr->second.Flags & FACTION_FLAG_PEACE_FORCED) - ss << GetMangosString(LANG_FACTION_PEACE_FORCED); - if(itr->second.Flags & FACTION_FLAG_HIDDEN) - ss << GetMangosString(LANG_FACTION_HIDDEN); - if(itr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED) - ss << GetMangosString(LANG_FACTION_INVISIBLE_FORCED); - if(itr->second.Flags & FACTION_FLAG_INACTIVE) - ss << GetMangosString(LANG_FACTION_INACTIVE); - - SendSysMessage(ss.str().c_str()); - } - } - return true; -} - -//show tickets -void ChatHandler::ShowTicket(uint64 guid, char const* text, char const* time) -{ - std::string name; - if(!objmgr.GetPlayerNameByGUID(guid,name)) - name = GetMangosString(LANG_UNKNOWN); - - PSendSysMessage(LANG_COMMAND_TICKETVIEW, name.c_str(),time,text); -} - -//ticket commands -bool ChatHandler::HandleTicketCommand(const char* args) -{ - char* px = strtok((char*)args, " "); - - // ticket - if (!px) - { - size_t count; - QueryResult *result = CharacterDatabase.Query("SELECT COUNT(ticket_id) FROM character_ticket"); - if(result) - { - count = (*result)[0].GetUInt32(); - delete result; - } - else - count = 0; - - PSendSysMessage(LANG_COMMAND_TICKETCOUNT, count, m_session->GetPlayer()->isAcceptTickets() ? GetMangosString(LANG_ON) : GetMangosString(LANG_OFF)); - return true; - } - - // ticket on - if(strncmp(px,"on",3) == 0) - { - m_session->GetPlayer()->SetAcceptTicket(true); - SendSysMessage(LANG_COMMAND_TICKETON); - return true; - } - - // ticket off - if(strncmp(px,"off",4) == 0) - { - m_session->GetPlayer()->SetAcceptTicket(false); - SendSysMessage(LANG_COMMAND_TICKETOFF); - return true; - } - - // ticket #num - int num = atoi(px); - if(num > 0) - { - QueryResult *result = CharacterDatabase.PQuery("SELECT guid,ticket_text,ticket_lastchange FROM character_ticket ORDER BY ticket_id ASC LIMIT %d,1",num-1); - - if(!result) - { - PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num); - delete result; - SetSentErrorMessage(true); - return false; - } - - Field* fields = result->Fetch(); - - uint64 guid = fields[0].GetUInt64(); - char const* text = fields[1].GetString(); - char const* time = fields[2].GetString(); - - ShowTicket(guid,text,time); - delete result; - return true; - } - - std::string name = px; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = objmgr.GetPlayerGUIDByName(name); - - if(!guid) - return false; - - // ticket $char_name - QueryResult *result = CharacterDatabase.PQuery("SELECT ticket_text,ticket_lastchange FROM character_ticket WHERE guid = '%u' ORDER BY ticket_id ASC",GUID_LOPART(guid)); - - if(!result) - return false; - - Field* fields = result->Fetch(); - - char const* text = fields[0].GetString(); - char const* time = fields[1].GetString(); - - ShowTicket(guid,text,time); - delete result; - - return true; -} - -uint32 ChatHandler::GetTicketIDByNum(uint32 num) -{ - QueryResult *result = CharacterDatabase.Query("SELECT ticket_id FROM character_ticket"); - - if(!result || num > result->GetRowCount()) - { - PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num); - delete result; - return 0; - } - - for(uint32 i = 1; i < num; ++i) - result->NextRow(); - - Field* fields = result->Fetch(); - - uint32 id = fields[0].GetUInt32(); - delete result; - return id; -} - -//dell all tickets -bool ChatHandler::HandleDelTicketCommand(const char *args) -{ - char* px = strtok((char*)args, " "); - if (!px) - return false; - - // delticket all - if(strncmp(px,"all",4) == 0) - { - QueryResult *result = CharacterDatabase.Query("SELECT guid FROM character_ticket"); - - if(!result) - return true; - - // notify players about ticket deleting - do - { - Field* fields = result->Fetch(); - - uint64 guid = fields[0].GetUInt64(); - - if(Player* sender = objmgr.GetPlayer(guid)) - sender->GetSession()->SendGMTicketGetTicket(0x0A,0); - - }while(result->NextRow()); - - delete result; - - CharacterDatabase.PExecute("DELETE FROM character_ticket"); - SendSysMessage(LANG_COMMAND_ALLTICKETDELETED); - return true; - } - - int num = (uint32)atoi(px); - - // delticket #num - if(num > 0) - { - QueryResult *result = CharacterDatabase.PQuery("SELECT ticket_id,guid FROM character_ticket LIMIT %i",num); - - if(!result || uint64(num) > result->GetRowCount()) - { - PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num); - delete result; - SetSentErrorMessage(true); - return false; - } - - for(int i = 1; i < num; ++i) - result->NextRow(); - - Field* fields = result->Fetch(); - - uint32 id = fields[0].GetUInt32(); - uint64 guid = fields[1].GetUInt64(); - delete result; - - CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE ticket_id = '%u'", id); - - // notify players about ticket deleting - if(Player* sender = objmgr.GetPlayer(guid)) - { - sender->GetSession()->SendGMTicketGetTicket(0x0A,0); - PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL,sender->GetName()); - } - else - SendSysMessage(LANG_COMMAND_TICKETDEL); - - return true; - } - - std::string name = px; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = objmgr.GetPlayerGUIDByName(name); - - if(!guid) - return false; - - // delticket $char_name - CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u'",GUID_LOPART(guid)); - - // notify players about ticket deleting - if(Player* sender = objmgr.GetPlayer(guid)) - sender->GetSession()->SendGMTicketGetTicket(0x0A,0); - - PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL,px); - return true; -} - -//set spawn dist of creature -bool ChatHandler::HandleSpawnDistCommand(const char* args) -{ - if(!*args) - return false; - - float option = atof((char*)args); - if (option < 0.0f) - { - SendSysMessage(LANG_BAD_VALUE); - return false; - } - - MovementGeneratorType mtype = IDLE_MOTION_TYPE; - if (option >0.0f) - mtype = RANDOM_MOTION_TYPE; - - Creature *pCreature = getSelectedCreature(); - uint32 u_guidlow = 0; - - if (pCreature) - u_guidlow = pCreature->GetDBTableGUIDLow(); - else - return false; - - pCreature->SetRespawnRadius((float)option); - pCreature->SetDefaultMovementType(mtype); - pCreature->GetMotionMaster()->Initialize(); - if(pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - - WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow); - PSendSysMessage(LANG_COMMAND_SPAWNDIST,option); - return true; -} - -bool ChatHandler::HandleSpawnTimeCommand(const char* args) -{ - if(!*args) - return false; - - char* stime = strtok((char*)args, " "); - - if (!stime) - return false; - - int i_stime = atoi((char*)stime); - - if (i_stime < 0) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Creature *pCreature = getSelectedCreature(); - uint32 u_guidlow = 0; - - if (pCreature) - u_guidlow = pCreature->GetDBTableGUIDLow(); - else - return false; - - WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow); - pCreature->SetRespawnDelay((uint32)i_stime); - PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime); - - return true; -} - -/** - * Add a waypoint to a creature. - * - * The user can either select an npc or provide its GUID. - * - * The user can even select a visual waypoint - then the new waypoint - * is placed *after* the selected one - this makes insertion of new - * waypoints possible. - * - * eg: - * .wp add 12345 - * -> adds a waypoint to the npc with the GUID 12345 - * - * .wp add - * -> adds a waypoint to the currently selected creature - * - * - * @param args if the user did not provide a GUID, it is NULL - * - * @return true - command did succeed, false - something went wrong - */ -bool ChatHandler::HandleWpAddCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpAddCommand"); - - // optional - char* guid_str = NULL; - - if(*args) - { - guid_str = strtok((char*)args, " "); - } - - uint32 lowguid = 0; - uint32 point = 0; - Creature* target = getSelectedCreature(); - // Did player provide a GUID? - if (!guid_str) - { - sLog.outDebug("DEBUG: HandleWpAddCommand - No GUID provided"); - - // No GUID provided - // -> Player must have selected a creature - - if(!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - if (target->GetEntry() == VISUAL_WAYPOINT ) - { - sLog.outDebug("DEBUG: HandleWpAddCommand - target->GetEntry() == VISUAL_WAYPOINT (1) "); - - QueryResult *result = - WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u", - target->GetGUIDLow() ); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUIDLow()); - // User selected a visual spawnpoint -> get the NPC - // Select NPC GUID - // Since we compare float values, we have to deal with - // some difficulties. - // Here we search for all waypoints that only differ in one from 1 thousand - // (0.001) - There is no other way to compare C++ floats with mySQL floats - // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html - const char* maxDIFF = "0.01"; - result = WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )", - target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow()); - SetSentErrorMessage(true); - return false; - } - } - do - { - Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32(); - point = fields[1].GetUInt32(); - }while( result->NextRow() ); - delete result; - - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); - if(!target) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - lowguid = target->GetDBTableGUIDLow(); - } - } - else - { - sLog.outDebug("DEBUG: HandleWpAddCommand - GUID provided"); - - // GUID provided - // Warn if player also selected a creature - // -> Creature selection is ignored <- - if(target) - { - SendSysMessage(LANG_WAYPOINT_CREATSELECTED); - } - lowguid = atoi((char*)guid_str); - - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); - if(!target) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - } - // lowguid -> GUID of the NPC - // point -> number of the waypoint (if not 0) - sLog.outDebug("DEBUG: HandleWpAddCommand - danach"); - - sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0"); - - Player* player = m_session->GetPlayer(); - WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0); - - // update movement type - if(target) - { - target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - target->GetMotionMaster()->Initialize(); - if(target->isAlive()) // dead creature will reset movement generator at respawn - { - target->setDeathState(JUST_DIED); - target->Respawn(); - } - target->SaveToDB(); - } - else - WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); - - PSendSysMessage(LANG_WAYPOINT_ADDED, point, lowguid); - - return true; -} // HandleWpAddCommand - -/** - * .wp modify emote | spell | text | del | move | add - * - * add -> add a WP after the selected visual waypoint - * User must select a visual waypoint and then issue ".wp modify add" - * - * emote - * User has selected a visual waypoint before. - * is added to this waypoint. Everytime the - * NPC comes to this waypoint, the emote is called. - * - * emote - * User has not selected visual waypoint before. - * For the waypoint for the NPC with - * an emote is added. - * Everytime the NPC comes to this waypoint, the emote is called. - * - * - * info -> User did not select a visual waypoint and - */ -bool ChatHandler::HandleWpModifyCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpModifyCommand"); - - if(!*args) - return false; - - // first arg: add del text emote spell waittime move - char* show_str = strtok((char*)args, " "); - if (!show_str) - { - return false; - } - - std::string show = show_str; - // Check - // Remember: "show" must also be the name of a column! - if( (show != "emote") && (show != "spell") && (show != "text1") && (show != "text2") - && (show != "text3") && (show != "text4") && (show != "text5") - && (show != "waittime") && (show != "del") && (show != "move") && (show != "add") - && (show != "model1") && (show != "model2") && (show != "orientation")) - { - return false; - } - - // Next arg is: - - // Did user provide a GUID - // or did the user select a creature? - // -> variable lowguid is filled with the GUID of the NPC - uint32 lowguid = 0; - uint32 point = 0; - uint32 wpGuid = 0; - Creature* target = getSelectedCreature(); - - if(target) - { - sLog.outDebug("DEBUG: HandleWpModifyCommand - User did select an NPC"); - - // Did the user select a visual spawnpoint? - if (target->GetEntry() != VISUAL_WAYPOINT ) - { - PSendSysMessage(LANG_WAYPOINT_VP_SELECT); - SetSentErrorMessage(true); - return false; - } - - wpGuid = target->GetGUIDLow(); - - // The visual waypoint - QueryResult *result = - WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u LIMIT 1", - target->GetGUIDLow() ); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid); - SetSentErrorMessage(true); - return false; - } - sLog.outDebug("DEBUG: HandleWpModifyCommand - After getting wpGuid"); - - Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32(); - point = fields[1].GetUInt32(); - - // Cleanup memory - sLog.outDebug("DEBUG: HandleWpModifyCommand - Cleanup memory"); - delete result; - } - else - { - // User did provide - - char* guid_str = strtok((char*)NULL, " "); - if( !guid_str ) - { - SendSysMessage(LANG_WAYPOINT_NOGUID); - return false; - } - lowguid = atoi((char*)guid_str); - - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage("DEBUG: GUID provided: %d", lowguid); - - char* point_str = strtok((char*)NULL, " "); - if( !point_str ) - { - SendSysMessage(LANG_WAYPOINT_NOWAYPOINTGIVEN); - return false; - } - point = atoi((char*)point_str); - - PSendSysMessage("DEBUG: wpNumber provided: %d", point); - - // Now we need the GUID of the visual waypoint - // -> "del", "move", "add" command - - QueryResult *result = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' AND point = '%u' LIMIT 1", lowguid, point); - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, lowguid, point); - SetSentErrorMessage(true); - return false; - } - - Field *fields = result->Fetch(); - wpGuid = fields[0].GetUInt32(); - - // Free memory - delete result; - } - - char* arg_str = NULL; - // Check for argument - if( (show.find("text") == std::string::npos ) && (show != "del") && (show != "move") && (show != "add")) - { - // Text is enclosed in "<>", all other arguments not - if( show.find("text") != std::string::npos ) - arg_str = strtok((char*)NULL, "<>"); - else - arg_str = strtok((char*)NULL, " "); - - if( !arg_str) - { - PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str); - return false; - } - } - - sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command"); - - // wpGuid -> GUID of the waypoint creature - // lowguid -> GUID of the NPC - // point -> waypoint number - - // Special functions: - // add - move - del -> no args commands - // Add a waypoint after the selected visual - if(show == "add" && target) - { - PSendSysMessage("DEBUG: wp modify add, GUID: %u", lowguid); - - // Get the creature for which we read the waypoint - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); - - if( !npcCreature ) - { - PSendSysMessage(LANG_WAYPOINT_NPCNOTFOUND); - SetSentErrorMessage(true); - return false; - } - - sLog.outDebug("DEBUG: HandleWpModifyCommand - add -- npcCreature"); - - // What to do: - // Add the visual spawnpoint (DB only) - // Adjust the waypoints - // Respawn the owner of the waypoints - sLog.outDebug("DEBUG: HandleWpModifyCommand - add"); - - Player* chr = m_session->GetPlayer(); - Map *map = chr->GetMap(); - - if(npcCreature) - { - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->Respawn(); - } - } - - // create the waypoint creature - wpGuid = 0; - Creature* wpCreature = new Creature; - if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map,VISUAL_WAYPOINT,0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - delete wpCreature; - } - else - { - wpCreature->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()); - - if(!wpCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY()); - delete wpCreature; - } - else - { - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), map); - map->Add(wpCreature); - wpGuid = wpCreature->GetGUIDLow(); - } - } - - WaypointMgr.AddAfterNode(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), 0, 0, wpGuid); - - if(!wpGuid) - return false; - - PSendSysMessage(LANG_WAYPOINT_ADDED_NO, point+1); - return true; - } // add - - if(show == "del" && target) - { - PSendSysMessage("DEBUG: wp modify del, GUID: %u", lowguid); - - // Get the creature for which we read the waypoint - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); - - // wpCreature - Creature* wpCreature = NULL; - if( wpGuid != 0 ) - { - wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); - wpCreature->DeleteFromDB(); - wpCreature->CleanupsBeforeDelete(); - wpCreature->AddObjectToRemoveList(); - } - - // What to do: - // Remove the visual spawnpoint - // Adjust the waypoints - // Respawn the owner of the waypoints - - WaypointMgr.DeleteNode(lowguid, point); - - if(npcCreature) - { - // Any waypoints left? - QueryResult *result2 = WorldDatabase.PQuery( "SELECT point FROM creature_movement WHERE id = '%u'",lowguid); - if(!result2) - { - npcCreature->SetDefaultMovementType(RANDOM_MOTION_TYPE); - } - else - { - npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - delete result2; - } - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->Respawn(); - } - npcCreature->SaveToDB(); - } - - PSendSysMessage(LANG_WAYPOINT_REMOVED); - return true; - } // del - - if(show == "move" && target) - { - PSendSysMessage("DEBUG: wp move, GUID: %u", lowguid); - - Player *chr = m_session->GetPlayer(); - Map *map = chr->GetMap(); - { - // Get the creature for which we read the waypoint - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); - - // wpCreature - Creature* wpCreature = NULL; - // What to do: - // Move the visual spawnpoint - // Respawn the owner of the waypoints - if( wpGuid != 0 ) - { - wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); - wpCreature->DeleteFromDB(); - wpCreature->CleanupsBeforeDelete(); - wpCreature->AddObjectToRemoveList(); - // re-create - Creature* wpCreature2 = new Creature; - if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, VISUAL_WAYPOINT, 0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - delete wpCreature2; - return false; - } - - wpCreature2->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()); - - if(!wpCreature2->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature2->GetGUIDLow(),wpCreature2->GetEntry(),wpCreature2->GetPositionX(),wpCreature2->GetPositionY()); - delete wpCreature2; - return false; - } - - wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map); - map->Add(wpCreature2); - //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2); - } - - WaypointMgr.SetNodePosition(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ()); - - if(npcCreature) - { - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->Respawn(); - } - } - PSendSysMessage(LANG_WAYPOINT_CHANGED); - } - return true; - } // move - - // Create creature - npc that has the waypoint - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - WaypointMgr.SetNodeText(lowguid, point, show_str, arg_str); - - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); - if(npcCreature) - { - npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->Respawn(); - } - } - PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str); - - return true; -} - -/** - * .wp show info | on | off - * - * info -> User has selected a visual waypoint before - * - * info -> User did not select a visual waypoint and - * provided the GUID of the NPC and the number of - * the waypoint. - * - * on -> User has selected an NPC; all visual waypoints for this - * NPC are added to the world - * - * on -> User did not select an NPC - instead the GUID of the - * NPC is provided. All visual waypoints for this NPC - * are added from the world. - * - * off -> User has selected an NPC; all visual waypoints for this - * NPC are removed from the world. - * - * on -> User did not select an NPC - instead the GUID of the - * NPC is provided. All visual waypoints for this NPC - * are removed from the world. - * - * - */ -bool ChatHandler::HandleWpShowCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpShowCommand"); - - if(!*args) - return false; - - // first arg: on, off, first, last - char* show_str = strtok((char*)args, " "); - if (!show_str) - { - return false; - } - // second arg: GUID (optional, if a creature is selected) - char* guid_str = strtok((char*)NULL, " "); - sLog.outDebug("DEBUG: HandleWpShowCommand: show_str: %s guid_str: %s", show_str, guid_str); - //if (!guid_str) { - // return false; - //} - - // Did user provide a GUID - // or did the user select a creature? - // -> variable lowguid is filled with the GUID - Creature* target = getSelectedCreature(); - // Did player provide a GUID? - if (!guid_str) - { - sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str"); - // No GUID provided - // -> Player must have selected a creature - - if(!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - } - else - { - sLog.outDebug("DEBUG: HandleWpShowCommand: GUID provided"); - // GUID provided - // Warn if player also selected a creature - // -> Creature selection is ignored <- - if(target) - { - SendSysMessage(LANG_WAYPOINT_CREATSELECTED); - } - - uint32 lowguid = atoi((char*)guid_str); - - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); - - if(!target) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - } - - uint32 lowguid = target->GetDBTableGUIDLow(); - - std::string show = show_str; - uint32 Maxpoint; - - sLog.outDebug("DEBUG: HandleWpShowCommand: lowguid: %u", lowguid); - - sLog.outDebug("DEBUG: HandleWpShowCommand: Habe creature: %ld", target ); - - sLog.outDebug("DEBUG: HandleWpShowCommand: wpshow - show: %s", show_str); - //PSendSysMessage("wpshow - show: %s", show); - - // Show info for the selected waypoint - if(show == "info") - { - PSendSysMessage("DEBUG: wp info, GUID: %u", lowguid); - - // Check if the user did specify a visual waypoint - if( target->GetEntry() != VISUAL_WAYPOINT ) - { - PSendSysMessage(LANG_WAYPOINT_VP_SELECT); - SetSentErrorMessage(true); - return false; - } - - //PSendSysMessage("wp on, GUID: %u", lowguid); - - //pCreature->GetPositionX(); - - QueryResult *result = - WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, text1, text2, text3, text4, text5, model1, model2 FROM creature_movement WHERE wpguid = %u", - target->GetGUID() ); - if(!result) - { - // Since we compare float values, we have to deal with - // some difficulties. - // Here we search for all waypoints that only differ in one from 1 thousand - // (0.001) - There is no other way to compare C++ floats with mySQL floats - // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html - const char* maxDIFF = "0.01"; - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUID()); - - result = WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, text1, text2, text3, text4, text5, model1, model2 FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )", - target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid); - SetSentErrorMessage(true); - return false; - } - } - do - { - Field *fields = result->Fetch(); - uint32 creGUID = fields[0].GetUInt32(); - uint32 point = fields[1].GetUInt32(); - int waittime = fields[2].GetUInt32(); - uint32 emote = fields[3].GetUInt32(); - uint32 spell = fields[4].GetUInt32(); - const char * text1 = fields[5].GetString(); - const char * text2 = fields[6].GetString(); - const char * text3 = fields[7].GetString(); - const char * text4 = fields[8].GetString(); - const char * text5 = fields[9].GetString(); - uint32 model1 = fields[10].GetUInt32(); - uint32 model2 = fields[11].GetUInt32(); - - // Get the creature for which we read the waypoint - Creature* wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(creGUID,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - - PSendSysMessage(LANG_WAYPOINT_INFO_TITLE, point, (wpCreature ? wpCreature->GetName() : ""), creGUID); - PSendSysMessage(LANG_WAYPOINT_INFO_WAITTIME, waittime); - PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 1, model1); - PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 2, model2); - PSendSysMessage(LANG_WAYPOINT_INFO_EMOTE, emote); - PSendSysMessage(LANG_WAYPOINT_INFO_SPELL, spell); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 1, text1); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 2, text2); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 3, text3); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 4, text4); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 5, text5); - - }while( result->NextRow() ); - // Cleanup memory - delete result; - return true; - } - - if(show == "on") - { - PSendSysMessage("DEBUG: wp on, GUID: %u", lowguid); - - QueryResult *result = WorldDatabase.PQuery( "SELECT point, position_x,position_y,position_z FROM creature_movement WHERE id = '%u'",lowguid); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - // Delete all visuals for this NPC - QueryResult *result2 = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' and wpguid <> 0", lowguid); - if(result2) - { - bool hasError = false; - do - { - Field *fields = result2->Fetch(); - uint32 wpguid = fields[0].GetUInt32(); - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - - if(!pCreature) - { - PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid); - hasError = true; - WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid); - } - else - { - pCreature->DeleteFromDB(); - pCreature->CleanupsBeforeDelete(); - pCreature->AddObjectToRemoveList(); - } - - }while( result2->NextRow() ); - delete result2; - if( hasError ) - { - PSendSysMessage(LANG_WAYPOINT_TOOFAR1); - PSendSysMessage(LANG_WAYPOINT_TOOFAR2); - PSendSysMessage(LANG_WAYPOINT_TOOFAR3); - } - } - - do - { - Field *fields = result->Fetch(); - uint32 point = fields[0].GetUInt32(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - Map *map = chr->GetMap(); - float o = chr->GetOrientation(); - - Creature* wpCreature = new Creature; - if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - delete wpCreature; - delete result; - return false; - } - - wpCreature->Relocate(x, y, z, o); - - if(!wpCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY()); - delete wpCreature; - delete result; - return false; - } - - wpCreature->SetVisibility(VISIBILITY_OFF); - sLog.outDebug("DEBUG: UPDATE creature_movement SET wpguid = '%u"); - // set "wpguid" column to the visual waypoint - WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), lowguid, point); - - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map); - map->Add(wpCreature); - //MapManager::Instance().GetMap(wpCreature->GetMapId())->Add(wpCreature); - }while( result->NextRow() ); - - // Cleanup memory - delete result; - return true; - } - - if(show == "first") - { - PSendSysMessage("DEBUG: wp first, GUID: %u", lowguid); - - QueryResult *result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point='1' AND id = '%u'",lowguid); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - float o = chr->GetOrientation(); - Map *map = chr->GetMap(); - - Creature* pCreature = new Creature; - if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, id, 0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - delete pCreature; - delete result; - return false; - } - - pCreature->Relocate(x, y, z, o); - - if(!pCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); - delete pCreature; - delete result; - return false; - } - - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); - map->Add(pCreature); - //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint"); - - // Cleanup memory - delete result; - return true; - } - - if(show == "last") - { - PSendSysMessage("DEBUG: wp last, GUID: %u", lowguid); - - QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid); - if( result ) - { - Maxpoint = (*result)[0].GetUInt32(); - - delete result; - } - else - Maxpoint = 0; - - result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point ='%u' AND id = '%u'",Maxpoint, lowguid); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, lowguid); - SetSentErrorMessage(true); - return false; - } - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - float o = chr->GetOrientation(); - Map *map = chr->GetMap(); - - Creature* pCreature = new Creature; - if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0)) - { - PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); - delete pCreature; - delete result; - return false; - } - - pCreature->Relocate(x, y, z, o); - - if(!pCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); - delete pCreature; - delete result; - return false; - } - - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); - map->Add(pCreature); - //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint"); - // Cleanup memory - delete result; - return true; - } - - if(show == "off") - { - QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%d'", VISUAL_WAYPOINT); - if(!result) - { - SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - bool hasError = false; - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - - //Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature) - { - PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid); - hasError = true; - WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid); - } - else - { - pCreature->DeleteFromDB(); - pCreature->CleanupsBeforeDelete(); - pCreature->AddObjectToRemoveList(); - } - }while(result->NextRow()); - // set "wpguid" column to "empty" - no visual waypoint spawned - WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0'"); - - if( hasError ) - { - PSendSysMessage(LANG_WAYPOINT_TOOFAR1); - PSendSysMessage(LANG_WAYPOINT_TOOFAR2); - PSendSysMessage(LANG_WAYPOINT_TOOFAR3); - } - - SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED); - // Cleanup memory - delete result; - - return true; - } - - PSendSysMessage("DEBUG: wpshow - no valid command found"); - - return true; -} // HandleWpShowCommand - -bool ChatHandler::HandleWpExportCommand(const char *args) -{ - if(!*args) - return false; - - // Next arg is: - - // Did user provide a GUID - // or did the user select a creature? - // -> variable lowguid is filled with the GUID of the NPC - uint32 lowguid = 0; - Creature* target = getSelectedCreature(); - char* arg_str = NULL; - if (target) - { - if (target->GetEntry() != VISUAL_WAYPOINT) - lowguid = target->GetGUIDLow(); - else - { - QueryResult *result = WorldDatabase.PQuery( "SELECT id FROM creature_movement WHERE wpguid = %u LIMIT 1", target->GetGUIDLow() ); - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow()); - return true; - } - Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32();; - delete result; - } - - arg_str = strtok((char*)args, " "); - } - else - { - // user provided - char* guid_str = strtok((char*)args, " "); - if( !guid_str ) - { - SendSysMessage(LANG_WAYPOINT_NOGUID); - return false; - } - lowguid = atoi((char*)guid_str); - - arg_str = strtok((char*)NULL, " "); - } - - if( !arg_str) - { - PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, "export"); - return false; - } - - PSendSysMessage("DEBUG: wp export, GUID: %u", lowguid); - - QueryResult *result = WorldDatabase.PQuery( - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - "SELECT point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, text1, text2, text3, text4, text5, id FROM creature_movement WHERE id = '%u' ORDER BY point", lowguid ); - - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTHINGTOEXPORT); - SetSentErrorMessage(true); - return false; - } - - std::ofstream outfile; - outfile.open (arg_str); - - do - { - Field *fields = result->Fetch(); - - outfile << "INSERT INTO creature_movement "; - outfile << "( id, point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, text1, text2, text3, text4, text5 ) VALUES "; - - outfile << "( "; - outfile << fields[15].GetUInt32(); // id - outfile << ", "; - outfile << fields[0].GetUInt32(); // point - outfile << ", "; - outfile << fields[1].GetFloat(); // position_x - outfile << ", "; - outfile << fields[2].GetFloat(); // position_y - outfile << ", "; - outfile << fields[3].GetUInt32(); // position_z - outfile << ", "; - outfile << fields[4].GetUInt32(); // orientation - outfile << ", "; - outfile << fields[5].GetUInt32(); // model1 - outfile << ", "; - outfile << fields[6].GetUInt32(); // model2 - outfile << ", "; - outfile << fields[7].GetUInt16(); // waittime - outfile << ", "; - outfile << fields[8].GetUInt32(); // emote - outfile << ", "; - outfile << fields[9].GetUInt32(); // spell - outfile << ", "; - const char *tmpChar = fields[10].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text1 - } - else - { - outfile << "'"; - outfile << tmpChar; // text1 - outfile << "'"; - } - outfile << ", "; - tmpChar = fields[11].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text2 - } - else - { - outfile << "'"; - outfile << tmpChar; // text2 - outfile << "'"; - } - outfile << ", "; - tmpChar = fields[12].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text3 - } - else - { - outfile << "'"; - outfile << tmpChar; // text3 - outfile << "'"; - } - outfile << ", "; - tmpChar = fields[13].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text4 - } - else - { - outfile << "'"; - outfile << tmpChar; // text4 - outfile << "'"; - } - outfile << ", "; - tmpChar = fields[14].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text5 - } - else - { - outfile << "'"; - outfile << tmpChar; // text5 - outfile << "'"; - } - outfile << ");\n "; - - } while( result->NextRow() ); - delete result; - - PSendSysMessage(LANG_WAYPOINT_EXPORTED); - outfile.close(); - - return true; -} - -bool ChatHandler::HandleWpImportCommand(const char *args) -{ - if(!*args) - return false; - - char* arg_str = strtok((char*)args, " "); - if (!arg_str) - return false; - - std::string line; - std::ifstream infile (arg_str); - if (infile.is_open()) - { - while (! infile.eof() ) - { - getline (infile,line); - //cout << line << endl; - QueryResult *result = WorldDatabase.PQuery(line.c_str()); - delete result; - } - infile.close(); - } - PSendSysMessage(LANG_WAYPOINT_IMPORTED); - - return true; -} - -//rename characters -bool ChatHandler::HandleRenameCommand(const char* args) -{ - Player* target = NULL; - uint64 targetGUID = 0; - std::string oldname; - - char* px = strtok((char*)args, " "); - - if(px) - { - oldname = px; - - if(!normalizePlayerName(oldname)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - target = objmgr.GetPlayer(oldname.c_str()); - - if (!target) - targetGUID = objmgr.GetPlayerGUIDByName(oldname); - } - - if(!target && !targetGUID) - { - target = getSelectedPlayer(); - } - - if(!target && !targetGUID) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if(target) - { - PSendSysMessage(LANG_RENAME_PLAYER, target->GetName()); - target->SetAtLoginFlag(AT_LOGIN_RENAME); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", target->GetGUIDLow()); - } - else - { - PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldname.c_str(), GUID_LOPART(targetGUID)); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", GUID_LOPART(targetGUID)); - } - - return true; -} - -//spawn go -bool ChatHandler::HandleGameObjectCommand(const char* args) -{ - if (!*args) - return false; - - char* pParam1 = strtok((char*)args, " "); - if (!pParam1) - return false; - - uint32 id = atoi((char*)pParam1); - if(!id) - return false; - - char* spawntimeSecs = strtok(NULL, " "); - - const GameObjectInfo *goI = objmgr.GetGameObjectInfo(id); - - if (!goI) - { - PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); - SetSentErrorMessage(true); - return false; - } - - Player *chr = m_session->GetPlayer(); - float x = float(chr->GetPositionX()); - float y = float(chr->GetPositionY()); - float z = float(chr->GetPositionZ()); - float o = float(chr->GetOrientation()); - Map *map = chr->GetMap(); - - float rot2 = sin(o/2); - float rot3 = cos(o/2); - - GameObject* pGameObj = new GameObject; - uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT); - - if(!pGameObj->Create(db_lowGUID, goI->id, map, x, y, z, o, 0, 0, rot2, rot3, 0, 1)) - { - delete pGameObj; - return false; - } - - if( spawntimeSecs ) - { - uint32 value = atoi((char*)spawntimeSecs); - pGameObj->SetRespawnTime(value); - //sLog.outDebug("*** spawntimeSecs: %d", value); - } - - // fill the gameobject data and save to the db - pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - - // this will generate a new guid if the object is in an instance - if(!pGameObj->LoadFromDB(db_lowGUID, map)) - { - delete pGameObj; - return false; - } - - sLog.outDebug(GetMangosString(LANG_GAMEOBJECT_CURRENT), goI->name, db_lowGUID, x, y, z, o); - - map->Add(pGameObj); - - // TODO: is it really necessary to add both the real and DB table guid here ? - objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID)); - - PSendSysMessage(LANG_GAMEOBJECT_ADD,id,goI->name,db_lowGUID,x,y,z); - return true; -} - -//show animation -bool ChatHandler::HandleAnimCommand(const char* args) -{ - if (!*args) - return false; - - uint32 anim_id = atoi((char*)args); - m_session->GetPlayer()->HandleEmoteCommand(anim_id); - return true; -} - -//change standstate -bool ChatHandler::HandleStandStateCommand(const char* args) -{ - if (!*args) - return false; - - uint32 anim_id = atoi((char*)args); - m_session->GetPlayer( )->SetUInt32Value( UNIT_NPC_EMOTESTATE , anim_id ); - - return true; -} - -bool ChatHandler::HandleAddHonorCommand(const char* args) -{ - if (!*args) - return false; - - Player *target = getSelectedPlayer(); - if(!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint32 amount = (uint32)atoi(args); - target->RewardHonor(NULL, 1, amount); - return true; -} - -bool ChatHandler::HandleHonorAddKillCommand(const char* /*args*/) -{ - Unit *target = getSelectedUnit(); - if(!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - m_session->GetPlayer()->RewardHonor(target, 1); - return true; -} - -bool ChatHandler::HandleUpdateHonorFieldsCommand(const char* /*args*/) -{ - Player *target = getSelectedPlayer(); - if(!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - target->UpdateHonorFields(); - return true; -} - -bool ChatHandler::HandleLookupEventCommand(const char* args) -{ - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - uint32 counter = 0; - - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - - for(uint32 id = 0; id < events.size(); ++id ) - { - GameEventData const& eventData = events[id]; - - std::string descr = eventData.description; - if(descr.empty()) - continue; - - if (Utf8FitTo(descr, wnamepart)) - { - char const* active = activeEvents.find(id) != activeEvents.end() ? GetMangosString(LANG_ACTIVE) : ""; - PSendSysMessage(LANG_EVENT_ENTRY_LIST,id,id,descr.c_str(),active ); - ++counter; - } - } - - if (counter==0) - SendSysMessage(LANG_NOEVENTFOUND); - - return true; -} - -bool ChatHandler::HandleEventActiveListCommand(const char* args) -{ - uint32 counter = 0; - - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - - char const* active = GetMangosString(LANG_ACTIVE); - - for(GameEvent::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr ) - { - uint32 event_id = *itr; - GameEventData const& eventData = events[event_id]; - - PSendSysMessage(LANG_EVENT_ENTRY_LIST,event_id,event_id,eventData.description.c_str(),active ); - ++counter; - } - - if (counter==0) - SendSysMessage(LANG_NOEVENTFOUND); - - return true; -} - -bool ChatHandler::HandleEventInfoCommand(const char* args) -{ - if(!*args) - return false; - - // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameevent"); - if(!cId) - return false; - - uint32 event_id = atoi(cId); - - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - - if(event_id >=events.size()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventData const& eventData = events[event_id]; - if(!eventData.isValid()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - bool active = activeEvents.find(event_id) != activeEvents.end(); - char const* activeStr = active ? GetMangosString(LANG_ACTIVE) : ""; - - std::string startTimeStr = TimeToTimestampStr(eventData.start); - std::string endTimeStr = TimeToTimestampStr(eventData.end); - - uint32 delay = gameeventmgr.NextCheck(event_id); - time_t nextTime = time(NULL)+delay; - std::string nextStr = nextTime >= eventData.start && nextTime < eventData.end ? TimeToTimestampStr(time(NULL)+delay) : "-"; - - std::string occurenceStr = secsToTimeString(eventData.occurence * MINUTE); - std::string lengthStr = secsToTimeString(eventData.length * MINUTE); - - PSendSysMessage(LANG_EVENT_INFO,event_id,eventData.description.c_str(),activeStr, - startTimeStr.c_str(),endTimeStr.c_str(),occurenceStr.c_str(),lengthStr.c_str(), - nextStr.c_str()); - return true; -} - -bool ChatHandler::HandleEventStartCommand(const char* args) -{ - if(!*args) - return false; - - // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameevent"); - if(!cId) - return false; - - int32 event_id = atoi(cId); - - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - - if(event_id < 1 || event_id >=events.size()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventData const& eventData = events[event_id]; - if(!eventData.isValid()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - if(activeEvents.find(event_id) != activeEvents.end()) - { - PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE,event_id); - SetSentErrorMessage(true); - return false; - } - - gameeventmgr.StartEvent(event_id,true); - return true; -} - -bool ChatHandler::HandleEventStopCommand(const char* args) -{ - if(!*args) - return false; - - // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameevent"); - if(!cId) - return false; - - int32 event_id = atoi(cId); - - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - - if(event_id < 1 || event_id >=events.size()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventData const& eventData = events[event_id]; - if(!eventData.isValid()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - - if(activeEvents.find(event_id) == activeEvents.end()) - { - PSendSysMessage(LANG_EVENT_NOT_ACTIVE,event_id); - SetSentErrorMessage(true); - return false; - } - - gameeventmgr.StopEvent(event_id,true); - return true; -} - -bool ChatHandler::HandleCombatStopCommand(const char* args) -{ - Player *player; - - if(*args) - { - std::string playername = args; - - if(!normalizePlayerName(playername)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - player = objmgr.GetPlayer(playername.c_str()); - - if(!player) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - } - else - { - player = getSelectedPlayer(); - - if (!player) - player = m_session->GetPlayer(); - } - - player->CombatStop(); - player->getHostilRefManager().deleteReferences(); - return true; -} - -bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/) -{ - uint32 classmask = m_session->GetPlayer()->getClassMask(); - - for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i) - { - SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i); - if( !skillInfo ) - continue; - - if( skillInfo->categoryId == SKILL_CATEGORY_PROFESSION || skillInfo->categoryId == SKILL_CATEGORY_SECONDARY ) - { - for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) - { - SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j); - if( !skillLine ) - continue; - - // skip racial skills - if( skillLine->racemask != 0 ) - continue; - - // skip wrong class skills - if( skillLine->classmask && (skillLine->classmask & classmask) == 0) - continue; - - if( skillLine->skillId != i || skillLine->forward_spellid ) - continue; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId); - if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) - continue; - - m_session->GetPlayer()->learnSpell(skillLine->spellId); - } - } - } - - SendSysMessage(LANG_COMMAND_LEARN_ALL_CRAFT); - return true; -} - -bool ChatHandler::HandleLearnAllRecipesCommand(const char* args) -{ - // Learns all recipes of specified profession and sets skill to max - // Example: .learn all_recipes enchanting - - Player* target = getSelectedPlayer(); - if( !target ) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - return false; - } - - if(!*args) - return false; - - std::wstring wnamepart; - - if(!Utf8toWStr(args,wnamepart)) - return false; - - uint32 counter = 0; // Counter for figure out that we found smth. - - // converting string that we try to find to lower case - wstrToLower( wnamepart ); - - uint32 classmask = m_session->GetPlayer()->getClassMask(); - - for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i) - { - SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i); - if( !skillInfo ) - continue; - - if( skillInfo->categoryId != SKILL_CATEGORY_PROFESSION && - skillInfo->categoryId != SKILL_CATEGORY_SECONDARY ) - continue; - - int loc = m_session->GetSessionDbcLocale(); - std::string name = skillInfo->name[loc]; - - if(Utf8FitTo(name, wnamepart)) - { - for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) - { - SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j); - if( !skillLine ) - continue; - - if( skillLine->skillId != i || skillLine->forward_spellid ) - continue; - - // skip racial skills - if( skillLine->racemask != 0 ) - continue; - - // skip wrong class skills - if( skillLine->classmask && (skillLine->classmask & classmask) == 0) - continue; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId); - if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) - continue; - - if( !target->HasSpell(spellInfo->Id) ) - m_session->GetPlayer()->learnSpell(skillLine->spellId); - } - - uint16 maxLevel = target->GetPureMaxSkillValue(skillInfo->id); - target->SetSkill(skillInfo->id, maxLevel, maxLevel); - PSendSysMessage(LANG_COMMAND_LEARN_ALL_RECIPES, name.c_str()); - return true; - } - } - - return false; -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Item.h" +#include "GameObject.h" +#include "Opcodes.h" +#include "Chat.h" +#include "ObjectAccessor.h" +#include "MapManager.h" +#include "Language.h" +#include "World.h" +#include "GameEvent.h" +#include "SpellMgr.h" +#include "AccountMgr.h" +#include "WaypointManager.h" +#include "Util.h" +#include +#include +#include +#include + +static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] = +{ + LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL, + LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED +}; + +//mute player for some times +bool ChatHandler::HandleMuteCommand(const char* args) +{ + if (!*args) + return false; + + char *charname = strtok((char*)args, " "); + if (!charname) + return false; + + std::string cname = charname; + + char *timetonotspeak = strtok(NULL, " "); + if(!timetonotspeak) + return false; + + uint32 notspeaktime = (uint32) atoi(timetonotspeak); + + if(!normalizePlayerName(cname)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str()); + if(!guid) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + Player *chr = objmgr.GetPlayer(guid); + + // check security + uint32 account_id = 0; + uint32 security = 0; + + if (chr) + { + account_id = chr->GetSession()->GetAccountId(); + security = chr->GetSession()->GetSecurity(); + } + else + { + account_id = objmgr.GetPlayerAccountIdByGUID(guid); + security = objmgr.GetSecurityByAccount(account_id); + } + + if(security >= m_session->GetSecurity()) + { + SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); + SetSentErrorMessage(true); + return false; + } + + time_t mutetime = time(NULL) + notspeaktime*60; + + if (chr) + chr->GetSession()->m_muteTime = mutetime; + + loginDatabase.PExecute("UPDATE account SET mutetime = " I64FMTD " WHERE id = '%u'",uint64(mutetime), account_id ); + + if(chr) + ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime); + + PSendSysMessage(LANG_YOU_DISABLE_CHAT, cname.c_str(), notspeaktime); + + return true; +} + +//unmute player +bool ChatHandler::HandleUnmuteCommand(const char* args) +{ + if (!*args) + return false; + + char *charname = strtok((char*)args, " "); + if (!charname) + return false; + + std::string cname = charname; + + if(!normalizePlayerName(cname)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str()); + if(!guid) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + Player *chr = objmgr.GetPlayer(guid); + + // check security + uint32 account_id = 0; + uint32 security = 0; + + if (chr) + { + account_id = chr->GetSession()->GetAccountId(); + security = chr->GetSession()->GetSecurity(); + } + else + { + account_id = objmgr.GetPlayerAccountIdByGUID(guid); + security = objmgr.GetSecurityByAccount(account_id); + } + + if(security >= m_session->GetSecurity()) + { + SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); + SetSentErrorMessage(true); + return false; + } + + if (chr) + { + if(chr->CanSpeak()) + { + SendSysMessage(LANG_CHAT_ALREADY_ENABLED); + SetSentErrorMessage(true); + return false; + } + + chr->GetSession()->m_muteTime = 0; + } + + loginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id ); + + if(chr) + ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_ENABLED); + + PSendSysMessage(LANG_YOU_ENABLE_CHAT, cname.c_str()); + return true; +} + +bool ChatHandler::HandleTargetObjectCommand(const char* args) +{ + Player* pl = m_session->GetPlayer(); + QueryResult *result; + GameEvent::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList(); + if(*args) + { + int32 id = atoi((char*)args); + if(id) + result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),id); + else + { + std::string name = args; + WorldDatabase.escape_string(name); + result = WorldDatabase.PQuery( + "SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ " + "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" ORDER BY order_ ASC LIMIT 1", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str()); + } + } + else + { + std::ostringstream eventFilter; + eventFilter << " AND (event IS NULL "; + bool initString = true; + + for (GameEvent::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr) + { + if (initString) + { + eventFilter << "OR event IN (" <<*itr; + initString =false; + } + else + eventFilter << "," << *itr; + } + + if (!initString) + eventFilter << "))"; + else + eventFilter << ")"; + + result = WorldDatabase.PQuery("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, " + "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject " + "LEFT OUTER JOIN game_event_gameobject on gameobject.guid=game_event_gameobject.guid WHERE map = '%i' %s ORDER BY order_ ASC LIMIT 1", + m_session->GetPlayer()->GetPositionX(), m_session->GetPlayer()->GetPositionY(), m_session->GetPlayer()->GetPositionZ(), m_session->GetPlayer()->GetMapId(),eventFilter.str().c_str()); + } + + if (!result) + { + SendSysMessage(LANG_COMMAND_TARGETOBJNOTFOUND); + return true; + } + + Field *fields = result->Fetch(); + uint32 lowguid = fields[0].GetUInt32(); + uint32 id = fields[1].GetUInt32(); + float x = fields[2].GetFloat(); + float y = fields[3].GetFloat(); + float z = fields[4].GetFloat(); + float o = fields[5].GetFloat(); + int mapid = fields[6].GetUInt16(); + delete result; + + GameObjectInfo const* goI = objmgr.GetGameObjectInfo(id); + + if (!goI) + { + PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); + return false; + } + + GameObject* target = ObjectAccessor::GetGameObject(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,id,HIGHGUID_GAMEOBJECT)); + + PSendSysMessage(LANG_GAMEOBJECT_DETAIL, lowguid, goI->name, lowguid, id, x, y, z, mapid, o); + + if(target) + { + int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL); + if(curRespawnDelay < 0) + curRespawnDelay = 0; + + std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true); + std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true); + + PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str()); + } + return true; +} + +//teleport to gameobject +bool ChatHandler::HandleGoObjectCommand(const char* args) +{ + if(!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if(!cId) + return false; + + int32 guid = atoi(cId); + if(!guid) + return false; + + float x, y, z, ort; + int mapid; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(guid)) + { + x = go_data->posX; + y = go_data->posY; + z = go_data->posZ; + ort = go_data->orientation; + mapid = go_data->mapid; + } + else + { + SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND); + SetSentErrorMessage(true); + return false; + } + + if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(mapid, x, y, z, ort); + return true; +} + +bool ChatHandler::HandleGoTriggerCommand(const char* args) +{ + Player* _player = m_session->GetPlayer(); + + if (!*args) + return false; + + char *atId = strtok((char*)args, " "); + if (!atId) + return false; + + int32 i_atId = atoi(atId); + + if(!i_atId) + return false; + + AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(i_atId); + if (!at) + { + PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND,i_atId); + SetSentErrorMessage(true); + return false; + } + + if(!MapManager::IsValidMapCoord(at->mapid,at->x,at->y,at->z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,at->x,at->y,at->mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(at->mapid, at->x, at->y, at->z, _player->GetOrientation()); + return true; +} + +bool ChatHandler::HandleGoGraveyardCommand(const char* args) +{ + Player* _player = m_session->GetPlayer(); + + if (!*args) + return false; + + char *gyId = strtok((char*)args, " "); + if (!gyId) + return false; + + int32 i_gyId = atoi(gyId); + + if(!i_gyId) + return false; + + WorldSafeLocsEntry const* gy = sWorldSafeLocsStore.LookupEntry(i_gyId); + if (!gy) + { + PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST,i_gyId); + SetSentErrorMessage(true); + return false; + } + + if(!MapManager::IsValidMapCoord(gy->map_id,gy->x,gy->y,gy->z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,gy->x,gy->y,gy->map_id); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(gy->map_id, gy->x, gy->y, gy->z, _player->GetOrientation()); + return true; +} + +/** \brief Teleport the GM to the specified creature + * + * .gocreature --> TP using creature.guid + * .gocreature azuregos --> TP player to the mob with this name + * Warning: If there is more than one mob with this name + * you will be teleported to the first one that is found. + * .gocreature id 6109 --> TP player to the mob, that has this creature_template.entry + * Warning: If there is more than one mob with this "id" + * you will be teleported to the first one that is found. + */ +//teleport to creature +bool ChatHandler::HandleGoCreatureCommand(const char* args) +{ + if(!*args) + return false; + Player* _player = m_session->GetPlayer(); + + // "id" or number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r + char* pParam1 = extractKeyFromLink((char*)args,"Hcreature"); + if (!pParam1) + return false; + + std::ostringstream whereClause; + + // User wants to teleport to the NPC's template entry + if( strcmp(pParam1, "id") == 0 ) + { + //sLog.outError("DEBUG: ID found"); + + // Get the "creature_template.entry" + // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r + char* tail = strtok(NULL,""); + if(!tail) + return false; + char* cId = extractKeyFromLink(tail,"Hcreature_entry"); + if(!cId) + return false; + + int32 tEntry = atoi(cId); + //sLog.outError("DEBUG: ID value: %d", tEntry); + if(!tEntry) + return false; + + whereClause << "WHERE id = '" << tEntry << "'"; + } + else + { + //sLog.outError("DEBUG: ID *not found*"); + + int32 guid = atoi(pParam1); + + // Number is invalid - maybe the user specified the mob's name + if(!guid) + { + std::string name = pParam1; + WorldDatabase.escape_string(name); + whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name "_LIKE_" '" << name << "'"; + } + else + { + whereClause << "WHERE guid = '" << guid << "'"; + } + } + //sLog.outError("DEBUG: %s", whereClause.c_str()); + + QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM creature %s", whereClause.str().c_str() ); + if (!result) + { + SendSysMessage(LANG_COMMAND_GOCREATNOTFOUND); + SetSentErrorMessage(true); + return false; + } + if( result->GetRowCount() > 1 ) + { + SendSysMessage(LANG_COMMAND_GOCREATMULTIPLE); + } + + Field *fields = result->Fetch(); + float x = fields[0].GetFloat(); + float y = fields[1].GetFloat(); + float z = fields[2].GetFloat(); + float ort = fields[3].GetFloat(); + int mapid = fields[4].GetUInt16(); + + delete result; + + if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if(_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(mapid, x, y, z, ort); + return true; +} + +bool ChatHandler::HandleGUIDCommand(const char* /*args*/) +{ + uint64 guid = m_session->GetPlayer()->GetSelection(); + + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_OBJECT_GUID, GUID_LOPART(guid), GUID_HIPART(guid)); + return true; +} + +bool ChatHandler::HandleLookupFactionCommand(const char* args) +{ + if(!*args) + return false; + + Player *target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + std::string namepart = args; + std::wstring wnamepart; + + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower( wnamepart ); + + uint32 counter = 0; // Counter for figure out that we found smth. + + for (uint32 id = 0; id < sFactionStore.GetNumRows(); id++) + //for(FactionStateList::const_iterator itr = target->m_factions.begin(); itr != target->m_factions.end(); ++itr) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry(id); + //FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID); + if (factionEntry) + { + FactionStateList::const_iterator repItr = target->m_factions.find(factionEntry->reputationListID); + + int loc = m_session->GetSessionDbcLocale(); + std::string name = factionEntry->name[loc]; + if(name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for(; loc < MAX_LOCALE; ++loc) + { + if(loc==m_session->GetSessionDbcLocale()) + continue; + + name = factionEntry->name[loc]; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if(loc < MAX_LOCALE) + { + // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format + // or "id - [faction] [no reputation]" format + std::ostringstream ss; + ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r"; + + if (repItr != target->m_factions.end()) + { + ReputationRank rank = target->GetReputationRank(factionEntry); + std::string rankName = GetMangosString(ReputationRankStrIndex[rank]); + + ss << " " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")"; + + if(repItr->second.Flags & FACTION_FLAG_VISIBLE) + ss << GetMangosString(LANG_FACTION_VISIBLE); + if(repItr->second.Flags & FACTION_FLAG_AT_WAR) + ss << GetMangosString(LANG_FACTION_ATWAR); + if(repItr->second.Flags & FACTION_FLAG_PEACE_FORCED) + ss << GetMangosString(LANG_FACTION_PEACE_FORCED); + if(repItr->second.Flags & FACTION_FLAG_HIDDEN) + ss << GetMangosString(LANG_FACTION_HIDDEN); + if(repItr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED) + ss << GetMangosString(LANG_FACTION_INVISIBLE_FORCED); + if(repItr->second.Flags & FACTION_FLAG_INACTIVE) + ss << GetMangosString(LANG_FACTION_INACTIVE); + } + else + ss << GetMangosString(LANG_FACTION_NOREPUTATION); + + SendSysMessage(ss.str().c_str()); + counter++; + } + } + } + + if (counter == 0) // if counter == 0 then we found nth + SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND); + return true; +} + +bool ChatHandler::HandleModifyRepCommand(const char * args) +{ + if (!*args) return false; + + Player* target = NULL; + target = getSelectedPlayer(); + + if(!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + char* factionTxt = extractKeyFromLink((char*)args,"Hfaction"); + if(!factionTxt) + return false; + + uint32 factionId = atoi(factionTxt); + + int32 amount = 0; + char *rankTxt = strtok(NULL, " "); + if (!factionTxt || !rankTxt) + return false; + + amount = atoi(rankTxt); + if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0])) + { + std::string rankStr = rankTxt; + std::wstring wrankStr; + if(!Utf8toWStr(rankStr,wrankStr)) + return false; + wstrToLower( wrankStr ); + + int r = 0; + amount = -42000; + for (; r < MAX_REPUTATION_RANK; ++r) + { + std::string rank = GetMangosString(ReputationRankStrIndex[r]); + if(rank.empty()) + continue; + + std::wstring wrank; + if(!Utf8toWStr(rank,wrank)) + continue; + + wstrToLower(wrank); + + if(wrank.substr(0,wrankStr.size())==wrankStr) + { + char *deltaTxt = strtok(NULL, " "); + if (deltaTxt) + { + int32 delta = atoi(deltaTxt); + if ((delta < 0) || (delta > Player::ReputationRank_Length[r] -1)) + { + PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (Player::ReputationRank_Length[r]-1)); + SetSentErrorMessage(true); + return false; + } + amount += delta; + } + break; + } + amount += Player::ReputationRank_Length[r]; + } + if (r >= MAX_REPUTATION_RANK) + { + PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt); + SetSentErrorMessage(true); + return false; + } + } + + FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId); + + if (!factionEntry) + { + PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId); + SetSentErrorMessage(true); + return false; + } + + if (factionEntry->reputationListID < 0) + { + PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->name[m_session->GetSessionDbcLocale()], factionId); + SetSentErrorMessage(true); + return false; + } + + target->SetFactionReputation(factionEntry,amount); + PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[m_session->GetSessionDbcLocale()], factionId, target->GetName(), target->GetReputation(factionId)); + return true; +} + +bool ChatHandler::HandleNameCommand(const char* args) +{ + /* Temp. disabled + if(!*args) + return false; + + if(strlen((char*)args)>75) + { + PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75); + return true; + } + + for (uint8 i = 0; i < strlen(args); i++) + { + if(!isalpha(args[i]) && args[i]!=' ') + { + SendSysMessage(LANG_CHARS_ONLY); + return false; + } + } + + uint64 guid; + guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + pCreature->SetName(args); + uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName()); + pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); + + pCreature->SaveToDB(); + */ + + return true; +} + +bool ChatHandler::HandleSubNameCommand(const char* /*args*/) +{ + /* Temp. disabled + + if(!*args) + args = ""; + + if(strlen((char*)args)>75) + { + + PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75); + return true; + } + + for (uint8 i = 0; i < strlen(args); i++) + { + if(!isalpha(args[i]) && args[i]!=' ') + { + SendSysMessage(LANG_CHARS_ONLY); + return false; + } + } + uint64 guid; + guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID)); + pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); + + pCreature->SaveToDB(); + */ + return true; +} + +//move item to other slot +bool ChatHandler::HandleItemMoveCommand(const char* args) +{ + if(!*args) + return false; + uint8 srcslot, dstslot; + + char* pParam1 = strtok((char*)args, " "); + if (!pParam1) + return false; + + char* pParam2 = strtok(NULL, " "); + if (!pParam2) + return false; + + srcslot = (uint8)atoi(pParam1); + dstslot = (uint8)atoi(pParam2); + + uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); + uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); + + if(srcslot==dstslot) + return true; + + m_session->GetPlayer()->SwapItem( src, dst ); + + return true; +} + +//add spawn of creature +bool ChatHandler::HandleAddSpwCommand(const char* args) +{ + if(!*args) + return false; + char* charID = strtok((char*)args, " "); + if (!charID) + return false; + + char* team = strtok(NULL, " "); + int32 teamval = 0; + if (team) { teamval = atoi(team); } + if (teamval < 0) { teamval = 0; } + + uint32 id = atoi(charID); + + Player *chr = m_session->GetPlayer(); + float x = chr->GetPositionX(); + float y = chr->GetPositionY(); + float z = chr->GetPositionZ(); + float o = chr->GetOrientation(); + Map *map = chr->GetMap(); + + Creature* pCreature = new Creature; + if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, (uint32)teamval)) + { + delete pCreature; + return false; + } + + pCreature->Relocate(x,y,z,o); + + if(!pCreature->IsPositionValid()) + { + sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); + delete pCreature; + return false; + } + + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); + + uint32 db_guid = pCreature->GetDBTableGUIDLow(); + + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + pCreature->LoadFromDB(db_guid, map); + + map->Add(pCreature); + objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid)); + return true; +} + +bool ChatHandler::HandleDelCreatureCommand(const char* args) +{ + Creature* unit = NULL; + + if(*args) + { + // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hcreature"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + if(!lowguid) + return false; + + if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid)) + unit = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT)); + } + else + unit = getSelectedCreature(); + + if(!unit || unit->isPet() || unit->isTotem()) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // Delete the creature + unit->CombatStop(); + unit->DeleteFromDB(); + unit->CleanupsBeforeDelete(); + unit->AddObjectToRemoveList(); + + SendSysMessage(LANG_COMMAND_DELCREATMESSAGE); + + return true; +} + +//delete object by selection or guid +bool ChatHandler::HandleDelObjectCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + if(!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if(!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + uint64 owner_guid = obj->GetOwnerGUID(); + if(owner_guid) + { + Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid); + if(!owner && !IS_PLAYER_GUID(owner_guid)) + { + PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow()); + SetSentErrorMessage(true); + return false; + } + + owner->RemoveGameObject(obj,false); + } + + obj->SetRespawnTime(0); // not save respawn time + obj->Delete(); + obj->DeleteFromDB(); + + PSendSysMessage(LANG_COMMAND_DELOBJMESSAGE, obj->GetGUIDLow()); + + return true; +} + +//turn selected object +bool ChatHandler::HandleTurnObjectCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + if(!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if(!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + char* po = strtok(NULL, " "); + float o; + + if (po) + { + o = (float)atof(po); + } + else + { + Player *chr = m_session->GetPlayer(); + o = chr->GetOrientation(); + } + + float rot2 = sin(o/2); + float rot3 = cos(o/2); + + Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj); + map->Remove(obj,false); + + obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o); + + obj->SetFloatValue(GAMEOBJECT_FACING, o); + obj->SetFloatValue(GAMEOBJECT_ROTATION+2, rot2); + obj->SetFloatValue(GAMEOBJECT_ROTATION+3, rot3); + + map->Add(obj); + + obj->SaveToDB(); + obj->Refresh(); + + PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), o); + + return true; +} + +//move selected creature +bool ChatHandler::HandleMoveCreatureCommand(const char* args) +{ + uint32 lowguid = 0; + + Creature* pCreature = getSelectedCreature(); + + if(!pCreature) + { + // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hcreature"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + + /* FIXME: impossibel without entry + if(lowguid) + pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); + */ + + // Attempting creature load from DB data + if(!pCreature) + { + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + uint32 map_id = data->mapid; + + if(m_session->GetPlayer()->GetMapId()!=map_id) + { + PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); + SetSentErrorMessage(true); + return false; + } + } + else + { + lowguid = pCreature->GetDBTableGUIDLow(); + } + } + else + { + lowguid = pCreature->GetDBTableGUIDLow(); + } + + float x = m_session->GetPlayer()->GetPositionX(); + float y = m_session->GetPlayer()->GetPositionY(); + float z = m_session->GetPlayer()->GetPositionZ(); + float o = m_session->GetPlayer()->GetOrientation(); + + if (pCreature) + { + if(CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow())) + { + const_cast(data)->posX = x; + const_cast(data)->posY = y; + const_cast(data)->posZ = z; + const_cast(data)->orientation = o; + } + MapManager::Instance().GetMap(pCreature->GetMapId(),pCreature)->CreatureRelocation(pCreature,x, y, z,o); + pCreature->GetMotionMaster()->Initialize(); + if(pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + } + + WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid); + PSendSysMessage(LANG_COMMAND_CREATUREMOVED); + return true; +} + +//move selected object +bool ChatHandler::HandleMoveObjectCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + if(!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if(!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + char* px = strtok(NULL, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + + if (!px) + { + Player *chr = m_session->GetPlayer(); + + Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj); + map->Remove(obj,false); + + obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation()); + obj->SetFloatValue(GAMEOBJECT_POS_X, chr->GetPositionX()); + obj->SetFloatValue(GAMEOBJECT_POS_Y, chr->GetPositionY()); + obj->SetFloatValue(GAMEOBJECT_POS_Z, chr->GetPositionZ()); + + map->Add(obj); + } + else + { + if(!py || !pz) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + float z = (float)atof(pz); + + if(!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId()); + SetSentErrorMessage(true); + return false; + } + + Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj); + map->Remove(obj,false); + + obj->Relocate(x, y, z, obj->GetOrientation()); + obj->SetFloatValue(GAMEOBJECT_POS_X, x); + obj->SetFloatValue(GAMEOBJECT_POS_Y, y); + obj->SetFloatValue(GAMEOBJECT_POS_Z, z); + + map->Add(obj); + } + + obj->SaveToDB(); + obj->Refresh(); + + PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow()); + + return true; +} + +//demorph player or unit +bool ChatHandler::HandleDeMorphCommand(const char* /*args*/) +{ + Unit *target = getSelectedUnit(); + if(!target) + target = m_session->GetPlayer(); + + target->DeMorph(); + + return true; +} + +//add item in vendorlist +bool ChatHandler::HandleAddVendorItemCommand(const char* args) +{ + if (!*args) + return false; + + Creature* vendor = getSelectedCreature(); + if (!vendor || !vendor->isVendor()) + { + SendSysMessage(LANG_COMMAND_VENDORSELECTION); + SetSentErrorMessage(true); + return false; + } + + char* pitem = extractKeyFromLink((char*)args,"Hitem"); + if (!pitem) + { + SendSysMessage(LANG_COMMAND_NEEDITEMSEND); + SetSentErrorMessage(true); + return false; + } + uint32 itemId = atol(pitem); + + char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0 + uint32 maxcount = 0; + if (fmaxcount) + maxcount = atol(fmaxcount); + + char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0 + uint32 incrtime = 0; + if (fincrtime) + incrtime = atol(fincrtime); + + char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0 + uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0; + + ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); + if(!pProto) + { + PSendSysMessage(LANG_ITEM_NOT_FOUND, itemId); + SetSentErrorMessage(true); + return false; + } + + if(extendedcost && !sItemExtendedCostStore.LookupEntry(extendedcost)) + { + PSendSysMessage(LANG_BAD_VALUE, extendedcost); + SetSentErrorMessage(true); + return false; + } + + // load vendor items if not yet + vendor->LoadGoods(); + + if(vendor->FindItem(itemId)) + { + PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST,itemId); + SetSentErrorMessage(true); + return false; + } + + if (vendor->GetItemCount() >= MAX_VENDOR_ITEMS) + { + SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS); + SetSentErrorMessage(true); + return false; + } + + // add to DB and to current ingame vendor + WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')",vendor->GetEntry(), itemId, maxcount,incrtime,extendedcost); + vendor->AddItem(itemId,maxcount,incrtime,extendedcost); + PSendSysMessage(LANG_ITEM_ADDED_TO_LIST,itemId,pProto->Name1,maxcount,incrtime,extendedcost); + return true; +} + +//del item from vendor list +bool ChatHandler::HandleDelVendorItemCommand(const char* args) +{ + if (!*args) + return false; + + Creature* vendor = getSelectedCreature(); + if (!vendor || !vendor->isVendor()) + { + SendSysMessage(LANG_COMMAND_VENDORSELECTION); + SetSentErrorMessage(true); + return false; + } + + char* pitem = extractKeyFromLink((char*)args,"Hitem"); + if (!pitem) + { + SendSysMessage(LANG_COMMAND_NEEDITEMSEND); + SetSentErrorMessage(true); + return false; + } + uint32 itemId = atol(pitem); + + ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); + if(!pProto) + { + PSendSysMessage(LANG_ITEM_NOT_FOUND, itemId); + SetSentErrorMessage(true); + return false; + } + + // load vendor items if not yet + vendor->LoadGoods(); + + if (!vendor->RemoveItem(itemId)) + { + PSendSysMessage(LANG_ITEM_NOT_IN_LIST,itemId); + SetSentErrorMessage(true); + return false; + } + + WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",vendor->GetEntry(), itemId); + PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST,itemId,pProto->Name1); + return true; +} + +//add move for creature +bool ChatHandler::HandleAddMoveCommand(const char* args) +{ + if(!*args) + return false; + + char* guid_str = strtok((char*)args, " "); + char* wait_str = strtok((char*)NULL, " "); + + uint32 lowguid = atoi((char*)guid_str); + + Creature* pCreature = NULL; + + /* FIXME: impossible without entry + if(lowguid) + pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); + */ + + // attempt check creature existence by DB data + if(!pCreature) + { + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + } + else + { + // obtain real GUID for DB operations + lowguid = pCreature->GetDBTableGUIDLow(); + } + + int wait = wait_str ? atoi(wait_str) : 0; + + if(wait < 0) + wait = 0; + + Player* player = m_session->GetPlayer(); + + WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0); + + // update movement type + WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); + if(pCreature) + { + pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); + pCreature->GetMotionMaster()->Initialize(); + if(pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + pCreature->SaveToDB(); + } + + SendSysMessage(LANG_WAYPOINT_ADDED); + + return true; +} + +/** + * Set the movement type for an NPC.
+ *
+ * Valid movement types are: + *
    + *
  • stay - NPC wont move
  • + *
  • random - NPC will move randomly according to the spawndist
  • + *
  • way - NPC will move with given waypoints set
  • + *
+ * additional parameter: NODEL - so no waypoints are deleted, if you + * change the movement type + */ +bool ChatHandler::HandleSetMoveTypeCommand(const char* args) +{ + if(!*args) + return false; + + // 3 arguments: + // GUID (optional - you can also select the creature) + // stay|random|way (determines the kind of movement) + // NODEL (optional - tells the system NOT to delete any waypoints) + // this is very handy if you want to do waypoints, that are + // later switched on/off according to special events (like escort + // quests, etc) + char* guid_str = strtok((char*)args, " "); + char* type_str = strtok((char*)NULL, " "); + char* dontdel_str = strtok((char*)NULL, " "); + + bool doNotDelete = false; + + if(!guid_str) + return false; + + uint32 lowguid = 0; + Creature* pCreature = NULL; + + if( dontdel_str ) + { + //sLog.outError("DEBUG: All 3 params are set"); + + // All 3 params are set + // GUID + // type + // doNotDEL + if( stricmp( dontdel_str, "NODEL" ) == 0 ) + { + //sLog.outError("DEBUG: doNotDelete = true;"); + doNotDelete = true; + } + } + else + { + // Only 2 params - but maybe NODEL is set + if( type_str ) + { + sLog.outError("DEBUG: Only 2 params "); + if( stricmp( type_str, "NODEL" ) == 0 ) + { + //sLog.outError("DEBUG: type_str, NODEL "); + doNotDelete = true; + type_str = NULL; + } + } + } + + if(!type_str) // case .setmovetype $move_type (with selected creature) + { + type_str = guid_str; + pCreature = getSelectedCreature(); + if(!pCreature) + return false; + lowguid = pCreature->GetDBTableGUIDLow(); + } + else // case .setmovetype #creature_guid $move_type (with selected creature) + { + lowguid = atoi((char*)guid_str); + + /* impossible without entry + if(lowguid) + pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); + */ + + // attempt check creature existence by DB data + if(!pCreature) + { + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + } + else + { + lowguid = pCreature->GetDBTableGUIDLow(); + } + } + + // now lowguid is low guid really existed creature + // and pCreature point (maybe) to this creature or NULL + + MovementGeneratorType move_type; + + std::string type = type_str; + + if(type == "stay") + move_type = IDLE_MOTION_TYPE; + else if(type == "random") + move_type = RANDOM_MOTION_TYPE; + else if(type == "way") + move_type = WAYPOINT_MOTION_TYPE; + else + return false; + + // update movement type + if(doNotDelete == false) + WaypointMgr.DeletePath(lowguid); + + if(pCreature) + { + pCreature->SetDefaultMovementType(move_type); + pCreature->GetMotionMaster()->Initialize(); + if(pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + pCreature->SaveToDB(); + } + if( doNotDelete == false ) + { + PSendSysMessage(LANG_MOVE_TYPE_SET,type_str); + } + else + { + PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL,type_str); + } + + return true; +} // HandleSetMoveTypeCommand + +//change level of creature or pet +bool ChatHandler::HandleChangeLevelCommand(const char* args) +{ + if (!*args) + return false; + + uint8 lvl = (uint8) atoi((char*)args); + if ( lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Creature* pCreature = getSelectedCreature(); + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if(pCreature->isPet()) + { + ((Pet*)pCreature)->GivePetLevel(lvl); + } + else + { + pCreature->SetMaxHealth( 100 + 30*lvl); + pCreature->SetHealth( 100 + 30*lvl); + pCreature->SetLevel( lvl); + pCreature->SaveToDB(); + } + + return true; +} + +//set npcflag of creature +bool ChatHandler::HandleNPCFlagCommand(const char* args) +{ + if (!*args) + return false; + + uint32 npcFlags = (uint32) atoi((char*)args); + + Creature* pCreature = getSelectedCreature(); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); + + WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); + + SendSysMessage(LANG_VALUE_SAVED_REJOIN); + + return true; +} + +//set model of creature +bool ChatHandler::HandleSetModelCommand(const char* args) +{ + if (!*args) + return false; + + uint32 displayId = (uint32) atoi((char*)args); + + Creature *pCreature = getSelectedCreature(); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->SetDisplayId(displayId); + pCreature->SetNativeDisplayId(displayId); + + pCreature->SaveToDB(); + + return true; +} + +//morph creature or player +bool ChatHandler::HandleMorphCommand(const char* args) +{ + if (!*args) + return false; + + uint16 display_id = (uint16)atoi((char*)args); + + Unit *target = getSelectedUnit(); + if(!target) + target = m_session->GetPlayer(); + + target->SetDisplayId(display_id); + + return true; +} + +//set faction of creature or go +bool ChatHandler::HandleFactionIdCommand(const char* args) +{ + if (!*args) + return false; + + uint32 factionId = (uint32) atoi((char*)args); + + if (!sFactionTemplateStore.LookupEntry(factionId)) + { + PSendSysMessage(LANG_WRONG_FACTION, factionId); + SetSentErrorMessage(true); + return false; + } + + Creature* pCreature = getSelectedCreature(); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->setFaction(factionId); + + // faction is set in creature_template - not inside creature + + // update in memory + if(CreatureInfo const *cinfo = pCreature->GetCreatureInfo()) + { + const_cast(cinfo)->faction_A = factionId; + const_cast(cinfo)->faction_H = factionId; + } + + // and DB + WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry()); + + return true; +} + +//kick player +bool ChatHandler::HandleKickPlayerCommand(const char *args) +{ + char* kickName = strtok((char*)args, " "); + if (!kickName) + { + Player* player = getSelectedPlayer(); + + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(player==m_session->GetPlayer()) + { + SendSysMessage(LANG_COMMAND_KICKSELF); + SetSentErrorMessage(true); + return false; + } + + player->GetSession()->KickPlayer(); + } + else + { + std::string name = kickName; + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if(name==m_session->GetPlayer()->GetName()) + { + SendSysMessage(LANG_COMMAND_KICKSELF); + SetSentErrorMessage(true); + return false; + } + + if(sWorld.KickPlayer(name)) + { + PSendSysMessage(LANG_COMMAND_KICKMESSAGE,name.c_str()); + } + else + PSendSysMessage(LANG_COMMAND_KICKNOTFOUNDPLAYER,name.c_str()); + } + + return true; +} + +//show info of player +bool ChatHandler::HandlePInfoCommand(const char* args) +{ + Player* target = NULL; + uint64 targetGUID = 0; + + char* px = strtok((char*)args, " "); + char* py = NULL; + + std::string name; + + if (px) + { + name = px; + + if(name.empty()) + return false; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + target = objmgr.GetPlayer(name.c_str()); + if (target) + py = strtok(NULL, " "); + else + { + targetGUID = objmgr.GetPlayerGUIDByName(name); + if(targetGUID) + py = strtok(NULL, " "); + else + py = px; + } + } + + if(!target && !targetGUID) + { + target = getSelectedPlayer(); + } + + if(!target && !targetGUID) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint32 accId = 0; + uint32 money = 0; + uint32 total_player_time = 0; + uint32 level = 0; + uint32 latency = 0; + + // get additional information from Player object + if(target) + { + targetGUID = target->GetGUID(); + name = target->GetName(); // re-read for case getSelectedPlayer() target + accId = target->GetSession()->GetAccountId(); + money = target->GetMoney(); + total_player_time = target->GetTotalPlayedTime(); + level = target->getLevel(); + latency = target->GetSession()->GetLatency(); + } + // get additional information from DB + else + { + accId = objmgr.GetPlayerAccountIdByGUID(targetGUID); + Player plr(m_session); // use current session for temporary load + plr.MinimalLoadFromDB(NULL, targetGUID); + money = plr.GetMoney(); + total_player_time = plr.GetTotalPlayedTime(); + level = plr.getLevel(); + } + + std::string username = GetMangosString(LANG_ERROR); + std::string last_ip = GetMangosString(LANG_ERROR); + uint32 security = 0; + std::string last_login = GetMangosString(LANG_ERROR); + + QueryResult* result = loginDatabase.PQuery("SELECT username,gmlevel,last_ip,last_login FROM account WHERE id = '%u'",accId); + if(result) + { + Field* fields = result->Fetch(); + username = fields[0].GetCppString(); + security = fields[1].GetUInt32(); + if(m_session->GetSecurity() >= security) + { + last_ip = fields[2].GetCppString(); + last_login = fields[3].GetCppString(); + } + else + { + last_ip = "-"; + last_login = "-"; + } + + delete result; + } + + PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetMangosString(LANG_OFFLINE)), name.c_str(), GUID_LOPART(targetGUID), username.c_str(), accId, security, last_ip.c_str(), last_login.c_str(), latency); + + std::string timeStr = secsToTimeString(total_player_time,true,true); + uint32 gold = money /GOLD; + uint32 silv = (money % GOLD) / SILVER; + uint32 copp = (money % GOLD) % SILVER; + PSendSysMessage(LANG_PINFO_LEVEL, timeStr.c_str(), level, gold,silv,copp ); + + if ( py && strncmp(py, "rep", 3) == 0 ) + { + if(!target) + { + // rep option not implemented for offline case + SendSysMessage(LANG_PINFO_NO_REP); + SetSentErrorMessage(true); + return false; + } + + char* FactionName; + for(FactionStateList::const_iterator itr = target->m_factions.begin(); itr != target->m_factions.end(); ++itr) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID); + if (factionEntry) + FactionName = factionEntry->name[m_session->GetSessionDbcLocale()]; + else + FactionName = "#Not found#"; + ReputationRank rank = target->GetReputationRank(factionEntry); + std::string rankName = GetMangosString(ReputationRankStrIndex[rank]); + std::ostringstream ss; + ss << itr->second.ID << ": |cffffffff|Hfaction:" << itr->second.ID << "|h[" << FactionName << "]|h|r " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")"; + + if(itr->second.Flags & FACTION_FLAG_VISIBLE) + ss << GetMangosString(LANG_FACTION_VISIBLE); + if(itr->second.Flags & FACTION_FLAG_AT_WAR) + ss << GetMangosString(LANG_FACTION_ATWAR); + if(itr->second.Flags & FACTION_FLAG_PEACE_FORCED) + ss << GetMangosString(LANG_FACTION_PEACE_FORCED); + if(itr->second.Flags & FACTION_FLAG_HIDDEN) + ss << GetMangosString(LANG_FACTION_HIDDEN); + if(itr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED) + ss << GetMangosString(LANG_FACTION_INVISIBLE_FORCED); + if(itr->second.Flags & FACTION_FLAG_INACTIVE) + ss << GetMangosString(LANG_FACTION_INACTIVE); + + SendSysMessage(ss.str().c_str()); + } + } + return true; +} + +//show tickets +void ChatHandler::ShowTicket(uint64 guid, char const* text, char const* time) +{ + std::string name; + if(!objmgr.GetPlayerNameByGUID(guid,name)) + name = GetMangosString(LANG_UNKNOWN); + + PSendSysMessage(LANG_COMMAND_TICKETVIEW, name.c_str(),time,text); +} + +//ticket commands +bool ChatHandler::HandleTicketCommand(const char* args) +{ + char* px = strtok((char*)args, " "); + + // ticket + if (!px) + { + size_t count; + QueryResult *result = CharacterDatabase.Query("SELECT COUNT(ticket_id) FROM character_ticket"); + if(result) + { + count = (*result)[0].GetUInt32(); + delete result; + } + else + count = 0; + + PSendSysMessage(LANG_COMMAND_TICKETCOUNT, count, m_session->GetPlayer()->isAcceptTickets() ? GetMangosString(LANG_ON) : GetMangosString(LANG_OFF)); + return true; + } + + // ticket on + if(strncmp(px,"on",3) == 0) + { + m_session->GetPlayer()->SetAcceptTicket(true); + SendSysMessage(LANG_COMMAND_TICKETON); + return true; + } + + // ticket off + if(strncmp(px,"off",4) == 0) + { + m_session->GetPlayer()->SetAcceptTicket(false); + SendSysMessage(LANG_COMMAND_TICKETOFF); + return true; + } + + // ticket #num + int num = atoi(px); + if(num > 0) + { + QueryResult *result = CharacterDatabase.PQuery("SELECT guid,ticket_text,ticket_lastchange FROM character_ticket ORDER BY ticket_id ASC LIMIT %d,1",num-1); + + if(!result) + { + PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num); + delete result; + SetSentErrorMessage(true); + return false; + } + + Field* fields = result->Fetch(); + + uint64 guid = fields[0].GetUInt64(); + char const* text = fields[1].GetString(); + char const* time = fields[2].GetString(); + + ShowTicket(guid,text,time); + delete result; + return true; + } + + std::string name = px; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = objmgr.GetPlayerGUIDByName(name); + + if(!guid) + return false; + + // ticket $char_name + QueryResult *result = CharacterDatabase.PQuery("SELECT ticket_text,ticket_lastchange FROM character_ticket WHERE guid = '%u' ORDER BY ticket_id ASC",GUID_LOPART(guid)); + + if(!result) + return false; + + Field* fields = result->Fetch(); + + char const* text = fields[0].GetString(); + char const* time = fields[1].GetString(); + + ShowTicket(guid,text,time); + delete result; + + return true; +} + +uint32 ChatHandler::GetTicketIDByNum(uint32 num) +{ + QueryResult *result = CharacterDatabase.Query("SELECT ticket_id FROM character_ticket"); + + if(!result || num > result->GetRowCount()) + { + PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num); + delete result; + return 0; + } + + for(uint32 i = 1; i < num; ++i) + result->NextRow(); + + Field* fields = result->Fetch(); + + uint32 id = fields[0].GetUInt32(); + delete result; + return id; +} + +//dell all tickets +bool ChatHandler::HandleDelTicketCommand(const char *args) +{ + char* px = strtok((char*)args, " "); + if (!px) + return false; + + // delticket all + if(strncmp(px,"all",4) == 0) + { + QueryResult *result = CharacterDatabase.Query("SELECT guid FROM character_ticket"); + + if(!result) + return true; + + // notify players about ticket deleting + do + { + Field* fields = result->Fetch(); + + uint64 guid = fields[0].GetUInt64(); + + if(Player* sender = objmgr.GetPlayer(guid)) + sender->GetSession()->SendGMTicketGetTicket(0x0A,0); + + }while(result->NextRow()); + + delete result; + + CharacterDatabase.PExecute("DELETE FROM character_ticket"); + SendSysMessage(LANG_COMMAND_ALLTICKETDELETED); + return true; + } + + int num = (uint32)atoi(px); + + // delticket #num + if(num > 0) + { + QueryResult *result = CharacterDatabase.PQuery("SELECT ticket_id,guid FROM character_ticket LIMIT %i",num); + + if(!result || uint64(num) > result->GetRowCount()) + { + PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num); + delete result; + SetSentErrorMessage(true); + return false; + } + + for(int i = 1; i < num; ++i) + result->NextRow(); + + Field* fields = result->Fetch(); + + uint32 id = fields[0].GetUInt32(); + uint64 guid = fields[1].GetUInt64(); + delete result; + + CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE ticket_id = '%u'", id); + + // notify players about ticket deleting + if(Player* sender = objmgr.GetPlayer(guid)) + { + sender->GetSession()->SendGMTicketGetTicket(0x0A,0); + PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL,sender->GetName()); + } + else + SendSysMessage(LANG_COMMAND_TICKETDEL); + + return true; + } + + std::string name = px; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = objmgr.GetPlayerGUIDByName(name); + + if(!guid) + return false; + + // delticket $char_name + CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u'",GUID_LOPART(guid)); + + // notify players about ticket deleting + if(Player* sender = objmgr.GetPlayer(guid)) + sender->GetSession()->SendGMTicketGetTicket(0x0A,0); + + PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL,px); + return true; +} + +//set spawn dist of creature +bool ChatHandler::HandleSpawnDistCommand(const char* args) +{ + if(!*args) + return false; + + float option = atof((char*)args); + if (option < 0.0f) + { + SendSysMessage(LANG_BAD_VALUE); + return false; + } + + MovementGeneratorType mtype = IDLE_MOTION_TYPE; + if (option >0.0f) + mtype = RANDOM_MOTION_TYPE; + + Creature *pCreature = getSelectedCreature(); + uint32 u_guidlow = 0; + + if (pCreature) + u_guidlow = pCreature->GetDBTableGUIDLow(); + else + return false; + + pCreature->SetRespawnRadius((float)option); + pCreature->SetDefaultMovementType(mtype); + pCreature->GetMotionMaster()->Initialize(); + if(pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + + WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow); + PSendSysMessage(LANG_COMMAND_SPAWNDIST,option); + return true; +} + +bool ChatHandler::HandleSpawnTimeCommand(const char* args) +{ + if(!*args) + return false; + + char* stime = strtok((char*)args, " "); + + if (!stime) + return false; + + int i_stime = atoi((char*)stime); + + if (i_stime < 0) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Creature *pCreature = getSelectedCreature(); + uint32 u_guidlow = 0; + + if (pCreature) + u_guidlow = pCreature->GetDBTableGUIDLow(); + else + return false; + + WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow); + pCreature->SetRespawnDelay((uint32)i_stime); + PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime); + + return true; +} + +/** + * Add a waypoint to a creature. + * + * The user can either select an npc or provide its GUID. + * + * The user can even select a visual waypoint - then the new waypoint + * is placed *after* the selected one - this makes insertion of new + * waypoints possible. + * + * eg: + * .wp add 12345 + * -> adds a waypoint to the npc with the GUID 12345 + * + * .wp add + * -> adds a waypoint to the currently selected creature + * + * + * @param args if the user did not provide a GUID, it is NULL + * + * @return true - command did succeed, false - something went wrong + */ +bool ChatHandler::HandleWpAddCommand(const char* args) +{ + sLog.outDebug("DEBUG: HandleWpAddCommand"); + + // optional + char* guid_str = NULL; + + if(*args) + { + guid_str = strtok((char*)args, " "); + } + + uint32 lowguid = 0; + uint32 point = 0; + Creature* target = getSelectedCreature(); + // Did player provide a GUID? + if (!guid_str) + { + sLog.outDebug("DEBUG: HandleWpAddCommand - No GUID provided"); + + // No GUID provided + // -> Player must have selected a creature + + if(!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + if (target->GetEntry() == VISUAL_WAYPOINT ) + { + sLog.outDebug("DEBUG: HandleWpAddCommand - target->GetEntry() == VISUAL_WAYPOINT (1) "); + + QueryResult *result = + WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u", + target->GetGUIDLow() ); + if(!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUIDLow()); + // User selected a visual spawnpoint -> get the NPC + // Select NPC GUID + // Since we compare float values, we have to deal with + // some difficulties. + // Here we search for all waypoints that only differ in one from 1 thousand + // (0.001) - There is no other way to compare C++ floats with mySQL floats + // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html + const char* maxDIFF = "0.01"; + result = WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )", + target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF); + if(!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow()); + SetSentErrorMessage(true); + return false; + } + } + do + { + Field *fields = result->Fetch(); + lowguid = fields[0].GetUInt32(); + point = fields[1].GetUInt32(); + }while( result->NextRow() ); + delete result; + + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); + if(!target) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid); + SetSentErrorMessage(true); + return false; + } + } + else + { + lowguid = target->GetDBTableGUIDLow(); + } + } + else + { + sLog.outDebug("DEBUG: HandleWpAddCommand - GUID provided"); + + // GUID provided + // Warn if player also selected a creature + // -> Creature selection is ignored <- + if(target) + { + SendSysMessage(LANG_WAYPOINT_CREATSELECTED); + } + lowguid = atoi((char*)guid_str); + + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); + if(!target) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + } + // lowguid -> GUID of the NPC + // point -> number of the waypoint (if not 0) + sLog.outDebug("DEBUG: HandleWpAddCommand - danach"); + + sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0"); + + Player* player = m_session->GetPlayer(); + WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0); + + // update movement type + if(target) + { + target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); + target->GetMotionMaster()->Initialize(); + if(target->isAlive()) // dead creature will reset movement generator at respawn + { + target->setDeathState(JUST_DIED); + target->Respawn(); + } + target->SaveToDB(); + } + else + WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); + + PSendSysMessage(LANG_WAYPOINT_ADDED, point, lowguid); + + return true; +} // HandleWpAddCommand + +/** + * .wp modify emote | spell | text | del | move | add + * + * add -> add a WP after the selected visual waypoint + * User must select a visual waypoint and then issue ".wp modify add" + * + * emote + * User has selected a visual waypoint before. + * is added to this waypoint. Everytime the + * NPC comes to this waypoint, the emote is called. + * + * emote + * User has not selected visual waypoint before. + * For the waypoint for the NPC with + * an emote is added. + * Everytime the NPC comes to this waypoint, the emote is called. + * + * + * info -> User did not select a visual waypoint and + */ +bool ChatHandler::HandleWpModifyCommand(const char* args) +{ + sLog.outDebug("DEBUG: HandleWpModifyCommand"); + + if(!*args) + return false; + + // first arg: add del text emote spell waittime move + char* show_str = strtok((char*)args, " "); + if (!show_str) + { + return false; + } + + std::string show = show_str; + // Check + // Remember: "show" must also be the name of a column! + if( (show != "emote") && (show != "spell") && (show != "text1") && (show != "text2") + && (show != "text3") && (show != "text4") && (show != "text5") + && (show != "waittime") && (show != "del") && (show != "move") && (show != "add") + && (show != "model1") && (show != "model2") && (show != "orientation")) + { + return false; + } + + // Next arg is: + + // Did user provide a GUID + // or did the user select a creature? + // -> variable lowguid is filled with the GUID of the NPC + uint32 lowguid = 0; + uint32 point = 0; + uint32 wpGuid = 0; + Creature* target = getSelectedCreature(); + + if(target) + { + sLog.outDebug("DEBUG: HandleWpModifyCommand - User did select an NPC"); + + // Did the user select a visual spawnpoint? + if (target->GetEntry() != VISUAL_WAYPOINT ) + { + PSendSysMessage(LANG_WAYPOINT_VP_SELECT); + SetSentErrorMessage(true); + return false; + } + + wpGuid = target->GetGUIDLow(); + + // The visual waypoint + QueryResult *result = + WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u LIMIT 1", + target->GetGUIDLow() ); + if(!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid); + SetSentErrorMessage(true); + return false; + } + sLog.outDebug("DEBUG: HandleWpModifyCommand - After getting wpGuid"); + + Field *fields = result->Fetch(); + lowguid = fields[0].GetUInt32(); + point = fields[1].GetUInt32(); + + // Cleanup memory + sLog.outDebug("DEBUG: HandleWpModifyCommand - Cleanup memory"); + delete result; + } + else + { + // User did provide + + char* guid_str = strtok((char*)NULL, " "); + if( !guid_str ) + { + SendSysMessage(LANG_WAYPOINT_NOGUID); + return false; + } + lowguid = atoi((char*)guid_str); + + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage("DEBUG: GUID provided: %d", lowguid); + + char* point_str = strtok((char*)NULL, " "); + if( !point_str ) + { + SendSysMessage(LANG_WAYPOINT_NOWAYPOINTGIVEN); + return false; + } + point = atoi((char*)point_str); + + PSendSysMessage("DEBUG: wpNumber provided: %d", point); + + // Now we need the GUID of the visual waypoint + // -> "del", "move", "add" command + + QueryResult *result = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' AND point = '%u' LIMIT 1", lowguid, point); + if (!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, lowguid, point); + SetSentErrorMessage(true); + return false; + } + + Field *fields = result->Fetch(); + wpGuid = fields[0].GetUInt32(); + + // Free memory + delete result; + } + + char* arg_str = NULL; + // Check for argument + if( (show.find("text") == std::string::npos ) && (show != "del") && (show != "move") && (show != "add")) + { + // Text is enclosed in "<>", all other arguments not + if( show.find("text") != std::string::npos ) + arg_str = strtok((char*)NULL, "<>"); + else + arg_str = strtok((char*)NULL, " "); + + if( !arg_str) + { + PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str); + return false; + } + } + + sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command"); + + // wpGuid -> GUID of the waypoint creature + // lowguid -> GUID of the NPC + // point -> waypoint number + + // Special functions: + // add - move - del -> no args commands + // Add a waypoint after the selected visual + if(show == "add" && target) + { + PSendSysMessage("DEBUG: wp modify add, GUID: %u", lowguid); + + // Get the creature for which we read the waypoint + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); + + if( !npcCreature ) + { + PSendSysMessage(LANG_WAYPOINT_NPCNOTFOUND); + SetSentErrorMessage(true); + return false; + } + + sLog.outDebug("DEBUG: HandleWpModifyCommand - add -- npcCreature"); + + // What to do: + // Add the visual spawnpoint (DB only) + // Adjust the waypoints + // Respawn the owner of the waypoints + sLog.outDebug("DEBUG: HandleWpModifyCommand - add"); + + Player* chr = m_session->GetPlayer(); + Map *map = chr->GetMap(); + + if(npcCreature) + { + npcCreature->GetMotionMaster()->Initialize(); + if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn + { + npcCreature->setDeathState(JUST_DIED); + npcCreature->Respawn(); + } + } + + // create the waypoint creature + wpGuid = 0; + Creature* wpCreature = new Creature; + if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map,VISUAL_WAYPOINT,0)) + { + PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); + delete wpCreature; + } + else + { + wpCreature->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()); + + if(!wpCreature->IsPositionValid()) + { + sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY()); + delete wpCreature; + } + else + { + wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), map); + map->Add(wpCreature); + wpGuid = wpCreature->GetGUIDLow(); + } + } + + WaypointMgr.AddAfterNode(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), 0, 0, wpGuid); + + if(!wpGuid) + return false; + + PSendSysMessage(LANG_WAYPOINT_ADDED_NO, point+1); + return true; + } // add + + if(show == "del" && target) + { + PSendSysMessage("DEBUG: wp modify del, GUID: %u", lowguid); + + // Get the creature for which we read the waypoint + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); + + // wpCreature + Creature* wpCreature = NULL; + if( wpGuid != 0 ) + { + wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); + wpCreature->DeleteFromDB(); + wpCreature->CleanupsBeforeDelete(); + wpCreature->AddObjectToRemoveList(); + } + + // What to do: + // Remove the visual spawnpoint + // Adjust the waypoints + // Respawn the owner of the waypoints + + WaypointMgr.DeleteNode(lowguid, point); + + if(npcCreature) + { + // Any waypoints left? + QueryResult *result2 = WorldDatabase.PQuery( "SELECT point FROM creature_movement WHERE id = '%u'",lowguid); + if(!result2) + { + npcCreature->SetDefaultMovementType(RANDOM_MOTION_TYPE); + } + else + { + npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); + delete result2; + } + npcCreature->GetMotionMaster()->Initialize(); + if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn + { + npcCreature->setDeathState(JUST_DIED); + npcCreature->Respawn(); + } + npcCreature->SaveToDB(); + } + + PSendSysMessage(LANG_WAYPOINT_REMOVED); + return true; + } // del + + if(show == "move" && target) + { + PSendSysMessage("DEBUG: wp move, GUID: %u", lowguid); + + Player *chr = m_session->GetPlayer(); + Map *map = chr->GetMap(); + { + // Get the creature for which we read the waypoint + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); + + // wpCreature + Creature* wpCreature = NULL; + // What to do: + // Move the visual spawnpoint + // Respawn the owner of the waypoints + if( wpGuid != 0 ) + { + wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); + wpCreature->DeleteFromDB(); + wpCreature->CleanupsBeforeDelete(); + wpCreature->AddObjectToRemoveList(); + // re-create + Creature* wpCreature2 = new Creature; + if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, VISUAL_WAYPOINT, 0)) + { + PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); + delete wpCreature2; + return false; + } + + wpCreature2->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()); + + if(!wpCreature2->IsPositionValid()) + { + sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature2->GetGUIDLow(),wpCreature2->GetEntry(),wpCreature2->GetPositionX(),wpCreature2->GetPositionY()); + delete wpCreature2; + return false; + } + + wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map); + map->Add(wpCreature2); + //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2); + } + + WaypointMgr.SetNodePosition(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ()); + + if(npcCreature) + { + npcCreature->GetMotionMaster()->Initialize(); + if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn + { + npcCreature->setDeathState(JUST_DIED); + npcCreature->Respawn(); + } + } + PSendSysMessage(LANG_WAYPOINT_CHANGED); + } + return true; + } // move + + // Create creature - npc that has the waypoint + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + WaypointMgr.SetNodeText(lowguid, point, show_str, arg_str); + + Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); + if(npcCreature) + { + npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); + npcCreature->GetMotionMaster()->Initialize(); + if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn + { + npcCreature->setDeathState(JUST_DIED); + npcCreature->Respawn(); + } + } + PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str); + + return true; +} + +/** + * .wp show info | on | off + * + * info -> User has selected a visual waypoint before + * + * info -> User did not select a visual waypoint and + * provided the GUID of the NPC and the number of + * the waypoint. + * + * on -> User has selected an NPC; all visual waypoints for this + * NPC are added to the world + * + * on -> User did not select an NPC - instead the GUID of the + * NPC is provided. All visual waypoints for this NPC + * are added from the world. + * + * off -> User has selected an NPC; all visual waypoints for this + * NPC are removed from the world. + * + * on -> User did not select an NPC - instead the GUID of the + * NPC is provided. All visual waypoints for this NPC + * are removed from the world. + * + * + */ +bool ChatHandler::HandleWpShowCommand(const char* args) +{ + sLog.outDebug("DEBUG: HandleWpShowCommand"); + + if(!*args) + return false; + + // first arg: on, off, first, last + char* show_str = strtok((char*)args, " "); + if (!show_str) + { + return false; + } + // second arg: GUID (optional, if a creature is selected) + char* guid_str = strtok((char*)NULL, " "); + sLog.outDebug("DEBUG: HandleWpShowCommand: show_str: %s guid_str: %s", show_str, guid_str); + //if (!guid_str) { + // return false; + //} + + // Did user provide a GUID + // or did the user select a creature? + // -> variable lowguid is filled with the GUID + Creature* target = getSelectedCreature(); + // Did player provide a GUID? + if (!guid_str) + { + sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str"); + // No GUID provided + // -> Player must have selected a creature + + if(!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + } + else + { + sLog.outDebug("DEBUG: HandleWpShowCommand: GUID provided"); + // GUID provided + // Warn if player also selected a creature + // -> Creature selection is ignored <- + if(target) + { + SendSysMessage(LANG_WAYPOINT_CREATSELECTED); + } + + uint32 lowguid = atoi((char*)guid_str); + + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); + + if(!target) + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + } + + uint32 lowguid = target->GetDBTableGUIDLow(); + + std::string show = show_str; + uint32 Maxpoint; + + sLog.outDebug("DEBUG: HandleWpShowCommand: lowguid: %u", lowguid); + + sLog.outDebug("DEBUG: HandleWpShowCommand: Habe creature: %ld", target ); + + sLog.outDebug("DEBUG: HandleWpShowCommand: wpshow - show: %s", show_str); + //PSendSysMessage("wpshow - show: %s", show); + + // Show info for the selected waypoint + if(show == "info") + { + PSendSysMessage("DEBUG: wp info, GUID: %u", lowguid); + + // Check if the user did specify a visual waypoint + if( target->GetEntry() != VISUAL_WAYPOINT ) + { + PSendSysMessage(LANG_WAYPOINT_VP_SELECT); + SetSentErrorMessage(true); + return false; + } + + //PSendSysMessage("wp on, GUID: %u", lowguid); + + //pCreature->GetPositionX(); + + QueryResult *result = + WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, text1, text2, text3, text4, text5, model1, model2 FROM creature_movement WHERE wpguid = %u", + target->GetGUID() ); + if(!result) + { + // Since we compare float values, we have to deal with + // some difficulties. + // Here we search for all waypoints that only differ in one from 1 thousand + // (0.001) - There is no other way to compare C++ floats with mySQL floats + // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html + const char* maxDIFF = "0.01"; + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUID()); + + result = WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, text1, text2, text3, text4, text5, model1, model2 FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )", + target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF); + if(!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid); + SetSentErrorMessage(true); + return false; + } + } + do + { + Field *fields = result->Fetch(); + uint32 creGUID = fields[0].GetUInt32(); + uint32 point = fields[1].GetUInt32(); + int waittime = fields[2].GetUInt32(); + uint32 emote = fields[3].GetUInt32(); + uint32 spell = fields[4].GetUInt32(); + const char * text1 = fields[5].GetString(); + const char * text2 = fields[6].GetString(); + const char * text3 = fields[7].GetString(); + const char * text4 = fields[8].GetString(); + const char * text5 = fields[9].GetString(); + uint32 model1 = fields[10].GetUInt32(); + uint32 model2 = fields[11].GetUInt32(); + + // Get the creature for which we read the waypoint + Creature* wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(creGUID,VISUAL_WAYPOINT,HIGHGUID_UNIT)); + + PSendSysMessage(LANG_WAYPOINT_INFO_TITLE, point, (wpCreature ? wpCreature->GetName() : ""), creGUID); + PSendSysMessage(LANG_WAYPOINT_INFO_WAITTIME, waittime); + PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 1, model1); + PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 2, model2); + PSendSysMessage(LANG_WAYPOINT_INFO_EMOTE, emote); + PSendSysMessage(LANG_WAYPOINT_INFO_SPELL, spell); + PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 1, text1); + PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 2, text2); + PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 3, text3); + PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 4, text4); + PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 5, text5); + + }while( result->NextRow() ); + // Cleanup memory + delete result; + return true; + } + + if(show == "on") + { + PSendSysMessage("DEBUG: wp on, GUID: %u", lowguid); + + QueryResult *result = WorldDatabase.PQuery( "SELECT point, position_x,position_y,position_z FROM creature_movement WHERE id = '%u'",lowguid); + if(!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + // Delete all visuals for this NPC + QueryResult *result2 = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' and wpguid <> 0", lowguid); + if(result2) + { + bool hasError = false; + do + { + Field *fields = result2->Fetch(); + uint32 wpguid = fields[0].GetUInt32(); + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); + + if(!pCreature) + { + PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid); + hasError = true; + WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid); + } + else + { + pCreature->DeleteFromDB(); + pCreature->CleanupsBeforeDelete(); + pCreature->AddObjectToRemoveList(); + } + + }while( result2->NextRow() ); + delete result2; + if( hasError ) + { + PSendSysMessage(LANG_WAYPOINT_TOOFAR1); + PSendSysMessage(LANG_WAYPOINT_TOOFAR2); + PSendSysMessage(LANG_WAYPOINT_TOOFAR3); + } + } + + do + { + Field *fields = result->Fetch(); + uint32 point = fields[0].GetUInt32(); + float x = fields[1].GetFloat(); + float y = fields[2].GetFloat(); + float z = fields[3].GetFloat(); + + uint32 id = VISUAL_WAYPOINT; + + Player *chr = m_session->GetPlayer(); + Map *map = chr->GetMap(); + float o = chr->GetOrientation(); + + Creature* wpCreature = new Creature; + if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0)) + { + PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); + delete wpCreature; + delete result; + return false; + } + + wpCreature->Relocate(x, y, z, o); + + if(!wpCreature->IsPositionValid()) + { + sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY()); + delete wpCreature; + delete result; + return false; + } + + wpCreature->SetVisibility(VISIBILITY_OFF); + sLog.outDebug("DEBUG: UPDATE creature_movement SET wpguid = '%u"); + // set "wpguid" column to the visual waypoint + WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), lowguid, point); + + wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map); + map->Add(wpCreature); + //MapManager::Instance().GetMap(wpCreature->GetMapId())->Add(wpCreature); + }while( result->NextRow() ); + + // Cleanup memory + delete result; + return true; + } + + if(show == "first") + { + PSendSysMessage("DEBUG: wp first, GUID: %u", lowguid); + + QueryResult *result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point='1' AND id = '%u'",lowguid); + if(!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + Field *fields = result->Fetch(); + float x = fields[0].GetFloat(); + float y = fields[1].GetFloat(); + float z = fields[2].GetFloat(); + uint32 id = VISUAL_WAYPOINT; + + Player *chr = m_session->GetPlayer(); + float o = chr->GetOrientation(); + Map *map = chr->GetMap(); + + Creature* pCreature = new Creature; + if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, id, 0)) + { + PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); + delete pCreature; + delete result; + return false; + } + + pCreature->Relocate(x, y, z, o); + + if(!pCreature->IsPositionValid()) + { + sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); + delete pCreature; + delete result; + return false; + } + + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); + pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); + map->Add(pCreature); + //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint"); + + // Cleanup memory + delete result; + return true; + } + + if(show == "last") + { + PSendSysMessage("DEBUG: wp last, GUID: %u", lowguid); + + QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid); + if( result ) + { + Maxpoint = (*result)[0].GetUInt32(); + + delete result; + } + else + Maxpoint = 0; + + result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point ='%u' AND id = '%u'",Maxpoint, lowguid); + if(!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, lowguid); + SetSentErrorMessage(true); + return false; + } + Field *fields = result->Fetch(); + float x = fields[0].GetFloat(); + float y = fields[1].GetFloat(); + float z = fields[2].GetFloat(); + uint32 id = VISUAL_WAYPOINT; + + Player *chr = m_session->GetPlayer(); + float o = chr->GetOrientation(); + Map *map = chr->GetMap(); + + Creature* pCreature = new Creature; + if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0)) + { + PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); + delete pCreature; + delete result; + return false; + } + + pCreature->Relocate(x, y, z, o); + + if(!pCreature->IsPositionValid()) + { + sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); + delete pCreature; + delete result; + return false; + } + + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); + pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); + map->Add(pCreature); + //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint"); + // Cleanup memory + delete result; + return true; + } + + if(show == "off") + { + QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%d'", VISUAL_WAYPOINT); + if(!result) + { + SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + bool hasError = false; + do + { + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); + + //Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if(!pCreature) + { + PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid); + hasError = true; + WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid); + } + else + { + pCreature->DeleteFromDB(); + pCreature->CleanupsBeforeDelete(); + pCreature->AddObjectToRemoveList(); + } + }while(result->NextRow()); + // set "wpguid" column to "empty" - no visual waypoint spawned + WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0'"); + + if( hasError ) + { + PSendSysMessage(LANG_WAYPOINT_TOOFAR1); + PSendSysMessage(LANG_WAYPOINT_TOOFAR2); + PSendSysMessage(LANG_WAYPOINT_TOOFAR3); + } + + SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED); + // Cleanup memory + delete result; + + return true; + } + + PSendSysMessage("DEBUG: wpshow - no valid command found"); + + return true; +} // HandleWpShowCommand + +bool ChatHandler::HandleWpExportCommand(const char *args) +{ + if(!*args) + return false; + + // Next arg is: + + // Did user provide a GUID + // or did the user select a creature? + // -> variable lowguid is filled with the GUID of the NPC + uint32 lowguid = 0; + Creature* target = getSelectedCreature(); + char* arg_str = NULL; + if (target) + { + if (target->GetEntry() != VISUAL_WAYPOINT) + lowguid = target->GetGUIDLow(); + else + { + QueryResult *result = WorldDatabase.PQuery( "SELECT id FROM creature_movement WHERE wpguid = %u LIMIT 1", target->GetGUIDLow() ); + if (!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow()); + return true; + } + Field *fields = result->Fetch(); + lowguid = fields[0].GetUInt32();; + delete result; + } + + arg_str = strtok((char*)args, " "); + } + else + { + // user provided + char* guid_str = strtok((char*)args, " "); + if( !guid_str ) + { + SendSysMessage(LANG_WAYPOINT_NOGUID); + return false; + } + lowguid = atoi((char*)guid_str); + + arg_str = strtok((char*)NULL, " "); + } + + if( !arg_str) + { + PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, "export"); + return false; + } + + PSendSysMessage("DEBUG: wp export, GUID: %u", lowguid); + + QueryResult *result = WorldDatabase.PQuery( + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + "SELECT point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, text1, text2, text3, text4, text5, id FROM creature_movement WHERE id = '%u' ORDER BY point", lowguid ); + + if (!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTHINGTOEXPORT); + SetSentErrorMessage(true); + return false; + } + + std::ofstream outfile; + outfile.open (arg_str); + + do + { + Field *fields = result->Fetch(); + + outfile << "INSERT INTO creature_movement "; + outfile << "( id, point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, text1, text2, text3, text4, text5 ) VALUES "; + + outfile << "( "; + outfile << fields[15].GetUInt32(); // id + outfile << ", "; + outfile << fields[0].GetUInt32(); // point + outfile << ", "; + outfile << fields[1].GetFloat(); // position_x + outfile << ", "; + outfile << fields[2].GetFloat(); // position_y + outfile << ", "; + outfile << fields[3].GetUInt32(); // position_z + outfile << ", "; + outfile << fields[4].GetUInt32(); // orientation + outfile << ", "; + outfile << fields[5].GetUInt32(); // model1 + outfile << ", "; + outfile << fields[6].GetUInt32(); // model2 + outfile << ", "; + outfile << fields[7].GetUInt16(); // waittime + outfile << ", "; + outfile << fields[8].GetUInt32(); // emote + outfile << ", "; + outfile << fields[9].GetUInt32(); // spell + outfile << ", "; + const char *tmpChar = fields[10].GetString(); + if( !tmpChar ) + { + outfile << "NULL"; // text1 + } + else + { + outfile << "'"; + outfile << tmpChar; // text1 + outfile << "'"; + } + outfile << ", "; + tmpChar = fields[11].GetString(); + if( !tmpChar ) + { + outfile << "NULL"; // text2 + } + else + { + outfile << "'"; + outfile << tmpChar; // text2 + outfile << "'"; + } + outfile << ", "; + tmpChar = fields[12].GetString(); + if( !tmpChar ) + { + outfile << "NULL"; // text3 + } + else + { + outfile << "'"; + outfile << tmpChar; // text3 + outfile << "'"; + } + outfile << ", "; + tmpChar = fields[13].GetString(); + if( !tmpChar ) + { + outfile << "NULL"; // text4 + } + else + { + outfile << "'"; + outfile << tmpChar; // text4 + outfile << "'"; + } + outfile << ", "; + tmpChar = fields[14].GetString(); + if( !tmpChar ) + { + outfile << "NULL"; // text5 + } + else + { + outfile << "'"; + outfile << tmpChar; // text5 + outfile << "'"; + } + outfile << ");\n "; + + } while( result->NextRow() ); + delete result; + + PSendSysMessage(LANG_WAYPOINT_EXPORTED); + outfile.close(); + + return true; +} + +bool ChatHandler::HandleWpImportCommand(const char *args) +{ + if(!*args) + return false; + + char* arg_str = strtok((char*)args, " "); + if (!arg_str) + return false; + + std::string line; + std::ifstream infile (arg_str); + if (infile.is_open()) + { + while (! infile.eof() ) + { + getline (infile,line); + //cout << line << endl; + QueryResult *result = WorldDatabase.PQuery(line.c_str()); + delete result; + } + infile.close(); + } + PSendSysMessage(LANG_WAYPOINT_IMPORTED); + + return true; +} + +//rename characters +bool ChatHandler::HandleRenameCommand(const char* args) +{ + Player* target = NULL; + uint64 targetGUID = 0; + std::string oldname; + + char* px = strtok((char*)args, " "); + + if(px) + { + oldname = px; + + if(!normalizePlayerName(oldname)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + target = objmgr.GetPlayer(oldname.c_str()); + + if (!target) + targetGUID = objmgr.GetPlayerGUIDByName(oldname); + } + + if(!target && !targetGUID) + { + target = getSelectedPlayer(); + } + + if(!target && !targetGUID) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if(target) + { + PSendSysMessage(LANG_RENAME_PLAYER, target->GetName()); + target->SetAtLoginFlag(AT_LOGIN_RENAME); + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", target->GetGUIDLow()); + } + else + { + PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldname.c_str(), GUID_LOPART(targetGUID)); + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", GUID_LOPART(targetGUID)); + } + + return true; +} + +//spawn go +bool ChatHandler::HandleGameObjectCommand(const char* args) +{ + if (!*args) + return false; + + char* pParam1 = strtok((char*)args, " "); + if (!pParam1) + return false; + + uint32 id = atoi((char*)pParam1); + if(!id) + return false; + + char* spawntimeSecs = strtok(NULL, " "); + + const GameObjectInfo *goI = objmgr.GetGameObjectInfo(id); + + if (!goI) + { + PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); + SetSentErrorMessage(true); + return false; + } + + Player *chr = m_session->GetPlayer(); + float x = float(chr->GetPositionX()); + float y = float(chr->GetPositionY()); + float z = float(chr->GetPositionZ()); + float o = float(chr->GetOrientation()); + Map *map = chr->GetMap(); + + float rot2 = sin(o/2); + float rot3 = cos(o/2); + + GameObject* pGameObj = new GameObject; + uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT); + + if(!pGameObj->Create(db_lowGUID, goI->id, map, x, y, z, o, 0, 0, rot2, rot3, 0, 1)) + { + delete pGameObj; + return false; + } + + if( spawntimeSecs ) + { + uint32 value = atoi((char*)spawntimeSecs); + pGameObj->SetRespawnTime(value); + //sLog.outDebug("*** spawntimeSecs: %d", value); + } + + // fill the gameobject data and save to the db + pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); + + // this will generate a new guid if the object is in an instance + if(!pGameObj->LoadFromDB(db_lowGUID, map)) + { + delete pGameObj; + return false; + } + + sLog.outDebug(GetMangosString(LANG_GAMEOBJECT_CURRENT), goI->name, db_lowGUID, x, y, z, o); + + map->Add(pGameObj); + + // TODO: is it really necessary to add both the real and DB table guid here ? + objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID)); + + PSendSysMessage(LANG_GAMEOBJECT_ADD,id,goI->name,db_lowGUID,x,y,z); + return true; +} + +//show animation +bool ChatHandler::HandleAnimCommand(const char* args) +{ + if (!*args) + return false; + + uint32 anim_id = atoi((char*)args); + m_session->GetPlayer()->HandleEmoteCommand(anim_id); + return true; +} + +//change standstate +bool ChatHandler::HandleStandStateCommand(const char* args) +{ + if (!*args) + return false; + + uint32 anim_id = atoi((char*)args); + m_session->GetPlayer( )->SetUInt32Value( UNIT_NPC_EMOTESTATE , anim_id ); + + return true; +} + +bool ChatHandler::HandleAddHonorCommand(const char* args) +{ + if (!*args) + return false; + + Player *target = getSelectedPlayer(); + if(!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint32 amount = (uint32)atoi(args); + target->RewardHonor(NULL, 1, amount); + return true; +} + +bool ChatHandler::HandleHonorAddKillCommand(const char* /*args*/) +{ + Unit *target = getSelectedUnit(); + if(!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + m_session->GetPlayer()->RewardHonor(target, 1); + return true; +} + +bool ChatHandler::HandleUpdateHonorFieldsCommand(const char* /*args*/) +{ + Player *target = getSelectedPlayer(); + if(!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + target->UpdateHonorFields(); + return true; +} + +bool ChatHandler::HandleLookupEventCommand(const char* args) +{ + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + uint32 counter = 0; + + GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + + for(uint32 id = 0; id < events.size(); ++id ) + { + GameEventData const& eventData = events[id]; + + std::string descr = eventData.description; + if(descr.empty()) + continue; + + if (Utf8FitTo(descr, wnamepart)) + { + char const* active = activeEvents.find(id) != activeEvents.end() ? GetMangosString(LANG_ACTIVE) : ""; + PSendSysMessage(LANG_EVENT_ENTRY_LIST,id,id,descr.c_str(),active ); + ++counter; + } + } + + if (counter==0) + SendSysMessage(LANG_NOEVENTFOUND); + + return true; +} + +bool ChatHandler::HandleEventActiveListCommand(const char* args) +{ + uint32 counter = 0; + + GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + + char const* active = GetMangosString(LANG_ACTIVE); + + for(GameEvent::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr ) + { + uint32 event_id = *itr; + GameEventData const& eventData = events[event_id]; + + PSendSysMessage(LANG_EVENT_ENTRY_LIST,event_id,event_id,eventData.description.c_str(),active ); + ++counter; + } + + if (counter==0) + SendSysMessage(LANG_NOEVENTFOUND); + + return true; +} + +bool ChatHandler::HandleEventInfoCommand(const char* args) +{ + if(!*args) + return false; + + // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameevent"); + if(!cId) + return false; + + uint32 event_id = atoi(cId); + + GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + + if(event_id >=events.size()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventData const& eventData = events[event_id]; + if(!eventData.isValid()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + bool active = activeEvents.find(event_id) != activeEvents.end(); + char const* activeStr = active ? GetMangosString(LANG_ACTIVE) : ""; + + std::string startTimeStr = TimeToTimestampStr(eventData.start); + std::string endTimeStr = TimeToTimestampStr(eventData.end); + + uint32 delay = gameeventmgr.NextCheck(event_id); + time_t nextTime = time(NULL)+delay; + std::string nextStr = nextTime >= eventData.start && nextTime < eventData.end ? TimeToTimestampStr(time(NULL)+delay) : "-"; + + std::string occurenceStr = secsToTimeString(eventData.occurence * MINUTE); + std::string lengthStr = secsToTimeString(eventData.length * MINUTE); + + PSendSysMessage(LANG_EVENT_INFO,event_id,eventData.description.c_str(),activeStr, + startTimeStr.c_str(),endTimeStr.c_str(),occurenceStr.c_str(),lengthStr.c_str(), + nextStr.c_str()); + return true; +} + +bool ChatHandler::HandleEventStartCommand(const char* args) +{ + if(!*args) + return false; + + // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameevent"); + if(!cId) + return false; + + int32 event_id = atoi(cId); + + GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + + if(event_id < 1 || event_id >=events.size()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventData const& eventData = events[event_id]; + if(!eventData.isValid()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + if(activeEvents.find(event_id) != activeEvents.end()) + { + PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE,event_id); + SetSentErrorMessage(true); + return false; + } + + gameeventmgr.StartEvent(event_id,true); + return true; +} + +bool ChatHandler::HandleEventStopCommand(const char* args) +{ + if(!*args) + return false; + + // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameevent"); + if(!cId) + return false; + + int32 event_id = atoi(cId); + + GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + + if(event_id < 1 || event_id >=events.size()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventData const& eventData = events[event_id]; + if(!eventData.isValid()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + + if(activeEvents.find(event_id) == activeEvents.end()) + { + PSendSysMessage(LANG_EVENT_NOT_ACTIVE,event_id); + SetSentErrorMessage(true); + return false; + } + + gameeventmgr.StopEvent(event_id,true); + return true; +} + +bool ChatHandler::HandleCombatStopCommand(const char* args) +{ + Player *player; + + if(*args) + { + std::string playername = args; + + if(!normalizePlayerName(playername)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + player = objmgr.GetPlayer(playername.c_str()); + + if(!player) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + } + else + { + player = getSelectedPlayer(); + + if (!player) + player = m_session->GetPlayer(); + } + + player->CombatStop(); + player->getHostilRefManager().deleteReferences(); + return true; +} + +bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/) +{ + uint32 classmask = m_session->GetPlayer()->getClassMask(); + + for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i) + { + SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i); + if( !skillInfo ) + continue; + + if( skillInfo->categoryId == SKILL_CATEGORY_PROFESSION || skillInfo->categoryId == SKILL_CATEGORY_SECONDARY ) + { + for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) + { + SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j); + if( !skillLine ) + continue; + + // skip racial skills + if( skillLine->racemask != 0 ) + continue; + + // skip wrong class skills + if( skillLine->classmask && (skillLine->classmask & classmask) == 0) + continue; + + if( skillLine->skillId != i || skillLine->forward_spellid ) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId); + if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) + continue; + + m_session->GetPlayer()->learnSpell(skillLine->spellId); + } + } + } + + SendSysMessage(LANG_COMMAND_LEARN_ALL_CRAFT); + return true; +} + +bool ChatHandler::HandleLearnAllRecipesCommand(const char* args) +{ + // Learns all recipes of specified profession and sets skill to max + // Example: .learn all_recipes enchanting + + Player* target = getSelectedPlayer(); + if( !target ) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + return false; + } + + if(!*args) + return false; + + std::wstring wnamepart; + + if(!Utf8toWStr(args,wnamepart)) + return false; + + uint32 counter = 0; // Counter for figure out that we found smth. + + // converting string that we try to find to lower case + wstrToLower( wnamepart ); + + uint32 classmask = m_session->GetPlayer()->getClassMask(); + + for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i) + { + SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i); + if( !skillInfo ) + continue; + + if( skillInfo->categoryId != SKILL_CATEGORY_PROFESSION && + skillInfo->categoryId != SKILL_CATEGORY_SECONDARY ) + continue; + + int loc = m_session->GetSessionDbcLocale(); + std::string name = skillInfo->name[loc]; + + if(Utf8FitTo(name, wnamepart)) + { + for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) + { + SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j); + if( !skillLine ) + continue; + + if( skillLine->skillId != i || skillLine->forward_spellid ) + continue; + + // skip racial skills + if( skillLine->racemask != 0 ) + continue; + + // skip wrong class skills + if( skillLine->classmask && (skillLine->classmask & classmask) == 0) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId); + if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) + continue; + + if( !target->HasSpell(spellInfo->Id) ) + m_session->GetPlayer()->learnSpell(skillLine->spellId); + } + + uint16 maxLevel = target->GetPureMaxSkillValue(skillInfo->id); + target->SetSkill(skillInfo->id, maxLevel, maxLevel); + PSendSysMessage(LANG_COMMAND_LEARN_ALL_RECIPES, name.c_str()); + return true; + } + } + + return false; +} + +bool ChatHandler::HandleLookupPlayerIpCommand(const char* args) +{ + + if(!*args) + return false; + + std::string ip = strtok((char*)args, " "); + char* limit_str = strtok(NULL, " "); + int32 limit = limit_str ? atoi(limit_str) : -1; + + loginDatabase.escape_string(ip); + + QueryResult* result = loginDatabase.PQuery("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str()); + + return LookupPlayerSearchCommand(result,limit); +} + +bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args) +{ + if(!*args) + return false; + + std::string account = strtok((char*)args, " "); + char* limit_str = strtok(NULL, " "); + int32 limit = limit_str ? atoi(limit_str) : -1; + + if(!AccountMgr::normilizeString(account)) + return false; + + loginDatabase.escape_string(account); + + QueryResult* result = loginDatabase.PQuery("SELECT id,username FROM account WHERE username = '%s'", account.c_str()); + + return LookupPlayerSearchCommand(result,limit); +} + +bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args) +{ + + if(!*args) + return false; + + std::string email = strtok((char*)args, " "); + char* limit_str = strtok(NULL, " "); + int32 limit = limit_str ? atoi(limit_str) : -1; + + loginDatabase.escape_string(email); + + QueryResult* result = loginDatabase.PQuery("SELECT id,username FROM account WHERE email = '%s'", email.c_str()); + + return LookupPlayerSearchCommand(result,limit); +} + +bool ChatHandler::LookupPlayerSearchCommand(QueryResult* result, int32 limit) +{ + if(!result) + { + PSendSysMessage(LANG_NO_PLAYERS_FOUND); + SetSentErrorMessage(true); + return false; + } + + int i =0; + do + { + Field* fields = result->Fetch(); + uint32 acc_id = fields[0].GetUInt32(); + std::string acc_name = fields[1].GetCppString(); + + QueryResult* chars = CharacterDatabase.PQuery("SELECT guid,name FROM characters WHERE account = '%u'", acc_id); + if(chars) + { + PSendSysMessage(LANG_LOOKUP_PLAYER_ACCOUNT,acc_name.c_str(),acc_id); + + uint64 guid = 0; + std::string name; + + do + { + Field* charfields = chars->Fetch(); + guid = charfields[0].GetUInt64(); + name = charfields[1].GetCppString(); + + PSendSysMessage(LANG_LOOKUP_PLAYER_CHARACTER,name.c_str(),guid); + ++i; + + } while( chars->NextRow() && ( limit == -1 || i < limit ) ); + + delete chars; + } + } while(result->NextRow()); + + delete result; + + return true; +} diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 93f39229b7d..5984dbbfe21 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -1,5424 +1,5459 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "PlayerDump.h" -#include "SpellMgr.h" -#include "Player.h" -#include "Opcodes.h" -#include "GameObject.h" -#include "Chat.h" -#include "Log.h" -#include "Guild.h" -#include "ObjectAccessor.h" -#include "MapManager.h" -#include "SpellAuras.h" -#include "ScriptCalls.h" -#include "Language.h" -#include "GridNotifiersImpl.h" -#include "CellImpl.h" -#include "Weather.h" -#include "PointMovementGenerator.h" -#include "TargetedMovementGenerator.h" -#include "SkillDiscovery.h" -#include "SkillExtraItems.h" -#include "SystemConfig.h" -#include "Config/ConfigEnv.h" -#include "Util.h" -#include "ItemEnchantmentMgr.h" -#include "InstanceSaveMgr.h" -#include "InstanceData.h" - -//reload commands -bool ChatHandler::HandleReloadCommand(const char* arg) -{ - // this is error catcher for wrong table name in .reload commands - PSendSysMessage("Db table with name starting from '%s' not found and can't be reloaded.",arg); - SetSentErrorMessage(true); - return false; -} - -bool ChatHandler::HandleReloadAllCommand(const char*) -{ - HandleReloadAreaTriggerTeleportCommand(""); - //HandleReloadAreaTriggerTavernCommand(""); -- reloaded in HandleReloadAreaTriggerTavernCommand - //HandleReloadQuestAreaTriggersCommand(""); -- reloaded in HandleReloadAllQuestCommand - HandleReloadSkillFishingBaseLevelCommand(""); - - HandleReloadAllLootCommand(""); - HandleReloadAllQuestCommand(""); - HandleReloadAllSpellCommand(""); - HandleReloadAllItemCommand(""); - - HandleReloadCommandCommand(""); - HandleReloadReservedNameCommand(""); - HandleReloadMangosStringCommand(""); - return true; -} - -bool ChatHandler::HandleReloadAllAreaCommand(const char*) -{ - HandleReloadAreaTriggerTeleportCommand(""); - //HandleReloadAreaTriggerTavernCommand(""); -- reloaded in HandleReloadAreaTriggerTavernCommand - return true; -} - -bool ChatHandler::HandleReloadAllQuestCommand(const char* /*args*/) -{ - HandleReloadQuestAreaTriggersCommand("a"); - HandleReloadQuestTemplateCommand("a"); - - sLog.outString( "Re-Loading Quests Relations..." ); - objmgr.LoadQuestRelations(); - SendGlobalSysMessage("DB tables `*_questrelation` and `*_involvedrelation` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAllLootCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables..." ); - LoadLootTables(); - SendGlobalSysMessage("DB tables `*_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAllScriptsCommand(const char*) -{ - if(sWorld.IsScriptScheduled()) - { - PSendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - sLog.outString( "Re-Loading Scripts..." ); - HandleReloadGameObjectScriptsCommand("a"); - HandleReloadEventScriptsCommand("a"); - HandleReloadQuestEndScriptsCommand("a"); - HandleReloadQuestStartScriptsCommand("a"); - HandleReloadSpellScriptsCommand("a"); - SendGlobalSysMessage("DB tables `*_scripts` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAllSpellCommand(const char*) -{ - HandleReloadSkillDiscoveryTemplateCommand("a"); - HandleReloadSkillExtraItemTemplateCommand("a"); - HandleReloadSpellAffectCommand("a"); - HandleReloadSpellChainCommand("a"); - HandleReloadSpellElixirCommand("a"); - HandleReloadSpellLearnSpellCommand("a"); - HandleReloadSpellProcEventCommand("a"); - HandleReloadSpellScriptTargetCommand("a"); - HandleReloadSpellTargetPositionCommand("a"); - HandleReloadSpellThreatsCommand("a"); - HandleReloadSpellPetAurasCommand("a"); - return true; -} - -bool ChatHandler::HandleReloadAllItemCommand(const char*) -{ - HandleReloadPageTextsCommand("a"); - HandleReloadItemEnchantementsCommand("a"); - return true; -} - -bool ChatHandler::HandleReloadConfigCommand(const char* arg) -{ - sLog.outString( "Re-Loading config settings..." ); - sWorld.LoadConfigSettings(true); - SendGlobalSysMessage("World config settings reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAreaTriggerTavernCommand(const char*) -{ - sLog.outString( "Re-Loading Tavern Area Triggers..." ); - objmgr.LoadTavernAreaTriggers(); - SendGlobalSysMessage("DB table `areatrigger_tavern` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAreaTriggerTeleportCommand(const char*) -{ - sLog.outString( "Re-Loading AreaTrigger teleport definitions..." ); - objmgr.LoadAreaTriggerTeleports(); - SendGlobalSysMessage("DB table `areatrigger_teleport` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadCommandCommand(const char*) -{ - load_command_table = true; - SendGlobalSysMessage("DB table `command` will be reloaded at next chat command use."); - return true; -} - -bool ChatHandler::HandleReloadCreatureQuestRelationsCommand(const char*) -{ - sLog.outString( "Loading Quests Relations... (`creature_questrelation`)" ); - objmgr.LoadCreatureQuestRelations(); - SendGlobalSysMessage("DB table `creature_questrelation` (creature quest givers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadCreatureQuestInvRelationsCommand(const char*) -{ - sLog.outString( "Loading Quests Relations... (`creature_involvedrelation`)" ); - objmgr.LoadCreatureInvolvedRelations(); - SendGlobalSysMessage("DB table `creature_involvedrelation` (creature quest takers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadGOQuestRelationsCommand(const char*) -{ - sLog.outString( "Loading Quests Relations... (`gameobject_questrelation`)" ); - objmgr.LoadGameobjectQuestRelations(); - SendGlobalSysMessage("DB table `gameobject_questrelation` (gameobject quest givers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadGOQuestInvRelationsCommand(const char*) -{ - sLog.outString( "Loading Quests Relations... (`gameobject_involvedrelation`)" ); - objmgr.LoadGameobjectInvolvedRelations(); - SendGlobalSysMessage("DB table `gameobject_involvedrelation` (gameobject quest takers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadQuestAreaTriggersCommand(const char*) -{ - sLog.outString( "Re-Loading Quest Area Triggers..." ); - objmgr.LoadQuestAreaTriggers(); - SendGlobalSysMessage("DB table `areatrigger_involvedrelation` (quest area triggers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadQuestTemplateCommand(const char*) -{ - sLog.outString( "Re-Loading Quest Templates..." ); - objmgr.LoadQuests(); - SendGlobalSysMessage("DB table `quest_template` (quest definitions) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesCreatureCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`creature_loot_template`)" ); - LoadLootTemplates_Creature(); - LootTemplates_Creature.CheckLootRefs(); - SendGlobalSysMessage("DB table `creature_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesDisenchantCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`disenchant_loot_template`)" ); - LoadLootTemplates_Disenchant(); - LootTemplates_Disenchant.CheckLootRefs(); - SendGlobalSysMessage("DB table `disenchant_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesFishingCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`fishing_loot_template`)" ); - LoadLootTemplates_Fishing(); - LootTemplates_Fishing.CheckLootRefs(); - SendGlobalSysMessage("DB table `fishing_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesGameobjectCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`gameobject_loot_template`)" ); - LoadLootTemplates_Gameobject(); - LootTemplates_Gameobject.CheckLootRefs(); - SendGlobalSysMessage("DB table `gameobject_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesItemCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`item_loot_template`)" ); - LoadLootTemplates_Item(); - LootTemplates_Item.CheckLootRefs(); - SendGlobalSysMessage("DB table `item_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesPickpocketingCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`pickpocketing_loot_template`)" ); - LoadLootTemplates_Pickpocketing(); - LootTemplates_Pickpocketing.CheckLootRefs(); - SendGlobalSysMessage("DB table `pickpocketing_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesProspectingCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`prospecting_loot_template`)" ); - LoadLootTemplates_Prospecting(); - LootTemplates_Prospecting.CheckLootRefs(); - SendGlobalSysMessage("DB table `prospecting_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesQuestMailCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`quest_mail_loot_template`)" ); - LoadLootTemplates_QuestMail(); - LootTemplates_QuestMail.CheckLootRefs(); - SendGlobalSysMessage("DB table `quest_mail_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesReferenceCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`reference_loot_template`)" ); - LoadLootTemplates_Reference(); - SendGlobalSysMessage("DB table `reference_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesSkinningCommand(const char*) -{ - sLog.outString( "Re-Loading Loot Tables... (`skinning_loot_template`)" ); - LoadLootTemplates_Skinning(); - LootTemplates_Skinning.CheckLootRefs(); - SendGlobalSysMessage("DB table `skinning_loot_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadMangosStringCommand(const char*) -{ - sLog.outString( "Re-Loading mangos_string Table!" ); - objmgr.LoadMangosStrings(); - SendGlobalSysMessage("DB table `mangos_string` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadReservedNameCommand(const char*) -{ - sLog.outString( "Loading ReservedNames... (`reserved_name`)" ); - objmgr.LoadReservedPlayersNames(); - SendGlobalSysMessage("DB table `reserved_name` (player reserved names) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSkillDiscoveryTemplateCommand(const char* /*args*/) -{ - sLog.outString( "Re-Loading Skill Discovery Table..." ); - LoadSkillDiscoveryTable(); - SendGlobalSysMessage("DB table `skill_discovery_template` (recipes discovered at crafting) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSkillExtraItemTemplateCommand(const char* /*args*/) -{ - sLog.outString( "Re-Loading Skill Extra Item Table..." ); - LoadSkillExtraItemTable(); - SendGlobalSysMessage("DB table `skill_extra_item_template` (extra item creation when crafting) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSkillFishingBaseLevelCommand(const char* /*args*/) -{ - sLog.outString( "Re-Loading Skill Fishing base level requirements..." ); - objmgr.LoadFishingBaseSkillLevel(); - SendGlobalSysMessage("DB table `skill_fishing_base_level` (fishing base level for zone/subzone) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellAffectCommand(const char*) -{ - sLog.outString( "Re-Loading SpellAffect definitions..." ); - spellmgr.LoadSpellAffects(); - SendGlobalSysMessage("DB table `spell_affect` (spell mods apply requirements) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellChainCommand(const char*) -{ - sLog.outString( "Re-Loading Spell Chain Data... " ); - spellmgr.LoadSpellChains(); - SendGlobalSysMessage("DB table `spell_chain` (spell ranks) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellElixirCommand(const char*) -{ - sLog.outString( "Re-Loading Spell Elixir types..." ); - spellmgr.LoadSpellElixirs(); - SendGlobalSysMessage("DB table `spell_elixir` (spell exlixir types) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellLearnSpellCommand(const char*) -{ - sLog.outString( "Re-Loading Spell Learn Spells..." ); - spellmgr.LoadSpellLearnSpells(); - SendGlobalSysMessage("DB table `spell_learn_spell` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellProcEventCommand(const char*) -{ - sLog.outString( "Re-Loading Spell Proc Event conditions..." ); - spellmgr.LoadSpellProcEvents(); - SendGlobalSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellScriptTargetCommand(const char*) -{ - sLog.outString( "Re-Loading SpellsScriptTarget..." ); - spellmgr.LoadSpellScriptTarget(); - SendGlobalSysMessage("DB table `spell_script_target` (spell targets selection in case specific creature/GO requirements) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellTargetPositionCommand(const char*) -{ - sLog.outString( "Re-Loading Spell target coordinates..." ); - spellmgr.LoadSpellTargetPositions(); - SendGlobalSysMessage("DB table `spell_target_position` (destination coordinates for spell targets) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellThreatsCommand(const char*) -{ - sLog.outString( "Re-Loading Aggro Spells Definitions..."); - spellmgr.LoadSpellThreats(); - SendGlobalSysMessage("DB table `spell_threat` (spell aggro definitions) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellPetAurasCommand(const char*) -{ - sLog.outString( "Re-Loading Spell pet auras..."); - spellmgr.LoadSpellPetAuras(); - SendGlobalSysMessage("DB table `spell_pet_auras` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadPageTextsCommand(const char*) -{ - sLog.outString( "Re-Loading Page Texts..." ); - objmgr.LoadPageTexts(); - SendGlobalSysMessage("DB table `page_texts` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadItemEnchantementsCommand(const char*) -{ - sLog.outString( "Re-Loading Item Random Enchantments Table..." ); - LoadRandomEnchantmentsTable(); - SendGlobalSysMessage("DB table `item_enchantment_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadGameObjectScriptsCommand(const char* arg) -{ - if(sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if(*arg!='a') - sLog.outString( "Re-Loading Scripts from `gameobject_scripts`..."); - - objmgr.LoadGameObjectScripts(); - - if(*arg!='a') - SendGlobalSysMessage("DB table `gameobject_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadEventScriptsCommand(const char* arg) -{ - if(sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if(*arg!='a') - sLog.outString( "Re-Loading Scripts from `event_scripts`..."); - - objmgr.LoadEventScripts(); - - if(*arg!='a') - SendGlobalSysMessage("DB table `event_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadQuestEndScriptsCommand(const char* arg) -{ - if(sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if(*arg!='a') - sLog.outString( "Re-Loading Scripts from `quest_end_scripts`..."); - - objmgr.LoadQuestEndScripts(); - - if(*arg!='a') - SendGlobalSysMessage("DB table `quest_end_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadQuestStartScriptsCommand(const char* arg) -{ - if(sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if(*arg!='a') - sLog.outString( "Re-Loading Scripts from `quest_start_scripts`..."); - - objmgr.LoadQuestStartScripts(); - - if(*arg!='a') - SendGlobalSysMessage("DB table `quest_start_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadSpellScriptsCommand(const char* arg) -{ - if(sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if(*arg!='a') - sLog.outString( "Re-Loading Scripts from `spell_scripts`..."); - - objmgr.LoadSpellScripts(); - - if(*arg!='a') - SendGlobalSysMessage("DB table `spell_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadGameGraveyardZoneCommand(const char* /*arg*/) -{ - sLog.outString( "Re-Loading Graveyard-zone links..."); - - objmgr.LoadGraveyardZones(); - - SendGlobalSysMessage("DB table `game_graveyard_zone` reloaded."); - - return true; -} - -bool ChatHandler::HandleLoadScriptsCommand(const char* args) -{ - if(!LoadScriptingModule(args)) return true; - - sWorld.SendWorldText(LANG_SCRIPTS_RELOADED); - return true; -} - -bool ChatHandler::HandleSecurityCommand(const char* args) -{ - char* arg1 = strtok((char*)args, " "); - if( !arg1 ) - return false; - - char* arg2 = 0; - - std::string targetName; - uint32 targetAccountId = 0; - uint32 targetSecurity = 0; - - Player* targetPlayer = getSelectedPlayer(); - if(targetPlayer) - { - targetName = targetPlayer->GetName(); - targetAccountId = targetPlayer->GetSession()->GetAccountId(); - targetSecurity = targetPlayer->GetSession()->GetSecurity(); - arg2 = arg1; - } - else - { - targetName = arg1; - if(!normalizePlayerName(targetName)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - targetPlayer = ObjectAccessor::Instance().FindPlayerByName(targetName.c_str()); - if(targetPlayer) - { - targetAccountId = targetPlayer->GetSession()->GetAccountId(); - targetSecurity = targetPlayer->GetSession()->GetSecurity(); - } - else - { - uint64 targetGUID = objmgr.GetPlayerGUIDByName(targetName.c_str()); - if(!targetGUID) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - targetAccountId = objmgr.GetPlayerAccountIdByGUID(targetGUID); - targetSecurity = objmgr.GetSecurityByAccount(targetAccountId); - } - - arg2 = strtok(NULL, " "); - } - - int32 gm = (int32)atoi(arg2); - if ( gm < SEC_PLAYER || gm > SEC_ADMINISTRATOR ) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - // can set security level only for target with less security and to less security that we have - if(targetSecurity >= m_session->GetSecurity() || uint32(gm) >= m_session->GetSecurity() ) - { - SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); - SetSentErrorMessage(true); - return false; - } - - if(targetPlayer) - { - if( targetPlayer != m_session->GetPlayer() ) - ChatHandler(targetPlayer).PSendSysMessage(LANG_YOURS_SECURITY_CHANGED,m_session->GetPlayer()->GetName(), gm); - - targetPlayer->GetSession()->SetSecurity(gm); - } - - PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetName.c_str(), gm); - loginDatabase.PExecute("UPDATE account SET gmlevel = '%i' WHERE id = '%u'", gm, targetAccountId); - - return true; -} - -bool ChatHandler::HandleAllowMovementCommand(const char* /*args*/) -{ - if(sWorld.getAllowMovement()) - { - sWorld.SetAllowMovement(false); - SendSysMessage(LANG_CREATURE_MOVE_DISABLED); - } - else - { - sWorld.SetAllowMovement(true); - SendSysMessage(LANG_CREATURE_MOVE_ENABLED); - } - return true; -} - -bool ChatHandler::HandleMaxSkillCommand(const char* /*args*/) -{ - Player* SelectedPlayer = getSelectedPlayer(); - if(!SelectedPlayer) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // each skills that have max skill value dependent from level seted to current level max skill value - SelectedPlayer->UpdateSkillsToMaxSkillsForLevel(); - return true; -} - -bool ChatHandler::HandleSetSkillCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hskill:skill_id|h[name]|h|r - char* skill_p = extractKeyFromLink((char*)args,"Hskill"); - if(!skill_p) - return false; - - char *level_p = strtok (NULL, " "); - - if( !level_p) - return false; - - char *max_p = strtok (NULL, " "); - - int32 skill = atoi(skill_p); - - if (skill <= 0) - { - PSendSysMessage(LANG_INVALID_SKILL_ID, skill); - SetSentErrorMessage(true); - return false; - } - - int32 level = atol (level_p); - - Player * target = getSelectedPlayer(); - if(!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - SkillLineEntry const* sl = sSkillLineStore.LookupEntry(skill); - if(!sl) - { - PSendSysMessage(LANG_INVALID_SKILL_ID, skill); - SetSentErrorMessage(true); - return false; - } - - if(!target->GetSkillValue(skill)) - { - PSendSysMessage(LANG_SET_SKILL_ERROR, target->GetName(), skill, sl->name[0]); - SetSentErrorMessage(true); - return false; - } - - int32 max = max_p ? atol (max_p) : target->GetPureMaxSkillValue(skill); - - if( level <= 0 || level > max || max <= 0 ) - return false; - - target->SetSkill(skill, level, max); - PSendSysMessage(LANG_SET_SKILL, skill, sl->name[0], target->GetName(), level, max); - - return true; -} - -bool ChatHandler::HandleUnLearnCommand(const char* args) -{ - if (!*args) - return false; - - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - uint32 min_id = extractSpellIdFromLink((char*)args); - if(!min_id) - return false; - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - char* tail = strtok(NULL,""); - - uint32 max_id = extractSpellIdFromLink(tail); - - if (!max_id) - { - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - max_id = min_id+1; - } - else - { - if (max_id < min_id) - std::swap(min_id,max_id); - - max_id=max_id+1; - } - - Player* target = getSelectedPlayer(); - if(!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - for(uint32 spell=min_id;spellHasSpell(spell)) - target->removeSpell(spell); - else - SendSysMessage(LANG_FORGET_SPELL); - } - - return true; -} - -bool ChatHandler::HandleCooldownCommand(const char* args) -{ - Player* target = getSelectedPlayer(); - if(!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if (!*args) - { - target->RemoveAllSpellCooldown(); - PSendSysMessage(LANG_REMOVEALL_COOLDOWN, target->GetName()); - } - else - { - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell_id = extractSpellIdFromLink((char*)args); - if(!spell_id) - return false; - - if(!sSpellStore.LookupEntry(spell_id)) - { - PSendSysMessage(LANG_UNKNOWN_SPELL, target==m_session->GetPlayer() ? GetMangosString(LANG_YOU) : target->GetName()); - SetSentErrorMessage(true); - return false; - } - - WorldPacket data( SMSG_CLEAR_COOLDOWN, (4+8) ); - data << uint32(spell_id); - data << uint64(target->GetGUID()); - target->GetSession()->SendPacket(&data); - target->RemoveSpellCooldown(spell_id); - PSendSysMessage(LANG_REMOVE_COOLDOWN, spell_id, target==m_session->GetPlayer() ? GetMangosString(LANG_YOU) : target->GetName()); - } - return true; -} - -bool ChatHandler::HandleLearnAllCommand(const char* /*args*/) -{ - static const char *allSpellList[] = - { - "3365", - "6233", - "6247", - "6246", - "6477", - "6478", - "22810", - "8386", - "21651", - "21652", - "522", - "7266", - "8597", - "2479", - "22027", - "6603", - "5019", - "133", - "168", - "227", - "5009", - "9078", - "668", - "203", - "20599", - "20600", - "81", - "20597", - "20598", - "20864", - "1459", - "5504", - "587", - "5143", - "118", - "5505", - "597", - "604", - "1449", - "1460", - "2855", - "1008", - "475", - "5506", - "1463", - "12824", - "8437", - "990", - "5145", - "8450", - "1461", - "759", - "8494", - "8455", - "8438", - "6127", - "8416", - "6129", - "8451", - "8495", - "8439", - "3552", - "8417", - "10138", - "12825", - "10169", - "10156", - "10144", - "10191", - "10201", - "10211", - "10053", - "10173", - "10139", - "10145", - "10192", - "10170", - "10202", - "10054", - "10174", - "10193", - "12826", - "2136", - "143", - "145", - "2137", - "2120", - "3140", - "543", - "2138", - "2948", - "8400", - "2121", - "8444", - "8412", - "8457", - "8401", - "8422", - "8445", - "8402", - "8413", - "8458", - "8423", - "8446", - "10148", - "10197", - "10205", - "10149", - "10215", - "10223", - "10206", - "10199", - "10150", - "10216", - "10207", - "10225", - "10151", - "116", - "205", - "7300", - "122", - "837", - "10", - "7301", - "7322", - "6143", - "120", - "865", - "8406", - "6141", - "7302", - "8461", - "8407", - "8492", - "8427", - "8408", - "6131", - "7320", - "10159", - "8462", - "10185", - "10179", - "10160", - "10180", - "10219", - "10186", - "10177", - "10230", - "10181", - "10161", - "10187", - "10220", - "2018", - "2663", - "12260", - "2660", - "3115", - "3326", - "2665", - "3116", - "2738", - "3293", - "2661", - "3319", - "2662", - "9983", - "8880", - "2737", - "2739", - "7408", - "3320", - "2666", - "3323", - "3324", - "3294", - "22723", - "23219", - "23220", - "23221", - "23228", - "23338", - "10788", - "10790", - "5611", - "5016", - "5609", - "2060", - "10963", - "10964", - "10965", - "22593", - "22594", - "596", - "996", - "499", - "768", - "17002", - "1448", - "1082", - "16979", - "1079", - "5215", - "20484", - "5221", - "15590", - "17007", - "6795", - "6807", - "5487", - "1446", - "1066", - "5421", - "3139", - "779", - "6811", - "6808", - "1445", - "5216", - "1737", - "5222", - "5217", - "1432", - "6812", - "9492", - "5210", - "3030", - "1441", - "783", - "6801", - "20739", - "8944", - "9491", - "22569", - "5226", - "6786", - "1433", - "8973", - "1828", - "9495", - "9006", - "6794", - "8993", - "5203", - "16914", - "6784", - "9635", - "22830", - "20722", - "9748", - "6790", - "9753", - "9493", - "9752", - "9831", - "9825", - "9822", - "5204", - "5401", - "22831", - "6793", - "9845", - "17401", - "9882", - "9868", - "20749", - "9893", - "9899", - "9895", - "9832", - "9902", - "9909", - "22832", - "9828", - "9851", - "9883", - "9869", - "17406", - "17402", - "9914", - "20750", - "9897", - "9848", - "3127", - "107", - "204", - "9116", - "2457", - "78", - "18848", - "331", - "403", - "2098", - "1752", - "11278", - "11288", - "11284", - "6461", - "2344", - "2345", - "6463", - "2346", - "2352", - "775", - "1434", - "1612", - "71", - "2468", - "2458", - "2467", - "7164", - "7178", - "7367", - "7376", - "7381", - "21156", - "5209", - "3029", - "5201", - "9849", - "9850", - "20719", - "22568", - "22827", - "22828", - "22829", - "6809", - "8972", - "9005", - "9823", - "9827", - "6783", - "9913", - "6785", - "6787", - "9866", - "9867", - "9894", - "9896", - "6800", - "8992", - "9829", - "9830", - "780", - "769", - "6749", - "6750", - "9755", - "9754", - "9908", - "20745", - "20742", - "20747", - "20748", - "9746", - "9745", - "9880", - "9881", - "5391", - "842", - "3025", - "3031", - "3287", - "3329", - "1945", - "3559", - "4933", - "4934", - "4935", - "4936", - "5142", - "5390", - "5392", - "5404", - "5420", - "6405", - "7293", - "7965", - "8041", - "8153", - "9033", - "9034", - //"9036", problems with ghost state - "16421", - "21653", - "22660", - "5225", - "9846", - "2426", - "5916", - "6634", - //"6718", phasing stealth, annoing for learn all case. - "6719", - "8822", - "9591", - "9590", - "10032", - "17746", - "17747", - "8203", - "11392", - "12495", - "16380", - "23452", - "4079", - "4996", - "4997", - "4998", - "4999", - "5000", - "6348", - "6349", - "6481", - "6482", - "6483", - "6484", - "11362", - "11410", - "11409", - "12510", - "12509", - "12885", - "13142", - "21463", - "23460", - "11421", - "11416", - "11418", - "1851", - "10059", - "11423", - "11417", - "11422", - "11419", - "11424", - "11420", - "27", - "31", - "33", - "34", - "35", - "15125", - "21127", - "22950", - "1180", - "201", - "12593", - "12842", - "16770", - "6057", - "12051", - "18468", - "12606", - "12605", - "18466", - "12502", - "12043", - "15060", - "12042", - "12341", - "12848", - "12344", - "12353", - "18460", - "11366", - "12350", - "12352", - "13043", - "11368", - "11113", - "12400", - "11129", - "16766", - "12573", - "15053", - "12580", - "12475", - "12472", - "12953", - "12488", - "11189", - "12985", - "12519", - "16758", - "11958", - "12490", - "11426", - "3565", - "3562", - "18960", - "3567", - "3561", - "3566", - "3563", - "1953", - "2139", - "12505", - "13018", - "12522", - "12523", - "5146", - "5144", - "5148", - "8419", - "8418", - "10213", - "10212", - "10157", - "12524", - "13019", - "12525", - "13020", - "12526", - "13021", - "18809", - "13031", - "13032", - "13033", - "4036", - "3920", - "3919", - "3918", - "7430", - "3922", - "3923", - "7411", - "7418", - "7421", - "13262", - "7412", - "7415", - "7413", - "7416", - "13920", - "13921", - "7745", - "7779", - "7428", - "7457", - "7857", - "7748", - "7426", - "13421", - "7454", - "13378", - "7788", - "14807", - "14293", - "7795", - "6296", - "20608", - "755", - "444", - "427", - "428", - "442", - "447", - "3578", - "3581", - "19027", - "3580", - "665", - "3579", - "3577", - "6755", - "3576", - "2575", - "2577", - "2578", - "2579", - "2580", - "2656", - "2657", - "2576", - "3564", - "10248", - "8388", - "2659", - "14891", - "3308", - "3307", - "10097", - "2658", - "3569", - "16153", - "3304", - "10098", - "4037", - "3929", - "3931", - "3926", - "3924", - "3930", - "3977", - "3925", - "136", - "228", - "5487", - "43", - "202", - "0" - }; - - int loop = 0; - while(strcmp(allSpellList[loop], "0")) - { - uint32 spell = atol((char*)allSpellList[loop++]); - - if (m_session->GetPlayer()->HasSpell(spell)) - continue; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - continue; - } - - m_session->GetPlayer()->learnSpell(spell); - } - - SendSysMessage(LANG_COMMAND_LEARN_MANY_SPELLS); - - return true; -} - -bool ChatHandler::HandleLearnAllGMCommand(const char* /*args*/) -{ - static const char *gmSpellList[] = - { - "24347", // Become A Fish, No Breath Bar - "35132", // Visual Boom - "38488", // Attack 4000-8000 AOE - "38795", // Attack 2000 AOE + Slow Down 90% - "15712", // Attack 200 - "1852", // GM Spell Silence - "31899", // Kill - "31924", // Kill - "29878", // Kill My Self - "26644", // More Kill - - "28550", //Invisible 24 - "23452", //Invisible + Target - "0" - }; - - uint16 gmSpellIter = 0; - while( strcmp(gmSpellList[gmSpellIter], "0") ) - { - uint32 spell = atol((char*)gmSpellList[gmSpellIter++]); - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - continue; - } - - m_session->GetPlayer()->learnSpell(spell); - } - - SendSysMessage(LANG_LEARNING_GM_SKILLS); - return true; -} - -bool ChatHandler::HandleLearnAllMyClassCommand(const char* /*args*/) -{ - HandleLearnAllMySpellsCommand(""); - HandleLearnAllMyTalentsCommand(""); - return true; -} - -bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/) -{ - ChrClassesEntry const* clsEntry = sChrClassesStore.LookupEntry(m_session->GetPlayer()->getClass()); - if(!clsEntry) - return true; - uint32 family = clsEntry->spellfamily; - - for (uint32 i = 0; i < sSpellStore.GetNumRows(); i++) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(i); - if(!spellInfo) - continue; - - // skip wrong class/race skills - if(!m_session->GetPlayer()->IsSpellFitByClassAndRace(spellInfo->Id)) - continue; - - // skip other spell families - if( spellInfo->SpellFamilyName != family) - continue; - - //TODO: skip triggered spells - - // skip spells with first rank learned as talent (and all talents then also) - uint32 first_rank = spellmgr.GetFirstSpellInChain(spellInfo->Id); - if(GetTalentSpellCost(first_rank) > 0 ) - continue; - - // skip broken spells - if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) - continue; - - m_session->GetPlayer()->learnSpell(i); - } - - SendSysMessage(LANG_COMMAND_LEARN_CLASS_SPELLS); - return true; -} - -static void learnAllHighRanks(Player* player, uint32 spellid) -{ - SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); - for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr) - { - player->learnSpell(itr->second); - learnAllHighRanks(player,itr->second); - } -} - -bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/) -{ - Player* player = m_session->GetPlayer(); - uint32 classMask = player->getClassMask(); - - for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++) - { - TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); - if(!talentInfo) - continue; - - TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab ); - if(!talentTabInfo) - continue; - - if( (classMask & talentTabInfo->ClassMask) == 0 ) - continue; - - // search highest talent rank - uint32 spellid = 0; - int rank = 4; - for(; rank >= 0; --rank) - { - if(talentInfo->RankID[rank]!=0) - { - spellid = talentInfo->RankID[rank]; - break; - } - } - - if(!spellid) // ??? none spells in telent - continue; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid); - if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) - continue; - - // learn highest rank of talent - player->learnSpell(spellid); - - // and learn all non-talent spell ranks (recursive by tree) - learnAllHighRanks(player,spellid); - } - - SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); - return true; -} - -bool ChatHandler::HandleLearnAllLangCommand(const char* /*args*/) -{ - // skipping UNIVERSAL language (0) - for(int i = 1; i < LANGUAGES_COUNT; ++i) - m_session->GetPlayer()->learnSpell(lang_description[i].spell_id); - - SendSysMessage(LANG_COMMAND_LEARN_ALL_LANG); - return true; -} - -bool ChatHandler::HandleLearnAllDefaultCommand(const char* args) -{ - char* pName = strtok((char*)args, ""); - Player *player = NULL; - if (pName) - { - std::string name = pName; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - player = objmgr.GetPlayer(name.c_str()); - } - else - player = getSelectedPlayer(); - - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - player->learnDefaultSpells(); - player->learnQuestRewardedSpells(); - - PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST,player->GetName()); - return true; -} - -bool ChatHandler::HandleLearnCommand(const char* args) -{ - Player* targetPlayer = getSelectedPlayer(); - - if(!targetPlayer) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if(!spell || !sSpellStore.LookupEntry(spell)) - return false; - - if (targetPlayer->HasSpell(spell)) - { - if(targetPlayer == m_session->GetPlayer()) - SendSysMessage(LANG_YOU_KNOWN_SPELL); - else - PSendSysMessage(LANG_TARGET_KNOWN_SPELL,targetPlayer->GetName()); - SetSentErrorMessage(true); - return false; - } - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - SetSentErrorMessage(true); - return false; - } - - targetPlayer->learnSpell(spell); - - return true; -} - -bool ChatHandler::HandleAddItemCommand(const char* args) -{ - if (!*args) - return false; - - uint32 itemId = 0; - - if(args[0]=='[') // [name] manual form - { - char* citemName = citemName = strtok((char*)args, "]"); - - if(citemName && citemName[0]) - { - std::string itemName = citemName+1; - WorldDatabase.escape_string(itemName); - QueryResult *result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE name = '%s'", itemName.c_str()); - if (!result) - { - PSendSysMessage(LANG_COMMAND_COULDNOTFIND, citemName+1); - SetSentErrorMessage(true); - return false; - } - itemId = result->Fetch()->GetUInt16(); - delete result; - } - else - return false; - } - else // item_id or [name] Shift-click form |color|Hitem:item_id:0:0:0|h[name]|h|r - { - char* cId = extractKeyFromLink((char*)args,"Hitem"); - if(!cId) - return false; - itemId = atol(cId); - } - - char* ccount = strtok(NULL, " "); - - int32 count = 1; - - if (ccount) - count = strtol(ccount, NULL, 10); - - if (count == 0) - count = 1; - - Player* pl = m_session->GetPlayer(); - Player* plTarget = getSelectedPlayer(); - if(!plTarget) - plTarget = pl; - - sLog.outDetail(GetMangosString(LANG_ADDITEM), itemId, count); - - ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); - if(!pProto) - { - PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemId); - SetSentErrorMessage(true); - return false; - } - - //Subtract - if (count < 0) - { - plTarget->DestroyItemCount(itemId, -count, true, false); - PSendSysMessage(LANG_REMOVEITEM, itemId, -count, plTarget->GetName()); - return true; - } - - //Adding items - uint32 noSpaceForCount = 0; - - // check space and find places - ItemPosCountVec dest; - uint8 msg = plTarget->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount ); - if( msg != EQUIP_ERR_OK ) // convert to possible store amount - count -= noSpaceForCount; - - if( count == 0 || dest.empty()) // can't add any - { - PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount ); - SetSentErrorMessage(true); - return false; - } - - Item* item = plTarget->StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); - - // remove binding (let GM give it to another player later) - if(pl==plTarget) - for(ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr) - if(Item* item1 = pl->GetItemByPos(itr->pos)) - item1->SetBinding( false ); - - if(count > 0 && item) - { - pl->SendNewItem(item,count,false,true); - if(pl!=plTarget) - plTarget->SendNewItem(item,count,true,false); - } - - if(noSpaceForCount > 0) - PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount); - - return true; -} - -bool ChatHandler::HandleAddItemSetCommand(const char* args) -{ - if (!*args) - return false; - - char* cId = extractKeyFromLink((char*)args,"Hitemset"); // number or [name] Shift-click form |color|Hitemset:itemset_id|h[name]|h|r - if (!cId) - return false; - - uint32 itemsetId = atol(cId); - - // prevent generation all items with itemset field value '0' - if (itemsetId == 0) - { - PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND,itemsetId); - SetSentErrorMessage(true); - return false; - } - - Player* pl = m_session->GetPlayer(); - Player* plTarget = getSelectedPlayer(); - if(!plTarget) - plTarget = pl; - - sLog.outDetail(GetMangosString(LANG_ADDITEMSET), itemsetId); - - QueryResult *result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE itemset = %u",itemsetId); - - if(!result) - { - PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND,itemsetId); - - SetSentErrorMessage(true); - return false; - } - - do - { - Field *fields = result->Fetch(); - uint32 itemId = fields[0].GetUInt32(); - - ItemPosCountVec dest; - uint8 msg = plTarget->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, 1 ); - if( msg == EQUIP_ERR_OK ) - { - Item* item = plTarget->StoreNewItem( dest, itemId, true); - - // remove binding (let GM give it to another player later) - if(pl==plTarget) - item->SetBinding( false ); - - pl->SendNewItem(item,1,false,true); - if(pl!=plTarget) - plTarget->SendNewItem(item,1,true,false); - } - else - { - pl->SendEquipError( msg, NULL, NULL ); - PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, 1); - } - - }while( result->NextRow() ); - - delete result; - - return true; -} - -bool ChatHandler::HandleListItemCommand(const char* args) -{ - if(!*args) - return false; - - char* cId = extractKeyFromLink((char*)args,"Hitem"); - if(!cId) - return false; - uint32 item_id = atol(cId); - - ItemPrototype const* itemProto = item_id ? itemProto = objmgr.GetItemPrototype(item_id) : NULL; - - if(!itemProto) - { - PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id); - SetSentErrorMessage(true); - return false; - } - - char* c_count = strtok(NULL, " "); - int count = c_count ? atol(c_count) : 10; - - if(count < 0) - return false; - - QueryResult *result; - - // inventory case - uint32 inv_count = 0; - result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM character_inventory WHERE item_template='%u'",item_id); - if(result) - { - inv_count = (*result)[0].GetUInt32(); - delete result; - } - - result=CharacterDatabase.PQuery( - // 0 1 2 3 4 5 - "SELECT ci.item, cibag.slot AS bag, ci.slot, ci.guid, characters.account,characters.name " - "FROM character_inventory AS ci LEFT JOIN character_inventory AS cibag ON (cibag.item=ci.bag),characters " - "WHERE ci.item_template='%u' AND ci.guid = characters.guid LIMIT %u ", - item_id,uint32(count)); - - if(result) - { - do - { - Field *fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 item_bag = fields[1].GetUInt32(); - uint32 item_slot = fields[2].GetUInt32(); - uint32 owner_guid = fields[3].GetUInt32(); - uint32 owner_acc = fields[4].GetUInt32(); - std::string owner_name = fields[5].GetCppString(); - - char const* item_pos = 0; - if(Player::IsEquipmentPos(item_bag,item_slot)) - item_pos = "[equipped]"; - else if(Player::IsInventoryPos(item_bag,item_slot)) - item_pos = "[in inventory]"; - else if(Player::IsBankPos(item_bag,item_slot)) - item_pos = "[in bank]"; - else - item_pos = ""; - - PSendSysMessage(LANG_ITEMLIST_SLOT, - item_guid,owner_name.c_str(),owner_guid,owner_acc,item_pos); - } while (result->NextRow()); - - int64 res_count = result->GetRowCount(); - - delete result; - - if(count > res_count) - count-=res_count; - else if(count) - count = 0; - } - - // mail case - uint32 mail_count = 0; - result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM mail_items WHERE item_template='%u'", item_id); - if(result) - { - mail_count = (*result)[0].GetUInt32(); - delete result; - } - - if(count > 0) - { - result=CharacterDatabase.PQuery( - // 0 1 2 3 4 5 6 - "SELECT mail_items.item_guid, mail.sender, mail.receiver, char_s.account, char_s.name, char_r.account, char_r.name " - "FROM mail,mail_items,characters as char_s,characters as char_r " - "WHERE mail_items.item_template='%u' AND char_s.guid = mail.sender AND char_r.guid = mail.receiver AND mail.id=mail_items.mail_id LIMIT %u", - item_id,uint32(count)); - } - else - result = NULL; - - if(result) - { - do - { - Field *fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 item_s = fields[1].GetUInt32(); - uint32 item_r = fields[2].GetUInt32(); - uint32 item_s_acc = fields[3].GetUInt32(); - std::string item_s_name = fields[4].GetCppString(); - uint32 item_r_acc = fields[5].GetUInt32(); - std::string item_r_name = fields[6].GetCppString(); - - char const* item_pos = "[in mail]"; - - PSendSysMessage(LANG_ITEMLIST_MAIL, - item_guid,item_s_name.c_str(),item_s,item_s_acc,item_r_name.c_str(),item_r,item_r_acc,item_pos); - } while (result->NextRow()); - - int64 res_count = result->GetRowCount(); - - delete result; - - if(count > res_count) - count-=res_count; - else if(count) - count = 0; - } - - // auction case - uint32 auc_count = 0; - result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM auctionhouse WHERE item_template='%u'",item_id); - if(result) - { - auc_count = (*result)[0].GetUInt32(); - delete result; - } - - if(count > 0) - { - result=CharacterDatabase.PQuery( - // 0 1 2 3 - "SELECT auctionhouse.itemguid, auctionhouse.itemowner, characters.account, characters.name " - "FROM auctionhouse,characters WHERE auctionhouse.item_template='%u' AND characters.guid = auctionhouse.itemowner LIMIT %u", - item_id,uint32(count)); - } - else - result = NULL; - - if(result) - { - do - { - Field *fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 owner = fields[1].GetUInt32(); - uint32 owner_acc = fields[2].GetUInt32(); - std::string owner_name = fields[3].GetCppString(); - - char const* item_pos = "[in auction]"; - - PSendSysMessage(LANG_ITEMLIST_AUCTION, item_guid, owner_name.c_str(), owner, owner_acc,item_pos); - } while (result->NextRow()); - - delete result; - } - - if(inv_count+mail_count+auc_count == 0) - { - SendSysMessage(LANG_COMMAND_NOITEMFOUND); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_COMMAND_LISTITEMMESSAGE,item_id,inv_count+mail_count+auc_count,inv_count,mail_count,auc_count); - - return true; -} - -bool ChatHandler::HandleListObjectCommand(const char* args) -{ - if(!*args) - return false; - - // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry"); - if(!cId) - return false; - - uint32 go_id = atol(cId); - - GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(go_id); - - if(!go_id || !gInfo) - { - PSendSysMessage(LANG_COMMAND_LISTOBJINVALIDID, go_id); - SetSentErrorMessage(true); - return false; - } - - char* c_count = strtok(NULL, " "); - int count = c_count ? atol(c_count) : 10; - - if(count < 0) - return false; - - Player* pl = m_session->GetPlayer(); - QueryResult *result; - - uint32 obj_count = 0; - result=WorldDatabase.PQuery("SELECT COUNT(guid) FROM gameobject WHERE id='%u'",go_id); - if(result) - { - obj_count = (*result)[0].GetUInt32(); - delete result; - } - - result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE id = '%u' ORDER BY order_ ASC LIMIT %u", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),go_id,uint32(count)); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - - PSendSysMessage(LANG_GO_LIST, guid, guid, gInfo->name, x, y, z, mapid); - } while (result->NextRow()); - - delete result; - } - - PSendSysMessage(LANG_COMMAND_LISTOBJMESSAGE,go_id,obj_count); - return true; -} - -bool ChatHandler::HandleNearObjectCommand(const char* args) -{ - float distance = (!*args) ? 10 : atol(args); - uint32 count = 0; - - Player* pl = m_session->GetPlayer(); - QueryResult *result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, " - "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ " - "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' ORDER BY order_", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), - pl->GetMapId(),pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),distance*distance); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - uint32 entry = fields[1].GetUInt32(); - float x = fields[2].GetFloat(); - float y = fields[3].GetFloat(); - float z = fields[4].GetFloat(); - int mapid = fields[5].GetUInt16(); - - GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(entry); - - if(!gInfo) - continue; - - PSendSysMessage(LANG_GO_LIST, guid, guid, gInfo->name, x, y, z, mapid); - - ++count; - } while (result->NextRow()); - - delete result; - } - - PSendSysMessage(LANG_COMMAND_NEAROBJMESSAGE,distance,count); - return true; -} - -bool ChatHandler::HandleListCreatureCommand(const char* args) -{ - if(!*args) - return false; - - // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hcreature_entry"); - if(!cId) - return false; - - uint32 cr_id = atol(cId); - - CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(cr_id); - - if(!cr_id || !cInfo) - { - PSendSysMessage(LANG_COMMAND_INVALIDCREATUREID, cr_id); - SetSentErrorMessage(true); - return false; - } - - char* c_count = strtok(NULL, " "); - int count = c_count ? atol(c_count) : 10; - - if(count < 0) - return false; - - Player* pl = m_session->GetPlayer(); - QueryResult *result; - - uint32 cr_count = 0; - result=WorldDatabase.PQuery("SELECT COUNT(guid) FROM creature WHERE id='%u'",cr_id); - if(result) - { - cr_count = (*result)[0].GetUInt32(); - delete result; - } - - result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM creature WHERE id = '%u' ORDER BY order_ ASC LIMIT %u", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), cr_id,uint32(count)); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - - PSendSysMessage(LANG_CREATURE_LIST, guid, guid, cInfo->Name, x, y, z, mapid); - } while (result->NextRow()); - - delete result; - } - - PSendSysMessage(LANG_COMMAND_LISTCREATUREMESSAGE,cr_id,cr_count); - return true; -} - -bool ChatHandler::HandleLookupItemCommand(const char* args) -{ - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - uint32 counter = 0; - - // Search in `item_template` - for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) - { - ItemPrototype const *pProto = sItemStorage.LookupEntry(id); - if(!pProto) - continue; - - int loc_idx = m_session->GetSessionDbLocaleIndex(); - if ( loc_idx >= 0 ) - { - ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); - if (il) - { - if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty()) - { - std::string name = il->Name[loc_idx]; - - if (Utf8FitTo(name, wnamepart)) - { - PSendSysMessage(LANG_ITEM_LIST, id, id, name.c_str()); - ++counter; - continue; - } - } - } - } - - std::string name = pProto->Name1; - if(name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - { - PSendSysMessage(LANG_ITEM_LIST, id, id, name.c_str()); - ++counter; - } - } - - if (counter==0) - SendSysMessage(LANG_COMMAND_NOITEMFOUND); - - return true; -} - -bool ChatHandler::HandleLookupItemSetCommand(const char* args) -{ - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower( wnamepart ); - - uint32 counter = 0; // Counter for figure out that we found smth. - - // Search in ItemSet.dbc - for (uint32 id = 0; id < sItemSetStore.GetNumRows(); id++) - { - ItemSetEntry const *set = sItemSetStore.LookupEntry(id); - if(set) - { - int loc = m_session->GetSessionDbcLocale(); - std::string name = set->name[m_session->GetSessionDbcLocale()]; - if(name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for(; loc < MAX_LOCALE; ++loc) - { - if(loc==m_session->GetSessionDbcLocale()) - continue; - - name = set->name[m_session->GetSessionDbcLocale()]; - if(name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if(loc < MAX_LOCALE) - { - // send item set in "id - [namedlink locale]" format - PSendSysMessage(LANG_ITEMSET_LIST,id,id,name.c_str(),localeNames[loc]); - ++counter; - } - } - } - if (counter == 0) // if counter == 0 then we found nth - SendSysMessage(LANG_COMMAND_NOITEMSETFOUND); - return true; -} - -bool ChatHandler::HandleLookupSkillCommand(const char* args) -{ - Player* target = getSelectedPlayer(); - if(!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower( wnamepart ); - - uint32 counter = 0; // Counter for figure out that we found smth. - - // Search in SkillLine.dbc - for (uint32 id = 0; id < sSkillLineStore.GetNumRows(); id++) - { - SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(id); - if(skillInfo) - { - int loc = m_session->GetSessionDbcLocale(); - std::string name = skillInfo->name[loc]; - if(name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for(; loc < MAX_LOCALE; ++loc) - { - if(loc==m_session->GetSessionDbcLocale()) - continue; - - name = skillInfo->name[loc]; - if(name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if(loc < MAX_LOCALE) - { - // send skill in "id - [namedlink locale]" format - PSendSysMessage(LANG_SKILL_LIST,id,id,name.c_str(),localeNames[loc],(target->HasSkill(id) ? m_session->GetMangosString(LANG_KNOWN) : "")); - - ++counter; - } - } - } - if (counter == 0) // if counter == 0 then we found nth - SendSysMessage(LANG_COMMAND_NOSKILLFOUND); - return true; -} - -bool ChatHandler::HandleLookupSpellCommand(const char* args) -{ - Player* target = getSelectedPlayer(); - if( !target ) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower( wnamepart ); - - uint32 counter = 0; // Counter for figure out that we found smth. - - // Search in Spell.dbc - for (uint32 id = 0; id < sSpellStore.GetNumRows(); id++) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(id); - if(spellInfo) - { - int loc = m_session->GetSessionDbcLocale(); - std::string name = spellInfo->SpellName[loc]; - if(name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for(; loc < MAX_LOCALE; ++loc) - { - if(loc==m_session->GetSessionDbcLocale()) - continue; - - name = spellInfo->SpellName[loc]; - if(name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if(loc < MAX_LOCALE) - { - bool known = target->HasSpell(id); - bool learn = (spellInfo->Effect[0] == SPELL_EFFECT_LEARN_SPELL); - - uint32 telentCost = GetTalentSpellCost(id); - - bool talent = (telentCost > 0); - bool passive = IsPassiveSpell(id); - bool active = target->HasAura(id,0) || target->HasAura(id,1) || target->HasAura(id,2); - - // unit32 used to prevent interpreting uint8 as char at output - // find rank of learned spell for learning spell, or talent rank - uint32 rank = telentCost ? telentCost : spellmgr.GetSpellRank(learn ? spellInfo->EffectTriggerSpell[0] : id); - - // send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format - std::ostringstream ss; - ss << id << " - |cffffffff|Hspell:" << id << "|h[" << name; - - // include rank in link name - if(rank) - ss << GetMangosString(LANG_SPELL_RANK) << rank; - - ss << " " << localeNames[loc] << "]|h|r"; - - if(talent) - ss << GetMangosString(LANG_TALENT); - if(passive) - ss << GetMangosString(LANG_PASSIVE); - if(learn) - ss << GetMangosString(LANG_LEARN); - if(known) - ss << GetMangosString(LANG_KNOWN); - if(active) - ss << GetMangosString(LANG_ACTIVE); - - SendSysMessage(ss.str().c_str()); - - ++counter; - } - } - } - if (counter == 0) // if counter == 0 then we found nth - SendSysMessage(LANG_COMMAND_NOSPELLFOUND); - return true; -} - -bool ChatHandler::HandleLookupQuestCommand(const char* args) -{ - Player* target = getSelectedPlayer(); - if( !target ) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - uint32 counter = 0 ; - - ObjectMgr::QuestMap const& qTemplates = objmgr.GetQuestTemplates(); - for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) - { - Quest * qinfo = iter->second; - - int loc_idx = m_session->GetSessionDbLocaleIndex(); - if ( loc_idx >= 0 ) - { - QuestLocale const *il = objmgr.GetQuestLocale(qinfo->GetQuestId()); - if (il) - { - if (il->Title.size() > loc_idx && !il->Title[loc_idx].empty()) - { - std::string title = il->Title[loc_idx]; - - if (Utf8FitTo(title, wnamepart)) - { - QuestStatus status = target->GetQuestStatus(qinfo->GetQuestId()); - - char const* statusStr = ""; - if(status == QUEST_STATUS_COMPLETE) - { - if(target->GetQuestRewardStatus(qinfo->GetQuestId())) - statusStr = GetMangosString(LANG_COMMAND_QUEST_REWARDED); - else - statusStr = GetMangosString(LANG_COMMAND_QUEST_COMPLETE); - } - else if(status == QUEST_STATUS_INCOMPLETE) - statusStr = GetMangosString(LANG_COMMAND_QUEST_ACTIVE); - - PSendSysMessage(LANG_QUEST_LIST,qinfo->GetQuestId(),qinfo->GetQuestId(),title.c_str(),(status == QUEST_STATUS_COMPLETE ? GetMangosString(LANG_COMPLETE) : (status == QUEST_STATUS_INCOMPLETE ? GetMangosString(LANG_ACTIVE) : "") )); - ++counter; - continue; - } - } - } - } - - std::string title = qinfo->GetTitle(); - if(title.empty()) - continue; - - if (Utf8FitTo(title, wnamepart)) - { - QuestStatus status = target->GetQuestStatus(qinfo->GetQuestId()); - - char const* statusStr = ""; - if(status == QUEST_STATUS_COMPLETE) - { - if(target->GetQuestRewardStatus(qinfo->GetQuestId())) - statusStr = GetMangosString(LANG_COMMAND_QUEST_REWARDED); - else - statusStr = GetMangosString(LANG_COMMAND_QUEST_COMPLETE); - } - else if(status == QUEST_STATUS_INCOMPLETE) - statusStr = GetMangosString(LANG_COMMAND_QUEST_ACTIVE); - - PSendSysMessage(LANG_QUEST_LIST,qinfo->GetQuestId(),qinfo->GetQuestId(), title.c_str(),(status == QUEST_STATUS_COMPLETE ? GetMangosString(LANG_COMPLETE) : (status == QUEST_STATUS_INCOMPLETE ? GetMangosString(LANG_ACTIVE) : "") )); - ++counter; - } - } - - if (counter==0) - SendSysMessage(LANG_COMMAND_NOQUESTFOUND); - - return true; -} - -bool ChatHandler::HandleLookupCreatureCommand(const char* args) -{ - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - uint32 counter = 0; - - for (uint32 id = 0; id< sCreatureStorage.MaxEntry; id++ ) - { - CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(id); - if(!cInfo) - continue; - - int loc_idx = m_session->GetSessionDbLocaleIndex(); - if ( loc_idx >= 0 ) - { - CreatureLocale const *cl = objmgr.GetCreatureLocale(id); - if (cl) - { - if (cl->Name.size() > loc_idx && !cl->Name[loc_idx].empty()) - { - std::string name = cl->Name[loc_idx]; - - if (Utf8FitTo(name, wnamepart)) - { - PSendSysMessage(LANG_CREATURE_ENTRY_LIST, id, id, name.c_str()); - ++counter; - continue; - } - } - } - } - - std::string name = cInfo->Name; - if(name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - { - PSendSysMessage(LANG_CREATURE_ENTRY_LIST,id,id,name.c_str()); - ++counter; - } - } - - if (counter==0) - SendSysMessage(LANG_COMMAND_NOCREATUREFOUND); - - return true; -} - -bool ChatHandler::HandleLookupObjectCommand(const char* args) -{ - if(!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if(!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - uint32 counter = 0; - - for (uint32 id = 0; id< sGOStorage.MaxEntry; id++ ) - { - GameObjectInfo const* gInfo = sGOStorage.LookupEntry(id); - if(!gInfo) - continue; - - int loc_idx = m_session->GetSessionDbLocaleIndex(); - if ( loc_idx >= 0 ) - { - GameObjectLocale const *gl = objmgr.GetGameObjectLocale(id); - if (gl) - { - if (gl->Name.size() > loc_idx && !gl->Name[loc_idx].empty()) - { - std::string name = gl->Name[loc_idx]; - - if (Utf8FitTo(name, wnamepart)) - { - PSendSysMessage(LANG_GO_ENTRY_LIST, id, id, name.c_str()); - ++counter; - continue; - } - } - } - } - - std::string name = gInfo->name; - if(name.empty()) - continue; - - if(Utf8FitTo(name, wnamepart)) - { - PSendSysMessage(LANG_GO_ENTRY_LIST, id, id, name.c_str()); - ++counter; - } - } - - if(counter==0) - SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND); - - return true; -} - -/** \brief GM command level 3 - Create a guild. - * - * This command allows a GM (level 3) to create a guild. - * - * The "args" parameter contains the name of the guild leader - * and then the name of the guild. - * - */ -bool ChatHandler::HandleGuildCreateCommand(const char* args) -{ - - if (!*args) - return false; - - Guild *guild; - Player * player; - char *lname,*gname; - std::string guildname; - - lname = strtok((char*)args, " "); - gname = strtok(NULL, ""); - - if(!lname) - return false; - else if(!gname) - { - SendSysMessage(LANG_INSERT_GUILD_NAME); - SetSentErrorMessage(true); - return false; - } - - guildname = gname; - player = ObjectAccessor::Instance().FindPlayerByName(lname); - - if(!player) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if(!player->GetGuildId()) - { - guild = new Guild; - if(!guild->create(player->GetGUID(),guildname)) - { - delete guild; - SendSysMessage(LANG_GUILD_NOT_CREATED); - SetSentErrorMessage(true); - return false; - } - - objmgr.AddGuild(guild); - } - else - SendSysMessage(LANG_PLAYER_IN_GUILD); - - return true; -} - -bool ChatHandler::HandleGuildInviteCommand(const char *args) -{ - if(!*args) - return false; - - char* par1 = strtok((char*)args, " "); - char* par2 = strtok (NULL, ""); - if(!par1 || !par2) - return false; - - std::string glName = par2; - Guild* targetGuild = objmgr.GetGuildByName(glName); - if(!targetGuild) - return false; - - std::string plName = par1; - if(!normalizePlayerName(plName)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 plGuid = 0; - if(Player* targetPlayer = ObjectAccessor::Instance().FindPlayerByName(plName.c_str())) - plGuid = targetPlayer->GetGUID(); - else - plGuid = objmgr.GetPlayerGUIDByName(plName.c_str()); - - if(!plGuid) - false; - - // players's guild membership checked in AddMember before add - if(!targetGuild->AddMember(plGuid,targetGuild->GetLowestRank())) - return false; - - return true; -} - -bool ChatHandler::HandleGuildUninviteCommand(const char *args) -{ - if(!*args) - return false; - - char* par1 = strtok((char*)args, " "); - if(!par1) - return false; - std::string plName = par1; - if(!normalizePlayerName(plName)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 plGuid = 0; - uint32 glId = 0; - if(Player* targetPlayer = ObjectAccessor::Instance().FindPlayerByName(plName.c_str())) - { - plGuid = targetPlayer->GetGUID(); - glId = targetPlayer->GetGuildId(); - } - else - { - plGuid = objmgr.GetPlayerGUIDByName(plName.c_str()); - glId = Player::GetGuildIdFromDB(plGuid); - } - - if(!plGuid || !glId) - return false; - - Guild* targetGuild = objmgr.GetGuildById(glId); - if(!targetGuild) - return false; - - targetGuild->DelMember(plGuid); - - return true; -} - -bool ChatHandler::HandleGuildRankCommand(const char *args) -{ - if(!*args) - return false; - - char* par1 = strtok((char*)args, " "); - char* par2 = strtok(NULL, " "); - if(!par1 || !par2) - return false; - std::string plName = par1; - if(!normalizePlayerName(plName)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 plGuid = 0; - uint32 glId = 0; - if(Player* targetPlayer = ObjectAccessor::Instance().FindPlayerByName(plName.c_str())) - { - plGuid = targetPlayer->GetGUID(); - glId = targetPlayer->GetGuildId(); - } - else - { - plGuid = objmgr.GetPlayerGUIDByName(plName.c_str()); - glId = Player::GetGuildIdFromDB(plGuid); - } - - if(!plGuid || !glId) - return false; - - Guild* targetGuild = objmgr.GetGuildById(glId); - if(!targetGuild) - return false; - - uint32 newrank = uint32(atoi(par2)); - if(newrank > targetGuild->GetLowestRank()) - return false; - - targetGuild->ChangeRank(plGuid,newrank); - - return true; -} - -bool ChatHandler::HandleGuildDeleteCommand(const char* args) -{ - if(!*args) - return false; - - char* par1 = strtok((char*)args, " "); - if(!par1) - return false; - - std::string gld = par1; - - Guild* targetGuild = objmgr.GetGuildByName(gld); - if(!targetGuild) - return false; - - targetGuild->Disband(); - - return true; -} - -bool ChatHandler::HandleGetDistanceCommand(const char* /*args*/) -{ - Unit* pUnit = getSelectedUnit(); - - if(!pUnit) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(pUnit),m_session->GetPlayer()->GetDistance2d(pUnit)); - - return true; -} - -// FIX-ME!!! - -bool ChatHandler::HandleAddWeaponCommand(const char* /*args*/) -{ - /*if (!*args) - return false; - - uint64 guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature *pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - char* pSlotID = strtok((char*)args, " "); - if (!pSlotID) - return false; - - char* pItemID = strtok(NULL, " "); - if (!pItemID) - return false; - - uint32 ItemID = atoi(pItemID); - uint32 SlotID = atoi(pSlotID); - - ItemPrototype* tmpItem = objmgr.GetItemPrototype(ItemID); - - bool added = false; - if(tmpItem) - { - switch(SlotID) - { - case 1: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID); - added = true; - break; - case 2: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID); - added = true; - break; - case 3: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID); - added = true; - break; - default: - PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID); - added = false; - break; - } - if(added) - { - PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID); - } - } - else - { - PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID); - return true; - } - */ - return true; -} - -bool ChatHandler::HandleDieCommand(const char* /*args*/) -{ - Unit* target = getSelectedUnit(); - - if(!target || !m_session->GetPlayer()->GetSelection()) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if( target->isAlive() ) - { - m_session->GetPlayer()->DealDamage(target, target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - - return true; -} - -bool ChatHandler::HandleDamageCommand(const char * args) -{ - if (!*args) - return false; - - Unit* target = getSelectedUnit(); - - if(!target || !m_session->GetPlayer()->GetSelection()) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if( !target->isAlive() ) - return true; - - char* damageStr = strtok((char*)args, " "); - if(!damageStr) - return false; - - int32 damage = atoi((char*)damageStr); - if(damage <=0) - return true; - - char* schoolStr = strtok((char*)NULL, " "); - - // flat melee damage without resistence/etc reduction - if(!schoolStr) - { - m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0); - return true; - } - - uint32 school = schoolStr ? atoi((char*)schoolStr) : SPELL_SCHOOL_NORMAL; - if(school >= MAX_SPELL_SCHOOL) - return false; - - SpellSchoolMask schoolmask = SpellSchoolMask(1 << school); - - if ( schoolmask & SPELL_SCHOOL_MASK_NORMAL ) - damage = m_session->GetPlayer()->CalcArmorReducedDamage(target, damage); - - char* spellStr = strtok((char*)NULL, " "); - - // melee damage by specific school - if(!spellStr) - { - uint32 absorb = 0; - uint32 resist = 0; - - m_session->GetPlayer()->CalcAbsorbResist(target,schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - - if (damage <= absorb + resist) - return true; - - damage -= absorb + resist; - - m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); - m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_NORMAL, 0); - return true; - } - - // non-melee damage - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spellid = extractSpellIdFromLink((char*)args); - if(!spellid || !sSpellStore.LookupEntry(spellid)) - return false; - - m_session->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage, false); - return true; -} - -bool ChatHandler::HandleModifyArenaCommand(const char * args) -{ - if (!*args) - return false; - - Player *target = getSelectedPlayer(); - if(!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - int32 amount = (uint32)atoi(args); - - target->ModifyArenaPoints(amount); - - PSendSysMessage(LANG_COMMAND_MODIFY_ARENA, target->GetName(), target->GetArenaPoints()); - - return true; -} - -bool ChatHandler::HandleReviveCommand(const char* args) -{ - Player* SelectedPlayer = NULL; - - if (*args) - { - std::string name = args; - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - SelectedPlayer = objmgr.GetPlayer(name.c_str()); - } - else - SelectedPlayer = getSelectedPlayer(); - - if(!SelectedPlayer) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - SelectedPlayer->ResurrectPlayer(0.5f); - SelectedPlayer->SpawnCorpseBones(); - SelectedPlayer->SaveToDB(); - return true; -} - -bool ChatHandler::HandleAuraCommand(const char* args) -{ - char* px = strtok((char*)args, " "); - if (!px) - return false; - - Unit *target = getSelectedUnit(); - if(!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint32 spellID = (uint32)atoi(px); - SpellEntry const *spellInfo = sSpellStore.LookupEntry( spellID ); - if(spellInfo) - { - for(uint32 i = 0;i<3;i++) - { - uint8 eff = spellInfo->Effect[i]; - if (eff>=TOTAL_SPELL_EFFECTS) - continue; - if( IsAreaAuraEffect(eff) || - eff == SPELL_EFFECT_APPLY_AURA || - eff == SPELL_EFFECT_PERSISTENT_AREA_AURA ) - { - Aura *Aur = CreateAura(spellInfo, i, NULL, target); - target->AddAura(Aur); - } - } - } - - return true; -} - -bool ChatHandler::HandleUnAuraCommand(const char* args) -{ - char* px = strtok((char*)args, " "); - if (!px) - return false; - - Unit *target = getSelectedUnit(); - if(!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - std::string argstr = args; - if (argstr == "all") - { - target->RemoveAllAuras(); - return true; - } - - uint32 spellID = (uint32)atoi(px); - target->RemoveAurasDueToSpell(spellID); - - return true; -} - -bool ChatHandler::HandleLinkGraveCommand(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - if (!px) - return false; - - uint32 g_id = (uint32)atoi(px); - - uint32 g_team; - - char* px2 = strtok(NULL, " "); - - if (!px2) - g_team = 0; - else if (strncmp(px2,"horde",6)==0) - g_team = HORDE; - else if (strncmp(px2,"alliance",9)==0) - g_team = ALLIANCE; - else - return false; - - WorldSafeLocsEntry const* graveyard = sWorldSafeLocsStore.LookupEntry(g_id); - - if(!graveyard ) - { - PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST, g_id); - SetSentErrorMessage(true); - return false; - } - - Player* player = m_session->GetPlayer(); - - uint32 zoneId = player->GetZoneId(); - - AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId); - if(!areaEntry || areaEntry->zone !=0 ) - { - PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, g_id,zoneId); - SetSentErrorMessage(true); - return false; - } - - if(graveyard->map_id != areaEntry->mapid && g_team != 0) - { - SendSysMessage(LANG_COMMAND_GRAVEYARDWRONGTEAM); - SetSentErrorMessage(true); - return false; - } - - if(objmgr.AddGraveYardLink(g_id,player->GetZoneId(),g_team)) - PSendSysMessage(LANG_COMMAND_GRAVEYARDLINKED, g_id,zoneId); - else - PSendSysMessage(LANG_COMMAND_GRAVEYARDALRLINKED, g_id,zoneId); - - return true; -} - -bool ChatHandler::HandleNearGraveCommand(const char* args) -{ - uint32 g_team; - - size_t argslen = strlen(args); - - if(!*args) - g_team = 0; - else if (strncmp((char*)args,"horde",argslen)==0) - g_team = HORDE; - else if (strncmp((char*)args,"alliance",argslen)==0) - g_team = ALLIANCE; - else - return false; - - Player* player = m_session->GetPlayer(); - - WorldSafeLocsEntry const* graveyard = objmgr.GetClosestGraveYard( - player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(),player->GetMapId(),g_team); - - if(graveyard) - { - uint32 g_id = graveyard->ID; - - GraveYardData const* data = objmgr.FindGraveYardData(g_id,player->GetZoneId()); - if (!data) - { - PSendSysMessage(LANG_COMMAND_GRAVEYARDERROR,g_id); - SetSentErrorMessage(true); - return false; - } - - g_team = data->team; - - std::string team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_NOTEAM); - - if(g_team == 0) - team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ANY); - else if(g_team == HORDE) - team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_HORDE); - else if(g_team == ALLIANCE) - team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ALLIANCE); - - PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, g_id,team_name.c_str(),player->GetZoneId()); - } - else - { - std::string team_name; - - if(g_team == 0) - team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ANY); - else if(g_team == HORDE) - team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_HORDE); - else if(g_team == ALLIANCE) - team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ALLIANCE); - - if(g_team == ~uint32(0)) - PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, player->GetZoneId()); - else - PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, player->GetZoneId(),team_name.c_str()); - } - - return true; -} - -bool ChatHandler::HandleSpawnTransportCommand(const char* /*args*/) -{ - return true; -} - -//play npc emote -bool ChatHandler::HandlePlayEmoteCommand(const char* args) -{ - uint32 emote = atoi((char*)args); - - Creature* target = getSelectedCreature(); - if(!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote); - - return true; -} - -bool ChatHandler::HandleNpcInfoCommand(const char* /*args*/) -{ - Creature* target = getSelectedCreature(); - - if(!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint32 faction = target->getFaction(); - uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS); - uint32 displayid = target->GetDisplayId(); - uint32 nativeid = target->GetNativeDisplayId(); - uint32 Entry = target->GetEntry(); - CreatureInfo const* cInfo = target->GetCreatureInfo(); - - int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL); - if(curRespawnDelay < 0) - curRespawnDelay = 0; - std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true); - std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true); - - PSendSysMessage(LANG_NPCINFO_CHAR, target->GetDBTableGUIDLow(), faction, npcflags, Entry, displayid, nativeid); - PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel()); - PSendSysMessage(LANG_NPCINFO_HEALTH,target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth()); - PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction()); - PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str()); - PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid,cInfo->pickpocketLootId,cInfo->SkinLootId); - PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId()); - PSendSysMessage(LANG_NPCINFO_POSITION,float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); - - if ((npcflags & UNIT_NPC_FLAG_VENDOR) ) - { - SendSysMessage(LANG_NPCINFO_VENDOR); - } - if ((npcflags & UNIT_NPC_FLAG_TRAINER) ) - { - SendSysMessage(LANG_NPCINFO_TRAINER); - } - - return true; -} - -bool ChatHandler::HandleExploreCheatCommand(const char* args) -{ - if (!*args) - return false; - - int flag = atoi((char*)args); - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if (flag != 0) - { - PSendSysMessage(LANG_YOU_SET_EXPLORE_ALL, chr->GetName()); - if(chr!=m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_ALL,m_session->GetPlayer()->GetName()); - } - else - { - PSendSysMessage(LANG_YOU_SET_EXPLORE_NOTHING, chr->GetName()); - if(chr!=m_session->GetPlayer()) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_NOTHING,m_session->GetPlayer()->GetName()); - } - - for (uint8 i=0; i<128; i++) - { - if (flag != 0) - { - m_session->GetPlayer()->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0xFFFFFFFF); - } - else - { - m_session->GetPlayer()->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0); - } - } - - return true; -} - -bool ChatHandler::HandleHoverCommand(const char* args) -{ - char* px = strtok((char*)args, " "); - uint32 flag; - if (!px) - flag = 1; - else - flag = atoi(px); - - m_session->GetPlayer()->SetHover(flag); - - if (flag) - SendSysMessage(LANG_HOVER_ENABLED); - else - SendSysMessage(LANG_HOVER_DISABLED); - - return true; -} - -bool ChatHandler::HandleLevelUpCommand(const char* args) -{ - char* px = strtok((char*)args, " "); - char* py = strtok((char*)NULL, " "); - - // command format parsing - char* pname = (char*)NULL; - int addlevel = 1; - - if(px && py) // .levelup name level - { - addlevel = atoi(py); - pname = px; - } - else if(px && !py) // .levelup name OR .levelup level - { - if(isalpha(px[0])) // .levelup name - pname = px; - else // .levelup level - addlevel = atoi(px); - } - // else .levelup - nothing do for prepering - - // player - Player *chr = NULL; - uint64 chr_guid = 0; - - std::string name; - - if(pname) // player by name - { - name = pname; - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - chr = objmgr.GetPlayer(name.c_str()); - if(!chr) // not in game - { - chr_guid = objmgr.GetPlayerGUIDByName(name); - if (chr_guid == 0) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - } - } - else // player by selection - { - chr = getSelectedPlayer(); - - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - name = chr->GetName(); - } - - assert(chr || chr_guid); - - int32 oldlevel = chr ? chr->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,chr_guid); - int32 newlevel = oldlevel + addlevel; - if(newlevel < 1) - newlevel = 1; - if(newlevel > 255) // hardcoded maximum level - newlevel = 255; - - if(chr) - { - chr->GiveLevel(newlevel); - chr->InitTalentForLevel(); - chr->SetUInt32Value(PLAYER_XP,0); - - if(oldlevel == newlevel) - ChatHandler(chr).SendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET); - else - if(oldlevel < newlevel) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_LEVEL_UP,newlevel-oldlevel); - else - if(oldlevel > newlevel) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_LEVEL_DOWN,newlevel-oldlevel); - } - else - { - // update levle and XP at level, all other will be updated at loading - Tokens values; - Player::LoadValuesArrayFromDB(values,chr_guid); - Player::SetUInt32ValueInArray(values,UNIT_FIELD_LEVEL,newlevel); - Player::SetUInt32ValueInArray(values,PLAYER_XP,0); - Player::SaveValuesArrayInDB(values,chr_guid); - } - - if(m_session->GetPlayer() != chr) // including chr==NULL - PSendSysMessage(LANG_YOU_CHANGE_LVL,name.c_str(),newlevel); - return true; -} - -bool ChatHandler::HandleShowAreaCommand(const char* args) -{ - if (!*args) - return false; - - int area = atoi((char*)args); - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - int offset = area / 32; - uint32 val = (uint32)(1 << (area % 32)); - - if(offset >= 128) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - uint32 currFields = chr->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); - chr->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val)); - - SendSysMessage(LANG_EXPLORE_AREA); - return true; -} - -bool ChatHandler::HandleHideAreaCommand(const char* args) -{ - if (!*args) - return false; - - int area = atoi((char*)args); - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - int offset = area / 32; - uint32 val = (uint32)(1 << (area % 32)); - - if(offset >= 128) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - uint32 currFields = chr->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); - chr->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields ^ val)); - - SendSysMessage(LANG_UNEXPLORE_AREA); - return true; -} - -bool ChatHandler::HandleUpdate(const char* args) -{ - if(!*args) - return false; - - uint32 updateIndex; - uint32 value; - - char* pUpdateIndex = strtok((char*)args, " "); - - Unit* chr = getSelectedUnit(); - if (chr == NULL) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if(!pUpdateIndex) - { - return true; - } - updateIndex = atoi(pUpdateIndex); - //check updateIndex - if(chr->GetTypeId() == TYPEID_PLAYER) - { - if (updateIndex>=PLAYER_END) return true; - } - else - { - if (updateIndex>=UNIT_END) return true; - } - - char* pvalue = strtok(NULL, " "); - if (!pvalue) - { - value=chr->GetUInt32Value(updateIndex); - - PSendSysMessage(LANG_UPDATE, chr->GetGUIDLow(),updateIndex,value); - return true; - } - - value=atoi(pvalue); - - PSendSysMessage(LANG_UPDATE_CHANGE, chr->GetGUIDLow(),updateIndex,value); - - chr->SetUInt32Value(updateIndex,value); - - return true; -} - -bool ChatHandler::HandleBankCommand(const char* /*args*/) -{ - m_session->SendShowBank( m_session->GetPlayer()->GetGUID() ); - - return true; -} - -bool ChatHandler::HandleChangeWeather(const char* args) -{ - if(!*args) - return false; - - //Weather is OFF - if (!sWorld.getConfig(CONFIG_WEATHER)) - { - SendSysMessage(LANG_WEATHER_DISABLED); - SetSentErrorMessage(true); - return false; - } - - //*Change the weather of a cell - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - - if (!px || !py) - return false; - - uint32 type = (uint32)atoi(px); //0 to 3, 0: fine, 1: rain, 2: snow, 3: sand - float grade = (float)atof(py); //0 to 1, sending -1 is instand good weather - - Player *player = m_session->GetPlayer(); - uint32 zoneid = player->GetZoneId(); - - Weather* wth = sWorld.FindWeather(zoneid); - - if(!wth) - wth = sWorld.AddWeather(zoneid); - if(!wth) - { - SendSysMessage(LANG_NO_WEATHER); - SetSentErrorMessage(true); - return false; - } - - wth->SetWeather(WeatherType(type), grade); - - return true; -} - -bool ChatHandler::HandleSetValue(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - - if (!px || !py) - return false; - - Unit* target = getSelectedUnit(); - if(!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = target->GetGUID(); - - uint32 Opcode = (uint32)atoi(px); - if(Opcode >= target->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); - return false; - } - uint32 iValue; - float fValue; - bool isint32 = true; - if(pz) - isint32 = (bool)atoi(pz); - if(isint32) - { - iValue = (uint32)atoi(py); - sLog.outDebug(GetMangosString(LANG_SET_UINT), GUID_LOPART(guid), Opcode, iValue); - target->SetUInt32Value( Opcode , iValue ); - PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), Opcode,iValue); - } - else - { - fValue = (float)atof(py); - sLog.outDebug(GetMangosString(LANG_SET_FLOAT), GUID_LOPART(guid), Opcode, fValue); - target->SetFloatValue( Opcode , fValue ); - PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), Opcode,fValue); - } - - return true; -} - -bool ChatHandler::HandleGetValue(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - char* pz = strtok(NULL, " "); - - if (!px) - return false; - - Unit* target = getSelectedUnit(); - if(!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = target->GetGUID(); - - uint32 Opcode = (uint32)atoi(px); - if(Opcode >= target->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); - return false; - } - uint32 iValue; - float fValue; - bool isint32 = true; - if(pz) - isint32 = (bool)atoi(pz); - - if(isint32) - { - iValue = target->GetUInt32Value( Opcode ); - sLog.outDebug(GetMangosString(LANG_GET_UINT), GUID_LOPART(guid), Opcode, iValue); - PSendSysMessage(LANG_GET_UINT_FIELD, GUID_LOPART(guid), Opcode, iValue); - } - else - { - fValue = target->GetFloatValue( Opcode ); - sLog.outDebug(GetMangosString(LANG_GET_FLOAT), GUID_LOPART(guid), Opcode, fValue); - PSendSysMessage(LANG_GET_FLOAT_FIELD, GUID_LOPART(guid), Opcode, fValue); - } - - return true; -} - -bool ChatHandler::HandleSet32Bit(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - - if (!px || !py) - return false; - - uint32 Opcode = (uint32)atoi(px); - uint32 Value = (uint32)atoi(py); - if (Value > 32) //uint32 = 32 bits - return false; - - sLog.outDebug(GetMangosString(LANG_SET_32BIT), Opcode, Value); - - m_session->GetPlayer( )->SetUInt32Value( Opcode , 2^Value ); - - PSendSysMessage(LANG_SET_32BIT_FIELD, Opcode,1); - return true; -} - -bool ChatHandler::HandleMod32Value(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - - if (!px || !py) - return false; - - uint32 Opcode = (uint32)atoi(px); - int Value = atoi(py); - - if(Opcode >= m_session->GetPlayer()->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, m_session->GetPlayer()->GetGUIDLow(), m_session->GetPlayer( )->GetValuesCount()); - return false; - } - - sLog.outDebug(GetMangosString(LANG_CHANGE_32BIT), Opcode, Value); - - int CurrentValue = (int)m_session->GetPlayer( )->GetUInt32Value( Opcode ); - - CurrentValue += Value; - m_session->GetPlayer( )->SetUInt32Value( Opcode , (uint32)CurrentValue ); - - PSendSysMessage(LANG_CHANGE_32BIT_FIELD, Opcode,CurrentValue); - - return true; -} - -bool ChatHandler::HandleAddTeleCommand(const char * args) -{ - if(!*args) - return false; - QueryResult *result; - Player *player=m_session->GetPlayer(); - if (!player) return false; - - std::string name = args; - WorldDatabase.escape_string(name); - result = WorldDatabase.PQuery("SELECT id FROM game_tele WHERE name = '%s'",name.c_str()); - if (result) - { - SendSysMessage(LANG_COMMAND_TP_ALREADYEXIST); - delete result; - SetSentErrorMessage(true); - return false; - } - - float x = player->GetPositionX(); - float y = player->GetPositionY(); - float z = player->GetPositionZ(); - float ort = player->GetOrientation(); - int mapid = player->GetMapId(); - - if(WorldDatabase.PExecuteLog("INSERT INTO game_tele (position_x,position_y,position_z,orientation,map,name) VALUES (%f,%f,%f,%f,%d,'%s')",x,y,z,ort,mapid,name.c_str())) - { - SendSysMessage(LANG_COMMAND_TP_ADDED); - } - else - { - SendSysMessage(LANG_COMMAND_TP_ADDEDERR); - SetSentErrorMessage(true); - return false; - } - - return true; -} - -bool ChatHandler::HandleDelTeleCommand(const char * args) -{ - if(!*args) - return false; - - std::string name = args; - WorldDatabase.escape_string(name); - - QueryResult *result=WorldDatabase.PQuery("SELECT id FROM game_tele WHERE name = '%s'",name.c_str()); - if (!result) - { - SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - delete result; - - if(WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",name.c_str())) - { - SendSysMessage(LANG_COMMAND_TP_DELETED); - } - else - { - SendSysMessage(LANG_COMMAND_TP_DELETEERR); - SetSentErrorMessage(true); - return false; - } - return true; -} - -bool ChatHandler::HandleListAurasCommand (const char * /*args*/) -{ - Unit *unit = getSelectedUnit(); - if(!unit) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - char const* talentStr = GetMangosString(LANG_TALENT); - char const* passiveStr = GetMangosString(LANG_PASSIVE); - - Unit::AuraMap const& uAuras = unit->GetAuras(); - PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, uAuras.size()); - for (Unit::AuraMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr) - { - bool talent = GetTalentSpellCost(itr->second->GetId()) > 0; - PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(), - itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), - itr->second->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()], - (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), - IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); - } - for (int i = 0; i < TOTAL_AURAS; i++) - { - Unit::AuraList const& uAuraList = unit->GetAurasByType(AuraType(i)); - if (uAuraList.empty()) continue; - PSendSysMessage(LANG_COMMAND_TARGET_LISTAURATYPE, uAuraList.size(), i); - for (Unit::AuraList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr) - { - bool talent = GetTalentSpellCost((*itr)->GetId()) > 0; - PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), - (*itr)->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()],((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), - IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); - } - } - return true; -} - -bool ChatHandler::HandleResetHonorCommand (const char * args) -{ - char* pName = strtok((char*)args, ""); - Player *player = NULL; - if (pName) - { - std::string name = pName; - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()); - player = objmgr.GetPlayer(guid); - } - else - player = getSelectedPlayer(); - - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - return true; - } - - player->SetUInt32Value(PLAYER_FIELD_KILLS, 0); - player->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 0); - player->SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, 0); - player->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); - player->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); - - return true; -} - -static bool HandleResetStatsOrLevelHelper(Player* player) -{ - PlayerInfo const *info = objmgr.GetPlayerInfo(player->getRace(), player->getClass()); - if(!info) return false; - - ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(player->getClass()); - if(!cEntry) - { - sLog.outError("Class %u not found in DBC (Wrong DBC files?)",player->getClass()); - return false; - } - - uint8 powertype = cEntry->powerType; - - uint32 unitfield; - if(powertype == POWER_RAGE) - unitfield = 0x1100EE00; - else if(powertype == POWER_ENERGY) - unitfield = 0x00000000; - else if(powertype == POWER_MANA) - unitfield = 0x0000EE00; - else - { - sLog.outError("Invalid default powertype %u for player (class %u)",powertype,player->getClass()); - return false; - } - - // reset m_form if no aura - if(!player->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) - player->m_form = FORM_NONE; - - player->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE ); - player->SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f ); - - player->setFactionForRace(player->getRace()); - - player->SetUInt32Value(UNIT_FIELD_BYTES_0, ( ( player->getRace() ) | ( player->getClass() << 8 ) | ( player->getGender() << 16 ) | ( powertype << 24 ) ) ); - - // reset only if player not in some form; - if(player->m_form==FORM_NONE) - { - switch(player->getGender()) - { - case GENDER_FEMALE: - player->SetDisplayId(info->displayId_f); - player->SetNativeDisplayId(info->displayId_f); - break; - case GENDER_MALE: - player->SetDisplayId(info->displayId_m); - player->SetNativeDisplayId(info->displayId_m); - break; - default: - break; - } - } - - // set UNIT_FIELD_BYTES_1 to init state but preserve m_form value - player->SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield); - player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK3 | UNIT_BYTE2_FLAG_UNK5 ); - player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form); - - player->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); - - //-1 is default value - player->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); - - //player->SetUInt32Value(PLAYER_FIELD_BYTES, 0xEEE00000 ); - return true; -} - -bool ChatHandler::HandleResetLevelCommand(const char * args) -{ - char* pName = strtok((char*)args, ""); - Player *player = NULL; - if (pName) - { - std::string name = pName; - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()); - player = objmgr.GetPlayer(guid); - } - else - player = getSelectedPlayer(); - - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(!HandleResetStatsOrLevelHelper(player)) - return false; - - player->SetLevel(1); - player->InitStatsForLevel(true); - player->InitTaxiNodesForLevel(); - player->InitTalentForLevel(); - player->SetUInt32Value(PLAYER_XP,0); - - // reset level to summoned pet - Pet* pet = player->GetPet(); - if(pet && pet->getPetType()==SUMMON_PET) - pet->InitStatsForLevel(1); - - return true; -} - -bool ChatHandler::HandleResetStatsCommand(const char * args) -{ - char* pName = strtok((char*)args, ""); - Player *player = NULL; - if (pName) - { - std::string name = pName; - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()); - player = objmgr.GetPlayer(guid); - } - else - player = getSelectedPlayer(); - - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(!HandleResetStatsOrLevelHelper(player)) - return false; - - player->InitStatsForLevel(true); - player->InitTaxiNodesForLevel(); - player->InitTalentForLevel(); - - return true; -} - -bool ChatHandler::HandleResetSpellsCommand(const char * args) -{ - char* pName = strtok((char*)args, ""); - Player *player = NULL; - uint64 playerGUID = 0; - if (pName) - { - std::string name = pName; - - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - player = objmgr.GetPlayer(name.c_str()); - if(!player) - playerGUID = objmgr.GetPlayerGUIDByName(name.c_str()); - } - else - player = getSelectedPlayer(); - - if(!player && !playerGUID) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(player) - { - player->resetSpells(); - - ChatHandler(player).SendSysMessage(LANG_RESET_SPELLS); - - if(m_session->GetPlayer()!=player) - PSendSysMessage(LANG_RESET_SPELLS_ONLINE,player->GetName()); - } - else - { - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_SPELLS), GUID_LOPART(playerGUID)); - PSendSysMessage(LANG_RESET_SPELLS_OFFLINE,pName); - } - - return true; -} - -bool ChatHandler::HandleResetTalentsCommand(const char * args) -{ - char* pName = strtok((char*)args, ""); - Player *player = NULL; - uint64 playerGUID = 0; - if (pName) - { - std::string name = pName; - if(!normalizePlayerName(name)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - player = objmgr.GetPlayer(name.c_str()); - if(!player) - playerGUID = objmgr.GetPlayerGUIDByName(name.c_str()); - } - else - player = getSelectedPlayer(); - - if(!player && !playerGUID) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if(player) - { - player->resetTalents(true); - - ChatHandler(player).SendSysMessage(LANG_RESET_TALENTS); - - if(m_session->GetPlayer()!=player) - PSendSysMessage(LANG_RESET_TALENTS_ONLINE,player->GetName()); - } - else - { - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_TALENTS), GUID_LOPART(playerGUID) ); - PSendSysMessage(LANG_RESET_TALENTS_OFFLINE,pName); - } - - return true; -} - -bool ChatHandler::HandleResetAllCommand(const char * args) -{ - if(!*args) - return false; - - std::string casename = args; - - AtLoginFlags atLogin; - - // Command specially created as single command to prevent using short case names - if(casename=="spells") - { - atLogin = AT_LOGIN_RESET_SPELLS; - sWorld.SendWorldText(LANG_RESETALL_SPELLS); - } - else if(casename=="talents") - { - atLogin = AT_LOGIN_RESET_TALENTS; - sWorld.SendWorldText(LANG_RESETALL_TALENTS); - } - else - { - PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE,args); - SetSentErrorMessage(true); - return false; - } - - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u'",atLogin); - HashMapHolder::MapType const& plist = ObjectAccessor::Instance().GetPlayers(); - for(HashMapHolder::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr) - itr->second->SetAtLoginFlag(atLogin); - - return true; -} - -bool ChatHandler::HandleShutDownCommand(const char* args) -{ - if(!*args) - return false; - - if(std::string(args)=="cancel") - { - sWorld.ShutdownCancel(); - } - else - { - int32 time = atoi(args); - - ///- Prevent interpret wrong arg value as 0 secs shutdown time - if(time == 0 && (args[0]!='0' || args[1]!='\0') || time < 0) - return false; - - sWorld.ShutdownServ(time); - } - return true; -} - -bool ChatHandler::HandleRestartCommand(const char* args) -{ - if(!*args) - return false; - - if(std::string(args)=="cancel") - { - sWorld.ShutdownCancel(); - } - else - { - int32 time = atoi(args); - - ///- Prevent interpret wrong arg value as 0 secs shutdown time - if(time == 0 && (args[0]!='0' || args[1]!='\0') || time < 0) - return false; - - sWorld.ShutdownServ(time, SHUTDOWN_MASK_RESTART); - } - return true; -} - -bool ChatHandler::HandleIdleRestartCommand(const char* args) -{ - if(!*args) - return false; - - if(std::string(args)=="cancel") - { - sWorld.ShutdownCancel(); - } - else - { - int32 time = atoi(args); - - ///- Prevent interpret wrong arg value as 0 secs shutdown time - if(time == 0 && (args[0]!='0' || args[1]!='\0') || time < 0) - return false; - - sWorld.ShutdownServ(time,SHUTDOWN_MASK_RESTART+SHUTDOWN_MASK_IDLE); - } - return true; -} - -bool ChatHandler::HandleIdleShutDownCommand(const char* args) -{ - if(!*args) - return false; - - if(std::string(args)=="cancel") - { - sWorld.ShutdownCancel(); - } - else - { - int32 time = atoi(args); - - ///- Prevent interpret wrong arg value as 0 secs shutdown time - if(time == 0 && (args[0]!='0' || args[1]!='\0') || time < 0) - return false; - - sWorld.ShutdownServ(time,SHUTDOWN_MASK_IDLE); - } - return true; -} - -bool ChatHandler::HandleAddQuest(const char* args) -{ - Player* player = getSelectedPlayer(); - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // .addquest #entry' - // number or [name] Shift-click form |color|Hquest:quest_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hquest"); - if(!cId) - return false; - - uint32 entry = atol(cId); - - Quest const* pQuest = objmgr.GetQuestTemplate(entry); - - if(!pQuest) - { - PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND,entry); - SetSentErrorMessage(true); - return false; - } - - // check item starting quest (it can work incorrectly if added without item in inventory) - QueryResult *result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE startquest = '%u' LIMIT 1",entry); - if(result) - { - Field* fields = result->Fetch(); - uint32 item_id = fields[0].GetUInt32(); - delete result; - - PSendSysMessage(LANG_COMMAND_QUEST_STARTFROMITEM, entry,item_id); - SetSentErrorMessage(true); - return false; - } - - // ok, normal (creature/GO starting) quest - if( player->CanAddQuest( pQuest, true ) ) - { - player->AddQuest( pQuest, NULL ); - - if ( player->CanCompleteQuest( entry ) ) - player->CompleteQuest( entry ); - } - - return true; -} - -bool ChatHandler::HandleRemoveQuest(const char* args) -{ - Player* player = getSelectedPlayer(); - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // .removequest #entry' - // number or [name] Shift-click form |color|Hquest:quest_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hquest"); - if(!cId) - return false; - - uint32 entry = atol(cId); - - Quest const* pQuest = objmgr.GetQuestTemplate(entry); - - if(!pQuest) - { - PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); - SetSentErrorMessage(true); - return false; - } - - // remove all quest entries for 'entry' from quest log - for(uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot ) - { - uint32 quest = player->GetQuestSlotQuestId(slot); - if(quest==entry) - { - player->SetQuestSlot(slot,0); - - // we ignore unequippable quest items in this case, its' still be equipped - player->TakeQuestSourceItem( quest, false ); - } - } - - // set quest status to not started (will updated in DB at next save) - player->SetQuestStatus( entry, QUEST_STATUS_NONE); - - // reset rewarded for restart repeatable quest - player->getQuestStatusMap()[entry].m_rewarded = false; - - SendSysMessage(LANG_COMMAND_QUEST_REMOVED); - return true; -} - -bool ChatHandler::HandleCompleteQuest(const char* args) -{ - Player* player = getSelectedPlayer(); - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // .quest complete #entry - // number or [name] Shift-click form |color|Hquest:quest_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hquest"); - if(!cId) - return false; - - uint32 entry = atol(cId); - - Quest const* pQuest = objmgr.GetQuestTemplate(entry); - - // If player doesn't have the quest - if(!pQuest || player->GetQuestStatus(entry) == QUEST_STATUS_NONE) - { - PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); - SetSentErrorMessage(true); - return false; - } - - // Add quest items for quests that require items - for(uint8 x = 0; x < QUEST_OBJECTIVES_COUNT; ++x) - { - uint32 id = pQuest->ReqItemId[x]; - uint32 count = pQuest->ReqItemCount[x]; - if(!id || !count) - continue; - - uint32 curItemCount = player->GetItemCount(id,true); - - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, id, count-curItemCount ); - if( msg == EQUIP_ERR_OK ) - { - Item* item = player->StoreNewItem( dest, id, true); - player->SendNewItem(item,count-curItemCount,true,false); - } - } - - // All creature/GO slain/casted (not required, but otherwise it will display "Creature slain 0/10") - for(uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - { - uint32 creature = pQuest->ReqCreatureOrGOId[i]; - uint32 creaturecount = pQuest->ReqCreatureOrGOCount[i]; - - if(uint32 spell_id = pQuest->ReqSpell[i]) - { - for(uint16 z = 0; z < creaturecount; ++z) - player->CastedCreatureOrGO(creature,0,spell_id); - } - else if(creature > 0) - { - for(uint16 z = 0; z < creaturecount; ++z) - player->KilledMonster(creature,0); - } - else if(creature < 0) - { - for(uint16 z = 0; z < creaturecount; ++z) - player->CastedCreatureOrGO(creature,0,0); - } - } - - // If the quest requires reputation to complete - if(uint32 repFaction = pQuest->GetRepObjectiveFaction()) - { - uint32 repValue = pQuest->GetRepObjectiveValue(); - uint32 curRep = player->GetReputation(repFaction); - if(curRep < repValue) - { - FactionEntry const *factionEntry = sFactionStore.LookupEntry(repFaction); - player->SetFactionReputation(factionEntry,repValue); - } - } - - // If the quest requires money - int32 ReqOrRewMoney = pQuest->GetRewOrReqMoney(); - if(ReqOrRewMoney < 0) - player->ModifyMoney(-ReqOrRewMoney); - - player->CompleteQuest(entry); - return true; -} - -bool ChatHandler::HandleBanCommand(const char* args) -{ - if(!args) - return false; - - char* type = strtok((char*)args, " "); - - if(!type) - return false; - char* nameOrIP = strtok(NULL, " "); - - if(!nameOrIP) - return false; - - char* duration = strtok(NULL," "); - if(!duration || !atoi(duration)) - return false; - - char* reason = strtok(NULL,""); - if(!reason) - return false; - - switch(sWorld.BanAccount(type, nameOrIP, duration, reason,m_session->GetPlayerName())) - { - case BAN_SUCCESS: - if(atoi(duration)>0) - PSendSysMessage(LANG_BAN_YOUBANNED,nameOrIP,secsToTimeString(TimeStringToSecs(duration),true).c_str(),reason); - else - PSendSysMessage(LANG_BAN_YOUPERMBANNED,nameOrIP,reason); - break; - case BAN_SYNTAX_ERROR: - return false; - case BAN_NOTFOUND: - PSendSysMessage(LANG_BAN_NOTFOUND,type,nameOrIP); - break; - } - - return true; -} - -bool ChatHandler::HandleUnBanCommand(const char* args) -{ - if(!args) - return false; - char* type = strtok((char*)args, " "); - if(!type) - return false; - char* nameOrIP = strtok(NULL, " "); - - if(!nameOrIP) - return false; - - if(sWorld.RemoveBanAccount(type,nameOrIP)) - PSendSysMessage(LANG_UNBAN_UNBANNED,nameOrIP); - else - PSendSysMessage(LANG_UNBAN_ERROR,nameOrIP); - - return true; -} - -bool ChatHandler::HandleBanInfoCommand(const char* args) -{ - if(!args) - return false; - - char* cType = strtok((char*)args, " "); - char* cnameOrIP = strtok(NULL, ""); - if(!cType || !cnameOrIP) - return false; - - std::string nameOrIP = cnameOrIP; - std::string type = cType; - if (!IsIPAddress(cnameOrIP) && type=="ip") - return false; - - Field *fields; - if(type != "ip") - { - //look the accountid up - uint32 accountid; - std::string accountname; - if(type == "account") - { - loginDatabase.escape_string(nameOrIP); - QueryResult *result = loginDatabase.PQuery("SELECT id, username FROM account WHERE username = '%s'",nameOrIP.c_str()); - if (!result) - { - PSendSysMessage(LANG_BANINFO_NOACCOUNT); - return true; - } - fields = result->Fetch(); - accountid = fields[0].GetUInt32(); - accountname = fields[1].GetCppString(); - delete result; - } - else if(type == "character") - { - if(!normalizePlayerName(nameOrIP)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - loginDatabase.escape_string(nameOrIP); - QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'", nameOrIP.c_str()); - if (!result) - { - PSendSysMessage(LANG_BANINFO_NOCHARACTER); - return true; - } - fields = result->Fetch(); - accountid = fields[0].GetUInt32(); - delete result; - result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", accountid); - if (!result) - { - PSendSysMessage(LANG_BANINFO_NOCHARACTER); - return true; - } - fields = result->Fetch(); - accountname = fields[0].GetCppString(); - delete result; - } - else - return false; - - QueryResult *result = loginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid); - if(!result) - { - PSendSysMessage(LANG_BANINFO_NOACCOUNTBAN, accountname.c_str()); - return true; - } - - PSendSysMessage(LANG_BANINFO_BANHISTORY,accountname.c_str()); - do - { - fields = result->Fetch(); - - time_t unbandate = time_t(fields[3].GetUInt64()); - bool active = false; - if(fields[2].GetBool() && (fields[1].GetUInt64() == (uint64)0 ||unbandate >= time(NULL)) ) - active = true; - bool permanent = (fields[1].GetUInt64() == (uint64)0); - std::string bantime = permanent?GetMangosString(LANG_BANINFO_INFINITE):secsToTimeString(fields[1].GetUInt64(), true); - PSendSysMessage(LANG_BANINFO_HISTORYENTRY, - fields[0].GetString(), bantime.c_str(), active ? GetMangosString(LANG_BANINFO_YES):GetMangosString(LANG_BANINFO_NO), fields[4].GetString(), fields[5].GetString()); - }while (result->NextRow()); - - delete result; - } - else - { - loginDatabase.escape_string(nameOrIP); - QueryResult *result = loginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str()); - if(!result) - { - PSendSysMessage(LANG_BANINFO_NOIP); - return true; - } - fields = result->Fetch(); - bool permanent = (fields[6].GetUInt64()==(uint64)0); - PSendSysMessage(LANG_BANINFO_IPENTRY, - fields[0].GetString(), fields[1].GetString(), permanent ? GetMangosString(LANG_BANINFO_NEVER):fields[2].GetString(), - permanent ? GetMangosString(LANG_BANINFO_INFINITE):secsToTimeString(fields[3].GetUInt64(), true).c_str(), fields[4].GetString(), fields[5].GetString()); - delete result; - } - return true; -} - -bool ChatHandler::HandleBanListCommand(const char* args) -{ - loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); - if(!*args) - return false; - char* cType = strtok((char*)args, " "); - char* cFilter = strtok(NULL, ""); - if(!cType || !cFilter) - return false; - std::string Filter = cFilter; - std::string Type = cType; - loginDatabase.escape_string(Filter); - - QueryResult* result = NULL; - Field *fields = NULL; - if(Type == "ip") - { - result = loginDatabase.PQuery("SELECT ip FROM ip_banned WHERE ip "_LIKE_" '""%%%s%%""'",Filter.c_str()); - if(!result) - { - PSendSysMessage(LANG_BANLIST_NOIP); - return true; - } - PSendSysMessage(LANG_BANLIST_MATCHINGIP); - do - { - fields = result->Fetch(); - PSendSysMessage("%s",fields[0].GetString()); - } while (result->NextRow()); - - delete result; - return true; - } - //lookup accountid - if(Type == "account") - { - result = loginDatabase.PQuery("SELECT id FROM account WHERE username "_LIKE_" '""%%%s%%""' ",Filter.c_str()); - if (!result) - { - PSendSysMessage(LANG_BANLIST_NOACCOUNT); - return true; - } - //do not delete result - } - else if(Type == "characters") - { - result = CharacterDatabase.PQuery("SELECT account FROM characters, WHERE name "_LIKE_" '""%%%s%%""' ",Filter.c_str()); - if (!result) - { - PSendSysMessage(LANG_BANLIST_NOCHARACTER); - return true; - } - } - else - return false; - - PSendSysMessage(LANG_BANLIST_MATCHINGACCOUNT); - do - { - fields = result->Fetch(); - uint32 accountid = fields[0].GetUInt32(); - QueryResult* banresult = loginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.active = '1' AND account_banned.id=account.id",accountid); - if(banresult) - { - Field* fields2 = banresult->Fetch(); - PSendSysMessage("%s",fields2[0].GetString()); - delete banresult; - } - } while (result->NextRow()); - - delete result; - return true; -} - -bool ChatHandler::HandleRespawnCommand(const char* /*args*/) -{ - Player* pl = m_session->GetPlayer(); - - CellPair p(MaNGOS::ComputeCellPair(pl->GetPositionX(), pl->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::RespawnDo u_do; - MaNGOS::WorldObjectWorker worker(u_do); - - TypeContainerVisitor, GridTypeMapContainer > obj_worker(worker); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, obj_worker, *MapManager::Instance().GetMap(pl->GetMapId(), pl)); - - return true; -} - -bool ChatHandler::HandleFlyModeCommand(const char* args) -{ - if(!args) - return false; - - Unit *unit = getSelectedUnit(); - if (!unit || (unit->GetTypeId() != TYPEID_PLAYER)) - unit = m_session->GetPlayer(); - - WorldPacket data(12); - if (strncmp(args, "on", 3) == 0) - data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); - else if (strncmp(args, "off", 4) == 0) - data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); - else - { - SendSysMessage(LANG_USE_BOL); - return false; - } - data.append(unit->GetPackGUID()); - data << uint32(0); // unknown - unit->SendMessageToSet(&data, true); - PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, unit->GetName(), args); - return true; -} - -bool ChatHandler::HandleLoadPDumpCommand(const char *args) -{ - if(!args) - return false; - - char * file = strtok((char*)args, " "); if(!file) return false; - char * acc = strtok(NULL, " "); if(!acc) return false; - if(!file || !acc) - return false; - - uint32 account_id = objmgr.GetAccountByAccountName(acc); - if(!account_id) - { - account_id = atoi(acc); - if(account_id) - { - std::string acc_name; - if(!objmgr.GetAccountNameByAccount(account_id,acc_name)) - return false; - } - else - return false; - } - - char * name = strtok(NULL, " "); - char * guid_str = name ? strtok(NULL, " ") : NULL; - - uint32 guid = guid_str ? atoi(guid_str) : 0; - - if(PlayerDumpReader().LoadDump(file, account_id, name ? name : "", guid)) - PSendSysMessage(LANG_COMMAND_IMPORT_SUCCESS); - else - PSendSysMessage(LANG_COMMAND_IMPORT_FAILED); - - return true; -} - -bool ChatHandler::HandleChangeEntryCommand(const char *args) -{ - if(!args) - return false; - - uint32 newEntryNum = atoi(args); - if(!newEntryNum) - return false; - - Unit* unit = getSelectedUnit(); - if(!unit || unit->GetTypeId() != TYPEID_UNIT) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - Creature* creature = (Creature*)unit; - if(creature->UpdateEntry(newEntryNum)) - SendSysMessage(LANG_DONE); - else - SendSysMessage(LANG_ERROR); - return true; -} - -bool ChatHandler::HandleWritePDumpCommand(const char *args) -{ - if(!args) - return false; - - char* file = strtok((char*)args, " "); - char* p2 = strtok(NULL, " "); - - if(!file || !p2) - return false; - - uint32 guid = objmgr.GetPlayerGUIDByName(p2); - if(!guid) - guid = atoi(p2); - - if (PlayerDumpWriter().WriteDump(file, guid)) - PSendSysMessage(LANG_COMMAND_EXPORT_SUCCESS); - else - PSendSysMessage(LANG_COMMAND_EXPORT_FAILED); - - return true; -} - -bool ChatHandler::HandleMovegensCommand(const char* /*args*/) -{ - Unit* unit = getSelectedUnit(); - if(!unit) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_MOVEGENS_LIST,(unit->GetTypeId()==TYPEID_PLAYER ? "Player" : "Creature" ),unit->GetGUIDLow()); - - MotionMaster* mm = unit->GetMotionMaster(); - for(MotionMaster::const_iterator itr = mm->begin(); itr != mm->end(); ++itr) - { - switch((*itr)->GetMovementGeneratorType()) - { - case IDLE_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_IDLE); break; - case RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_RANDOM); break; - case WAYPOINT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_WAYPOINT); break; - case ANIMAL_RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_ANIMAL_RANDOM); break; - case CONFUSED_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_CONFUSED); break; - case TARGETED_MOTION_TYPE: - { - if(unit->GetTypeId()==TYPEID_PLAYER) - { - TargetedMovementGenerator const* mgen = static_cast const*>(*itr); - Unit* target = mgen->GetTarget(); - if(target) - PSendSysMessage(LANG_MOVEGENS_TARGETED_PLAYER,target->GetName(),target->GetGUIDLow()); - else - SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); - } - else - { - TargetedMovementGenerator const* mgen = static_cast const*>(*itr); - Unit* target = mgen->GetTarget(); - if(target) - PSendSysMessage(LANG_MOVEGENS_TARGETED_CREATURE,target->GetName(),target->GetGUIDLow()); - else - SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); - } - break; - } - case HOME_MOTION_TYPE: - if(unit->GetTypeId()==TYPEID_UNIT) - { - float x,y,z; - (*itr)->GetDestination(x,y,z); - PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE,x,y,z); - } - else - SendSysMessage(LANG_MOVEGENS_HOME_PLAYER); - break; - case FLIGHT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FLIGHT); break; - case POINT_MOTION_TYPE: - { - float x,y,z; - (*itr)->GetDestination(x,y,z); - PSendSysMessage(LANG_MOVEGENS_POINT,x,y,z); - break; - } - case FLEEING_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FEAR); break; - case DISTRACT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_DISTRACT); break; - default: - PSendSysMessage(LANG_MOVEGENS_UNKNOWN,(*itr)->GetMovementGeneratorType()); - break; - } - } - return true; -} - -bool ChatHandler::HandlePLimitCommand(const char *args) -{ - if(*args) - { - char* param = strtok((char*)args, " "); - if(!param) - return false; - - int l = strlen(param); - - if( strncmp(param,"player",l) == 0 ) - sWorld.SetPlayerLimit(-SEC_PLAYER); - else if(strncmp(param,"moderator",l) == 0 ) - sWorld.SetPlayerLimit(-SEC_MODERATOR); - else if(strncmp(param,"gamemaster",l) == 0 ) - sWorld.SetPlayerLimit(-SEC_GAMEMASTER); - else if(strncmp(param,"administrator",l) == 0 ) - sWorld.SetPlayerLimit(-SEC_ADMINISTRATOR); - else if(strncmp(param,"reset",l) == 0 ) - sWorld.SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT) ); - else - { - int val = atoi(param); - if(val < -SEC_ADMINISTRATOR) val = -SEC_ADMINISTRATOR; - - sWorld.SetPlayerLimit(val); - } - - // kick all low security level players - if(sWorld.GetPlayerAmountLimit() > SEC_PLAYER) - sWorld.KickAllLess(sWorld.GetPlayerSecurityLimit()); - } - - uint32 pLimit = sWorld.GetPlayerAmountLimit(); - AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); - char const* secName = ""; - switch(allowedAccountType) - { - case SEC_PLAYER: secName = "Player"; break; - case SEC_MODERATOR: secName = "Moderator"; break; - case SEC_GAMEMASTER: secName = "Gamemaster"; break; - case SEC_ADMINISTRATOR: secName = "Administrator"; break; - default: secName = ""; break; - } - - PSendSysMessage("Player limits: amount %u, min. security level %s.",pLimit,secName); - - return true; -} - -bool ChatHandler::HandleCastCommand(const char* args) -{ - if(!*args) - return false; - - Unit* target = getSelectedUnit(); - - if(!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if(!spell) - return false; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if(!spellInfo) - return false; - - if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - SetSentErrorMessage(true); - return false; - } - - char* trig_str = strtok(NULL, " "); - if(trig_str) - { - int l = strlen(trig_str); - if(strncmp(trig_str,"triggered",l) != 0 ) - return false; - } - - bool triggered = (trig_str != NULL); - - m_session->GetPlayer()->CastSpell(target,spell,triggered); - - return true; -} - -bool ChatHandler::HandleCastBackCommand(const char* args) -{ - Creature* caster = getSelectedCreature(); - - if(!caster) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if(!spell || !sSpellStore.LookupEntry(spell)) - return false; - - char* trig_str = strtok(NULL, " "); - if(trig_str) - { - int l = strlen(trig_str); - if(strncmp(trig_str,"triggered",l) != 0 ) - return false; - } - - bool triggered = (trig_str != NULL); - - // update orientation at server - caster->SetOrientation(caster->GetAngle(m_session->GetPlayer())); - - // and client - WorldPacket data; - caster->BuildHeartBeatMsg(&data); - caster->SendMessageToSet(&data,true); - - caster->CastSpell(m_session->GetPlayer(),spell,false); - - return true; -} - -bool ChatHandler::HandleCastDistCommand(const char* args) -{ - if(!*args) - return false; - - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if(!spell) - return false; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if(!spellInfo) - return false; - - if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - SetSentErrorMessage(true); - return false; - } - - char *distStr = strtok(NULL, " "); - - float dist = 0; - - if(distStr) - sscanf(distStr, "%f", &dist); - - char* trig_str = strtok(NULL, " "); - if(trig_str) - { - int l = strlen(trig_str); - if(strncmp(trig_str,"triggered",l) != 0 ) - return false; - } - - bool triggered = (trig_str != NULL); - - float x,y,z; - m_session->GetPlayer()->GetClosePoint(x,y,z,dist); - - m_session->GetPlayer()->CastSpell(x,y,z,spell,triggered); - return true; -} - -bool ChatHandler::HandleCastTargetCommand(const char* args) -{ - Creature* caster = getSelectedCreature(); - - if(!caster) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if(!caster->getVictim()) - { - SendSysMessage(LANG_SELECTED_TARGET_NOT_HAVE_VICTIM); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if(!spell || !sSpellStore.LookupEntry(spell)) - return false; - - char* trig_str = strtok(NULL, " "); - if(trig_str) - { - int l = strlen(trig_str); - if(strncmp(trig_str,"triggered",l) != 0 ) - return false; - } - - bool triggered = (trig_str != NULL); - - // update orientation at server - caster->SetOrientation(caster->GetAngle(m_session->GetPlayer())); - - // and client - WorldPacket data; - caster->BuildHeartBeatMsg(&data); - caster->SendMessageToSet(&data,true); - - caster->CastSpell(caster->getVictim(),spell,false); - - return true; -} - -/* -ComeToMe command REQUIRED for 3rd party scripting library to have access to PointMovementGenerator -Without this function 3rd party scripting library will get linking errors (unresolved external) -when attempting to use the PointMovementGenerator -*/ -bool ChatHandler::HandleComeToMeCommand(const char *args) -{ - Creature* caster = getSelectedCreature(); - - if(!caster) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - char* newFlagStr = strtok((char*)args, " "); - - if(!newFlagStr) - return false; - - uint32 newFlags = atoi(newFlagStr); - - caster->SetUnitMovementFlags(newFlags); - - Player* pl = m_session->GetPlayer(); - - caster->GetMotionMaster()->MovePoint(0, pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ()); - return true; -} - -bool ChatHandler::HandleCastSelfCommand(const char* args) -{ - if(!*args) - return false; - - Unit* target = getSelectedUnit(); - - if(!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if(!spell) - return false; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if(!spellInfo) - return false; - - if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - SetSentErrorMessage(true); - return false; - } - - target->CastSpell(target,spell,false); - - return true; -} - -std::string GetTimeString(uint32 time) -{ - uint16 days = time / DAY, hours = (time % DAY) / HOUR, minute = (time % HOUR) / MINUTE; - std::ostringstream ss; - if(days) ss << days << "d "; - if(hours) ss << hours << "h "; - ss << minute << "m"; - return ss.str(); -} - -bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) -{ - Player* player = getSelectedPlayer(); - if (!player) player = m_session->GetPlayer(); - uint32 counter = 0; - for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) - { - Player::BoundInstancesMap &binds = player->GetBoundInstances(i); - for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end(); ++itr) - { - InstanceSave *save = itr->second.save; - std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); - counter++; - } - } - PSendSysMessage("player binds: %d", counter); - counter = 0; - Group *group = player->GetGroup(); - if(group) - { - for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) - { - Group::BoundInstancesMap &binds = group->GetBoundInstances(i); - for(Group::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end(); ++itr) - { - InstanceSave *save = itr->second.save; - std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); - counter++; - } - } - } - PSendSysMessage("group binds: %d", counter); - - return true; -} - -bool ChatHandler::HandleInstanceUnbindCommand(const char* args) -{ - if(!*args) - return false; - - std::string cmd = args; - if(cmd == "all") - { - Player* player = getSelectedPlayer(); - if (!player) player = m_session->GetPlayer(); - uint32 counter = 0; - for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) - { - Player::BoundInstancesMap &binds = player->GetBoundInstances(i); - for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();) - { - if(itr->first != player->GetMapId()) - { - InstanceSave *save = itr->second.save; - std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("unbinding map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); - player->UnbindInstance(itr, i); - counter++; - } - else - ++itr; - } - } - PSendSysMessage("instances unbound: %d", counter); - } - return true; -} - -bool ChatHandler::HandleInstanceStatsCommand(const char* /*args*/) -{ - PSendSysMessage("instances loaded: %d", MapManager::Instance().GetNumInstances()); - PSendSysMessage("players in instances: %d", MapManager::Instance().GetNumPlayersInInstances()); - PSendSysMessage("instance saves: %d", sInstanceSaveManager.GetNumInstanceSaves()); - PSendSysMessage("players bound: %d", sInstanceSaveManager.GetNumBoundPlayersTotal()); - PSendSysMessage("groups bound: %d", sInstanceSaveManager.GetNumBoundGroupsTotal()); - return true; -} - -bool ChatHandler::HandleInstanceSaveDataCommand(const char * /*args*/) -{ - Player* pl = m_session->GetPlayer(); - - Map* map = pl->GetMap(); - if (!map->IsDungeon()) - { - PSendSysMessage("Map is not a dungeon."); - SetSentErrorMessage(true); - return false; - } - - if (!((InstanceMap*)map)->GetInstanceData()) - { - PSendSysMessage("Map has no instance data."); - SetSentErrorMessage(true); - return false; - } - - ((InstanceMap*)map)->GetInstanceData()->SaveToDB(); - return true; -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "PlayerDump.h" +#include "SpellMgr.h" +#include "Player.h" +#include "Opcodes.h" +#include "GameObject.h" +#include "Chat.h" +#include "Log.h" +#include "Guild.h" +#include "ObjectAccessor.h" +#include "MapManager.h" +#include "SpellAuras.h" +#include "ScriptCalls.h" +#include "Language.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "Weather.h" +#include "PointMovementGenerator.h" +#include "TargetedMovementGenerator.h" +#include "SkillDiscovery.h" +#include "SkillExtraItems.h" +#include "SystemConfig.h" +#include "Config/ConfigEnv.h" +#include "Util.h" +#include "ItemEnchantmentMgr.h" +#include "InstanceSaveMgr.h" +#include "InstanceData.h" + +//reload commands +bool ChatHandler::HandleReloadCommand(const char* arg) +{ + // this is error catcher for wrong table name in .reload commands + PSendSysMessage("Db table with name starting from '%s' not found and can't be reloaded.",arg); + SetSentErrorMessage(true); + return false; +} + +bool ChatHandler::HandleReloadAllCommand(const char*) +{ + HandleReloadAreaTriggerTeleportCommand(""); + HandleReloadSkillFishingBaseLevelCommand(""); + + HandleReloadAllAreaCommand(""); + HandleReloadAllLootCommand(""); + HandleReloadAllNpcCommand(""); + HandleReloadAllQuestCommand(""); + HandleReloadAllSpellCommand(""); + HandleReloadAllItemCommand(""); + + HandleReloadCommandCommand(""); + HandleReloadReservedNameCommand(""); + HandleReloadMangosStringCommand(""); + HandleReloadGameTeleCommand(""); + return true; +} + +bool ChatHandler::HandleReloadAllAreaCommand(const char*) +{ + //HandleReloadQuestAreaTriggersCommand(""); -- reloaded in HandleReloadAllQuestCommand + HandleReloadAreaTriggerTeleportCommand(""); + HandleReloadAreaTriggerTavernCommand(""); + HandleReloadGameGraveyardZoneCommand(""); + return true; +} + +bool ChatHandler::HandleReloadAllLootCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables..." ); + LoadLootTables(); + SendGlobalSysMessage("DB tables `*_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/) +{ + HandleReloadNpcGossipCommand("a"); + HandleReloadNpcTrainerCommand("a"); + HandleReloadNpcVendorCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadAllQuestCommand(const char* /*args*/) +{ + HandleReloadQuestAreaTriggersCommand("a"); + HandleReloadQuestTemplateCommand("a"); + + sLog.outString( "Re-Loading Quests Relations..." ); + objmgr.LoadQuestRelations(); + SendGlobalSysMessage("DB tables `*_questrelation` and `*_involvedrelation` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAllScriptsCommand(const char*) +{ + if(sWorld.IsScriptScheduled()) + { + PSendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + sLog.outString( "Re-Loading Scripts..." ); + HandleReloadGameObjectScriptsCommand("a"); + HandleReloadEventScriptsCommand("a"); + HandleReloadQuestEndScriptsCommand("a"); + HandleReloadQuestStartScriptsCommand("a"); + HandleReloadSpellScriptsCommand("a"); + SendGlobalSysMessage("DB tables `*_scripts` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAllSpellCommand(const char*) +{ + HandleReloadSkillDiscoveryTemplateCommand("a"); + HandleReloadSkillExtraItemTemplateCommand("a"); + HandleReloadSpellAffectCommand("a"); + HandleReloadSpellChainCommand("a"); + HandleReloadSpellElixirCommand("a"); + HandleReloadSpellLearnSpellCommand("a"); + HandleReloadSpellProcEventCommand("a"); + HandleReloadSpellScriptTargetCommand("a"); + HandleReloadSpellTargetPositionCommand("a"); + HandleReloadSpellThreatsCommand("a"); + HandleReloadSpellPetAurasCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadAllItemCommand(const char*) +{ + HandleReloadPageTextsCommand("a"); + HandleReloadItemEnchantementsCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadConfigCommand(const char* arg) +{ + sLog.outString( "Re-Loading config settings..." ); + sWorld.LoadConfigSettings(true); + SendGlobalSysMessage("World config settings reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAreaTriggerTavernCommand(const char*) +{ + sLog.outString( "Re-Loading Tavern Area Triggers..." ); + objmgr.LoadTavernAreaTriggers(); + SendGlobalSysMessage("DB table `areatrigger_tavern` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAreaTriggerTeleportCommand(const char*) +{ + sLog.outString( "Re-Loading AreaTrigger teleport definitions..." ); + objmgr.LoadAreaTriggerTeleports(); + SendGlobalSysMessage("DB table `areatrigger_teleport` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadCommandCommand(const char*) +{ + load_command_table = true; + SendGlobalSysMessage("DB table `command` will be reloaded at next chat command use."); + return true; +} + +bool ChatHandler::HandleReloadCreatureQuestRelationsCommand(const char*) +{ + sLog.outString( "Loading Quests Relations... (`creature_questrelation`)" ); + objmgr.LoadCreatureQuestRelations(); + SendGlobalSysMessage("DB table `creature_questrelation` (creature quest givers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadCreatureQuestInvRelationsCommand(const char*) +{ + sLog.outString( "Loading Quests Relations... (`creature_involvedrelation`)" ); + objmgr.LoadCreatureInvolvedRelations(); + SendGlobalSysMessage("DB table `creature_involvedrelation` (creature quest takers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadGOQuestRelationsCommand(const char*) +{ + sLog.outString( "Loading Quests Relations... (`gameobject_questrelation`)" ); + objmgr.LoadGameobjectQuestRelations(); + SendGlobalSysMessage("DB table `gameobject_questrelation` (gameobject quest givers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadGOQuestInvRelationsCommand(const char*) +{ + sLog.outString( "Loading Quests Relations... (`gameobject_involvedrelation`)" ); + objmgr.LoadGameobjectInvolvedRelations(); + SendGlobalSysMessage("DB table `gameobject_involvedrelation` (gameobject quest takers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadQuestAreaTriggersCommand(const char*) +{ + sLog.outString( "Re-Loading Quest Area Triggers..." ); + objmgr.LoadQuestAreaTriggers(); + SendGlobalSysMessage("DB table `areatrigger_involvedrelation` (quest area triggers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadQuestTemplateCommand(const char*) +{ + sLog.outString( "Re-Loading Quest Templates..." ); + objmgr.LoadQuests(); + SendGlobalSysMessage("DB table `quest_template` (quest definitions) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesCreatureCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`creature_loot_template`)" ); + LoadLootTemplates_Creature(); + LootTemplates_Creature.CheckLootRefs(); + SendGlobalSysMessage("DB table `creature_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesDisenchantCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`disenchant_loot_template`)" ); + LoadLootTemplates_Disenchant(); + LootTemplates_Disenchant.CheckLootRefs(); + SendGlobalSysMessage("DB table `disenchant_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesFishingCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`fishing_loot_template`)" ); + LoadLootTemplates_Fishing(); + LootTemplates_Fishing.CheckLootRefs(); + SendGlobalSysMessage("DB table `fishing_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesGameobjectCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`gameobject_loot_template`)" ); + LoadLootTemplates_Gameobject(); + LootTemplates_Gameobject.CheckLootRefs(); + SendGlobalSysMessage("DB table `gameobject_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesItemCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`item_loot_template`)" ); + LoadLootTemplates_Item(); + LootTemplates_Item.CheckLootRefs(); + SendGlobalSysMessage("DB table `item_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesPickpocketingCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`pickpocketing_loot_template`)" ); + LoadLootTemplates_Pickpocketing(); + LootTemplates_Pickpocketing.CheckLootRefs(); + SendGlobalSysMessage("DB table `pickpocketing_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesProspectingCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`prospecting_loot_template`)" ); + LoadLootTemplates_Prospecting(); + LootTemplates_Prospecting.CheckLootRefs(); + SendGlobalSysMessage("DB table `prospecting_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesQuestMailCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`quest_mail_loot_template`)" ); + LoadLootTemplates_QuestMail(); + LootTemplates_QuestMail.CheckLootRefs(); + SendGlobalSysMessage("DB table `quest_mail_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesReferenceCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`reference_loot_template`)" ); + LoadLootTemplates_Reference(); + SendGlobalSysMessage("DB table `reference_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesSkinningCommand(const char*) +{ + sLog.outString( "Re-Loading Loot Tables... (`skinning_loot_template`)" ); + LoadLootTemplates_Skinning(); + LootTemplates_Skinning.CheckLootRefs(); + SendGlobalSysMessage("DB table `skinning_loot_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadMangosStringCommand(const char*) +{ + sLog.outString( "Re-Loading mangos_string Table!" ); + objmgr.LoadMangosStrings(); + SendGlobalSysMessage("DB table `mangos_string` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadNpcGossipCommand(const char*) +{ + sLog.outString( "Re-Loading `npc_gossip` Table!" ); + objmgr.LoadNpcTextId(); + SendGlobalSysMessage("DB table `npc_gossip` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadNpcTrainerCommand(const char*) +{ + sLog.outString( "Re-Loading `npc_trainer` Table!" ); + objmgr.LoadTrainerSpell(); + SendGlobalSysMessage("DB table `npc_trainer` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadNpcVendorCommand(const char*) +{ + sLog.outString( "Re-Loading `npc_vendor` Table!" ); + objmgr.LoadVendors(); + SendGlobalSysMessage("DB table `npc_vendor` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadReservedNameCommand(const char*) +{ + sLog.outString( "Loading ReservedNames... (`reserved_name`)" ); + objmgr.LoadReservedPlayersNames(); + SendGlobalSysMessage("DB table `reserved_name` (player reserved names) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSkillDiscoveryTemplateCommand(const char* /*args*/) +{ + sLog.outString( "Re-Loading Skill Discovery Table..." ); + LoadSkillDiscoveryTable(); + SendGlobalSysMessage("DB table `skill_discovery_template` (recipes discovered at crafting) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSkillExtraItemTemplateCommand(const char* /*args*/) +{ + sLog.outString( "Re-Loading Skill Extra Item Table..." ); + LoadSkillExtraItemTable(); + SendGlobalSysMessage("DB table `skill_extra_item_template` (extra item creation when crafting) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSkillFishingBaseLevelCommand(const char* /*args*/) +{ + sLog.outString( "Re-Loading Skill Fishing base level requirements..." ); + objmgr.LoadFishingBaseSkillLevel(); + SendGlobalSysMessage("DB table `skill_fishing_base_level` (fishing base level for zone/subzone) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellAffectCommand(const char*) +{ + sLog.outString( "Re-Loading SpellAffect definitions..." ); + spellmgr.LoadSpellAffects(); + SendGlobalSysMessage("DB table `spell_affect` (spell mods apply requirements) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellChainCommand(const char*) +{ + sLog.outString( "Re-Loading Spell Chain Data... " ); + spellmgr.LoadSpellChains(); + SendGlobalSysMessage("DB table `spell_chain` (spell ranks) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellElixirCommand(const char*) +{ + sLog.outString( "Re-Loading Spell Elixir types..." ); + spellmgr.LoadSpellElixirs(); + SendGlobalSysMessage("DB table `spell_elixir` (spell exlixir types) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellLearnSpellCommand(const char*) +{ + sLog.outString( "Re-Loading Spell Learn Spells..." ); + spellmgr.LoadSpellLearnSpells(); + SendGlobalSysMessage("DB table `spell_learn_spell` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellProcEventCommand(const char*) +{ + sLog.outString( "Re-Loading Spell Proc Event conditions..." ); + spellmgr.LoadSpellProcEvents(); + SendGlobalSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellScriptTargetCommand(const char*) +{ + sLog.outString( "Re-Loading SpellsScriptTarget..." ); + spellmgr.LoadSpellScriptTarget(); + SendGlobalSysMessage("DB table `spell_script_target` (spell targets selection in case specific creature/GO requirements) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellTargetPositionCommand(const char*) +{ + sLog.outString( "Re-Loading Spell target coordinates..." ); + spellmgr.LoadSpellTargetPositions(); + SendGlobalSysMessage("DB table `spell_target_position` (destination coordinates for spell targets) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellThreatsCommand(const char*) +{ + sLog.outString( "Re-Loading Aggro Spells Definitions..."); + spellmgr.LoadSpellThreats(); + SendGlobalSysMessage("DB table `spell_threat` (spell aggro definitions) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellPetAurasCommand(const char*) +{ + sLog.outString( "Re-Loading Spell pet auras..."); + spellmgr.LoadSpellPetAuras(); + SendGlobalSysMessage("DB table `spell_pet_auras` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadPageTextsCommand(const char*) +{ + sLog.outString( "Re-Loading Page Texts..." ); + objmgr.LoadPageTexts(); + SendGlobalSysMessage("DB table `page_texts` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadItemEnchantementsCommand(const char*) +{ + sLog.outString( "Re-Loading Item Random Enchantments Table..." ); + LoadRandomEnchantmentsTable(); + SendGlobalSysMessage("DB table `item_enchantment_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadGameObjectScriptsCommand(const char* arg) +{ + if(sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if(*arg!='a') + sLog.outString( "Re-Loading Scripts from `gameobject_scripts`..."); + + objmgr.LoadGameObjectScripts(); + + if(*arg!='a') + SendGlobalSysMessage("DB table `gameobject_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadEventScriptsCommand(const char* arg) +{ + if(sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if(*arg!='a') + sLog.outString( "Re-Loading Scripts from `event_scripts`..."); + + objmgr.LoadEventScripts(); + + if(*arg!='a') + SendGlobalSysMessage("DB table `event_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadQuestEndScriptsCommand(const char* arg) +{ + if(sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if(*arg!='a') + sLog.outString( "Re-Loading Scripts from `quest_end_scripts`..."); + + objmgr.LoadQuestEndScripts(); + + if(*arg!='a') + SendGlobalSysMessage("DB table `quest_end_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadQuestStartScriptsCommand(const char* arg) +{ + if(sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if(*arg!='a') + sLog.outString( "Re-Loading Scripts from `quest_start_scripts`..."); + + objmgr.LoadQuestStartScripts(); + + if(*arg!='a') + SendGlobalSysMessage("DB table `quest_start_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadSpellScriptsCommand(const char* arg) +{ + if(sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if(*arg!='a') + sLog.outString( "Re-Loading Scripts from `spell_scripts`..."); + + objmgr.LoadSpellScripts(); + + if(*arg!='a') + SendGlobalSysMessage("DB table `spell_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadGameGraveyardZoneCommand(const char* /*arg*/) +{ + sLog.outString( "Re-Loading Graveyard-zone links..."); + + objmgr.LoadGraveyardZones(); + + SendGlobalSysMessage("DB table `game_graveyard_zone` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadGameTeleCommand(const char* /*arg*/) +{ + sLog.outString( "Re-Loading Game Tele coordinates..."); + + objmgr.LoadGameTele(); + + SendGlobalSysMessage("DB table `game_tele` reloaded."); + + return true; +} + +bool ChatHandler::HandleLoadScriptsCommand(const char* args) +{ + if(!LoadScriptingModule(args)) return true; + + sWorld.SendWorldText(LANG_SCRIPTS_RELOADED); + return true; +} + +bool ChatHandler::HandleSecurityCommand(const char* args) +{ + char* arg1 = strtok((char*)args, " "); + if( !arg1 ) + return false; + + char* arg2 = 0; + + std::string targetName; + uint32 targetAccountId = 0; + uint32 targetSecurity = 0; + + Player* targetPlayer = getSelectedPlayer(); + if(targetPlayer) + { + targetName = targetPlayer->GetName(); + targetAccountId = targetPlayer->GetSession()->GetAccountId(); + targetSecurity = targetPlayer->GetSession()->GetSecurity(); + arg2 = arg1; + } + else + { + targetName = arg1; + if(!normalizePlayerName(targetName)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + targetPlayer = ObjectAccessor::Instance().FindPlayerByName(targetName.c_str()); + if(targetPlayer) + { + targetAccountId = targetPlayer->GetSession()->GetAccountId(); + targetSecurity = targetPlayer->GetSession()->GetSecurity(); + } + else + { + uint64 targetGUID = objmgr.GetPlayerGUIDByName(targetName.c_str()); + if(!targetGUID) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + targetAccountId = objmgr.GetPlayerAccountIdByGUID(targetGUID); + targetSecurity = objmgr.GetSecurityByAccount(targetAccountId); + } + + arg2 = strtok(NULL, " "); + } + + int32 gm = (int32)atoi(arg2); + if ( gm < SEC_PLAYER || gm > SEC_ADMINISTRATOR ) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + // can set security level only for target with less security and to less security that we have + if(targetSecurity >= m_session->GetSecurity() || uint32(gm) >= m_session->GetSecurity() ) + { + SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); + SetSentErrorMessage(true); + return false; + } + + if(targetPlayer) + { + if( targetPlayer != m_session->GetPlayer() ) + ChatHandler(targetPlayer).PSendSysMessage(LANG_YOURS_SECURITY_CHANGED,m_session->GetPlayer()->GetName(), gm); + + targetPlayer->GetSession()->SetSecurity(gm); + } + + PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetName.c_str(), gm); + loginDatabase.PExecute("UPDATE account SET gmlevel = '%i' WHERE id = '%u'", gm, targetAccountId); + + return true; +} + +bool ChatHandler::HandleAllowMovementCommand(const char* /*args*/) +{ + if(sWorld.getAllowMovement()) + { + sWorld.SetAllowMovement(false); + SendSysMessage(LANG_CREATURE_MOVE_DISABLED); + } + else + { + sWorld.SetAllowMovement(true); + SendSysMessage(LANG_CREATURE_MOVE_ENABLED); + } + return true; +} + +bool ChatHandler::HandleMaxSkillCommand(const char* /*args*/) +{ + Player* SelectedPlayer = getSelectedPlayer(); + if(!SelectedPlayer) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // each skills that have max skill value dependent from level seted to current level max skill value + SelectedPlayer->UpdateSkillsToMaxSkillsForLevel(); + return true; +} + +bool ChatHandler::HandleSetSkillCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hskill:skill_id|h[name]|h|r + char* skill_p = extractKeyFromLink((char*)args,"Hskill"); + if(!skill_p) + return false; + + char *level_p = strtok (NULL, " "); + + if( !level_p) + return false; + + char *max_p = strtok (NULL, " "); + + int32 skill = atoi(skill_p); + + if (skill <= 0) + { + PSendSysMessage(LANG_INVALID_SKILL_ID, skill); + SetSentErrorMessage(true); + return false; + } + + int32 level = atol (level_p); + + Player * target = getSelectedPlayer(); + if(!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + SkillLineEntry const* sl = sSkillLineStore.LookupEntry(skill); + if(!sl) + { + PSendSysMessage(LANG_INVALID_SKILL_ID, skill); + SetSentErrorMessage(true); + return false; + } + + if(!target->GetSkillValue(skill)) + { + PSendSysMessage(LANG_SET_SKILL_ERROR, target->GetName(), skill, sl->name[0]); + SetSentErrorMessage(true); + return false; + } + + int32 max = max_p ? atol (max_p) : target->GetPureMaxSkillValue(skill); + + if( level <= 0 || level > max || max <= 0 ) + return false; + + target->SetSkill(skill, level, max); + PSendSysMessage(LANG_SET_SKILL, skill, sl->name[0], target->GetName(), level, max); + + return true; +} + +bool ChatHandler::HandleUnLearnCommand(const char* args) +{ + if (!*args) + return false; + + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r + uint32 min_id = extractSpellIdFromLink((char*)args); + if(!min_id) + return false; + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r + char* tail = strtok(NULL,""); + + uint32 max_id = extractSpellIdFromLink(tail); + + if (!max_id) + { + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r + max_id = min_id+1; + } + else + { + if (max_id < min_id) + std::swap(min_id,max_id); + + max_id=max_id+1; + } + + Player* target = getSelectedPlayer(); + if(!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + for(uint32 spell=min_id;spellHasSpell(spell)) + target->removeSpell(spell); + else + SendSysMessage(LANG_FORGET_SPELL); + } + + return true; +} + +bool ChatHandler::HandleCooldownCommand(const char* args) +{ + Player* target = getSelectedPlayer(); + if(!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if (!*args) + { + target->RemoveAllSpellCooldown(); + PSendSysMessage(LANG_REMOVEALL_COOLDOWN, target->GetName()); + } + else + { + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell_id = extractSpellIdFromLink((char*)args); + if(!spell_id) + return false; + + if(!sSpellStore.LookupEntry(spell_id)) + { + PSendSysMessage(LANG_UNKNOWN_SPELL, target==m_session->GetPlayer() ? GetMangosString(LANG_YOU) : target->GetName()); + SetSentErrorMessage(true); + return false; + } + + WorldPacket data( SMSG_CLEAR_COOLDOWN, (4+8) ); + data << uint32(spell_id); + data << uint64(target->GetGUID()); + target->GetSession()->SendPacket(&data); + target->RemoveSpellCooldown(spell_id); + PSendSysMessage(LANG_REMOVE_COOLDOWN, spell_id, target==m_session->GetPlayer() ? GetMangosString(LANG_YOU) : target->GetName()); + } + return true; +} + +bool ChatHandler::HandleLearnAllCommand(const char* /*args*/) +{ + static const char *allSpellList[] = + { + "3365", + "6233", + "6247", + "6246", + "6477", + "6478", + "22810", + "8386", + "21651", + "21652", + "522", + "7266", + "8597", + "2479", + "22027", + "6603", + "5019", + "133", + "168", + "227", + "5009", + "9078", + "668", + "203", + "20599", + "20600", + "81", + "20597", + "20598", + "20864", + "1459", + "5504", + "587", + "5143", + "118", + "5505", + "597", + "604", + "1449", + "1460", + "2855", + "1008", + "475", + "5506", + "1463", + "12824", + "8437", + "990", + "5145", + "8450", + "1461", + "759", + "8494", + "8455", + "8438", + "6127", + "8416", + "6129", + "8451", + "8495", + "8439", + "3552", + "8417", + "10138", + "12825", + "10169", + "10156", + "10144", + "10191", + "10201", + "10211", + "10053", + "10173", + "10139", + "10145", + "10192", + "10170", + "10202", + "10054", + "10174", + "10193", + "12826", + "2136", + "143", + "145", + "2137", + "2120", + "3140", + "543", + "2138", + "2948", + "8400", + "2121", + "8444", + "8412", + "8457", + "8401", + "8422", + "8445", + "8402", + "8413", + "8458", + "8423", + "8446", + "10148", + "10197", + "10205", + "10149", + "10215", + "10223", + "10206", + "10199", + "10150", + "10216", + "10207", + "10225", + "10151", + "116", + "205", + "7300", + "122", + "837", + "10", + "7301", + "7322", + "6143", + "120", + "865", + "8406", + "6141", + "7302", + "8461", + "8407", + "8492", + "8427", + "8408", + "6131", + "7320", + "10159", + "8462", + "10185", + "10179", + "10160", + "10180", + "10219", + "10186", + "10177", + "10230", + "10181", + "10161", + "10187", + "10220", + "2018", + "2663", + "12260", + "2660", + "3115", + "3326", + "2665", + "3116", + "2738", + "3293", + "2661", + "3319", + "2662", + "9983", + "8880", + "2737", + "2739", + "7408", + "3320", + "2666", + "3323", + "3324", + "3294", + "22723", + "23219", + "23220", + "23221", + "23228", + "23338", + "10788", + "10790", + "5611", + "5016", + "5609", + "2060", + "10963", + "10964", + "10965", + "22593", + "22594", + "596", + "996", + "499", + "768", + "17002", + "1448", + "1082", + "16979", + "1079", + "5215", + "20484", + "5221", + "15590", + "17007", + "6795", + "6807", + "5487", + "1446", + "1066", + "5421", + "3139", + "779", + "6811", + "6808", + "1445", + "5216", + "1737", + "5222", + "5217", + "1432", + "6812", + "9492", + "5210", + "3030", + "1441", + "783", + "6801", + "20739", + "8944", + "9491", + "22569", + "5226", + "6786", + "1433", + "8973", + "1828", + "9495", + "9006", + "6794", + "8993", + "5203", + "16914", + "6784", + "9635", + "22830", + "20722", + "9748", + "6790", + "9753", + "9493", + "9752", + "9831", + "9825", + "9822", + "5204", + "5401", + "22831", + "6793", + "9845", + "17401", + "9882", + "9868", + "20749", + "9893", + "9899", + "9895", + "9832", + "9902", + "9909", + "22832", + "9828", + "9851", + "9883", + "9869", + "17406", + "17402", + "9914", + "20750", + "9897", + "9848", + "3127", + "107", + "204", + "9116", + "2457", + "78", + "18848", + "331", + "403", + "2098", + "1752", + "11278", + "11288", + "11284", + "6461", + "2344", + "2345", + "6463", + "2346", + "2352", + "775", + "1434", + "1612", + "71", + "2468", + "2458", + "2467", + "7164", + "7178", + "7367", + "7376", + "7381", + "21156", + "5209", + "3029", + "5201", + "9849", + "9850", + "20719", + "22568", + "22827", + "22828", + "22829", + "6809", + "8972", + "9005", + "9823", + "9827", + "6783", + "9913", + "6785", + "6787", + "9866", + "9867", + "9894", + "9896", + "6800", + "8992", + "9829", + "9830", + "780", + "769", + "6749", + "6750", + "9755", + "9754", + "9908", + "20745", + "20742", + "20747", + "20748", + "9746", + "9745", + "9880", + "9881", + "5391", + "842", + "3025", + "3031", + "3287", + "3329", + "1945", + "3559", + "4933", + "4934", + "4935", + "4936", + "5142", + "5390", + "5392", + "5404", + "5420", + "6405", + "7293", + "7965", + "8041", + "8153", + "9033", + "9034", + //"9036", problems with ghost state + "16421", + "21653", + "22660", + "5225", + "9846", + "2426", + "5916", + "6634", + //"6718", phasing stealth, annoing for learn all case. + "6719", + "8822", + "9591", + "9590", + "10032", + "17746", + "17747", + "8203", + "11392", + "12495", + "16380", + "23452", + "4079", + "4996", + "4997", + "4998", + "4999", + "5000", + "6348", + "6349", + "6481", + "6482", + "6483", + "6484", + "11362", + "11410", + "11409", + "12510", + "12509", + "12885", + "13142", + "21463", + "23460", + "11421", + "11416", + "11418", + "1851", + "10059", + "11423", + "11417", + "11422", + "11419", + "11424", + "11420", + "27", + "31", + "33", + "34", + "35", + "15125", + "21127", + "22950", + "1180", + "201", + "12593", + "12842", + "16770", + "6057", + "12051", + "18468", + "12606", + "12605", + "18466", + "12502", + "12043", + "15060", + "12042", + "12341", + "12848", + "12344", + "12353", + "18460", + "11366", + "12350", + "12352", + "13043", + "11368", + "11113", + "12400", + "11129", + "16766", + "12573", + "15053", + "12580", + "12475", + "12472", + "12953", + "12488", + "11189", + "12985", + "12519", + "16758", + "11958", + "12490", + "11426", + "3565", + "3562", + "18960", + "3567", + "3561", + "3566", + "3563", + "1953", + "2139", + "12505", + "13018", + "12522", + "12523", + "5146", + "5144", + "5148", + "8419", + "8418", + "10213", + "10212", + "10157", + "12524", + "13019", + "12525", + "13020", + "12526", + "13021", + "18809", + "13031", + "13032", + "13033", + "4036", + "3920", + "3919", + "3918", + "7430", + "3922", + "3923", + "7411", + "7418", + "7421", + "13262", + "7412", + "7415", + "7413", + "7416", + "13920", + "13921", + "7745", + "7779", + "7428", + "7457", + "7857", + "7748", + "7426", + "13421", + "7454", + "13378", + "7788", + "14807", + "14293", + "7795", + "6296", + "20608", + "755", + "444", + "427", + "428", + "442", + "447", + "3578", + "3581", + "19027", + "3580", + "665", + "3579", + "3577", + "6755", + "3576", + "2575", + "2577", + "2578", + "2579", + "2580", + "2656", + "2657", + "2576", + "3564", + "10248", + "8388", + "2659", + "14891", + "3308", + "3307", + "10097", + "2658", + "3569", + "16153", + "3304", + "10098", + "4037", + "3929", + "3931", + "3926", + "3924", + "3930", + "3977", + "3925", + "136", + "228", + "5487", + "43", + "202", + "0" + }; + + int loop = 0; + while(strcmp(allSpellList[loop], "0")) + { + uint32 spell = atol((char*)allSpellList[loop++]); + + if (m_session->GetPlayer()->HasSpell(spell)) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + continue; + } + + m_session->GetPlayer()->learnSpell(spell); + } + + SendSysMessage(LANG_COMMAND_LEARN_MANY_SPELLS); + + return true; +} + +bool ChatHandler::HandleLearnAllGMCommand(const char* /*args*/) +{ + static const char *gmSpellList[] = + { + "24347", // Become A Fish, No Breath Bar + "35132", // Visual Boom + "38488", // Attack 4000-8000 AOE + "38795", // Attack 2000 AOE + Slow Down 90% + "15712", // Attack 200 + "1852", // GM Spell Silence + "31899", // Kill + "31924", // Kill + "29878", // Kill My Self + "26644", // More Kill + + "28550", //Invisible 24 + "23452", //Invisible + Target + "0" + }; + + uint16 gmSpellIter = 0; + while( strcmp(gmSpellList[gmSpellIter], "0") ) + { + uint32 spell = atol((char*)gmSpellList[gmSpellIter++]); + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + continue; + } + + m_session->GetPlayer()->learnSpell(spell); + } + + SendSysMessage(LANG_LEARNING_GM_SKILLS); + return true; +} + +bool ChatHandler::HandleLearnAllMyClassCommand(const char* /*args*/) +{ + HandleLearnAllMySpellsCommand(""); + HandleLearnAllMyTalentsCommand(""); + return true; +} + +bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/) +{ + ChrClassesEntry const* clsEntry = sChrClassesStore.LookupEntry(m_session->GetPlayer()->getClass()); + if(!clsEntry) + return true; + uint32 family = clsEntry->spellfamily; + + for (uint32 i = 0; i < sSpellStore.GetNumRows(); i++) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(i); + if(!spellInfo) + continue; + + // skip wrong class/race skills + if(!m_session->GetPlayer()->IsSpellFitByClassAndRace(spellInfo->Id)) + continue; + + // skip other spell families + if( spellInfo->SpellFamilyName != family) + continue; + + //TODO: skip triggered spells + + // skip spells with first rank learned as talent (and all talents then also) + uint32 first_rank = spellmgr.GetFirstSpellInChain(spellInfo->Id); + if(GetTalentSpellCost(first_rank) > 0 ) + continue; + + // skip broken spells + if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) + continue; + + m_session->GetPlayer()->learnSpell(i); + } + + SendSysMessage(LANG_COMMAND_LEARN_CLASS_SPELLS); + return true; +} + +static void learnAllHighRanks(Player* player, uint32 spellid) +{ + SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); + for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr) + { + player->learnSpell(itr->second); + learnAllHighRanks(player,itr->second); + } +} + +bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/) +{ + Player* player = m_session->GetPlayer(); + uint32 classMask = player->getClassMask(); + + for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++) + { + TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); + if(!talentInfo) + continue; + + TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab ); + if(!talentTabInfo) + continue; + + if( (classMask & talentTabInfo->ClassMask) == 0 ) + continue; + + // search highest talent rank + uint32 spellid = 0; + int rank = 4; + for(; rank >= 0; --rank) + { + if(talentInfo->RankID[rank]!=0) + { + spellid = talentInfo->RankID[rank]; + break; + } + } + + if(!spellid) // ??? none spells in telent + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid); + if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) + continue; + + // learn highest rank of talent + player->learnSpell(spellid); + + // and learn all non-talent spell ranks (recursive by tree) + learnAllHighRanks(player,spellid); + } + + SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); + return true; +} + +bool ChatHandler::HandleLearnAllLangCommand(const char* /*args*/) +{ + // skipping UNIVERSAL language (0) + for(int i = 1; i < LANGUAGES_COUNT; ++i) + m_session->GetPlayer()->learnSpell(lang_description[i].spell_id); + + SendSysMessage(LANG_COMMAND_LEARN_ALL_LANG); + return true; +} + +bool ChatHandler::HandleLearnAllDefaultCommand(const char* args) +{ + char* pName = strtok((char*)args, ""); + Player *player = NULL; + if (pName) + { + std::string name = pName; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + player = objmgr.GetPlayer(name.c_str()); + } + else + player = getSelectedPlayer(); + + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + player->learnDefaultSpells(); + player->learnQuestRewardedSpells(); + + PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST,player->GetName()); + return true; +} + +bool ChatHandler::HandleLearnCommand(const char* args) +{ + Player* targetPlayer = getSelectedPlayer(); + + if(!targetPlayer) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if(!spell || !sSpellStore.LookupEntry(spell)) + return false; + + if (targetPlayer->HasSpell(spell)) + { + if(targetPlayer == m_session->GetPlayer()) + SendSysMessage(LANG_YOU_KNOWN_SPELL); + else + PSendSysMessage(LANG_TARGET_KNOWN_SPELL,targetPlayer->GetName()); + SetSentErrorMessage(true); + return false; + } + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + SetSentErrorMessage(true); + return false; + } + + targetPlayer->learnSpell(spell); + + return true; +} + +bool ChatHandler::HandleAddItemCommand(const char* args) +{ + if (!*args) + return false; + + uint32 itemId = 0; + + if(args[0]=='[') // [name] manual form + { + char* citemName = citemName = strtok((char*)args, "]"); + + if(citemName && citemName[0]) + { + std::string itemName = citemName+1; + WorldDatabase.escape_string(itemName); + QueryResult *result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE name = '%s'", itemName.c_str()); + if (!result) + { + PSendSysMessage(LANG_COMMAND_COULDNOTFIND, citemName+1); + SetSentErrorMessage(true); + return false; + } + itemId = result->Fetch()->GetUInt16(); + delete result; + } + else + return false; + } + else // item_id or [name] Shift-click form |color|Hitem:item_id:0:0:0|h[name]|h|r + { + char* cId = extractKeyFromLink((char*)args,"Hitem"); + if(!cId) + return false; + itemId = atol(cId); + } + + char* ccount = strtok(NULL, " "); + + int32 count = 1; + + if (ccount) + count = strtol(ccount, NULL, 10); + + if (count == 0) + count = 1; + + Player* pl = m_session->GetPlayer(); + Player* plTarget = getSelectedPlayer(); + if(!plTarget) + plTarget = pl; + + sLog.outDetail(GetMangosString(LANG_ADDITEM), itemId, count); + + ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); + if(!pProto) + { + PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemId); + SetSentErrorMessage(true); + return false; + } + + //Subtract + if (count < 0) + { + plTarget->DestroyItemCount(itemId, -count, true, false); + PSendSysMessage(LANG_REMOVEITEM, itemId, -count, plTarget->GetName()); + return true; + } + + //Adding items + uint32 noSpaceForCount = 0; + + // check space and find places + ItemPosCountVec dest; + uint8 msg = plTarget->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount ); + if( msg != EQUIP_ERR_OK ) // convert to possible store amount + count -= noSpaceForCount; + + if( count == 0 || dest.empty()) // can't add any + { + PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount ); + SetSentErrorMessage(true); + return false; + } + + Item* item = plTarget->StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); + + // remove binding (let GM give it to another player later) + if(pl==plTarget) + for(ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr) + if(Item* item1 = pl->GetItemByPos(itr->pos)) + item1->SetBinding( false ); + + if(count > 0 && item) + { + pl->SendNewItem(item,count,false,true); + if(pl!=plTarget) + plTarget->SendNewItem(item,count,true,false); + } + + if(noSpaceForCount > 0) + PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount); + + return true; +} + +bool ChatHandler::HandleAddItemSetCommand(const char* args) +{ + if (!*args) + return false; + + char* cId = extractKeyFromLink((char*)args,"Hitemset"); // number or [name] Shift-click form |color|Hitemset:itemset_id|h[name]|h|r + if (!cId) + return false; + + uint32 itemsetId = atol(cId); + + // prevent generation all items with itemset field value '0' + if (itemsetId == 0) + { + PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND,itemsetId); + SetSentErrorMessage(true); + return false; + } + + Player* pl = m_session->GetPlayer(); + Player* plTarget = getSelectedPlayer(); + if(!plTarget) + plTarget = pl; + + sLog.outDetail(GetMangosString(LANG_ADDITEMSET), itemsetId); + + QueryResult *result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE itemset = %u",itemsetId); + + if(!result) + { + PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND,itemsetId); + + SetSentErrorMessage(true); + return false; + } + + do + { + Field *fields = result->Fetch(); + uint32 itemId = fields[0].GetUInt32(); + + ItemPosCountVec dest; + uint8 msg = plTarget->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, 1 ); + if( msg == EQUIP_ERR_OK ) + { + Item* item = plTarget->StoreNewItem( dest, itemId, true); + + // remove binding (let GM give it to another player later) + if(pl==plTarget) + item->SetBinding( false ); + + pl->SendNewItem(item,1,false,true); + if(pl!=plTarget) + plTarget->SendNewItem(item,1,true,false); + } + else + { + pl->SendEquipError( msg, NULL, NULL ); + PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, 1); + } + + }while( result->NextRow() ); + + delete result; + + return true; +} + +bool ChatHandler::HandleListItemCommand(const char* args) +{ + if(!*args) + return false; + + char* cId = extractKeyFromLink((char*)args,"Hitem"); + if(!cId) + return false; + uint32 item_id = atol(cId); + + ItemPrototype const* itemProto = item_id ? itemProto = objmgr.GetItemPrototype(item_id) : NULL; + + if(!itemProto) + { + PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id); + SetSentErrorMessage(true); + return false; + } + + char* c_count = strtok(NULL, " "); + int count = c_count ? atol(c_count) : 10; + + if(count < 0) + return false; + + QueryResult *result; + + // inventory case + uint32 inv_count = 0; + result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM character_inventory WHERE item_template='%u'",item_id); + if(result) + { + inv_count = (*result)[0].GetUInt32(); + delete result; + } + + result=CharacterDatabase.PQuery( + // 0 1 2 3 4 5 + "SELECT ci.item, cibag.slot AS bag, ci.slot, ci.guid, characters.account,characters.name " + "FROM character_inventory AS ci LEFT JOIN character_inventory AS cibag ON (cibag.item=ci.bag),characters " + "WHERE ci.item_template='%u' AND ci.guid = characters.guid LIMIT %u ", + item_id,uint32(count)); + + if(result) + { + do + { + Field *fields = result->Fetch(); + uint32 item_guid = fields[0].GetUInt32(); + uint32 item_bag = fields[1].GetUInt32(); + uint32 item_slot = fields[2].GetUInt32(); + uint32 owner_guid = fields[3].GetUInt32(); + uint32 owner_acc = fields[4].GetUInt32(); + std::string owner_name = fields[5].GetCppString(); + + char const* item_pos = 0; + if(Player::IsEquipmentPos(item_bag,item_slot)) + item_pos = "[equipped]"; + else if(Player::IsInventoryPos(item_bag,item_slot)) + item_pos = "[in inventory]"; + else if(Player::IsBankPos(item_bag,item_slot)) + item_pos = "[in bank]"; + else + item_pos = ""; + + PSendSysMessage(LANG_ITEMLIST_SLOT, + item_guid,owner_name.c_str(),owner_guid,owner_acc,item_pos); + } while (result->NextRow()); + + int64 res_count = result->GetRowCount(); + + delete result; + + if(count > res_count) + count-=res_count; + else if(count) + count = 0; + } + + // mail case + uint32 mail_count = 0; + result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM mail_items WHERE item_template='%u'", item_id); + if(result) + { + mail_count = (*result)[0].GetUInt32(); + delete result; + } + + if(count > 0) + { + result=CharacterDatabase.PQuery( + // 0 1 2 3 4 5 6 + "SELECT mail_items.item_guid, mail.sender, mail.receiver, char_s.account, char_s.name, char_r.account, char_r.name " + "FROM mail,mail_items,characters as char_s,characters as char_r " + "WHERE mail_items.item_template='%u' AND char_s.guid = mail.sender AND char_r.guid = mail.receiver AND mail.id=mail_items.mail_id LIMIT %u", + item_id,uint32(count)); + } + else + result = NULL; + + if(result) + { + do + { + Field *fields = result->Fetch(); + uint32 item_guid = fields[0].GetUInt32(); + uint32 item_s = fields[1].GetUInt32(); + uint32 item_r = fields[2].GetUInt32(); + uint32 item_s_acc = fields[3].GetUInt32(); + std::string item_s_name = fields[4].GetCppString(); + uint32 item_r_acc = fields[5].GetUInt32(); + std::string item_r_name = fields[6].GetCppString(); + + char const* item_pos = "[in mail]"; + + PSendSysMessage(LANG_ITEMLIST_MAIL, + item_guid,item_s_name.c_str(),item_s,item_s_acc,item_r_name.c_str(),item_r,item_r_acc,item_pos); + } while (result->NextRow()); + + int64 res_count = result->GetRowCount(); + + delete result; + + if(count > res_count) + count-=res_count; + else if(count) + count = 0; + } + + // auction case + uint32 auc_count = 0; + result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM auctionhouse WHERE item_template='%u'",item_id); + if(result) + { + auc_count = (*result)[0].GetUInt32(); + delete result; + } + + if(count > 0) + { + result=CharacterDatabase.PQuery( + // 0 1 2 3 + "SELECT auctionhouse.itemguid, auctionhouse.itemowner, characters.account, characters.name " + "FROM auctionhouse,characters WHERE auctionhouse.item_template='%u' AND characters.guid = auctionhouse.itemowner LIMIT %u", + item_id,uint32(count)); + } + else + result = NULL; + + if(result) + { + do + { + Field *fields = result->Fetch(); + uint32 item_guid = fields[0].GetUInt32(); + uint32 owner = fields[1].GetUInt32(); + uint32 owner_acc = fields[2].GetUInt32(); + std::string owner_name = fields[3].GetCppString(); + + char const* item_pos = "[in auction]"; + + PSendSysMessage(LANG_ITEMLIST_AUCTION, item_guid, owner_name.c_str(), owner, owner_acc,item_pos); + } while (result->NextRow()); + + delete result; + } + + if(inv_count+mail_count+auc_count == 0) + { + SendSysMessage(LANG_COMMAND_NOITEMFOUND); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_COMMAND_LISTITEMMESSAGE,item_id,inv_count+mail_count+auc_count,inv_count,mail_count,auc_count); + + return true; +} + +bool ChatHandler::HandleListObjectCommand(const char* args) +{ + if(!*args) + return false; + + // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry"); + if(!cId) + return false; + + uint32 go_id = atol(cId); + + GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(go_id); + + if(!go_id || !gInfo) + { + PSendSysMessage(LANG_COMMAND_LISTOBJINVALIDID, go_id); + SetSentErrorMessage(true); + return false; + } + + char* c_count = strtok(NULL, " "); + int count = c_count ? atol(c_count) : 10; + + if(count < 0) + return false; + + Player* pl = m_session->GetPlayer(); + QueryResult *result; + + uint32 obj_count = 0; + result=WorldDatabase.PQuery("SELECT COUNT(guid) FROM gameobject WHERE id='%u'",go_id); + if(result) + { + obj_count = (*result)[0].GetUInt32(); + delete result; + } + + result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE id = '%u' ORDER BY order_ ASC LIMIT %u", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),go_id,uint32(count)); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + float x = fields[1].GetFloat(); + float y = fields[2].GetFloat(); + float z = fields[3].GetFloat(); + int mapid = fields[4].GetUInt16(); + + PSendSysMessage(LANG_GO_LIST, guid, guid, gInfo->name, x, y, z, mapid); + } while (result->NextRow()); + + delete result; + } + + PSendSysMessage(LANG_COMMAND_LISTOBJMESSAGE,go_id,obj_count); + return true; +} + +bool ChatHandler::HandleNearObjectCommand(const char* args) +{ + float distance = (!*args) ? 10 : atol(args); + uint32 count = 0; + + Player* pl = m_session->GetPlayer(); + QueryResult *result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, " + "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ " + "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' ORDER BY order_", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), + pl->GetMapId(),pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),distance*distance); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + uint32 entry = fields[1].GetUInt32(); + float x = fields[2].GetFloat(); + float y = fields[3].GetFloat(); + float z = fields[4].GetFloat(); + int mapid = fields[5].GetUInt16(); + + GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(entry); + + if(!gInfo) + continue; + + PSendSysMessage(LANG_GO_LIST, guid, guid, gInfo->name, x, y, z, mapid); + + ++count; + } while (result->NextRow()); + + delete result; + } + + PSendSysMessage(LANG_COMMAND_NEAROBJMESSAGE,distance,count); + return true; +} + +bool ChatHandler::HandleListCreatureCommand(const char* args) +{ + if(!*args) + return false; + + // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hcreature_entry"); + if(!cId) + return false; + + uint32 cr_id = atol(cId); + + CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(cr_id); + + if(!cr_id || !cInfo) + { + PSendSysMessage(LANG_COMMAND_INVALIDCREATUREID, cr_id); + SetSentErrorMessage(true); + return false; + } + + char* c_count = strtok(NULL, " "); + int count = c_count ? atol(c_count) : 10; + + if(count < 0) + return false; + + Player* pl = m_session->GetPlayer(); + QueryResult *result; + + uint32 cr_count = 0; + result=WorldDatabase.PQuery("SELECT COUNT(guid) FROM creature WHERE id='%u'",cr_id); + if(result) + { + cr_count = (*result)[0].GetUInt32(); + delete result; + } + + result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM creature WHERE id = '%u' ORDER BY order_ ASC LIMIT %u", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), cr_id,uint32(count)); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + float x = fields[1].GetFloat(); + float y = fields[2].GetFloat(); + float z = fields[3].GetFloat(); + int mapid = fields[4].GetUInt16(); + + PSendSysMessage(LANG_CREATURE_LIST, guid, guid, cInfo->Name, x, y, z, mapid); + } while (result->NextRow()); + + delete result; + } + + PSendSysMessage(LANG_COMMAND_LISTCREATUREMESSAGE,cr_id,cr_count); + return true; +} + +bool ChatHandler::HandleLookupItemCommand(const char* args) +{ + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + uint32 counter = 0; + + // Search in `item_template` + for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) + { + ItemPrototype const *pProto = sItemStorage.LookupEntry(id); + if(!pProto) + continue; + + int loc_idx = m_session->GetSessionDbLocaleIndex(); + if ( loc_idx >= 0 ) + { + ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); + if (il) + { + if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty()) + { + std::string name = il->Name[loc_idx]; + + if (Utf8FitTo(name, wnamepart)) + { + PSendSysMessage(LANG_ITEM_LIST, id, id, name.c_str()); + ++counter; + continue; + } + } + } + } + + std::string name = pProto->Name1; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + { + PSendSysMessage(LANG_ITEM_LIST, id, id, name.c_str()); + ++counter; + } + } + + if (counter==0) + SendSysMessage(LANG_COMMAND_NOITEMFOUND); + + return true; +} + +bool ChatHandler::HandleLookupItemSetCommand(const char* args) +{ + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower( wnamepart ); + + uint32 counter = 0; // Counter for figure out that we found smth. + + // Search in ItemSet.dbc + for (uint32 id = 0; id < sItemSetStore.GetNumRows(); id++) + { + ItemSetEntry const *set = sItemSetStore.LookupEntry(id); + if(set) + { + int loc = m_session->GetSessionDbcLocale(); + std::string name = set->name[m_session->GetSessionDbcLocale()]; + if(name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for(; loc < MAX_LOCALE; ++loc) + { + if(loc==m_session->GetSessionDbcLocale()) + continue; + + name = set->name[m_session->GetSessionDbcLocale()]; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if(loc < MAX_LOCALE) + { + // send item set in "id - [namedlink locale]" format + PSendSysMessage(LANG_ITEMSET_LIST,id,id,name.c_str(),localeNames[loc]); + ++counter; + } + } + } + if (counter == 0) // if counter == 0 then we found nth + SendSysMessage(LANG_COMMAND_NOITEMSETFOUND); + return true; +} + +bool ChatHandler::HandleLookupSkillCommand(const char* args) +{ + Player* target = getSelectedPlayer(); + if(!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower( wnamepart ); + + uint32 counter = 0; // Counter for figure out that we found smth. + + // Search in SkillLine.dbc + for (uint32 id = 0; id < sSkillLineStore.GetNumRows(); id++) + { + SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(id); + if(skillInfo) + { + int loc = m_session->GetSessionDbcLocale(); + std::string name = skillInfo->name[loc]; + if(name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for(; loc < MAX_LOCALE; ++loc) + { + if(loc==m_session->GetSessionDbcLocale()) + continue; + + name = skillInfo->name[loc]; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if(loc < MAX_LOCALE) + { + // send skill in "id - [namedlink locale]" format + PSendSysMessage(LANG_SKILL_LIST,id,id,name.c_str(),localeNames[loc],(target->HasSkill(id) ? m_session->GetMangosString(LANG_KNOWN) : "")); + + ++counter; + } + } + } + if (counter == 0) // if counter == 0 then we found nth + SendSysMessage(LANG_COMMAND_NOSKILLFOUND); + return true; +} + +bool ChatHandler::HandleLookupSpellCommand(const char* args) +{ + Player* target = getSelectedPlayer(); + if( !target ) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower( wnamepart ); + + uint32 counter = 0; // Counter for figure out that we found smth. + + // Search in Spell.dbc + for (uint32 id = 0; id < sSpellStore.GetNumRows(); id++) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(id); + if(spellInfo) + { + int loc = m_session->GetSessionDbcLocale(); + std::string name = spellInfo->SpellName[loc]; + if(name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for(; loc < MAX_LOCALE; ++loc) + { + if(loc==m_session->GetSessionDbcLocale()) + continue; + + name = spellInfo->SpellName[loc]; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if(loc < MAX_LOCALE) + { + bool known = target->HasSpell(id); + bool learn = (spellInfo->Effect[0] == SPELL_EFFECT_LEARN_SPELL); + + uint32 telentCost = GetTalentSpellCost(id); + + bool talent = (telentCost > 0); + bool passive = IsPassiveSpell(id); + bool active = target->HasAura(id,0) || target->HasAura(id,1) || target->HasAura(id,2); + + // unit32 used to prevent interpreting uint8 as char at output + // find rank of learned spell for learning spell, or talent rank + uint32 rank = telentCost ? telentCost : spellmgr.GetSpellRank(learn ? spellInfo->EffectTriggerSpell[0] : id); + + // send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format + std::ostringstream ss; + ss << id << " - |cffffffff|Hspell:" << id << "|h[" << name; + + // include rank in link name + if(rank) + ss << GetMangosString(LANG_SPELL_RANK) << rank; + + ss << " " << localeNames[loc] << "]|h|r"; + + if(talent) + ss << GetMangosString(LANG_TALENT); + if(passive) + ss << GetMangosString(LANG_PASSIVE); + if(learn) + ss << GetMangosString(LANG_LEARN); + if(known) + ss << GetMangosString(LANG_KNOWN); + if(active) + ss << GetMangosString(LANG_ACTIVE); + + SendSysMessage(ss.str().c_str()); + + ++counter; + } + } + } + if (counter == 0) // if counter == 0 then we found nth + SendSysMessage(LANG_COMMAND_NOSPELLFOUND); + return true; +} + +bool ChatHandler::HandleLookupQuestCommand(const char* args) +{ + Player* target = getSelectedPlayer(); + if( !target ) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + uint32 counter = 0 ; + + ObjectMgr::QuestMap const& qTemplates = objmgr.GetQuestTemplates(); + for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) + { + Quest * qinfo = iter->second; + + int loc_idx = m_session->GetSessionDbLocaleIndex(); + if ( loc_idx >= 0 ) + { + QuestLocale const *il = objmgr.GetQuestLocale(qinfo->GetQuestId()); + if (il) + { + if (il->Title.size() > loc_idx && !il->Title[loc_idx].empty()) + { + std::string title = il->Title[loc_idx]; + + if (Utf8FitTo(title, wnamepart)) + { + QuestStatus status = target->GetQuestStatus(qinfo->GetQuestId()); + + char const* statusStr = ""; + if(status == QUEST_STATUS_COMPLETE) + { + if(target->GetQuestRewardStatus(qinfo->GetQuestId())) + statusStr = GetMangosString(LANG_COMMAND_QUEST_REWARDED); + else + statusStr = GetMangosString(LANG_COMMAND_QUEST_COMPLETE); + } + else if(status == QUEST_STATUS_INCOMPLETE) + statusStr = GetMangosString(LANG_COMMAND_QUEST_ACTIVE); + + PSendSysMessage(LANG_QUEST_LIST,qinfo->GetQuestId(),qinfo->GetQuestId(),title.c_str(),(status == QUEST_STATUS_COMPLETE ? GetMangosString(LANG_COMPLETE) : (status == QUEST_STATUS_INCOMPLETE ? GetMangosString(LANG_ACTIVE) : "") )); + ++counter; + continue; + } + } + } + } + + std::string title = qinfo->GetTitle(); + if(title.empty()) + continue; + + if (Utf8FitTo(title, wnamepart)) + { + QuestStatus status = target->GetQuestStatus(qinfo->GetQuestId()); + + char const* statusStr = ""; + if(status == QUEST_STATUS_COMPLETE) + { + if(target->GetQuestRewardStatus(qinfo->GetQuestId())) + statusStr = GetMangosString(LANG_COMMAND_QUEST_REWARDED); + else + statusStr = GetMangosString(LANG_COMMAND_QUEST_COMPLETE); + } + else if(status == QUEST_STATUS_INCOMPLETE) + statusStr = GetMangosString(LANG_COMMAND_QUEST_ACTIVE); + + PSendSysMessage(LANG_QUEST_LIST,qinfo->GetQuestId(),qinfo->GetQuestId(), title.c_str(),(status == QUEST_STATUS_COMPLETE ? GetMangosString(LANG_COMPLETE) : (status == QUEST_STATUS_INCOMPLETE ? GetMangosString(LANG_ACTIVE) : "") )); + ++counter; + } + } + + if (counter==0) + SendSysMessage(LANG_COMMAND_NOQUESTFOUND); + + return true; +} + +bool ChatHandler::HandleLookupCreatureCommand(const char* args) +{ + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + uint32 counter = 0; + + for (uint32 id = 0; id< sCreatureStorage.MaxEntry; id++ ) + { + CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(id); + if(!cInfo) + continue; + + int loc_idx = m_session->GetSessionDbLocaleIndex(); + if ( loc_idx >= 0 ) + { + CreatureLocale const *cl = objmgr.GetCreatureLocale(id); + if (cl) + { + if (cl->Name.size() > loc_idx && !cl->Name[loc_idx].empty()) + { + std::string name = cl->Name[loc_idx]; + + if (Utf8FitTo(name, wnamepart)) + { + PSendSysMessage(LANG_CREATURE_ENTRY_LIST, id, id, name.c_str()); + ++counter; + continue; + } + } + } + } + + std::string name = cInfo->Name; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + { + PSendSysMessage(LANG_CREATURE_ENTRY_LIST,id,id,name.c_str()); + ++counter; + } + } + + if (counter==0) + SendSysMessage(LANG_COMMAND_NOCREATUREFOUND); + + return true; +} + +bool ChatHandler::HandleLookupObjectCommand(const char* args) +{ + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + uint32 counter = 0; + + for (uint32 id = 0; id< sGOStorage.MaxEntry; id++ ) + { + GameObjectInfo const* gInfo = sGOStorage.LookupEntry(id); + if(!gInfo) + continue; + + int loc_idx = m_session->GetSessionDbLocaleIndex(); + if ( loc_idx >= 0 ) + { + GameObjectLocale const *gl = objmgr.GetGameObjectLocale(id); + if (gl) + { + if (gl->Name.size() > loc_idx && !gl->Name[loc_idx].empty()) + { + std::string name = gl->Name[loc_idx]; + + if (Utf8FitTo(name, wnamepart)) + { + PSendSysMessage(LANG_GO_ENTRY_LIST, id, id, name.c_str()); + ++counter; + continue; + } + } + } + } + + std::string name = gInfo->name; + if(name.empty()) + continue; + + if(Utf8FitTo(name, wnamepart)) + { + PSendSysMessage(LANG_GO_ENTRY_LIST, id, id, name.c_str()); + ++counter; + } + } + + if(counter==0) + SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND); + + return true; +} + +/** \brief GM command level 3 - Create a guild. + * + * This command allows a GM (level 3) to create a guild. + * + * The "args" parameter contains the name of the guild leader + * and then the name of the guild. + * + */ +bool ChatHandler::HandleGuildCreateCommand(const char* args) +{ + + if (!*args) + return false; + + Guild *guild; + Player * player; + char *lname,*gname; + std::string guildname; + + lname = strtok((char*)args, " "); + gname = strtok(NULL, ""); + + if(!lname) + return false; + else if(!gname) + { + SendSysMessage(LANG_INSERT_GUILD_NAME); + SetSentErrorMessage(true); + return false; + } + + guildname = gname; + player = ObjectAccessor::Instance().FindPlayerByName(lname); + + if(!player) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if(!player->GetGuildId()) + { + guild = new Guild; + if(!guild->create(player->GetGUID(),guildname)) + { + delete guild; + SendSysMessage(LANG_GUILD_NOT_CREATED); + SetSentErrorMessage(true); + return false; + } + + objmgr.AddGuild(guild); + } + else + SendSysMessage(LANG_PLAYER_IN_GUILD); + + return true; +} + +bool ChatHandler::HandleGuildInviteCommand(const char *args) +{ + if(!*args) + return false; + + char* par1 = strtok((char*)args, " "); + char* par2 = strtok (NULL, ""); + if(!par1 || !par2) + return false; + + std::string glName = par2; + Guild* targetGuild = objmgr.GetGuildByName(glName); + if(!targetGuild) + return false; + + std::string plName = par1; + if(!normalizePlayerName(plName)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 plGuid = 0; + if(Player* targetPlayer = ObjectAccessor::Instance().FindPlayerByName(plName.c_str())) + plGuid = targetPlayer->GetGUID(); + else + plGuid = objmgr.GetPlayerGUIDByName(plName.c_str()); + + if(!plGuid) + false; + + // players's guild membership checked in AddMember before add + if(!targetGuild->AddMember(plGuid,targetGuild->GetLowestRank())) + return false; + + return true; +} + +bool ChatHandler::HandleGuildUninviteCommand(const char *args) +{ + if(!*args) + return false; + + char* par1 = strtok((char*)args, " "); + if(!par1) + return false; + std::string plName = par1; + if(!normalizePlayerName(plName)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 plGuid = 0; + uint32 glId = 0; + if(Player* targetPlayer = ObjectAccessor::Instance().FindPlayerByName(plName.c_str())) + { + plGuid = targetPlayer->GetGUID(); + glId = targetPlayer->GetGuildId(); + } + else + { + plGuid = objmgr.GetPlayerGUIDByName(plName.c_str()); + glId = Player::GetGuildIdFromDB(plGuid); + } + + if(!plGuid || !glId) + return false; + + Guild* targetGuild = objmgr.GetGuildById(glId); + if(!targetGuild) + return false; + + targetGuild->DelMember(plGuid); + + return true; +} + +bool ChatHandler::HandleGuildRankCommand(const char *args) +{ + if(!*args) + return false; + + char* par1 = strtok((char*)args, " "); + char* par2 = strtok(NULL, " "); + if(!par1 || !par2) + return false; + std::string plName = par1; + if(!normalizePlayerName(plName)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 plGuid = 0; + uint32 glId = 0; + if(Player* targetPlayer = ObjectAccessor::Instance().FindPlayerByName(plName.c_str())) + { + plGuid = targetPlayer->GetGUID(); + glId = targetPlayer->GetGuildId(); + } + else + { + plGuid = objmgr.GetPlayerGUIDByName(plName.c_str()); + glId = Player::GetGuildIdFromDB(plGuid); + } + + if(!plGuid || !glId) + return false; + + Guild* targetGuild = objmgr.GetGuildById(glId); + if(!targetGuild) + return false; + + uint32 newrank = uint32(atoi(par2)); + if(newrank > targetGuild->GetLowestRank()) + return false; + + targetGuild->ChangeRank(plGuid,newrank); + + return true; +} + +bool ChatHandler::HandleGuildDeleteCommand(const char* args) +{ + if(!*args) + return false; + + char* par1 = strtok((char*)args, " "); + if(!par1) + return false; + + std::string gld = par1; + + Guild* targetGuild = objmgr.GetGuildByName(gld); + if(!targetGuild) + return false; + + targetGuild->Disband(); + + return true; +} + +bool ChatHandler::HandleGetDistanceCommand(const char* /*args*/) +{ + Unit* pUnit = getSelectedUnit(); + + if(!pUnit) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(pUnit),m_session->GetPlayer()->GetDistance2d(pUnit)); + + return true; +} + +// FIX-ME!!! + +bool ChatHandler::HandleAddWeaponCommand(const char* /*args*/) +{ + /*if (!*args) + return false; + + uint64 guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature *pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + char* pSlotID = strtok((char*)args, " "); + if (!pSlotID) + return false; + + char* pItemID = strtok(NULL, " "); + if (!pItemID) + return false; + + uint32 ItemID = atoi(pItemID); + uint32 SlotID = atoi(pSlotID); + + ItemPrototype* tmpItem = objmgr.GetItemPrototype(ItemID); + + bool added = false; + if(tmpItem) + { + switch(SlotID) + { + case 1: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID); + added = true; + break; + case 2: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID); + added = true; + break; + case 3: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID); + added = true; + break; + default: + PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID); + added = false; + break; + } + if(added) + { + PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID); + } + } + else + { + PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID); + return true; + } + */ + return true; +} + +bool ChatHandler::HandleDieCommand(const char* /*args*/) +{ + Unit* target = getSelectedUnit(); + + if(!target || !m_session->GetPlayer()->GetSelection()) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if( target->isAlive() ) + { + m_session->GetPlayer()->DealDamage(target, target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + return true; +} + +bool ChatHandler::HandleDamageCommand(const char * args) +{ + if (!*args) + return false; + + Unit* target = getSelectedUnit(); + + if(!target || !m_session->GetPlayer()->GetSelection()) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if( !target->isAlive() ) + return true; + + char* damageStr = strtok((char*)args, " "); + if(!damageStr) + return false; + + int32 damage = atoi((char*)damageStr); + if(damage <=0) + return true; + + char* schoolStr = strtok((char*)NULL, " "); + + // flat melee damage without resistence/etc reduction + if(!schoolStr) + { + m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0); + return true; + } + + uint32 school = schoolStr ? atoi((char*)schoolStr) : SPELL_SCHOOL_NORMAL; + if(school >= MAX_SPELL_SCHOOL) + return false; + + SpellSchoolMask schoolmask = SpellSchoolMask(1 << school); + + if ( schoolmask & SPELL_SCHOOL_MASK_NORMAL ) + damage = m_session->GetPlayer()->CalcArmorReducedDamage(target, damage); + + char* spellStr = strtok((char*)NULL, " "); + + // melee damage by specific school + if(!spellStr) + { + uint32 absorb = 0; + uint32 resist = 0; + + m_session->GetPlayer()->CalcAbsorbResist(target,schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + + if (damage <= absorb + resist) + return true; + + damage -= absorb + resist; + + m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); + m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_NORMAL, 0); + return true; + } + + // non-melee damage + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spellid = extractSpellIdFromLink((char*)args); + if(!spellid || !sSpellStore.LookupEntry(spellid)) + return false; + + m_session->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage, false); + return true; +} + +bool ChatHandler::HandleModifyArenaCommand(const char * args) +{ + if (!*args) + return false; + + Player *target = getSelectedPlayer(); + if(!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + int32 amount = (uint32)atoi(args); + + target->ModifyArenaPoints(amount); + + PSendSysMessage(LANG_COMMAND_MODIFY_ARENA, target->GetName(), target->GetArenaPoints()); + + return true; +} + +bool ChatHandler::HandleReviveCommand(const char* args) +{ + Player* SelectedPlayer = NULL; + + if (*args) + { + std::string name = args; + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + SelectedPlayer = objmgr.GetPlayer(name.c_str()); + } + else + SelectedPlayer = getSelectedPlayer(); + + if(!SelectedPlayer) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + SelectedPlayer->ResurrectPlayer(0.5f); + SelectedPlayer->SpawnCorpseBones(); + SelectedPlayer->SaveToDB(); + return true; +} + +bool ChatHandler::HandleAuraCommand(const char* args) +{ + char* px = strtok((char*)args, " "); + if (!px) + return false; + + Unit *target = getSelectedUnit(); + if(!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint32 spellID = (uint32)atoi(px); + SpellEntry const *spellInfo = sSpellStore.LookupEntry( spellID ); + if(spellInfo) + { + for(uint32 i = 0;i<3;i++) + { + uint8 eff = spellInfo->Effect[i]; + if (eff>=TOTAL_SPELL_EFFECTS) + continue; + if( IsAreaAuraEffect(eff) || + eff == SPELL_EFFECT_APPLY_AURA || + eff == SPELL_EFFECT_PERSISTENT_AREA_AURA ) + { + Aura *Aur = CreateAura(spellInfo, i, NULL, target); + target->AddAura(Aur); + } + } + } + + return true; +} + +bool ChatHandler::HandleUnAuraCommand(const char* args) +{ + char* px = strtok((char*)args, " "); + if (!px) + return false; + + Unit *target = getSelectedUnit(); + if(!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + std::string argstr = args; + if (argstr == "all") + { + target->RemoveAllAuras(); + return true; + } + + uint32 spellID = (uint32)atoi(px); + target->RemoveAurasDueToSpell(spellID); + + return true; +} + +bool ChatHandler::HandleLinkGraveCommand(const char* args) +{ + if(!*args) + return false; + + char* px = strtok((char*)args, " "); + if (!px) + return false; + + uint32 g_id = (uint32)atoi(px); + + uint32 g_team; + + char* px2 = strtok(NULL, " "); + + if (!px2) + g_team = 0; + else if (strncmp(px2,"horde",6)==0) + g_team = HORDE; + else if (strncmp(px2,"alliance",9)==0) + g_team = ALLIANCE; + else + return false; + + WorldSafeLocsEntry const* graveyard = sWorldSafeLocsStore.LookupEntry(g_id); + + if(!graveyard ) + { + PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST, g_id); + SetSentErrorMessage(true); + return false; + } + + Player* player = m_session->GetPlayer(); + + uint32 zoneId = player->GetZoneId(); + + AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId); + if(!areaEntry || areaEntry->zone !=0 ) + { + PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, g_id,zoneId); + SetSentErrorMessage(true); + return false; + } + + if(graveyard->map_id != areaEntry->mapid && g_team != 0) + { + SendSysMessage(LANG_COMMAND_GRAVEYARDWRONGTEAM); + SetSentErrorMessage(true); + return false; + } + + if(objmgr.AddGraveYardLink(g_id,player->GetZoneId(),g_team)) + PSendSysMessage(LANG_COMMAND_GRAVEYARDLINKED, g_id,zoneId); + else + PSendSysMessage(LANG_COMMAND_GRAVEYARDALRLINKED, g_id,zoneId); + + return true; +} + +bool ChatHandler::HandleNearGraveCommand(const char* args) +{ + uint32 g_team; + + size_t argslen = strlen(args); + + if(!*args) + g_team = 0; + else if (strncmp((char*)args,"horde",argslen)==0) + g_team = HORDE; + else if (strncmp((char*)args,"alliance",argslen)==0) + g_team = ALLIANCE; + else + return false; + + Player* player = m_session->GetPlayer(); + + WorldSafeLocsEntry const* graveyard = objmgr.GetClosestGraveYard( + player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(),player->GetMapId(),g_team); + + if(graveyard) + { + uint32 g_id = graveyard->ID; + + GraveYardData const* data = objmgr.FindGraveYardData(g_id,player->GetZoneId()); + if (!data) + { + PSendSysMessage(LANG_COMMAND_GRAVEYARDERROR,g_id); + SetSentErrorMessage(true); + return false; + } + + g_team = data->team; + + std::string team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_NOTEAM); + + if(g_team == 0) + team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ANY); + else if(g_team == HORDE) + team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_HORDE); + else if(g_team == ALLIANCE) + team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ALLIANCE); + + PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, g_id,team_name.c_str(),player->GetZoneId()); + } + else + { + std::string team_name; + + if(g_team == 0) + team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ANY); + else if(g_team == HORDE) + team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_HORDE); + else if(g_team == ALLIANCE) + team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ALLIANCE); + + if(g_team == ~uint32(0)) + PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, player->GetZoneId()); + else + PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, player->GetZoneId(),team_name.c_str()); + } + + return true; +} + +bool ChatHandler::HandleSpawnTransportCommand(const char* /*args*/) +{ + return true; +} + +//play npc emote +bool ChatHandler::HandlePlayEmoteCommand(const char* args) +{ + uint32 emote = atoi((char*)args); + + Creature* target = getSelectedCreature(); + if(!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote); + + return true; +} + +bool ChatHandler::HandleNpcInfoCommand(const char* /*args*/) +{ + Creature* target = getSelectedCreature(); + + if(!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint32 faction = target->getFaction(); + uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS); + uint32 displayid = target->GetDisplayId(); + uint32 nativeid = target->GetNativeDisplayId(); + uint32 Entry = target->GetEntry(); + CreatureInfo const* cInfo = target->GetCreatureInfo(); + + int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL); + if(curRespawnDelay < 0) + curRespawnDelay = 0; + std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true); + std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true); + + PSendSysMessage(LANG_NPCINFO_CHAR, target->GetDBTableGUIDLow(), faction, npcflags, Entry, displayid, nativeid); + PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel()); + PSendSysMessage(LANG_NPCINFO_HEALTH,target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth()); + PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction()); + PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str()); + PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid,cInfo->pickpocketLootId,cInfo->SkinLootId); + PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId()); + PSendSysMessage(LANG_NPCINFO_POSITION,float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); + + if ((npcflags & UNIT_NPC_FLAG_VENDOR) ) + { + SendSysMessage(LANG_NPCINFO_VENDOR); + } + if ((npcflags & UNIT_NPC_FLAG_TRAINER) ) + { + SendSysMessage(LANG_NPCINFO_TRAINER); + } + + return true; +} + +bool ChatHandler::HandleExploreCheatCommand(const char* args) +{ + if (!*args) + return false; + + int flag = atoi((char*)args); + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if (flag != 0) + { + PSendSysMessage(LANG_YOU_SET_EXPLORE_ALL, chr->GetName()); + if(chr!=m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_ALL,m_session->GetPlayer()->GetName()); + } + else + { + PSendSysMessage(LANG_YOU_SET_EXPLORE_NOTHING, chr->GetName()); + if(chr!=m_session->GetPlayer()) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_NOTHING,m_session->GetPlayer()->GetName()); + } + + for (uint8 i=0; i<128; i++) + { + if (flag != 0) + { + m_session->GetPlayer()->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0xFFFFFFFF); + } + else + { + m_session->GetPlayer()->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0); + } + } + + return true; +} + +bool ChatHandler::HandleHoverCommand(const char* args) +{ + char* px = strtok((char*)args, " "); + uint32 flag; + if (!px) + flag = 1; + else + flag = atoi(px); + + m_session->GetPlayer()->SetHover(flag); + + if (flag) + SendSysMessage(LANG_HOVER_ENABLED); + else + SendSysMessage(LANG_HOVER_DISABLED); + + return true; +} + +bool ChatHandler::HandleLevelUpCommand(const char* args) +{ + char* px = strtok((char*)args, " "); + char* py = strtok((char*)NULL, " "); + + // command format parsing + char* pname = (char*)NULL; + int addlevel = 1; + + if(px && py) // .levelup name level + { + addlevel = atoi(py); + pname = px; + } + else if(px && !py) // .levelup name OR .levelup level + { + if(isalpha(px[0])) // .levelup name + pname = px; + else // .levelup level + addlevel = atoi(px); + } + // else .levelup - nothing do for prepering + + // player + Player *chr = NULL; + uint64 chr_guid = 0; + + std::string name; + + if(pname) // player by name + { + name = pname; + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + chr = objmgr.GetPlayer(name.c_str()); + if(!chr) // not in game + { + chr_guid = objmgr.GetPlayerGUIDByName(name); + if (chr_guid == 0) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + } + } + else // player by selection + { + chr = getSelectedPlayer(); + + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + name = chr->GetName(); + } + + assert(chr || chr_guid); + + int32 oldlevel = chr ? chr->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,chr_guid); + int32 newlevel = oldlevel + addlevel; + if(newlevel < 1) + newlevel = 1; + if(newlevel > 255) // hardcoded maximum level + newlevel = 255; + + if(chr) + { + chr->GiveLevel(newlevel); + chr->InitTalentForLevel(); + chr->SetUInt32Value(PLAYER_XP,0); + + if(oldlevel == newlevel) + ChatHandler(chr).SendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET); + else + if(oldlevel < newlevel) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_LEVEL_UP,newlevel-oldlevel); + else + if(oldlevel > newlevel) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_LEVEL_DOWN,newlevel-oldlevel); + } + else + { + // update levle and XP at level, all other will be updated at loading + Tokens values; + Player::LoadValuesArrayFromDB(values,chr_guid); + Player::SetUInt32ValueInArray(values,UNIT_FIELD_LEVEL,newlevel); + Player::SetUInt32ValueInArray(values,PLAYER_XP,0); + Player::SaveValuesArrayInDB(values,chr_guid); + } + + if(m_session->GetPlayer() != chr) // including chr==NULL + PSendSysMessage(LANG_YOU_CHANGE_LVL,name.c_str(),newlevel); + return true; +} + +bool ChatHandler::HandleShowAreaCommand(const char* args) +{ + if (!*args) + return false; + + int area = atoi((char*)args); + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + int offset = area / 32; + uint32 val = (uint32)(1 << (area % 32)); + + if(offset >= 128) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + uint32 currFields = chr->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); + chr->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val)); + + SendSysMessage(LANG_EXPLORE_AREA); + return true; +} + +bool ChatHandler::HandleHideAreaCommand(const char* args) +{ + if (!*args) + return false; + + int area = atoi((char*)args); + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + int offset = area / 32; + uint32 val = (uint32)(1 << (area % 32)); + + if(offset >= 128) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + uint32 currFields = chr->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); + chr->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields ^ val)); + + SendSysMessage(LANG_UNEXPLORE_AREA); + return true; +} + +bool ChatHandler::HandleUpdate(const char* args) +{ + if(!*args) + return false; + + uint32 updateIndex; + uint32 value; + + char* pUpdateIndex = strtok((char*)args, " "); + + Unit* chr = getSelectedUnit(); + if (chr == NULL) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if(!pUpdateIndex) + { + return true; + } + updateIndex = atoi(pUpdateIndex); + //check updateIndex + if(chr->GetTypeId() == TYPEID_PLAYER) + { + if (updateIndex>=PLAYER_END) return true; + } + else + { + if (updateIndex>=UNIT_END) return true; + } + + char* pvalue = strtok(NULL, " "); + if (!pvalue) + { + value=chr->GetUInt32Value(updateIndex); + + PSendSysMessage(LANG_UPDATE, chr->GetGUIDLow(),updateIndex,value); + return true; + } + + value=atoi(pvalue); + + PSendSysMessage(LANG_UPDATE_CHANGE, chr->GetGUIDLow(),updateIndex,value); + + chr->SetUInt32Value(updateIndex,value); + + return true; +} + +bool ChatHandler::HandleBankCommand(const char* /*args*/) +{ + m_session->SendShowBank( m_session->GetPlayer()->GetGUID() ); + + return true; +} + +bool ChatHandler::HandleChangeWeather(const char* args) +{ + if(!*args) + return false; + + //Weather is OFF + if (!sWorld.getConfig(CONFIG_WEATHER)) + { + SendSysMessage(LANG_WEATHER_DISABLED); + SetSentErrorMessage(true); + return false; + } + + //*Change the weather of a cell + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + + if (!px || !py) + return false; + + uint32 type = (uint32)atoi(px); //0 to 3, 0: fine, 1: rain, 2: snow, 3: sand + float grade = (float)atof(py); //0 to 1, sending -1 is instand good weather + + Player *player = m_session->GetPlayer(); + uint32 zoneid = player->GetZoneId(); + + Weather* wth = sWorld.FindWeather(zoneid); + + if(!wth) + wth = sWorld.AddWeather(zoneid); + if(!wth) + { + SendSysMessage(LANG_NO_WEATHER); + SetSentErrorMessage(true); + return false; + } + + wth->SetWeather(WeatherType(type), grade); + + return true; +} + +bool ChatHandler::HandleSetValue(const char* args) +{ + if(!*args) + return false; + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + + if (!px || !py) + return false; + + Unit* target = getSelectedUnit(); + if(!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = target->GetGUID(); + + uint32 Opcode = (uint32)atoi(px); + if(Opcode >= target->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); + return false; + } + uint32 iValue; + float fValue; + bool isint32 = true; + if(pz) + isint32 = (bool)atoi(pz); + if(isint32) + { + iValue = (uint32)atoi(py); + sLog.outDebug(GetMangosString(LANG_SET_UINT), GUID_LOPART(guid), Opcode, iValue); + target->SetUInt32Value( Opcode , iValue ); + PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), Opcode,iValue); + } + else + { + fValue = (float)atof(py); + sLog.outDebug(GetMangosString(LANG_SET_FLOAT), GUID_LOPART(guid), Opcode, fValue); + target->SetFloatValue( Opcode , fValue ); + PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), Opcode,fValue); + } + + return true; +} + +bool ChatHandler::HandleGetValue(const char* args) +{ + if(!*args) + return false; + + char* px = strtok((char*)args, " "); + char* pz = strtok(NULL, " "); + + if (!px) + return false; + + Unit* target = getSelectedUnit(); + if(!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = target->GetGUID(); + + uint32 Opcode = (uint32)atoi(px); + if(Opcode >= target->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); + return false; + } + uint32 iValue; + float fValue; + bool isint32 = true; + if(pz) + isint32 = (bool)atoi(pz); + + if(isint32) + { + iValue = target->GetUInt32Value( Opcode ); + sLog.outDebug(GetMangosString(LANG_GET_UINT), GUID_LOPART(guid), Opcode, iValue); + PSendSysMessage(LANG_GET_UINT_FIELD, GUID_LOPART(guid), Opcode, iValue); + } + else + { + fValue = target->GetFloatValue( Opcode ); + sLog.outDebug(GetMangosString(LANG_GET_FLOAT), GUID_LOPART(guid), Opcode, fValue); + PSendSysMessage(LANG_GET_FLOAT_FIELD, GUID_LOPART(guid), Opcode, fValue); + } + + return true; +} + +bool ChatHandler::HandleSet32Bit(const char* args) +{ + if(!*args) + return false; + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + + if (!px || !py) + return false; + + uint32 Opcode = (uint32)atoi(px); + uint32 Value = (uint32)atoi(py); + if (Value > 32) //uint32 = 32 bits + return false; + + sLog.outDebug(GetMangosString(LANG_SET_32BIT), Opcode, Value); + + m_session->GetPlayer( )->SetUInt32Value( Opcode , 2^Value ); + + PSendSysMessage(LANG_SET_32BIT_FIELD, Opcode,1); + return true; +} + +bool ChatHandler::HandleMod32Value(const char* args) +{ + if(!*args) + return false; + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + + if (!px || !py) + return false; + + uint32 Opcode = (uint32)atoi(px); + int Value = atoi(py); + + if(Opcode >= m_session->GetPlayer()->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, m_session->GetPlayer()->GetGUIDLow(), m_session->GetPlayer( )->GetValuesCount()); + return false; + } + + sLog.outDebug(GetMangosString(LANG_CHANGE_32BIT), Opcode, Value); + + int CurrentValue = (int)m_session->GetPlayer( )->GetUInt32Value( Opcode ); + + CurrentValue += Value; + m_session->GetPlayer( )->SetUInt32Value( Opcode , (uint32)CurrentValue ); + + PSendSysMessage(LANG_CHANGE_32BIT_FIELD, Opcode,CurrentValue); + + return true; +} + +bool ChatHandler::HandleAddTeleCommand(const char * args) +{ + if(!*args) + return false; + + Player *player=m_session->GetPlayer(); + if (!player) + return false; + + std::string name = args; + + if(objmgr.GetGameTele(name)) + { + SendSysMessage(LANG_COMMAND_TP_ALREADYEXIST); + SetSentErrorMessage(true); + return false; + } + + GameTele tele; + tele.position_x = player->GetPositionX(); + tele.position_y = player->GetPositionY(); + tele.position_z = player->GetPositionZ(); + tele.orientation = player->GetOrientation(); + tele.mapId = player->GetMapId(); + tele.name = name; + + if(objmgr.AddGameTele(tele)) + { + SendSysMessage(LANG_COMMAND_TP_ADDED); + } + else + { + SendSysMessage(LANG_COMMAND_TP_ADDEDERR); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +bool ChatHandler::HandleDelTeleCommand(const char * args) +{ + if(!*args) + return false; + + std::string name = args; + + if(!objmgr.DeleteGameTele(name)) + { + SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + + SendSysMessage(LANG_COMMAND_TP_DELETED); + return true; +} + +bool ChatHandler::HandleListAurasCommand (const char * /*args*/) +{ + Unit *unit = getSelectedUnit(); + if(!unit) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + char const* talentStr = GetMangosString(LANG_TALENT); + char const* passiveStr = GetMangosString(LANG_PASSIVE); + + Unit::AuraMap const& uAuras = unit->GetAuras(); + PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, uAuras.size()); + for (Unit::AuraMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr) + { + bool talent = GetTalentSpellCost(itr->second->GetId()) > 0; + PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(), + itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), + itr->second->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()], + (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); + } + for (int i = 0; i < TOTAL_AURAS; i++) + { + Unit::AuraList const& uAuraList = unit->GetAurasByType(AuraType(i)); + if (uAuraList.empty()) continue; + PSendSysMessage(LANG_COMMAND_TARGET_LISTAURATYPE, uAuraList.size(), i); + for (Unit::AuraList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr) + { + bool talent = GetTalentSpellCost((*itr)->GetId()) > 0; + PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), + (*itr)->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()],((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); + } + } + return true; +} + +bool ChatHandler::HandleResetHonorCommand (const char * args) +{ + char* pName = strtok((char*)args, ""); + Player *player = NULL; + if (pName) + { + std::string name = pName; + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()); + player = objmgr.GetPlayer(guid); + } + else + player = getSelectedPlayer(); + + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + return true; + } + + player->SetUInt32Value(PLAYER_FIELD_KILLS, 0); + player->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 0); + player->SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, 0); + player->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); + player->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); + + return true; +} + +static bool HandleResetStatsOrLevelHelper(Player* player) +{ + PlayerInfo const *info = objmgr.GetPlayerInfo(player->getRace(), player->getClass()); + if(!info) return false; + + ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(player->getClass()); + if(!cEntry) + { + sLog.outError("Class %u not found in DBC (Wrong DBC files?)",player->getClass()); + return false; + } + + uint8 powertype = cEntry->powerType; + + uint32 unitfield; + if(powertype == POWER_RAGE) + unitfield = 0x1100EE00; + else if(powertype == POWER_ENERGY) + unitfield = 0x00000000; + else if(powertype == POWER_MANA) + unitfield = 0x0000EE00; + else + { + sLog.outError("Invalid default powertype %u for player (class %u)",powertype,player->getClass()); + return false; + } + + // reset m_form if no aura + if(!player->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) + player->m_form = FORM_NONE; + + player->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE ); + player->SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f ); + + player->setFactionForRace(player->getRace()); + + player->SetUInt32Value(UNIT_FIELD_BYTES_0, ( ( player->getRace() ) | ( player->getClass() << 8 ) | ( player->getGender() << 16 ) | ( powertype << 24 ) ) ); + + // reset only if player not in some form; + if(player->m_form==FORM_NONE) + { + switch(player->getGender()) + { + case GENDER_FEMALE: + player->SetDisplayId(info->displayId_f); + player->SetNativeDisplayId(info->displayId_f); + break; + case GENDER_MALE: + player->SetDisplayId(info->displayId_m); + player->SetNativeDisplayId(info->displayId_m); + break; + default: + break; + } + } + + // set UNIT_FIELD_BYTES_1 to init state but preserve m_form value + player->SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield); + player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK3 | UNIT_BYTE2_FLAG_UNK5 ); + player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form); + + player->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + + //-1 is default value + player->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); + + //player->SetUInt32Value(PLAYER_FIELD_BYTES, 0xEEE00000 ); + return true; +} + +bool ChatHandler::HandleResetLevelCommand(const char * args) +{ + char* pName = strtok((char*)args, ""); + Player *player = NULL; + if (pName) + { + std::string name = pName; + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()); + player = objmgr.GetPlayer(guid); + } + else + player = getSelectedPlayer(); + + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(!HandleResetStatsOrLevelHelper(player)) + return false; + + player->SetLevel(1); + player->InitStatsForLevel(true); + player->InitTaxiNodesForLevel(); + player->InitTalentForLevel(); + player->SetUInt32Value(PLAYER_XP,0); + + // reset level to summoned pet + Pet* pet = player->GetPet(); + if(pet && pet->getPetType()==SUMMON_PET) + pet->InitStatsForLevel(1); + + return true; +} + +bool ChatHandler::HandleResetStatsCommand(const char * args) +{ + char* pName = strtok((char*)args, ""); + Player *player = NULL; + if (pName) + { + std::string name = pName; + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()); + player = objmgr.GetPlayer(guid); + } + else + player = getSelectedPlayer(); + + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(!HandleResetStatsOrLevelHelper(player)) + return false; + + player->InitStatsForLevel(true); + player->InitTaxiNodesForLevel(); + player->InitTalentForLevel(); + + return true; +} + +bool ChatHandler::HandleResetSpellsCommand(const char * args) +{ + char* pName = strtok((char*)args, ""); + Player *player = NULL; + uint64 playerGUID = 0; + if (pName) + { + std::string name = pName; + + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + player = objmgr.GetPlayer(name.c_str()); + if(!player) + playerGUID = objmgr.GetPlayerGUIDByName(name.c_str()); + } + else + player = getSelectedPlayer(); + + if(!player && !playerGUID) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(player) + { + player->resetSpells(); + + ChatHandler(player).SendSysMessage(LANG_RESET_SPELLS); + + if(m_session->GetPlayer()!=player) + PSendSysMessage(LANG_RESET_SPELLS_ONLINE,player->GetName()); + } + else + { + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_SPELLS), GUID_LOPART(playerGUID)); + PSendSysMessage(LANG_RESET_SPELLS_OFFLINE,pName); + } + + return true; +} + +bool ChatHandler::HandleResetTalentsCommand(const char * args) +{ + char* pName = strtok((char*)args, ""); + Player *player = NULL; + uint64 playerGUID = 0; + if (pName) + { + std::string name = pName; + if(!normalizePlayerName(name)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + player = objmgr.GetPlayer(name.c_str()); + if(!player) + playerGUID = objmgr.GetPlayerGUIDByName(name.c_str()); + } + else + player = getSelectedPlayer(); + + if(!player && !playerGUID) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if(player) + { + player->resetTalents(true); + + ChatHandler(player).SendSysMessage(LANG_RESET_TALENTS); + + if(m_session->GetPlayer()!=player) + PSendSysMessage(LANG_RESET_TALENTS_ONLINE,player->GetName()); + } + else + { + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_TALENTS), GUID_LOPART(playerGUID) ); + PSendSysMessage(LANG_RESET_TALENTS_OFFLINE,pName); + } + + return true; +} + +bool ChatHandler::HandleResetAllCommand(const char * args) +{ + if(!*args) + return false; + + std::string casename = args; + + AtLoginFlags atLogin; + + // Command specially created as single command to prevent using short case names + if(casename=="spells") + { + atLogin = AT_LOGIN_RESET_SPELLS; + sWorld.SendWorldText(LANG_RESETALL_SPELLS); + } + else if(casename=="talents") + { + atLogin = AT_LOGIN_RESET_TALENTS; + sWorld.SendWorldText(LANG_RESETALL_TALENTS); + } + else + { + PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE,args); + SetSentErrorMessage(true); + return false; + } + + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u'",atLogin); + HashMapHolder::MapType const& plist = ObjectAccessor::Instance().GetPlayers(); + for(HashMapHolder::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr) + itr->second->SetAtLoginFlag(atLogin); + + return true; +} + +bool ChatHandler::HandleShutDownCommand(const char* args) +{ + if(!*args) + return false; + + if(std::string(args)=="cancel") + { + sWorld.ShutdownCancel(); + } + else + { + int32 time = atoi(args); + + ///- Prevent interpret wrong arg value as 0 secs shutdown time + if(time == 0 && (args[0]!='0' || args[1]!='\0') || time < 0) + return false; + + sWorld.ShutdownServ(time); + } + return true; +} + +bool ChatHandler::HandleRestartCommand(const char* args) +{ + if(!*args) + return false; + + if(std::string(args)=="cancel") + { + sWorld.ShutdownCancel(); + } + else + { + int32 time = atoi(args); + + ///- Prevent interpret wrong arg value as 0 secs shutdown time + if(time == 0 && (args[0]!='0' || args[1]!='\0') || time < 0) + return false; + + sWorld.ShutdownServ(time, SHUTDOWN_MASK_RESTART); + } + return true; +} + +bool ChatHandler::HandleIdleRestartCommand(const char* args) +{ + if(!*args) + return false; + + if(std::string(args)=="cancel") + { + sWorld.ShutdownCancel(); + } + else + { + int32 time = atoi(args); + + ///- Prevent interpret wrong arg value as 0 secs shutdown time + if(time == 0 && (args[0]!='0' || args[1]!='\0') || time < 0) + return false; + + sWorld.ShutdownServ(time,SHUTDOWN_MASK_RESTART+SHUTDOWN_MASK_IDLE); + } + return true; +} + +bool ChatHandler::HandleIdleShutDownCommand(const char* args) +{ + if(!*args) + return false; + + if(std::string(args)=="cancel") + { + sWorld.ShutdownCancel(); + } + else + { + int32 time = atoi(args); + + ///- Prevent interpret wrong arg value as 0 secs shutdown time + if(time == 0 && (args[0]!='0' || args[1]!='\0') || time < 0) + return false; + + sWorld.ShutdownServ(time,SHUTDOWN_MASK_IDLE); + } + return true; +} + +bool ChatHandler::HandleAddQuest(const char* args) +{ + Player* player = getSelectedPlayer(); + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // .addquest #entry' + // number or [name] Shift-click form |color|Hquest:quest_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hquest"); + if(!cId) + return false; + + uint32 entry = atol(cId); + + Quest const* pQuest = objmgr.GetQuestTemplate(entry); + + if(!pQuest) + { + PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND,entry); + SetSentErrorMessage(true); + return false; + } + + // check item starting quest (it can work incorrectly if added without item in inventory) + QueryResult *result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE startquest = '%u' LIMIT 1",entry); + if(result) + { + Field* fields = result->Fetch(); + uint32 item_id = fields[0].GetUInt32(); + delete result; + + PSendSysMessage(LANG_COMMAND_QUEST_STARTFROMITEM, entry,item_id); + SetSentErrorMessage(true); + return false; + } + + // ok, normal (creature/GO starting) quest + if( player->CanAddQuest( pQuest, true ) ) + { + player->AddQuest( pQuest, NULL ); + + if ( player->CanCompleteQuest( entry ) ) + player->CompleteQuest( entry ); + } + + return true; +} + +bool ChatHandler::HandleRemoveQuest(const char* args) +{ + Player* player = getSelectedPlayer(); + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // .removequest #entry' + // number or [name] Shift-click form |color|Hquest:quest_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hquest"); + if(!cId) + return false; + + uint32 entry = atol(cId); + + Quest const* pQuest = objmgr.GetQuestTemplate(entry); + + if(!pQuest) + { + PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); + SetSentErrorMessage(true); + return false; + } + + // remove all quest entries for 'entry' from quest log + for(uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot ) + { + uint32 quest = player->GetQuestSlotQuestId(slot); + if(quest==entry) + { + player->SetQuestSlot(slot,0); + + // we ignore unequippable quest items in this case, its' still be equipped + player->TakeQuestSourceItem( quest, false ); + } + } + + // set quest status to not started (will updated in DB at next save) + player->SetQuestStatus( entry, QUEST_STATUS_NONE); + + // reset rewarded for restart repeatable quest + player->getQuestStatusMap()[entry].m_rewarded = false; + + SendSysMessage(LANG_COMMAND_QUEST_REMOVED); + return true; +} + +bool ChatHandler::HandleCompleteQuest(const char* args) +{ + Player* player = getSelectedPlayer(); + if(!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // .quest complete #entry + // number or [name] Shift-click form |color|Hquest:quest_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hquest"); + if(!cId) + return false; + + uint32 entry = atol(cId); + + Quest const* pQuest = objmgr.GetQuestTemplate(entry); + + // If player doesn't have the quest + if(!pQuest || player->GetQuestStatus(entry) == QUEST_STATUS_NONE) + { + PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); + SetSentErrorMessage(true); + return false; + } + + // Add quest items for quests that require items + for(uint8 x = 0; x < QUEST_OBJECTIVES_COUNT; ++x) + { + uint32 id = pQuest->ReqItemId[x]; + uint32 count = pQuest->ReqItemCount[x]; + if(!id || !count) + continue; + + uint32 curItemCount = player->GetItemCount(id,true); + + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, id, count-curItemCount ); + if( msg == EQUIP_ERR_OK ) + { + Item* item = player->StoreNewItem( dest, id, true); + player->SendNewItem(item,count-curItemCount,true,false); + } + } + + // All creature/GO slain/casted (not required, but otherwise it will display "Creature slain 0/10") + for(uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + { + uint32 creature = pQuest->ReqCreatureOrGOId[i]; + uint32 creaturecount = pQuest->ReqCreatureOrGOCount[i]; + + if(uint32 spell_id = pQuest->ReqSpell[i]) + { + for(uint16 z = 0; z < creaturecount; ++z) + player->CastedCreatureOrGO(creature,0,spell_id); + } + else if(creature > 0) + { + for(uint16 z = 0; z < creaturecount; ++z) + player->KilledMonster(creature,0); + } + else if(creature < 0) + { + for(uint16 z = 0; z < creaturecount; ++z) + player->CastedCreatureOrGO(creature,0,0); + } + } + + // If the quest requires reputation to complete + if(uint32 repFaction = pQuest->GetRepObjectiveFaction()) + { + uint32 repValue = pQuest->GetRepObjectiveValue(); + uint32 curRep = player->GetReputation(repFaction); + if(curRep < repValue) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry(repFaction); + player->SetFactionReputation(factionEntry,repValue); + } + } + + // If the quest requires money + int32 ReqOrRewMoney = pQuest->GetRewOrReqMoney(); + if(ReqOrRewMoney < 0) + player->ModifyMoney(-ReqOrRewMoney); + + player->CompleteQuest(entry); + return true; +} + +bool ChatHandler::HandleBanCommand(const char* args) +{ + if(!args) + return false; + + char* type = strtok((char*)args, " "); + + if(!type) + return false; + char* nameOrIP = strtok(NULL, " "); + + if(!nameOrIP) + return false; + + char* duration = strtok(NULL," "); + if(!duration || !atoi(duration)) + return false; + + char* reason = strtok(NULL,""); + if(!reason) + return false; + + switch(sWorld.BanAccount(type, nameOrIP, duration, reason,m_session->GetPlayerName())) + { + case BAN_SUCCESS: + if(atoi(duration)>0) + PSendSysMessage(LANG_BAN_YOUBANNED,nameOrIP,secsToTimeString(TimeStringToSecs(duration),true).c_str(),reason); + else + PSendSysMessage(LANG_BAN_YOUPERMBANNED,nameOrIP,reason); + break; + case BAN_SYNTAX_ERROR: + return false; + case BAN_NOTFOUND: + PSendSysMessage(LANG_BAN_NOTFOUND,type,nameOrIP); + break; + } + + return true; +} + +bool ChatHandler::HandleUnBanCommand(const char* args) +{ + if(!args) + return false; + char* type = strtok((char*)args, " "); + if(!type) + return false; + char* nameOrIP = strtok(NULL, " "); + + if(!nameOrIP) + return false; + + if(sWorld.RemoveBanAccount(type,nameOrIP)) + PSendSysMessage(LANG_UNBAN_UNBANNED,nameOrIP); + else + PSendSysMessage(LANG_UNBAN_ERROR,nameOrIP); + + return true; +} + +bool ChatHandler::HandleBanInfoCommand(const char* args) +{ + if(!args) + return false; + + char* cType = strtok((char*)args, " "); + char* cnameOrIP = strtok(NULL, ""); + if(!cType || !cnameOrIP) + return false; + + std::string nameOrIP = cnameOrIP; + std::string type = cType; + if (!IsIPAddress(cnameOrIP) && type=="ip") + return false; + + Field *fields; + if(type != "ip") + { + //look the accountid up + uint32 accountid; + std::string accountname; + if(type == "account") + { + loginDatabase.escape_string(nameOrIP); + QueryResult *result = loginDatabase.PQuery("SELECT id, username FROM account WHERE username = '%s'",nameOrIP.c_str()); + if (!result) + { + PSendSysMessage(LANG_BANINFO_NOACCOUNT); + return true; + } + fields = result->Fetch(); + accountid = fields[0].GetUInt32(); + accountname = fields[1].GetCppString(); + delete result; + } + else if(type == "character") + { + if(!normalizePlayerName(nameOrIP)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + loginDatabase.escape_string(nameOrIP); + QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'", nameOrIP.c_str()); + if (!result) + { + PSendSysMessage(LANG_BANINFO_NOCHARACTER); + return true; + } + fields = result->Fetch(); + accountid = fields[0].GetUInt32(); + delete result; + result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", accountid); + if (!result) + { + PSendSysMessage(LANG_BANINFO_NOCHARACTER); + return true; + } + fields = result->Fetch(); + accountname = fields[0].GetCppString(); + delete result; + } + else + return false; + + QueryResult *result = loginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid); + if(!result) + { + PSendSysMessage(LANG_BANINFO_NOACCOUNTBAN, accountname.c_str()); + return true; + } + + PSendSysMessage(LANG_BANINFO_BANHISTORY,accountname.c_str()); + do + { + fields = result->Fetch(); + + time_t unbandate = time_t(fields[3].GetUInt64()); + bool active = false; + if(fields[2].GetBool() && (fields[1].GetUInt64() == (uint64)0 ||unbandate >= time(NULL)) ) + active = true; + bool permanent = (fields[1].GetUInt64() == (uint64)0); + std::string bantime = permanent?GetMangosString(LANG_BANINFO_INFINITE):secsToTimeString(fields[1].GetUInt64(), true); + PSendSysMessage(LANG_BANINFO_HISTORYENTRY, + fields[0].GetString(), bantime.c_str(), active ? GetMangosString(LANG_BANINFO_YES):GetMangosString(LANG_BANINFO_NO), fields[4].GetString(), fields[5].GetString()); + }while (result->NextRow()); + + delete result; + } + else + { + loginDatabase.escape_string(nameOrIP); + QueryResult *result = loginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str()); + if(!result) + { + PSendSysMessage(LANG_BANINFO_NOIP); + return true; + } + fields = result->Fetch(); + bool permanent = (fields[6].GetUInt64()==(uint64)0); + PSendSysMessage(LANG_BANINFO_IPENTRY, + fields[0].GetString(), fields[1].GetString(), permanent ? GetMangosString(LANG_BANINFO_NEVER):fields[2].GetString(), + permanent ? GetMangosString(LANG_BANINFO_INFINITE):secsToTimeString(fields[3].GetUInt64(), true).c_str(), fields[4].GetString(), fields[5].GetString()); + delete result; + } + return true; +} + +bool ChatHandler::HandleBanListCommand(const char* args) +{ + loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); + if(!*args) + return false; + char* cType = strtok((char*)args, " "); + char* cFilter = strtok(NULL, ""); + if(!cType || !cFilter) + return false; + std::string Filter = cFilter; + std::string Type = cType; + loginDatabase.escape_string(Filter); + + QueryResult* result = NULL; + Field *fields = NULL; + if(Type == "ip") + { + result = loginDatabase.PQuery("SELECT ip FROM ip_banned WHERE ip "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),Filter.c_str()); + if(!result) + { + PSendSysMessage(LANG_BANLIST_NOIP); + return true; + } + PSendSysMessage(LANG_BANLIST_MATCHINGIP); + do + { + fields = result->Fetch(); + PSendSysMessage("%s",fields[0].GetString()); + } while (result->NextRow()); + + delete result; + return true; + } + //lookup accountid + if(Type == "account") + { + result = loginDatabase.PQuery("SELECT id FROM account WHERE username "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),Filter.c_str()); + if (!result) + { + PSendSysMessage(LANG_BANLIST_NOACCOUNT); + return true; + } + //do not delete result + } + else if(Type == "characters") + { + result = CharacterDatabase.PQuery("SELECT account FROM characters, WHERE name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),Filter.c_str()); + if (!result) + { + PSendSysMessage(LANG_BANLIST_NOCHARACTER); + return true; + } + } + else + return false; + + PSendSysMessage(LANG_BANLIST_MATCHINGACCOUNT); + do + { + fields = result->Fetch(); + uint32 accountid = fields[0].GetUInt32(); + QueryResult* banresult = loginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.active = '1' AND account_banned.id=account.id",accountid); + if(banresult) + { + Field* fields2 = banresult->Fetch(); + PSendSysMessage("%s",fields2[0].GetString()); + delete banresult; + } + } while (result->NextRow()); + + delete result; + return true; +} + +bool ChatHandler::HandleRespawnCommand(const char* /*args*/) +{ + Player* pl = m_session->GetPlayer(); + + CellPair p(MaNGOS::ComputeCellPair(pl->GetPositionX(), pl->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::RespawnDo u_do; + MaNGOS::WorldObjectWorker worker(u_do); + + TypeContainerVisitor, GridTypeMapContainer > obj_worker(worker); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, obj_worker, *MapManager::Instance().GetMap(pl->GetMapId(), pl)); + + return true; +} + +bool ChatHandler::HandleFlyModeCommand(const char* args) +{ + if(!args) + return false; + + Unit *unit = getSelectedUnit(); + if (!unit || (unit->GetTypeId() != TYPEID_PLAYER)) + unit = m_session->GetPlayer(); + + WorldPacket data(12); + if (strncmp(args, "on", 3) == 0) + data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); + else if (strncmp(args, "off", 4) == 0) + data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); + else + { + SendSysMessage(LANG_USE_BOL); + return false; + } + data.append(unit->GetPackGUID()); + data << uint32(0); // unknown + unit->SendMessageToSet(&data, true); + PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, unit->GetName(), args); + return true; +} + +bool ChatHandler::HandleLoadPDumpCommand(const char *args) +{ + if(!args) + return false; + + char * file = strtok((char*)args, " "); if(!file) return false; + char * acc = strtok(NULL, " "); if(!acc) return false; + if(!file || !acc) + return false; + + uint32 account_id = objmgr.GetAccountByAccountName(acc); + if(!account_id) + { + account_id = atoi(acc); + if(account_id) + { + std::string acc_name; + if(!objmgr.GetAccountNameByAccount(account_id,acc_name)) + return false; + } + else + return false; + } + + char * name = strtok(NULL, " "); + char * guid_str = name ? strtok(NULL, " ") : NULL; + + uint32 guid = guid_str ? atoi(guid_str) : 0; + + if(PlayerDumpReader().LoadDump(file, account_id, name ? name : "", guid)) + PSendSysMessage(LANG_COMMAND_IMPORT_SUCCESS); + else + PSendSysMessage(LANG_COMMAND_IMPORT_FAILED); + + return true; +} + +bool ChatHandler::HandleChangeEntryCommand(const char *args) +{ + if(!args) + return false; + + uint32 newEntryNum = atoi(args); + if(!newEntryNum) + return false; + + Unit* unit = getSelectedUnit(); + if(!unit || unit->GetTypeId() != TYPEID_UNIT) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + Creature* creature = (Creature*)unit; + if(creature->UpdateEntry(newEntryNum)) + SendSysMessage(LANG_DONE); + else + SendSysMessage(LANG_ERROR); + return true; +} + +bool ChatHandler::HandleWritePDumpCommand(const char *args) +{ + if(!args) + return false; + + char* file = strtok((char*)args, " "); + char* p2 = strtok(NULL, " "); + + if(!file || !p2) + return false; + + uint32 guid = objmgr.GetPlayerGUIDByName(p2); + if(!guid) + guid = atoi(p2); + + if (PlayerDumpWriter().WriteDump(file, guid)) + PSendSysMessage(LANG_COMMAND_EXPORT_SUCCESS); + else + PSendSysMessage(LANG_COMMAND_EXPORT_FAILED); + + return true; +} + +bool ChatHandler::HandleMovegensCommand(const char* /*args*/) +{ + Unit* unit = getSelectedUnit(); + if(!unit) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_MOVEGENS_LIST,(unit->GetTypeId()==TYPEID_PLAYER ? "Player" : "Creature" ),unit->GetGUIDLow()); + + MotionMaster* mm = unit->GetMotionMaster(); + for(MotionMaster::const_iterator itr = mm->begin(); itr != mm->end(); ++itr) + { + switch((*itr)->GetMovementGeneratorType()) + { + case IDLE_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_IDLE); break; + case RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_RANDOM); break; + case WAYPOINT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_WAYPOINT); break; + case ANIMAL_RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_ANIMAL_RANDOM); break; + case CONFUSED_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_CONFUSED); break; + case TARGETED_MOTION_TYPE: + { + if(unit->GetTypeId()==TYPEID_PLAYER) + { + TargetedMovementGenerator const* mgen = static_cast const*>(*itr); + Unit* target = mgen->GetTarget(); + if(target) + PSendSysMessage(LANG_MOVEGENS_TARGETED_PLAYER,target->GetName(),target->GetGUIDLow()); + else + SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); + } + else + { + TargetedMovementGenerator const* mgen = static_cast const*>(*itr); + Unit* target = mgen->GetTarget(); + if(target) + PSendSysMessage(LANG_MOVEGENS_TARGETED_CREATURE,target->GetName(),target->GetGUIDLow()); + else + SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); + } + break; + } + case HOME_MOTION_TYPE: + if(unit->GetTypeId()==TYPEID_UNIT) + { + float x,y,z; + (*itr)->GetDestination(x,y,z); + PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE,x,y,z); + } + else + SendSysMessage(LANG_MOVEGENS_HOME_PLAYER); + break; + case FLIGHT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FLIGHT); break; + case POINT_MOTION_TYPE: + { + float x,y,z; + (*itr)->GetDestination(x,y,z); + PSendSysMessage(LANG_MOVEGENS_POINT,x,y,z); + break; + } + case FLEEING_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FEAR); break; + case DISTRACT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_DISTRACT); break; + default: + PSendSysMessage(LANG_MOVEGENS_UNKNOWN,(*itr)->GetMovementGeneratorType()); + break; + } + } + return true; +} + +bool ChatHandler::HandlePLimitCommand(const char *args) +{ + if(*args) + { + char* param = strtok((char*)args, " "); + if(!param) + return false; + + int l = strlen(param); + + if( strncmp(param,"player",l) == 0 ) + sWorld.SetPlayerLimit(-SEC_PLAYER); + else if(strncmp(param,"moderator",l) == 0 ) + sWorld.SetPlayerLimit(-SEC_MODERATOR); + else if(strncmp(param,"gamemaster",l) == 0 ) + sWorld.SetPlayerLimit(-SEC_GAMEMASTER); + else if(strncmp(param,"administrator",l) == 0 ) + sWorld.SetPlayerLimit(-SEC_ADMINISTRATOR); + else if(strncmp(param,"reset",l) == 0 ) + sWorld.SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT) ); + else + { + int val = atoi(param); + if(val < -SEC_ADMINISTRATOR) val = -SEC_ADMINISTRATOR; + + sWorld.SetPlayerLimit(val); + } + + // kick all low security level players + if(sWorld.GetPlayerAmountLimit() > SEC_PLAYER) + sWorld.KickAllLess(sWorld.GetPlayerSecurityLimit()); + } + + uint32 pLimit = sWorld.GetPlayerAmountLimit(); + AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); + char const* secName = ""; + switch(allowedAccountType) + { + case SEC_PLAYER: secName = "Player"; break; + case SEC_MODERATOR: secName = "Moderator"; break; + case SEC_GAMEMASTER: secName = "Gamemaster"; break; + case SEC_ADMINISTRATOR: secName = "Administrator"; break; + default: secName = ""; break; + } + + PSendSysMessage("Player limits: amount %u, min. security level %s.",pLimit,secName); + + return true; +} + +bool ChatHandler::HandleCastCommand(const char* args) +{ + if(!*args) + return false; + + Unit* target = getSelectedUnit(); + + if(!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if(!spell) + return false; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if(!spellInfo) + return false; + + if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + SetSentErrorMessage(true); + return false; + } + + char* trig_str = strtok(NULL, " "); + if(trig_str) + { + int l = strlen(trig_str); + if(strncmp(trig_str,"triggered",l) != 0 ) + return false; + } + + bool triggered = (trig_str != NULL); + + m_session->GetPlayer()->CastSpell(target,spell,triggered); + + return true; +} + +bool ChatHandler::HandleCastBackCommand(const char* args) +{ + Creature* caster = getSelectedCreature(); + + if(!caster) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if(!spell || !sSpellStore.LookupEntry(spell)) + return false; + + char* trig_str = strtok(NULL, " "); + if(trig_str) + { + int l = strlen(trig_str); + if(strncmp(trig_str,"triggered",l) != 0 ) + return false; + } + + bool triggered = (trig_str != NULL); + + // update orientation at server + caster->SetOrientation(caster->GetAngle(m_session->GetPlayer())); + + // and client + WorldPacket data; + caster->BuildHeartBeatMsg(&data); + caster->SendMessageToSet(&data,true); + + caster->CastSpell(m_session->GetPlayer(),spell,false); + + return true; +} + +bool ChatHandler::HandleCastDistCommand(const char* args) +{ + if(!*args) + return false; + + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if(!spell) + return false; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if(!spellInfo) + return false; + + if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + SetSentErrorMessage(true); + return false; + } + + char *distStr = strtok(NULL, " "); + + float dist = 0; + + if(distStr) + sscanf(distStr, "%f", &dist); + + char* trig_str = strtok(NULL, " "); + if(trig_str) + { + int l = strlen(trig_str); + if(strncmp(trig_str,"triggered",l) != 0 ) + return false; + } + + bool triggered = (trig_str != NULL); + + float x,y,z; + m_session->GetPlayer()->GetClosePoint(x,y,z,dist); + + m_session->GetPlayer()->CastSpell(x,y,z,spell,triggered); + return true; +} + +bool ChatHandler::HandleCastTargetCommand(const char* args) +{ + Creature* caster = getSelectedCreature(); + + if(!caster) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if(!caster->getVictim()) + { + SendSysMessage(LANG_SELECTED_TARGET_NOT_HAVE_VICTIM); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if(!spell || !sSpellStore.LookupEntry(spell)) + return false; + + char* trig_str = strtok(NULL, " "); + if(trig_str) + { + int l = strlen(trig_str); + if(strncmp(trig_str,"triggered",l) != 0 ) + return false; + } + + bool triggered = (trig_str != NULL); + + // update orientation at server + caster->SetOrientation(caster->GetAngle(m_session->GetPlayer())); + + // and client + WorldPacket data; + caster->BuildHeartBeatMsg(&data); + caster->SendMessageToSet(&data,true); + + caster->CastSpell(caster->getVictim(),spell,false); + + return true; +} + +/* +ComeToMe command REQUIRED for 3rd party scripting library to have access to PointMovementGenerator +Without this function 3rd party scripting library will get linking errors (unresolved external) +when attempting to use the PointMovementGenerator +*/ +bool ChatHandler::HandleComeToMeCommand(const char *args) +{ + Creature* caster = getSelectedCreature(); + + if(!caster) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + char* newFlagStr = strtok((char*)args, " "); + + if(!newFlagStr) + return false; + + uint32 newFlags = atoi(newFlagStr); + + caster->SetUnitMovementFlags(newFlags); + + Player* pl = m_session->GetPlayer(); + + caster->GetMotionMaster()->MovePoint(0, pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ()); + return true; +} + +bool ChatHandler::HandleCastSelfCommand(const char* args) +{ + if(!*args) + return false; + + Unit* target = getSelectedUnit(); + + if(!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if(!spell) + return false; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if(!spellInfo) + return false; + + if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + SetSentErrorMessage(true); + return false; + } + + target->CastSpell(target,spell,false); + + return true; +} + +std::string GetTimeString(uint32 time) +{ + uint16 days = time / DAY, hours = (time % DAY) / HOUR, minute = (time % HOUR) / MINUTE; + std::ostringstream ss; + if(days) ss << days << "d "; + if(hours) ss << hours << "h "; + ss << minute << "m"; + return ss.str(); +} + +bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) +{ + Player* player = getSelectedPlayer(); + if (!player) player = m_session->GetPlayer(); + uint32 counter = 0; + for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) + { + Player::BoundInstancesMap &binds = player->GetBoundInstances(i); + for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end(); ++itr) + { + InstanceSave *save = itr->second.save; + std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); + PSendSysMessage("map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); + counter++; + } + } + PSendSysMessage("player binds: %d", counter); + counter = 0; + Group *group = player->GetGroup(); + if(group) + { + for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) + { + Group::BoundInstancesMap &binds = group->GetBoundInstances(i); + for(Group::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end(); ++itr) + { + InstanceSave *save = itr->second.save; + std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); + PSendSysMessage("map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); + counter++; + } + } + } + PSendSysMessage("group binds: %d", counter); + + return true; +} + +bool ChatHandler::HandleInstanceUnbindCommand(const char* args) +{ + if(!*args) + return false; + + std::string cmd = args; + if(cmd == "all") + { + Player* player = getSelectedPlayer(); + if (!player) player = m_session->GetPlayer(); + uint32 counter = 0; + for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) + { + Player::BoundInstancesMap &binds = player->GetBoundInstances(i); + for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();) + { + if(itr->first != player->GetMapId()) + { + InstanceSave *save = itr->second.save; + std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); + PSendSysMessage("unbinding map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); + player->UnbindInstance(itr, i); + counter++; + } + else + ++itr; + } + } + PSendSysMessage("instances unbound: %d", counter); + } + return true; +} + +bool ChatHandler::HandleInstanceStatsCommand(const char* /*args*/) +{ + PSendSysMessage("instances loaded: %d", MapManager::Instance().GetNumInstances()); + PSendSysMessage("players in instances: %d", MapManager::Instance().GetNumPlayersInInstances()); + PSendSysMessage("instance saves: %d", sInstanceSaveManager.GetNumInstanceSaves()); + PSendSysMessage("players bound: %d", sInstanceSaveManager.GetNumBoundPlayersTotal()); + PSendSysMessage("groups bound: %d", sInstanceSaveManager.GetNumBoundGroupsTotal()); + return true; +} + +bool ChatHandler::HandleInstanceSaveDataCommand(const char * /*args*/) +{ + Player* pl = m_session->GetPlayer(); + + Map* map = pl->GetMap(); + if (!map->IsDungeon()) + { + PSendSysMessage("Map is not a dungeon."); + SetSentErrorMessage(true); + return false; + } + + if (!((InstanceMap*)map)->GetInstanceData()) + { + PSendSysMessage("Map has no instance data."); + SetSentErrorMessage(true); + return false; + } + + ((InstanceMap*)map)->GetInstanceData()->SaveToDB(); + return true; +} diff --git a/src/game/Makefile.am b/src/game/Makefile.am index cffd1f7b093..6d9fc63af82 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -30,6 +30,8 @@ libgame_a_CPPFLAGS = \ $(MYSQL_INCLUDES) \ $(POSTGRE_INCLUDES) \ -I$(top_srcdir)/dep/include \ +-I$(top_srcdir)/dep/ACE_wrappers \ +-I$(top_builddir)/dep/ACE_wrappers \ -I$(top_srcdir)/src/framework \ -I$(top_srcdir)/src/shared \ -I$(top_srcdir)/src/shared/vmap diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index 5739f56e328..5d3e9b61aa2 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -1,832 +1,826 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Language.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "World.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Player.h" -#include "GossipDef.h" -#include "SpellAuras.h" -#include "UpdateMask.h" -#include "ScriptCalls.h" -#include "ObjectAccessor.h" -#include "Creature.h" -#include "MapManager.h" -#include "Pet.h" -#include "BattleGroundMgr.h" -#include "BattleGround.h" -#include "Guild.h" - -void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - uint64 guid; - recv_data >> guid; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TABARDDESIGNER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - SendTabardVendorActivate(guid); -} - -void WorldSession::SendTabardVendorActivate( uint64 guid ) -{ - WorldPacket data( MSG_TABARDVENDOR_ACTIVATE, 8 ); - data << guid; - SendPacket( &data ); -} - -void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - uint64 guid; - - sLog.outDebug( "WORLD: Received CMSG_BANKER_ACTIVATE" ); - - recv_data >> guid; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_BANKER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - SendShowBank(guid); -} - -void WorldSession::SendShowBank( uint64 guid ) -{ - WorldPacket data( SMSG_SHOW_BANK, 8 ); - data << guid; - SendPacket( &data ); -} - -void WorldSession::HandleTrainerListOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - uint64 guid; - - recv_data >> guid; - SendTrainerList( guid ); -} - -void WorldSession::SendTrainerList( uint64 guid ) -{ - std::string str = GetMangosString(LANG_NPC_TAINER_HELLO); - SendTrainerList( guid, str ); -} - -void WorldSession::SendTrainerList( uint64 guid,std::string strTitle ) -{ - sLog.outDebug( "WORLD: SendTrainerList" ); - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TRAINER); - if (!unit) - { - sLog.outDebug( "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - // Lazy loading at first access - unit->LoadTrainerSpells(); - - // trainer list loaded at check; - if(!unit->isCanTrainingOf(_player,true)) - return; - - CreatureInfo const *ci = unit->GetCreatureInfo(); - - if (!ci) - { - sLog.outDebug( "WORLD: SendTrainerList - (%u) NO CREATUREINFO! (GUID: %u)", uint32(GUID_LOPART(guid)), guid ); - return; - } - - Creature::SpellsList const& trainer_spells = unit->GetTrainerSpells(); - - WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells.size()*38 + strTitle.size()+1); - data << guid; - data << uint32(unit->GetTrainerType()); - - size_t count_pos = data.wpos(); - data << uint32(trainer_spells.size()); - - // reputation discount - float fDiscountMod = _player->GetReputationPriceDiscount(unit); - - uint32 count = 0; - for(Creature::SpellsList::const_iterator itr = trainer_spells.begin(); itr != trainer_spells.end(); ++itr) - { - if(!_player->IsSpellFitByClassAndRace(itr->spell->Id)) - continue; - - ++count; - - bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(itr->spell->Id); - - SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(itr->spell->Id); - - data << uint32(itr->spell->Id); - data << uint8(_player->GetTrainerSpellState(&*itr)); - data << uint32(floor(itr->spellcost * fDiscountMod)); - - data << uint32(primary_prof_first_rank ? 1 : 0); // primary prof. learn confirmation dialog - data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state - data << uint8(itr->reqlevel ? itr->reqlevel : itr->spell->spellLevel); - data << uint32(itr->reqskill); - data << uint32(itr->reqskillvalue); - data << uint32(chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0); - data << uint32(chain_node && chain_node->prev ? chain_node->req : 0); - data << uint32(0); - } - - data << strTitle; - - data.put(count_pos,count); - SendPacket( &data ); -} - -void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8+4); - - uint64 guid; - uint32 spellId = 0; - - recv_data >> guid >> spellId; - sLog.outDebug( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId ); - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_TRAINER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - // Lazy loading at first access - unit->LoadTrainerSpells(); - - if(!unit->isCanTrainingOf(_player,true)) - return; - - TrainerSpell const* trainer_spell = NULL; - - // check present spell in trainer spell list - Creature::SpellsList const& trainer_spells = unit->GetTrainerSpells(); - for(Creature::SpellsList::const_iterator itr = trainer_spells.begin(); itr != trainer_spells.end(); ++itr) - { - if(itr->spell->Id == spellId) - { - trainer_spell = &*itr; - break; - } - } - - // not found, cheat? - if(!trainer_spell) - return; - - // can't be learn, cheat? Or double learn with lags... - if(_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) - return; - - // apply reputation discount - uint32 nSpellCost = uint32(floor(trainer_spell->spellcost * _player->GetReputationPriceDiscount(unit))); - - // check money requirement - if(_player->GetMoney() < nSpellCost ) - return; - - WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer - data << uint64(guid) << uint32(0xB3); - SendPacket(&data); - - data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player - data << uint64(_player->GetGUID()) << uint32(0x016A); - SendPacket(&data); - - _player->ModifyMoney( -int32(nSpellCost) ); - - // learn explicitly to prevent lost money at lags, learning spell will be only show spell animation - _player->learnSpell(trainer_spell->spell->Id); - - data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12); - data << uint64(guid) << uint32(spellId); - SendPacket(&data); -} - -void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - sLog.outDebug( "WORLD: Received CMSG_GOSSIP_HELLO" ); - - uint64 guid; - recv_data >> guid; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE); - if (!unit) - { - sLog.outDebug( "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - if( unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider()) - { - unit->StopMoving(); - } - - // If spiritguide, no need for gossip menu, just put player into resurrect queue - if (unit->isSpiritGuide()) - { - BattleGround *bg = _player->GetBattleGround(); - if(bg) - { - bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); - sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); - return; - } - } - - if(!Script->GossipHello( _player, unit )) - { - _player->TalkedToCreature(unit->GetEntry(),unit->GetGUID()); - unit->prepareGossipMenu(_player,0); - unit->sendPreparedGossip( _player ); - } -} - -void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8+4+4); - - sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION"); - - uint32 option; - uint32 unk; - uint64 guid; - std::string code = ""; - - recv_data >> guid >> unk >> option; - - if(_player->PlayerTalkClass->GossipOptionCoded( option )) - { - // recheck - CHECK_PACKET_SIZE(recv_data,8+4+1); - sLog.outBasic("reading string"); - recv_data >> code; - sLog.outBasic("string read: %s", code.c_str()); - } - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE); - if (!unit) - { - sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - if(!code.empty()) - { - - if(!Script->GossipSelectWithCode( _player, unit, _player->PlayerTalkClass->GossipOptionSender( option ), _player->PlayerTalkClass->GossipOptionAction( option ), code.c_str()) ) - unit->OnGossipSelect( _player, option ); - } - else - - if(!Script->GossipSelect( _player, unit, _player->PlayerTalkClass->GossipOptionSender( option ), _player->PlayerTalkClass->GossipOptionAction( option )) ) - unit->OnGossipSelect( _player, option ); -} - -void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE"); - - uint64 guid; - - recv_data >> guid; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_SPIRITHEALER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - SendSpiritResurrect(); -} - -void WorldSession::SendSpiritResurrect() -{ - _player->ResurrectPlayer(0.5f,false, true); - - _player->DurabilityLossAll(0.25f,true); - - // get corpse nearest graveyard - WorldSafeLocsEntry const *corpseGrave = NULL; - Corpse *corpse = _player->GetCorpse(); - if(corpse) - corpseGrave = objmgr.GetClosestGraveYard( - corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam() ); - - // now can spawn bones - _player->SpawnCorpseBones(); - - // teleport to nearest from corpse graveyard, if different from nearest to player ghost - if(corpseGrave) - { - WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard( - _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam() ); - - if(corpseGrave != ghostGrave) - _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); - // or update at original position - else - ObjectAccessor::UpdateVisibilityForPlayer(_player); - } - // or update at original position - else - ObjectAccessor::UpdateVisibilityForPlayer(_player); - - _player->SaveToDB(); -} - -void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - uint64 npcGUID; - recv_data >> npcGUID; - - if(!GetPlayer()->isAlive()) - return; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID,UNIT_NPC_FLAG_INNKEEPER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - SendBindPoint(unit); -} - -void WorldSession::SendBindPoint(Creature *npc) -{ - uint32 bindspell = 3286; - - // update sql homebind - CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), _player->GetZoneId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow()); - _player->m_homebindMapId = _player->GetMapId(); - _player->m_homebindZoneId = _player->GetZoneId(); - _player->m_homebindX = _player->GetPositionX(); - _player->m_homebindY = _player->GetPositionY(); - _player->m_homebindZ = _player->GetPositionZ(); - - // send spell for bind 3286 bind magic - npc->CastSpell(_player, bindspell, true); - - WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4)); - data << npc->GetGUID(); - data << bindspell; - SendPacket( &data ); - - // binding - data.Initialize( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) ); - data << float(_player->GetPositionX()); - data << float(_player->GetPositionY()); - data << float(_player->GetPositionZ()); - data << uint32(_player->GetMapId()); - data << uint32(_player->GetZoneId()); - SendPacket( &data ); - - DEBUG_LOG("New Home Position X is %f",_player->GetPositionX()); - DEBUG_LOG("New Home Position Y is %f",_player->GetPositionY()); - DEBUG_LOG("New Home Position Z is %f",_player->GetPositionZ()); - DEBUG_LOG("New Home MapId is %u",_player->GetMapId()); - DEBUG_LOG("New Home ZoneId is %u",_player->GetZoneId()); - - // zone update - data.Initialize( SMSG_PLAYERBOUND, 8+4 ); - data << uint64(_player->GetGUID()); - data << uint32(_player->GetZoneId()); - SendPacket( &data ); - - _player->PlayerTalkClass->CloseGossip(); -} - -//Need fix -void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS"); - uint64 npcGUID; - - recv_data >> npcGUID; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - SendStablePet(npcGUID); -} - -void WorldSession::SendStablePet(uint64 guid ) -{ - sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send."); - - WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size - data << uint64 ( guid ); - - Pet *pet = _player->GetPet(); - - data << uint8(0); // place holder for slot show number - data << uint8(GetPlayer()->m_stableSlots); - - uint8 num = 0; // counter for place holder - - // not let move dead pet in slot - if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET) - { - data << uint32(pet->GetCharmInfo()->GetPetNumber()); - data << uint32(pet->GetEntry()); - data << uint32(pet->getLevel()); - data << pet->GetName(); // petname - data << uint32(pet->GetLoyaltyLevel()); // loyalty - data << uint8(0x01); // client slot 1 == current pet (0) - ++num; - } - - // 0 1 2 3 4 5 6 - QueryResult* result = CharacterDatabase.PQuery("SELECT owner, slot, id, entry, level, loyalty, name FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow()); - - if(result) - { - do - { - Field *fields = result->Fetch(); - - data << uint32(fields[2].GetUInt32()); // petnumber - data << uint32(fields[3].GetUInt32()); // creature entry - data << uint32(fields[4].GetUInt32()); // level - data << fields[6].GetString(); // name - data << uint32(fields[5].GetUInt32()); // loyalty - data << uint8(fields[1].GetUInt32()+1); // slot - - ++num; - }while( result->NextRow() ); - - delete result; - } - - data.put(8, num); // set real data to placeholder - SendPacket(&data); -} - -void WorldSession::HandleStablePet( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - sLog.outDebug("WORLD: Recv CMSG_STABLE_PET not dispose."); - uint64 npcGUID; - - recv_data >> npcGUID; - - if(!GetPlayer()->isAlive()) - return; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - Pet *pet = _player->GetPet(); - - WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size - - // can't place in stable dead pet - if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET) - { - data << uint8(0x06); - SendPacket(&data); - return; - } - - uint32 free_slot = 1; - - QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3 ORDER BY slot ",_player->GetGUIDLow()); - if(result) - { - do - { - Field *fields = result->Fetch(); - - uint32 slot = fields[1].GetUInt32(); - - if(slot==free_slot) // this slot not free - ++free_slot; - }while( result->NextRow() ); - } - delete result; - - if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots) - { - _player->RemovePet(pet,PetSaveMode(free_slot)); - data << uint8(0x08); - } - else - data << uint8(0x06); - - SendPacket(&data); -} - -void WorldSession::HandleUnstablePet( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8+4); - - sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET."); - uint64 npcGUID; - uint32 petnumber; - - recv_data >> npcGUID >> petnumber; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size - - Pet* pet = _player->GetPet(); - if(pet && pet->isAlive()) - { - uint8 i = 0x06; - data << uint8(i); - SendPacket(&data); - return; - } - - // delete dead pet - if(pet) - _player->RemovePet(pet,PET_SAVE_AS_DELETED); - - Pet *newpet = NULL; - - QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow(),petnumber); - if(result) - { - Field *fields = result->Fetch(); - uint32 petentry = fields[0].GetUInt32(); - - newpet = new Pet(HUNTER_PET); - if(!newpet->LoadPetFromDB(_player,petentry,petnumber)) - { - delete newpet; - newpet = NULL; - } - delete result; - } - - if(newpet) - data << uint8(0x09); - else - data << uint8(0x06); - SendPacket(&data); -} - -void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8); - - sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT."); - uint64 npcGUID; - - recv_data >> npcGUID; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - WorldPacket data(SMSG_STABLE_RESULT, 200); - - if(GetPlayer()->m_stableSlots < 2) // max slots amount = 2 - { - StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); - if(_player->GetMoney() >= SlotPrice->Price) - { - ++GetPlayer()->m_stableSlots; - _player->ModifyMoney(-int32(SlotPrice->Price)); - data << uint8(0x0A); // success buy - } - else - data << uint8(0x06); - } - else - data << uint8(0x06); - - SendPacket(&data); -} - -void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */) -{ - sLog.outDebug("HandleStableRevivePet: Not implemented"); -} - -void WorldSession::HandleStableSwapPet( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8+4); - - sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET."); - uint64 npcGUID; - uint32 pet_number; - - recv_data >> npcGUID >> pet_number; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size - - Pet* pet = _player->GetPet(); - - if(!pet || pet->getPetType()!=HUNTER_PET) - return; - - // find swapped pet slot in stable - QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",_player->GetGUIDLow(),pet_number); - if(!result) - return; - - Field *fields = result->Fetch(); - - uint32 slot = fields[0].GetUInt32(); - uint32 petentry = fields[1].GetUInt32(); - delete result; - - // move alive pet to slot or delele dead pet - _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED); - - // summon unstabled pet - Pet *newpet = new Pet; - if(!newpet->LoadPetFromDB(_player,petentry,pet_number)) - { - delete newpet; - data << uint8(0x06); - } - else - data << uint8(0x09); - - SendPacket(&data); -} - -void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data ) -{ - CHECK_PACKET_SIZE(recv_data,8+8+1); - - sLog.outDebug("WORLD: CMSG_REPAIR_ITEM"); - - uint64 npcGUID, itemGUID; - uint8 guildBank; // new in 2.3.2, bool that means from guild bank money - - recv_data >> npcGUID >> itemGUID >> guildBank; - - Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_REPAIR); - if (!unit) - { - sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); - return; - } - - // remove fake death - if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - // reputation discount - float discountMod = _player->GetReputationPriceDiscount(unit); - - uint32 TotalCost = 0; - if (itemGUID) - { - sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID)); - - Item* item = _player->GetItemByGuid(itemGUID); - - if(item) - TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false); - } - else - { - sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID)); - - TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false); - } - if (guildBank) - { - uint32 GuildId = _player->GetGuildId(); - if (!GuildId) - return; - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost); - pGuild->SendMoneyInfo(this, _player->GetGUIDLow()); - } -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Language.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "World.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Player.h" +#include "GossipDef.h" +#include "SpellAuras.h" +#include "UpdateMask.h" +#include "ScriptCalls.h" +#include "ObjectAccessor.h" +#include "Creature.h" +#include "MapManager.h" +#include "Pet.h" +#include "BattleGroundMgr.h" +#include "BattleGround.h" +#include "Guild.h" + +void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + uint64 guid; + recv_data >> guid; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TABARDDESIGNER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + SendTabardVendorActivate(guid); +} + +void WorldSession::SendTabardVendorActivate( uint64 guid ) +{ + WorldPacket data( MSG_TABARDVENDOR_ACTIVATE, 8 ); + data << guid; + SendPacket( &data ); +} + +void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + uint64 guid; + + sLog.outDebug( "WORLD: Received CMSG_BANKER_ACTIVATE" ); + + recv_data >> guid; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_BANKER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + SendShowBank(guid); +} + +void WorldSession::SendShowBank( uint64 guid ) +{ + WorldPacket data( SMSG_SHOW_BANK, 8 ); + data << guid; + SendPacket( &data ); +} + +void WorldSession::HandleTrainerListOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + uint64 guid; + + recv_data >> guid; + SendTrainerList( guid ); +} + +void WorldSession::SendTrainerList( uint64 guid ) +{ + std::string str = GetMangosString(LANG_NPC_TAINER_HELLO); + SendTrainerList( guid, str ); +} + +void WorldSession::SendTrainerList( uint64 guid,std::string strTitle ) +{ + sLog.outDebug( "WORLD: SendTrainerList" ); + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TRAINER); + if (!unit) + { + sLog.outDebug( "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + // trainer list loaded at check; + if(!unit->isCanTrainingOf(_player,true)) + return; + + CreatureInfo const *ci = unit->GetCreatureInfo(); + + if (!ci) + { + sLog.outDebug( "WORLD: SendTrainerList - (%u) NO CREATUREINFO! (GUID: %u)", uint32(GUID_LOPART(guid)), guid ); + return; + } + + TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); + if(!trainer_spells) + { + sLog.outDebug( "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)", guid, unit->GetEntry()); + return; + } + + WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); + data << guid; + data << uint32(trainer_spells->trainerType); + + size_t count_pos = data.wpos(); + data << uint32(trainer_spells->spellList.size()); + + // reputation discount + float fDiscountMod = _player->GetReputationPriceDiscount(unit); + + uint32 count = 0; + for(TrainerSpellList::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) + { + TrainerSpell const* tSpell = *itr; + + if(!_player->IsSpellFitByClassAndRace(tSpell->spell)) + continue; + + ++count; + + bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->spell); + + SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->spell); + + data << uint32(tSpell->spell); + data << uint8(_player->GetTrainerSpellState(tSpell)); + data << uint32(floor(tSpell->spellcost * fDiscountMod)); + + data << uint32(primary_prof_first_rank ? 1 : 0); // primary prof. learn confirmation dialog + data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state + data << uint8(tSpell->reqlevel); + data << uint32(tSpell->reqskill); + data << uint32(tSpell->reqskillvalue); + data << uint32(chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0); + data << uint32(chain_node && chain_node->prev ? chain_node->req : 0); + data << uint32(0); + } + + data << strTitle; + + data.put(count_pos,count); + SendPacket( &data ); +} + +void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8+4); + + uint64 guid; + uint32 spellId = 0; + + recv_data >> guid >> spellId; + sLog.outDebug( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId ); + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_TRAINER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + if(!unit->isCanTrainingOf(_player,true)) + return; + + // check present spell in trainer spell list + TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); + if(!trainer_spells) + return; + + // not found, cheat? + TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); + if(!trainer_spell) + return; + + // can't be learn, cheat? Or double learn with lags... + if(_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) + return; + + // apply reputation discount + uint32 nSpellCost = uint32(floor(trainer_spell->spellcost * _player->GetReputationPriceDiscount(unit))); + + // check money requirement + if(_player->GetMoney() < nSpellCost ) + return; + + WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer + data << uint64(guid) << uint32(0xB3); + SendPacket(&data); + + data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player + data << uint64(_player->GetGUID()) << uint32(0x016A); + SendPacket(&data); + + _player->ModifyMoney( -int32(nSpellCost) ); + + // learn explicitly to prevent lost money at lags, learning spell will be only show spell animation + _player->learnSpell(trainer_spell->spell); + + data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12); + data << uint64(guid) << uint32(spellId); + SendPacket(&data); +} + +void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + sLog.outDebug( "WORLD: Received CMSG_GOSSIP_HELLO" ); + + uint64 guid; + recv_data >> guid; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE); + if (!unit) + { + sLog.outDebug( "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + if( unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider()) + { + unit->StopMoving(); + } + + // If spiritguide, no need for gossip menu, just put player into resurrect queue + if (unit->isSpiritGuide()) + { + BattleGround *bg = _player->GetBattleGround(); + if(bg) + { + bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); + sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); + return; + } + } + + if(!Script->GossipHello( _player, unit )) + { + _player->TalkedToCreature(unit->GetEntry(),unit->GetGUID()); + unit->prepareGossipMenu(_player,0); + unit->sendPreparedGossip( _player ); + } +} + +void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8+4+4); + + sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION"); + + uint32 option; + uint32 unk; + uint64 guid; + std::string code = ""; + + recv_data >> guid >> unk >> option; + + if(_player->PlayerTalkClass->GossipOptionCoded( option )) + { + // recheck + CHECK_PACKET_SIZE(recv_data,8+4+1); + sLog.outBasic("reading string"); + recv_data >> code; + sLog.outBasic("string read: %s", code.c_str()); + } + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE); + if (!unit) + { + sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + if(!code.empty()) + { + + if(!Script->GossipSelectWithCode( _player, unit, _player->PlayerTalkClass->GossipOptionSender( option ), _player->PlayerTalkClass->GossipOptionAction( option ), code.c_str()) ) + unit->OnGossipSelect( _player, option ); + } + else + + if(!Script->GossipSelect( _player, unit, _player->PlayerTalkClass->GossipOptionSender( option ), _player->PlayerTalkClass->GossipOptionAction( option )) ) + unit->OnGossipSelect( _player, option ); +} + +void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE"); + + uint64 guid; + + recv_data >> guid; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_SPIRITHEALER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + SendSpiritResurrect(); +} + +void WorldSession::SendSpiritResurrect() +{ + _player->ResurrectPlayer(0.5f,false, true); + + _player->DurabilityLossAll(0.25f,true); + + // get corpse nearest graveyard + WorldSafeLocsEntry const *corpseGrave = NULL; + Corpse *corpse = _player->GetCorpse(); + if(corpse) + corpseGrave = objmgr.GetClosestGraveYard( + corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam() ); + + // now can spawn bones + _player->SpawnCorpseBones(); + + // teleport to nearest from corpse graveyard, if different from nearest to player ghost + if(corpseGrave) + { + WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard( + _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam() ); + + if(corpseGrave != ghostGrave) + _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); + // or update at original position + else + ObjectAccessor::UpdateVisibilityForPlayer(_player); + } + // or update at original position + else + ObjectAccessor::UpdateVisibilityForPlayer(_player); + + _player->SaveToDB(); +} + +void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + uint64 npcGUID; + recv_data >> npcGUID; + + if(!GetPlayer()->isAlive()) + return; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID,UNIT_NPC_FLAG_INNKEEPER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + SendBindPoint(unit); +} + +void WorldSession::SendBindPoint(Creature *npc) +{ + uint32 bindspell = 3286; + + // update sql homebind + CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), _player->GetZoneId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow()); + _player->m_homebindMapId = _player->GetMapId(); + _player->m_homebindZoneId = _player->GetZoneId(); + _player->m_homebindX = _player->GetPositionX(); + _player->m_homebindY = _player->GetPositionY(); + _player->m_homebindZ = _player->GetPositionZ(); + + // send spell for bind 3286 bind magic + npc->CastSpell(_player, bindspell, true); + + WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4)); + data << npc->GetGUID(); + data << bindspell; + SendPacket( &data ); + + // binding + data.Initialize( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) ); + data << float(_player->GetPositionX()); + data << float(_player->GetPositionY()); + data << float(_player->GetPositionZ()); + data << uint32(_player->GetMapId()); + data << uint32(_player->GetZoneId()); + SendPacket( &data ); + + DEBUG_LOG("New Home Position X is %f",_player->GetPositionX()); + DEBUG_LOG("New Home Position Y is %f",_player->GetPositionY()); + DEBUG_LOG("New Home Position Z is %f",_player->GetPositionZ()); + DEBUG_LOG("New Home MapId is %u",_player->GetMapId()); + DEBUG_LOG("New Home ZoneId is %u",_player->GetZoneId()); + + // zone update + data.Initialize( SMSG_PLAYERBOUND, 8+4 ); + data << uint64(_player->GetGUID()); + data << uint32(_player->GetZoneId()); + SendPacket( &data ); + + _player->PlayerTalkClass->CloseGossip(); +} + +//Need fix +void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS"); + uint64 npcGUID; + + recv_data >> npcGUID; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + SendStablePet(npcGUID); +} + +void WorldSession::SendStablePet(uint64 guid ) +{ + sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send."); + + WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size + data << uint64 ( guid ); + + Pet *pet = _player->GetPet(); + + data << uint8(0); // place holder for slot show number + data << uint8(GetPlayer()->m_stableSlots); + + uint8 num = 0; // counter for place holder + + // not let move dead pet in slot + if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET) + { + data << uint32(pet->GetCharmInfo()->GetPetNumber()); + data << uint32(pet->GetEntry()); + data << uint32(pet->getLevel()); + data << pet->GetName(); // petname + data << uint32(pet->GetLoyaltyLevel()); // loyalty + data << uint8(0x01); // client slot 1 == current pet (0) + ++num; + } + + // 0 1 2 3 4 5 6 + QueryResult* result = CharacterDatabase.PQuery("SELECT owner, slot, id, entry, level, loyalty, name FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow()); + + if(result) + { + do + { + Field *fields = result->Fetch(); + + data << uint32(fields[2].GetUInt32()); // petnumber + data << uint32(fields[3].GetUInt32()); // creature entry + data << uint32(fields[4].GetUInt32()); // level + data << fields[6].GetString(); // name + data << uint32(fields[5].GetUInt32()); // loyalty + data << uint8(fields[1].GetUInt32()+1); // slot + + ++num; + }while( result->NextRow() ); + + delete result; + } + + data.put(8, num); // set real data to placeholder + SendPacket(&data); +} + +void WorldSession::HandleStablePet( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + sLog.outDebug("WORLD: Recv CMSG_STABLE_PET not dispose."); + uint64 npcGUID; + + recv_data >> npcGUID; + + if(!GetPlayer()->isAlive()) + return; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + Pet *pet = _player->GetPet(); + + WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size + + // can't place in stable dead pet + if(!pet||!pet->isAlive()||pet->getPetType()!=HUNTER_PET) + { + data << uint8(0x06); + SendPacket(&data); + return; + } + + uint32 free_slot = 1; + + QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3 ORDER BY slot ",_player->GetGUIDLow()); + if(result) + { + do + { + Field *fields = result->Fetch(); + + uint32 slot = fields[1].GetUInt32(); + + if(slot==free_slot) // this slot not free + ++free_slot; + }while( result->NextRow() ); + } + delete result; + + if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots) + { + _player->RemovePet(pet,PetSaveMode(free_slot)); + data << uint8(0x08); + } + else + data << uint8(0x06); + + SendPacket(&data); +} + +void WorldSession::HandleUnstablePet( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8+4); + + sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET."); + uint64 npcGUID; + uint32 petnumber; + + recv_data >> npcGUID >> petnumber; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size + + Pet* pet = _player->GetPet(); + if(pet && pet->isAlive()) + { + uint8 i = 0x06; + data << uint8(i); + SendPacket(&data); + return; + } + + // delete dead pet + if(pet) + _player->RemovePet(pet,PET_SAVE_AS_DELETED); + + Pet *newpet = NULL; + + QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow(),petnumber); + if(result) + { + Field *fields = result->Fetch(); + uint32 petentry = fields[0].GetUInt32(); + + newpet = new Pet(HUNTER_PET); + if(!newpet->LoadPetFromDB(_player,petentry,petnumber)) + { + delete newpet; + newpet = NULL; + } + delete result; + } + + if(newpet) + data << uint8(0x09); + else + data << uint8(0x06); + SendPacket(&data); +} + +void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8); + + sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT."); + uint64 npcGUID; + + recv_data >> npcGUID; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + WorldPacket data(SMSG_STABLE_RESULT, 200); + + if(GetPlayer()->m_stableSlots < 2) // max slots amount = 2 + { + StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); + if(_player->GetMoney() >= SlotPrice->Price) + { + ++GetPlayer()->m_stableSlots; + _player->ModifyMoney(-int32(SlotPrice->Price)); + data << uint8(0x0A); // success buy + } + else + data << uint8(0x06); + } + else + data << uint8(0x06); + + SendPacket(&data); +} + +void WorldSession::HandleStableRevivePet( WorldPacket &/* recv_data */) +{ + sLog.outDebug("HandleStableRevivePet: Not implemented"); +} + +void WorldSession::HandleStableSwapPet( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8+4); + + sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET."); + uint64 npcGUID; + uint32 pet_number; + + recv_data >> npcGUID >> pet_number; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size + + Pet* pet = _player->GetPet(); + + if(!pet || pet->getPetType()!=HUNTER_PET) + return; + + // find swapped pet slot in stable + QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",_player->GetGUIDLow(),pet_number); + if(!result) + return; + + Field *fields = result->Fetch(); + + uint32 slot = fields[0].GetUInt32(); + uint32 petentry = fields[1].GetUInt32(); + delete result; + + // move alive pet to slot or delele dead pet + _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED); + + // summon unstabled pet + Pet *newpet = new Pet; + if(!newpet->LoadPetFromDB(_player,petentry,pet_number)) + { + delete newpet; + data << uint8(0x06); + } + else + data << uint8(0x09); + + SendPacket(&data); +} + +void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8+8+1); + + sLog.outDebug("WORLD: CMSG_REPAIR_ITEM"); + + uint64 npcGUID, itemGUID; + uint8 guildBank; // new in 2.3.2, bool that means from guild bank money + + recv_data >> npcGUID >> itemGUID >> guildBank; + + Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_REPAIR); + if (!unit) + { + sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) ); + return; + } + + // remove fake death + if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + // reputation discount + float discountMod = _player->GetReputationPriceDiscount(unit); + + uint32 TotalCost = 0; + if (itemGUID) + { + sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID)); + + Item* item = _player->GetItemByGuid(itemGUID); + + if(item) + TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false); + } + else + { + sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID)); + + TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false); + } + if (guildBank) + { + uint32 GuildId = _player->GetGuildId(); + if (!GuildId) + return; + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost); + pGuild->SendMoneyInfo(this, _player->GetGUIDLow()); + } +} diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 982ae3c4bc4..a6cbb0e653d 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -1,6512 +1,6858 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "Database/SQLStorage.h" - -#include "Log.h" -#include "MapManager.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "UpdateMask.h" -#include "World.h" -#include "WorldSession.h" -#include "Group.h" -#include "Guild.h" -#include "ArenaTeam.h" -#include "Transports.h" -#include "ProgressBar.h" -#include "Policies/SingletonImp.h" -#include "Language.h" -#include "GameEvent.h" -#include "Spell.h" -#include "Chat.h" -#include "InstanceSaveMgr.h" -#include "SpellAuras.h" -#include "Util.h" - -INSTANTIATE_SINGLETON_1(ObjectMgr); - -ScriptMapMap sQuestEndScripts; -ScriptMapMap sQuestStartScripts; -ScriptMapMap sSpellScripts; -ScriptMapMap sGameObjectScripts; -ScriptMapMap sEventScripts; - -bool normalizePlayerName(std::string& name) -{ - if(name.empty()) - return false; - - wchar_t wstr_buf[MAX_INTERNAL_PLAYER_NAME+1]; - size_t wstr_len = MAX_INTERNAL_PLAYER_NAME; - - if(!Utf8toWStr(name,&wstr_buf[0],wstr_len)) - return false; - - wstr_buf[0] = wcharToUpper(wstr_buf[0]); - for(size_t i = 1; i < wstr_len; ++i) - wstr_buf[i] = wcharToLower(wstr_buf[i]); - - if(!WStrToUtf8(wstr_buf,wstr_len,name)) - return false; - - return true; -} - -ObjectMgr::ObjectMgr() -{ - m_hiCharGuid = 1; - m_hiCreatureGuid = 1; - m_hiPetGuid = 1; - m_hiItemGuid = 1; - m_hiGoGuid = 1; - m_hiDoGuid = 1; - m_hiCorpseGuid = 1; - - m_hiPetNumber = 1; - - mGuildBankTabPrice.resize(GUILD_BANK_MAX_TABS); - mGuildBankTabPrice[0] = 100; - mGuildBankTabPrice[1] = 250; - mGuildBankTabPrice[2] = 500; - mGuildBankTabPrice[3] = 1000; - mGuildBankTabPrice[4] = 2500; - mGuildBankTabPrice[5] = 5000; - - // Only zero condition left, others will be added while loading DB tables - mConditions.resize(1); -} - -ObjectMgr::~ObjectMgr() -{ - for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++ i ) - { - delete i->second; - } - mQuestTemplates.clear( ); - - for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++ i ) - { - delete i->second; - } - mGossipText.clear( ); - - mAreaTriggers.clear(); - - for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++ i ) - { - delete[] i->second; - } - petInfo.clear(); - - // free only if loaded - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - delete[] playerClassInfo[class_].levelInfo; - - for (int race = 0; race < MAX_RACES; ++race) - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - delete[] playerInfo[race][class_].levelInfo; - - // free group and guild objects - for (GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) - delete (*itr); - for (GuildSet::iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr) - delete (*itr); - - for(ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr) - delete itr->second; -} - -Group * ObjectMgr::GetGroupByLeader(const uint64 &guid) const -{ - for(GroupSet::const_iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) - if ((*itr)->GetLeaderGUID() == guid) - return *itr; - - return NULL; -} - -Guild * ObjectMgr::GetGuildById(const uint32 GuildId) const -{ - for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++) - if ((*itr)->GetId() == GuildId) - return *itr; - - return NULL; -} - -Guild * ObjectMgr::GetGuildByName(std::string guildname) const -{ - for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++) - if ((*itr)->GetName() == guildname) - return *itr; - - return NULL; -} - -std::string ObjectMgr::GetGuildNameById(const uint32 GuildId) const -{ - for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++) - if ((*itr)->GetId() == GuildId) - return (*itr)->GetName(); - - return ""; -} - -Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const -{ - for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr) - if( (*itr)->GetLeader() == guid) - return *itr; - - return NULL; -} - -ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 ArenaTeamId) const -{ - for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++) - if ((*itr)->GetId() == ArenaTeamId) - return *itr; - - return NULL; -} - -ArenaTeam* ObjectMgr::GetArenaTeamByName(std::string arenateamname) const -{ - for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++) - if ((*itr)->GetName() == arenateamname) - return *itr; - - return NULL; -} - -ArenaTeam* ObjectMgr::GetArenaTeamByCapitan(uint64 const& guid) const -{ - for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++) - if ((*itr)->GetCaptain() == guid) - return *itr; - - return NULL; -} - -AuctionHouseObject * ObjectMgr::GetAuctionsMap( uint32 location ) -{ - switch ( location ) - { - case 6: //horde - return & mHordeAuctions; - break; - case 2: //alliance - return & mAllianceAuctions; - break; - default: //neutral - return & mNeutralAuctions; - } -} - -uint32 ObjectMgr::GetAuctionCut(uint32 location, uint32 highBid) -{ - if (location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) - return (uint32) (0.15f * highBid * sWorld.getRate(RATE_AUCTION_CUT)); - else - return (uint32) (0.05f * highBid * sWorld.getRate(RATE_AUCTION_CUT)); -} - -uint32 ObjectMgr::GetAuctionDeposit(uint32 location, uint32 time, Item *pItem) -{ - float percentance; // in 0..1 - if ( location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) - percentance = 0.75f; - else - percentance = 0.15f; - - percentance *= sWorld.getRate(RATE_AUCTION_DEPOSIT); - - return uint32( percentance * pItem->GetProto()->SellPrice * pItem->GetCount() * (time / MIN_AUCTION_TIME ) ); -} - -/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c -uint32 ObjectMgr::GetAuctionOutBid(uint32 currentBid) -{ - uint32 outbid = (currentBid / 100) * 5; - if (!outbid) - outbid = 1; - return outbid; -} - -//does not clear ram -void ObjectMgr::SendAuctionWonMail( AuctionEntry *auction ) -{ - Item *pItem = objmgr.GetAItem(auction->item_guidlow); - if(!pItem) - return; - - uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); - Player *bidder = objmgr.GetPlayer(bidder_guid); - - uint32 bidder_accId = 0; - - // data for gm.log - if( sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) - { - uint32 bidder_security = 0; - std::string bidder_name; - if (bidder) - { - bidder_accId = bidder->GetSession()->GetAccountId(); - bidder_security = bidder->GetSession()->GetSecurity(); - bidder_name = bidder->GetName(); - } - else - { - bidder_accId = GetPlayerAccountIdByGUID(bidder_guid); - bidder_security = GetSecurityByAccount(bidder_accId); - - if(bidder_security > SEC_PLAYER ) // not do redundant DB requests - { - if(!GetPlayerNameByGUID(bidder_guid,bidder_name)) - bidder_name = GetMangosStringForDBCLocale(LANG_UNKNOWN); - } - } - - if( bidder_security > SEC_PLAYER ) - { - std::string owner_name; - if(!GetPlayerNameByGUID(auction->owner,owner_name)) - owner_name = GetMangosStringForDBCLocale(LANG_UNKNOWN); - - uint32 owner_accid = GetPlayerAccountIdByGUID(auction->owner); - - sLog.outCommand("GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", - bidder_name.c_str(),bidder_accId,pItem->GetProto()->Name1,pItem->GetEntry(),pItem->GetCount(),auction->bid,owner_name.c_str(),owner_accid); - } - } - else if(!bidder) - bidder_accId = GetPlayerAccountIdByGUID(bidder_guid); - - // receiver exist - if(bidder || bidder_accId) - { - std::ostringstream msgAuctionWonSubject; - msgAuctionWonSubject << auction->item_template << ":0:" << AUCTION_WON; - - std::ostringstream msgAuctionWonBody; - msgAuctionWonBody.width(16); - msgAuctionWonBody << std::right << std::hex << auction->owner; - msgAuctionWonBody << std::dec << ":" << auction->bid << ":" << auction->buyout; - sLog.outDebug( "AuctionWon body string : %s", msgAuctionWonBody.str().c_str() ); - - //prepare mail data... : - uint32 itemTextId = this->CreateItemText( msgAuctionWonBody.str() ); - - // set owner to bidder (to prevent delete item with sender char deleting) - // owner in `data` will set at mail receive and item extracting - CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'",auction->bidder,pItem->GetGUIDLow()); - CharacterDatabase.CommitTransaction(); - - MailItemsInfo mi; - mi.AddItem(auction->item_guidlow, auction->item_template, pItem); - - if (bidder) - bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, bidder_guid, 0, 0, auction->item_template); - else - objmgr.RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! - - // will delete item or place to receiver mail list - WorldSession::SendMailTo(bidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionWonSubject.str(), itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_AUCTION); - } - // receiver not exist - else - { - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", pItem->GetGUIDLow()); - objmgr.RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! - delete pItem; - } -} - -void ObjectMgr::SendAuctionSalePendingMail( AuctionEntry * auction ) -{ - uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); - Player *owner = objmgr.GetPlayer(owner_guid); - - // owner exist (online or offline) - if(owner || GetPlayerAccountIdByGUID(owner_guid)) - { - std::ostringstream msgAuctionSalePendingSubject; - msgAuctionSalePendingSubject << auction->item_template << ":0:" << AUCTION_SALE_PENDING; - - std::ostringstream msgAuctionSalePendingBody; - uint32 auctionCut = GetAuctionCut(auction->location, auction->bid); - - time_t distrTime = time(NULL) + HOUR; - - msgAuctionSalePendingBody.width(16); - msgAuctionSalePendingBody << std::right << std::hex << auction->bidder; - msgAuctionSalePendingBody << std::dec << ":" << auction->bid << ":" << auction->buyout; - msgAuctionSalePendingBody << ":" << auction->deposit << ":" << auctionCut << ":0:"; - msgAuctionSalePendingBody << secsToTimeBitFields(distrTime); - - sLog.outDebug("AuctionSalePending body string : %s", msgAuctionSalePendingBody.str().c_str()); - - uint32 itemTextId = this->CreateItemText( msgAuctionSalePendingBody.str() ); - - WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSalePendingSubject.str(), itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_AUCTION); - } -} - -//call this method to send mail to auction owner, when auction is successful, it does not clear ram -void ObjectMgr::SendAuctionSuccessfulMail( AuctionEntry * auction ) -{ - uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); - Player *owner = objmgr.GetPlayer(owner_guid); - - uint32 owner_accId = 0; - if(!owner) - owner_accId = GetPlayerAccountIdByGUID(owner_guid); - - // owner exist - if(owner || owner_accId) - { - std::ostringstream msgAuctionSuccessfulSubject; - msgAuctionSuccessfulSubject << auction->item_template << ":0:" << AUCTION_SUCCESSFUL; - - std::ostringstream auctionSuccessfulBody; - uint32 auctionCut = GetAuctionCut(auction->location, auction->bid); - - auctionSuccessfulBody.width(16); - auctionSuccessfulBody << std::right << std::hex << auction->bidder; - auctionSuccessfulBody << std::dec << ":" << auction->bid << ":" << auction->buyout; - auctionSuccessfulBody << ":" << auction->deposit << ":" << auctionCut; - - sLog.outDebug("AuctionSuccessful body string : %s", auctionSuccessfulBody.str().c_str()); - - uint32 itemTextId = this->CreateItemText( auctionSuccessfulBody.str() ); - - uint32 profit = auction->bid + auction->deposit - auctionCut; - - if (owner) - { - //send auction owner notification, bidder must be current! - owner->GetSession()->SendAuctionOwnerNotification( auction ); - } - - WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSuccessfulSubject.str(), itemTextId, NULL, profit, 0, MAIL_CHECK_MASK_AUCTION, HOUR); - } -} - -//does not clear ram -void ObjectMgr::SendAuctionExpiredMail( AuctionEntry * auction ) -{ //return an item in auction to its owner by mail - Item *pItem = objmgr.GetAItem(auction->item_guidlow); - if(!pItem) - { - sLog.outError("Auction item (GUID: %u) not found, and lost.",auction->item_guidlow); - return; - } - - uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); - Player *owner = objmgr.GetPlayer(owner_guid); - - uint32 owner_accId = 0; - if(!owner) - owner_accId = GetPlayerAccountIdByGUID(owner_guid); - - // owner exist - if(owner || owner_accId) - { - std::ostringstream subject; - subject << auction->item_template << ":0:" << AUCTION_EXPIRED; - - if ( owner ) - owner->GetSession()->SendAuctionOwnerNotification( auction ); - else - objmgr.RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! - - MailItemsInfo mi; - mi.AddItem(auction->item_guidlow, auction->item_template, pItem); - - // will delete item or place to receiver mail list - WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, GUID_LOPART(owner_guid), subject.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE); - - } - // owner not found - else - { - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'",pItem->GetGUIDLow()); - objmgr.RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! - delete pItem; - } -} - -CreatureInfo const* ObjectMgr::GetCreatureTemplate(uint32 id) -{ - return sCreatureStorage.LookupEntry(id); -} - -void ObjectMgr::LoadCreatureLocales() -{ - QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,subname_loc1,name_loc2,subname_loc2,name_loc3,subname_loc3,name_loc4,subname_loc4,name_loc5,subname_loc5,name_loc6,subname_loc6,name_loc7,subname_loc7,name_loc8,subname_loc8 FROM locales_creature"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - sLog.outString(">> Loaded 0 creature locale strings. DB table `locales_creature` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - CreatureLocale& data = mCreatureLocaleMap[entry]; - - for(int i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[1+2*(i-1)].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Name.size() <= idx) - data.Name.resize(idx+1); - - data.Name[idx] = str; - } - } - str = fields[1+2*(i-1)+1].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.SubName.size() <= idx) - data.SubName.resize(idx+1); - - data.SubName[idx] = str; - } - } - } - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() ); -} - -void ObjectMgr::LoadCreatureTemplates() -{ - sCreatureStorage.Load(); - - sLog.outString( ">> Loaded %u creature definitions", sCreatureStorage.RecordCount ); - sLog.outString(); - - std::set heroicEntries; // already loaded heroic value in creatures - std::set hasHeroicEntries; // already loaded creatures with heroic entry values - - // check data correctness - for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i) - { - CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i); - if(!cInfo) - continue; - - if(cInfo->HeroicEntry) - { - CreatureInfo const* heroicInfo = GetCreatureTemplate(cInfo->HeroicEntry); - if(!heroicInfo) - { - sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u not exist.",cInfo->HeroicEntry,cInfo->HeroicEntry); - continue; - } - - if(heroicEntries.find(i)!=heroicEntries.end()) - { - sLog.outErrorDb("Creature (Entry: %u) listed as heroic but have value in `heroic_entry`.",i); - continue; - } - - if(heroicEntries.find(cInfo->HeroicEntry)!=heroicEntries.end()) - { - sLog.outErrorDb("Creature (Entry: %u) already listed as heroic for another entry.",cInfo->HeroicEntry); - continue; - } - - if(hasHeroicEntries.find(cInfo->HeroicEntry)!=hasHeroicEntries.end()) - { - sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u have heroic entry also.",i,cInfo->HeroicEntry,cInfo->HeroicEntry); - continue; - } - - if(cInfo->npcflag != heroicInfo->npcflag) - { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `npcflag` in heroic mode.",i); - continue; - } - - if(cInfo->classNum != heroicInfo->classNum) - { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `classNum` in heroic mode.",i); - continue; - } - - if(cInfo->race != heroicInfo->race) - { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `race` in heroic mode.",i); - continue; - } - - if(cInfo->trainer_type != heroicInfo->trainer_type) - { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_type` in heroic mode.",i); - continue; - } - - if(cInfo->trainer_spell != heroicInfo->trainer_spell) - { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_spell` in heroic mode.",i); - continue; - } - - hasHeroicEntries.insert(i); - heroicEntries.insert(cInfo->HeroicEntry); - } - - FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A); - if(!factionTemplate) - sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A); - - factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H); - if(!factionTemplate) - sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H); - - CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->DisplayID_A); - if (!minfo) - sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_A (%u)", cInfo->Entry, cInfo->DisplayID_A); - minfo = sCreatureModelStorage.LookupEntry(cInfo->DisplayID_H); - if (!minfo) - sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_H (%u)", cInfo->Entry, cInfo->DisplayID_H); - - if(cInfo->dmgschool >= MAX_SPELL_SCHOOL) - { - sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool); - const_cast(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL; - } - - if(cInfo->baseattacktime == 0) - const_cast(cInfo)->baseattacktime = BASE_ATTACK_TIME; - - if(cInfo->rangeattacktime == 0) - const_cast(cInfo)->rangeattacktime = BASE_ATTACK_TIME; - - if((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE) - sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type); - - if(cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE) - { - sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType); - const_cast(cInfo)->InhabitType = INHABIT_ANYWHERE; - } - - if(cInfo->PetSpellDataId) - { - CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId); - if(!spellDataId) - sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId); - } - - if(cInfo->MovementType >= MAX_DB_MOTION_TYPE) - { - sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType); - const_cast(cInfo)->MovementType = IDLE_MOTION_TYPE; - } - - if(cInfo->equipmentId > 0) // 0 no equipment - { - if(!GetEquipmentInfo(cInfo->equipmentId)) - { - sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId); - const_cast(cInfo)->equipmentId = 0; - } - } - - /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc - if(cInfo->scale <= 0.0f) - { - CreatureDisplayInfoEntry const* ScaleEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->DisplayID_A); - const_cast(cInfo)->scale = ScaleEntry ? ScaleEntry->scale : 1.0f; - } - } -} - -void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr) -{ - // Now add the auras, format "spellid effectindex spellid effectindex..." - char *p,*s; - std::vector val; - s=p=(char*)reinterpret_cast(addon->auras); - if(p) - { - while (p[0]!=0) - { - ++p; - if (p[0]==' ') - { - val.push_back(atoi(s)); - s=++p; - } - } - if (p!=s) - val.push_back(atoi(s)); - - // free char* loaded memory - delete[] (char*)reinterpret_cast(addon->auras); - - // wrong list - if (val.size()%2) - { - addon->auras = NULL; - sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`.",guidEntryStr,addon->guidOrEntry,table); - return; - } - } - - // empty list - if(val.empty()) - { - addon->auras = NULL; - return; - } - - // replace by new strucutres array - const_cast(addon->auras) = new CreatureDataAddonAura[val.size()/2+1]; - - int i=0; - for(int j=0;j(addon->auras[i]); - cAura.spell_id = (uint32)val[2*j+0]; - cAura.effect_idx = (uint32)val[2*j+1]; - if ( cAura.effect_idx > 2 ) - { - sLog.outErrorDb("Creature (%s: %u) has wrong effect %u for spell %u in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table); - continue; - } - SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura.spell_id); - if (!AdditionalSpellInfo) - { - sLog.outErrorDb("Creature (%s: %u) has wrong spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table); - continue; - } - - if (!AdditionalSpellInfo->Effect[cAura.effect_idx] || !AdditionalSpellInfo->EffectApplyAuraName[cAura.effect_idx]) - { - sLog.outErrorDb("Creature (%s: %u) has not aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table); - continue; - } - - ++i; - } - - // fill terminator element (after last added) - CreatureDataAddonAura& endAura = const_cast(addon->auras[i]); - endAura.spell_id = 0; - endAura.effect_idx = 0; -} - -void ObjectMgr::LoadCreatureAddons() -{ - sCreatureInfoAddonStorage.Load(); - - sLog.outString( ">> Loaded %u creature template addons", sCreatureInfoAddonStorage.RecordCount ); - sLog.outString(); - - // check data correctness and convert 'auras' - for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i) - { - CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry(i); - if(!addon) - continue; - - ConvertCreatureAddonAuras(const_cast(addon), "creature_template_addon", "Entry"); - - if(!sCreatureStorage.LookupEntry(addon->guidOrEntry)) - sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `creature_template_addon`",addon->guidOrEntry); - } - - sCreatureDataAddonStorage.Load(); - - sLog.outString( ">> Loaded %u creature addons", sCreatureDataAddonStorage.RecordCount ); - sLog.outString(); - - // check data correctness and convert 'auras' - for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i) - { - CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry(i); - if(!addon) - continue; - - ConvertCreatureAddonAuras(const_cast(addon), "creature_addon", "GUIDLow"); - - if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end()) - sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry); - } -} - -EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry) -{ - return sEquipmentStorage.LookupEntry(entry); -} - -void ObjectMgr::LoadEquipmentTemplates() -{ - sEquipmentStorage.Load(); - - sLog.outString( ">> Loaded %u equipment template", sEquipmentStorage.RecordCount ); - sLog.outString(); -} - -CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid) -{ - return sCreatureModelStorage.LookupEntry(modelid); -} - -uint32 ObjectMgr::ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data) -{ - // Load creature model (display id) - uint32 display_id; - if (!data || data->displayid == 0) // use defaults from the template - { - // DisplayID_A is used if no team is given - if (team == HORDE) - display_id = (cinfo->DisplayID_H2 != 0 && urand(0,1) == 0) ? cinfo->DisplayID_H2 : cinfo->DisplayID_H; - else - display_id = (cinfo->DisplayID_A2 != 0 && urand(0,1) == 0) ? cinfo->DisplayID_A2 : cinfo->DisplayID_A; - } - else // overriden in creature data - display_id = data->displayid; - - return display_id; -} - -CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_id) -{ - CreatureModelInfo const *minfo = GetCreatureModelInfo(display_id); - if(!minfo) - return NULL; - - // If a model for another gender exists, 50% chance to use it - if(minfo->modelid_other_gender != 0 && urand(0,1) == 0) - { - CreatureModelInfo const *minfo_tmp = GetCreatureModelInfo(minfo->modelid_other_gender); - if(!minfo_tmp) - { - sLog.outErrorDb("Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", minfo->modelid, minfo->modelid_other_gender); - return minfo; // not fatal, just use the previous one - } - else - return minfo_tmp; - } - else - return minfo; -} - -void ObjectMgr::LoadCreatureModelInfo() -{ - sCreatureModelStorage.Load(); - - sLog.outString( ">> Loaded %u creature model based info", sCreatureModelStorage.RecordCount ); - sLog.outString(); -} - -void ObjectMgr::LoadCreatures() -{ - uint32 count = 0; - // 0 1 2 3 - QueryResult *result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid," - // 4 5 6 7 8 9 10 11 - "equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint," - // 12 13 14 15 16 17 - "curhealth, curmana, DeathState, MovementType, spawnMask, event " - "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty."); - return; - } - - // build single time for check creature data - std::set heroicCreatures; - for(uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i) - if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) - if(cInfo->HeroicEntry) - heroicCreatures.insert(cInfo->HeroicEntry); - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 guid = fields[0].GetUInt32(); - - CreatureData& data = mCreatureDataMap[guid]; - - data.id = fields[ 1].GetUInt32(); - data.mapid = fields[ 2].GetUInt32(); - data.displayid = fields[ 3].GetUInt32(); - data.equipmentId = fields[ 4].GetUInt32(); - data.posX = fields[ 5].GetFloat(); - data.posY = fields[ 6].GetFloat(); - data.posZ = fields[ 7].GetFloat(); - data.orientation = fields[ 8].GetFloat(); - data.spawntimesecs = fields[ 9].GetUInt32(); - data.spawndist = fields[10].GetFloat(); - data.currentwaypoint= fields[11].GetUInt32(); - data.curhealth = fields[12].GetUInt32(); - data.curmana = fields[13].GetUInt32(); - data.is_dead = fields[14].GetBool(); - data.movementType = fields[15].GetUInt8(); - data.spawnMask = fields[16].GetUInt8(); - int16 gameEvent = fields[17].GetInt16(); - - CreatureInfo const* cInfo = GetCreatureTemplate(data.id); - if(!cInfo) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u) with not existed creature entry %u, skipped.",guid,data.id ); - continue; - } - - if(heroicCreatures.find(data.id)!=heroicCreatures.end()) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template in `creature_template_substitution`, skipped.",guid,data.id ); - continue; - } - - if(data.equipmentId > 0) // -1 no equipment, 0 use default - { - if(!GetEquipmentInfo(data.equipmentId)) - { - sLog.outErrorDb("Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId); - data.equipmentId = -1; - } - } - - if(cInfo->RegenHealth && data.curhealth < cInfo->minhealth) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.",guid,data.id,data.curhealth, cInfo->minhealth ); - data.curhealth = cInfo->minhealth; - } - - if(data.curmana < cInfo->minmana) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana ); - data.curmana = cInfo->minmana; - } - - if(data.spawndist < 0.0f) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.",guid,data.id ); - data.spawndist = 0.0f; - } - else if(data.movementType == RANDOM_MOTION_TYPE) - { - if(data.spawndist == 0.0f) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=1 (random movement) but with `spawndist`=0, replace by idle movement type (0).",guid,data.id ); - data.movementType = IDLE_MOTION_TYPE; - } - } - else if(data.movementType == IDLE_MOTION_TYPE) - { - if(data.spawndist != 0.0f) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=0 (idle) have `spawndist`<>0, set to 0.",guid,data.id ); - data.spawndist = 0.0f; - } - } - - if (gameEvent==0) // if not this is to be managed by GameEvent System - AddCreatureToGrid(guid, &data); - ++count; - - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u creatures", mCreatureDataMap.size() ); -} - -void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data) -{ - uint8 mask = data->spawnMask; - for(uint8 i = 0; mask != 0; i++, mask >>= 1) - { - if(mask & 1) - { - CellPair cell_pair = MaNGOS::ComputeCellPair(data->posX, data->posY); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; - cell_guids.creatures.insert(guid); - } - } -} - -void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data) -{ - uint8 mask = data->spawnMask; - for(uint8 i = 0; mask != 0; i++, mask >>= 1) - { - if(mask & 1) - { - CellPair cell_pair = MaNGOS::ComputeCellPair(data->posX, data->posY); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; - cell_guids.creatures.erase(guid); - } - } -} - -void ObjectMgr::LoadGameobjects() -{ - uint32 count = 0; - - // 0 1 2 3 4 5 6 - QueryResult *result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation," - // 7 8 9 10 11 12 13 14 15 - "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, event " - "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 gameobjects. DB table `gameobject` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 guid = fields[0].GetUInt32(); - - GameObjectData& data = mGameObjectDataMap[guid]; - - data.id = fields[ 1].GetUInt32(); - data.mapid = fields[ 2].GetUInt32(); - data.posX = fields[ 3].GetFloat(); - data.posY = fields[ 4].GetFloat(); - data.posZ = fields[ 5].GetFloat(); - data.orientation = fields[ 6].GetFloat(); - data.rotation0 = fields[ 7].GetFloat(); - data.rotation1 = fields[ 8].GetFloat(); - data.rotation2 = fields[ 9].GetFloat(); - data.rotation3 = fields[10].GetFloat(); - data.spawntimesecs = fields[11].GetInt32(); - data.animprogress = fields[12].GetUInt32(); - data.go_state = fields[13].GetUInt32(); - data.spawnMask = fields[14].GetUInt8(); - int16 gameEvent = fields[15].GetInt16(); - - GameObjectInfo const* gInfo = GetGameObjectInfo(data.id); - if(!gInfo) - { - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u) with not existed gameobject entry %u, skipped.",guid,data.id ); - continue; - } - - if (gameEvent==0) // if not this is to be managed by GameEvent System - AddGameobjectToGrid(guid, &data); - ++count; - - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u gameobjects", mGameObjectDataMap.size()); -} - -void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data) -{ - uint8 mask = data->spawnMask; - for(uint8 i = 0; mask != 0; i++, mask >>= 1) - { - if(mask & 1) - { - CellPair cell_pair = MaNGOS::ComputeCellPair(data->posX, data->posY); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; - cell_guids.gameobjects.insert(guid); - } - } -} - -void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data) -{ - uint8 mask = data->spawnMask; - for(uint8 i = 0; mask != 0; i++, mask >>= 1) - { - if(mask & 1) - { - CellPair cell_pair = MaNGOS::ComputeCellPair(data->posX, data->posY); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; - cell_guids.gameobjects.erase(guid); - } - } -} - -void ObjectMgr::LoadCreatureRespawnTimes() -{ - // remove outdated data - WorldDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); - - uint32 count = 0; - - QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM creature_respawn"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded 0 creature respawn time."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 loguid = fields[0].GetUInt32(); - uint64 respawn_time = fields[1].GetUInt64(); - uint32 instance = fields[2].GetUInt32(); - - mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time); - - ++count; - } while (result->NextRow()); - - delete result; - - sLog.outString( ">> Loaded %u creature respawn times", mCreatureRespawnTimes.size() ); - sLog.outString(); -} - -void ObjectMgr::LoadGameobjectRespawnTimes() -{ - // remove outdated data - WorldDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); - - uint32 count = 0; - - QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM gameobject_respawn"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded 0 gameobject respawn time."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 loguid = fields[0].GetUInt32(); - uint64 respawn_time = fields[1].GetUInt64(); - uint32 instance = fields[2].GetUInt32(); - - mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time); - - ++count; - } while (result->NextRow()); - - delete result; - - sLog.outString( ">> Loaded %u gameobject respawn times", mGORespawnTimes.size() ); - sLog.outString(); -} - -// name must be checked to correctness (if received) before call this function -uint64 ObjectMgr::GetPlayerGUIDByName(std::string name) const -{ - uint64 guid = 0; - - CharacterDatabase.escape_string(name); - - // Player name safe to sending to DB (checked at login) and this function using - QueryResult *result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE name = '%s'", name.c_str()); - if(result) - { - guid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); - - delete result; - } - - return guid; -} - -bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const -{ - // prevent DB access for online player - if(Player* player = GetPlayer(guid)) - { - name = player->GetName(); - return true; - } - - QueryResult *result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); - - if(result) - { - name = (*result)[0].GetCppString(); - delete result; - return true; - } - - return false; -} - -uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const -{ - QueryResult *result = CharacterDatabase.PQuery("SELECT race FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); - - if(result) - { - uint8 race = (*result)[0].GetUInt8(); - delete result; - return Player::TeamForRace(race); - } - - return 0; -} - -uint32 ObjectMgr::GetPlayerAccountIdByGUID(const uint64 &guid) const -{ - QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); - if(result) - { - uint32 acc = (*result)[0].GetUInt32(); - delete result; - return acc; - } - - return 0; -} - -uint32 ObjectMgr::GetSecurityByAccount(uint32 acc_id) const -{ - QueryResult *result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id); - if(result) - { - uint32 sec = (*result)[0].GetUInt32(); - delete result; - return sec; - } - - return 0; -} - -bool ObjectMgr::GetAccountNameByAccount(uint32 acc_id, std::string &name) const -{ - QueryResult *result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id); - if(result) - { - name = (*result)[0].GetCppString(); - delete result; - return true; - } - - return false; -} - -uint32 ObjectMgr::GetAccountByAccountName(std::string name) const -{ - loginDatabase.escape_string(name); - QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", name.c_str()); - if(result) - { - uint32 id = (*result)[0].GetUInt32(); - delete result; - return id; - } - - return 0; -} - -void ObjectMgr::LoadAuctions() -{ - QueryResult *result = CharacterDatabase.Query("SELECT COUNT(*) FROM auctionhouse"); - if( !result ) - return; - - Field *fields = result->Fetch(); - uint32 AuctionCount=fields[0].GetUInt32(); - delete result; - - if(!AuctionCount) - return; - - result = CharacterDatabase.Query( "SELECT id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit,location FROM auctionhouse" ); - if( !result ) - return; - - barGoLink bar( AuctionCount ); - - AuctionEntry *aItem; - - do - { - fields = result->Fetch(); - - bar.step(); - - aItem = new AuctionEntry; - aItem->Id = fields[0].GetUInt32(); - aItem->auctioneer = fields[1].GetUInt32(); - aItem->item_guidlow = fields[2].GetUInt32(); - aItem->item_template = fields[3].GetUInt32(); - aItem->owner = fields[4].GetUInt32(); - aItem->buyout = fields[5].GetUInt32(); - aItem->time = fields[6].GetUInt32(); - aItem->bidder = fields[7].GetUInt32(); - aItem->bid = fields[8].GetUInt32(); - aItem->startbid = fields[9].GetUInt32(); - aItem->deposit = fields[10].GetUInt32(); - aItem->location = fields[11].GetUInt8(); - //check if sold item exists - if ( this->GetAItem( aItem->item_guidlow ) ) - { - GetAuctionsMap( aItem->location )->AddAuction(aItem); - } - else - { - CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",aItem->Id); - sLog.outError("Auction %u has not a existing item : %u", aItem->Id, aItem->item_guidlow); - delete aItem; - } - } while (result->NextRow()); - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u auctions", AuctionCount ); - sLog.outString(); -} - -void ObjectMgr::LoadItemLocales() -{ - QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,description_loc1,name_loc2,description_loc2,name_loc3,description_loc3,name_loc4,description_loc4,name_loc5,description_loc5,name_loc6,description_loc6,name_loc7,description_loc7,name_loc8,description_loc8 FROM locales_item"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - sLog.outString(">> Loaded 0 Item locale strings. DB table `locales_item` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - ItemLocale& data = mItemLocaleMap[entry]; - - for(int i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[1+2*(i-1)].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Name.size() <= idx) - data.Name.resize(idx+1); - - data.Name[idx] = str; - } - } - - str = fields[1+2*(i-1)+1].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Description.size() <= idx) - data.Description.resize(idx+1); - - data.Description[idx] = str; - } - } - } - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u Item locale strings", mItemLocaleMap.size() ); -} - -void ObjectMgr::LoadItemPrototypes() -{ - sItemStorage.Load (); - sLog.outString( ">> Loaded %u item prototypes", sItemStorage.RecordCount ); - sLog.outString(); - - // check data correctness - for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i) - { - ItemPrototype const* proto = sItemStorage.LookupEntry(i); - ItemEntry const *dbcitem = sItemStore.LookupEntry(i); - if(!proto) - { - /* to many errors, and possible not all items really used in game - if (dbcitem) - sLog.outErrorDb("Item (Entry: %u) doesn't exists in DB, but must exist.",i); - */ - continue; - } - - if(dbcitem) - { - if(proto->InventoryType != dbcitem->InventoryType) - { - sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType); - // It safe let use InventoryType from DB - } - - if(proto->DisplayInfoID != dbcitem->DisplayId) - { - sLog.outErrorDb("Item (Entry: %u) not correct %u display id, must be %u (using it).",i,proto->DisplayInfoID,dbcitem->DisplayId); - const_cast(proto)->DisplayInfoID = dbcitem->DisplayId; - } - if(proto->Sheath != dbcitem->Sheath) - { - sLog.outErrorDb("Item (Entry: %u) not correct %u sheath, must be %u (using it).",i,proto->Sheath,dbcitem->Sheath); - const_cast(proto)->Sheath = dbcitem->Sheath; - } - } - else - { - sLog.outErrorDb("Item (Entry: %u) not correct (not listed in list of existed items).",i); - } - - if(proto->Class >= MAX_ITEM_CLASS) - { - sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class); - const_cast(proto)->Class = ITEM_CLASS_JUNK; - } - - if(proto->SubClass >= MaxItemSubclassValues[proto->Class]) - { - sLog.outErrorDb("Item (Entry: %u) has wrong Subclass value (%u) for class %u",i,proto->SubClass,proto->Class); - const_cast(proto)->SubClass = 0;// exist for all item classes - } - - if(proto->Quality >= MAX_ITEM_QUALITY) - { - sLog.outErrorDb("Item (Entry: %u) has wrong Quality value (%u)",i,proto->Quality); - const_cast(proto)->Quality = ITEM_QUALITY_NORMAL; - } - - if(proto->BuyCount <= 0) - { - sLog.outErrorDb("Item (Entry: %u) has wrong BuyCount value (%u), set to default(1).",i,proto->BuyCount); - const_cast(proto)->BuyCount = 1; - } - - if(proto->InventoryType >= MAX_INVTYPE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong InventoryType value (%u)",i,proto->InventoryType); - const_cast(proto)->InventoryType = INVTYPE_NON_EQUIP; - } - - if(proto->RequiredSkill >= MAX_SKILL_TYPE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill); - const_cast(proto)->RequiredSkill = 0; - } - - if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE)) - { - sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped.",i,proto->AllowableClass); - } - - if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE)) - { - sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped.",i,proto->AllowableRace); - } - - if(proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell)) - { - sLog.outErrorDb("Item (Entry: %u) have wrong (non-existed) spell in RequiredSpell (%u)",i,proto->RequiredSpell); - const_cast(proto)->RequiredSpell = 0; - } - - if(proto->RequiredReputationRank >= MAX_REPUTATION_RANK) - sLog.outErrorDb("Item (Entry: %u) has wrong reputation rank in RequiredReputationRank (%u), item can't be used.",i,proto->RequiredReputationRank); - - if(proto->RequiredReputationFaction) - { - if(!sFactionStore.LookupEntry(proto->RequiredReputationFaction)) - { - sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) faction in RequiredReputationFaction (%u)",i,proto->RequiredReputationFaction); - const_cast(proto)->RequiredReputationFaction = 0; - } - - if(proto->RequiredReputationRank == MIN_REPUTATION_RANK) - sLog.outErrorDb("Item (Entry: %u) has min. reputation rank in RequiredReputationRank (0) but RequiredReputationFaction > 0, faction setting is useless.",i); - } - else if(proto->RequiredReputationRank > MIN_REPUTATION_RANK) - sLog.outErrorDb("Item (Entry: %u) has RequiredReputationFaction ==0 but RequiredReputationRank > 0, rank setting is useless.",i); - - if(proto->Stackable==0) - { - sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%u), replace by default 1.",i,proto->Stackable); - const_cast(proto)->Stackable = 1; - } - else if(proto->Stackable > 255) - { - sLog.outErrorDb("Item (Entry: %u) has too large value in stackable (%u), replace by hardcoded upper limit (255).",i,proto->Stackable); - const_cast(proto)->Stackable = 255; - } - - for (int j = 0; j < 10; j++) - { - // for ItemStatValue != 0 - if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD) - { - sLog.outErrorDb("Item (Entry: %u) has wrong stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType); - const_cast(proto)->ItemStat[j].ItemStatType = 0; - } - } - - for (int j = 0; j < 5; j++) - { - if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL) - { - sLog.outErrorDb("Item (Entry: %u) has wrong dmg_type%d (%u)",i,j+1,proto->Damage[j].DamageType); - const_cast(proto)->Damage[j].DamageType = 0; - } - } - - // special format - if(proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN) - { - // spell_1 - if(proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format",i,0+1,proto->Spells[0].SpellTrigger); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[0].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - const_cast(proto)->Spells[1].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - - // spell_2 have learning spell - if(proto->Spells[1].SpellTrigger != ITEM_SPELLTRIGGER_LEARN_SPELL_ID) - { - sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format.",i,1+1,proto->Spells[1].SpellTrigger); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[1].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else if(!proto->Spells[1].SpellId) - { - sLog.outErrorDb("Item (Entry: %u) not has expected spell in spellid_%d in special learning format.",i,1+1); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[1].SpellId); - if(!spellInfo) - { - sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[1].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - // allowed only in special format - else if(proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN) - { - sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[1].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - } - - // spell_3*,spell_4*,spell_5* is empty - for (int j = 2; j < 5; j++) - { - if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger); - const_cast(proto)->Spells[j].SpellId = 0; - const_cast(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else if(proto->Spells[j].SpellId != 0) - { - sLog.outErrorDb("Item (Entry: %u) has wrong spell in spellid_%d (%u) for learning special format",i,j+1,proto->Spells[j].SpellId); - const_cast(proto)->Spells[j].SpellId = 0; - } - } - } - // normal spell list - else - { - for (int j = 0; j < 5; j++) - { - if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID) - { - sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger); - const_cast(proto)->Spells[j].SpellId = 0; - const_cast(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - - if(proto->Spells[j].SpellId) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId); - if(!spellInfo) - { - sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId); - const_cast(proto)->Spells[j].SpellId = 0; - } - // allowed only in special format - else if(proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN) - { - sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId); - const_cast(proto)->Spells[j].SpellId = 0; - } - } - } - } - - if(proto->Bonding >= MAX_BIND_TYPE) - sLog.outErrorDb("Item (Entry: %u) has wrong Bonding value (%u)",i,proto->Bonding); - - if(proto->PageText && !sPageTextStore.LookupEntry(proto->PageText)) - sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText); - - if(proto->LockID && !sLockStore.LookupEntry(proto->LockID)) - sLog.outErrorDb("Item (Entry: %u) has wrong LockID (%u)",i,proto->LockID); - - if(proto->Sheath >= MAX_SHEATHETYPE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong Sheath (%u)",i,proto->Sheath); - const_cast(proto)->Sheath = SHEATHETYPE_NONE; - } - - if(proto->RandomProperty && !sItemRandomPropertiesStore.LookupEntry(GetItemEnchantMod(proto->RandomProperty))) - { - sLog.outErrorDb("Item (Entry: %u) has unknown (wrong or not listed in `item_enchantment_template`) RandomProperty (%u)",i,proto->RandomProperty); - const_cast(proto)->RandomProperty = 0; - } - - if(proto->RandomSuffix && !sItemRandomSuffixStore.LookupEntry(GetItemEnchantMod(proto->RandomSuffix))) - { - sLog.outErrorDb("Item (Entry: %u) has wrong RandomSuffix (%u)",i,proto->RandomSuffix); - const_cast(proto)->RandomSuffix = 0; - } - - if(proto->ItemSet && !sItemSetStore.LookupEntry(proto->ItemSet)) - { - sLog.outErrorDb("Item (Entry: %u) have wrong ItemSet (%u)",i,proto->ItemSet); - const_cast(proto)->ItemSet = 0; - } - - if(proto->Area && !GetAreaEntryByAreaID(proto->Area)) - sLog.outErrorDb("Item (Entry: %u) has wrong Area (%u)",i,proto->Area); - - if(proto->Map && !sMapStore.LookupEntry(proto->Map)) - sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map); - - if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory)) - sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory); - - for (int j = 0; j < 3; j++) - { - if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color) - { - sLog.outErrorDb("Item (Entry: %u) has wrong socketColor_%d (%u)",i,j+1,proto->Socket[j].Color); - const_cast(proto)->Socket[j].Color = 0; - } - } - - if(proto->GemProperties && !sGemPropertiesStore.LookupEntry(proto->GemProperties)) - sLog.outErrorDb("Item (Entry: %u) has wrong GemProperties (%u)",i,proto->GemProperties); - - if(proto->FoodType >= MAX_PET_DIET) - { - sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType); - const_cast(proto)->FoodType = 0; - } - } - - // this DBC used currently only for check item templates in DB. - sItemStore.Clear(); -} - -void ObjectMgr::LoadAuctionItems() -{ - QueryResult *result = CharacterDatabase.Query( "SELECT itemguid,item_template FROM auctionhouse" ); - - if( !result ) - return; - - barGoLink bar( result->GetRowCount() ); - - uint32 count = 0; - - Field *fields; - do - { - bar.step(); - - fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 item_template = fields[1].GetUInt32(); - - ItemPrototype const *proto = objmgr.GetItemPrototype(item_template); - - if(!proto) - { - sLog.outError( "ObjectMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped.", item_guid,item_template); - continue; - } - - Item *item = NewItemOrBag(proto); - - if(!item->LoadFromDB(item_guid,0)) - { - delete item; - continue; - } - AddAItem(item); - - ++count; - } - while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u auction items", count ); -} - -void ObjectMgr::LoadPetLevelInfo() -{ - // Loading levels data - { - // 0 1 2 3 4 5 6 7 8 9 - QueryResult *result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar( 1 ); - - sLog.outString(); - sLog.outString( ">> Loaded %u level pet stats definitions", count ); - sLog.outErrorDb( "Error loading `pet_levelstats` table or empty table."); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - Field* fields = result->Fetch(); - - uint32 creature_id = fields[0].GetUInt32(); - if(!sCreatureStorage.LookupEntry(creature_id)) - { - sLog.outErrorDb("Wrong creature id %u in `pet_levelstats` table, ignoring.",creature_id); - continue; - } - - uint32 current_level = fields[1].GetUInt32(); - if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - if(current_level > 255) // hardcoded level maximum - sLog.outErrorDb("Wrong (> 255) level %u in `pet_levelstats` table, ignoring.",current_level); - else - sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `pet_levelstats` table, ignoring.",current_level); - continue; - } - else if(current_level < 1) - { - sLog.outErrorDb("Wrong (<1) level %u in `pet_levelstats` table, ignoring.",current_level); - continue; - } - - PetLevelInfo*& pInfoMapEntry = petInfo[creature_id]; - - if(pInfoMapEntry==NULL) - pInfoMapEntry = new PetLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; - - // data for level 1 stored in [0] array element, ... - PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level-1]; - - pLevelInfo->health = fields[2].GetUInt16(); - pLevelInfo->mana = fields[3].GetUInt16(); - pLevelInfo->armor = fields[9].GetUInt16(); - - for (int i = 0; i < MAX_STATS; i++) - { - pLevelInfo->stats[i] = fields[i+4].GetUInt16(); - } - - bar.step(); - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u level pet stats definitions", count ); - } - - // Fill gaps and check integrity - for (PetLevelInfoMap::iterator itr = petInfo.begin(); itr != petInfo.end(); ++itr) - { - PetLevelInfo* pInfo = itr->second; - - // fatal error if no level 1 data - if(!pInfo || pInfo[0].health == 0 ) - { - sLog.outErrorDb("Creature %u does not have pet stats data for Level 1!",itr->first); - exit(1); - } - - // fill level gaps - for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - { - if(pInfo[level].health == 0) - { - sLog.outErrorDb("Creature %u has no data for Level %i pet stats data, using data of Level %i.",itr->first,level+1, level); - pInfo[level] = pInfo[level-1]; - } - } - } -} - -PetLevelInfo const* ObjectMgr::GetPetLevelInfo(uint32 creature_id, uint32 level) const -{ - if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); - - PetLevelInfoMap::const_iterator itr = petInfo.find(creature_id); - if(itr == petInfo.end()) - return NULL; - - return &itr->second[level-1]; // data for level 1 stored in [0] array element, ... -} - -void ObjectMgr::LoadPlayerInfo() -{ - // Load playercreate - { - // 0 1 2 3 4 5 6 - QueryResult *result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z FROM playercreateinfo"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar( 1 ); - - sLog.outString(); - sLog.outString( ">> Loaded %u player create definitions", count ); - sLog.outErrorDb( "Error loading `playercreateinfo` table or empty table."); - exit(1); - } - - barGoLink bar( result->GetRowCount() ); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - uint32 current_class = fields[1].GetUInt32(); - uint32 mapId = fields[2].GetUInt32(); - uint32 zoneId = fields[3].GetUInt32(); - float positionX = fields[4].GetFloat(); - float positionY = fields[5].GetFloat(); - float positionZ = fields[6].GetFloat(); - - if(current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race); - continue; - } - - ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(current_race); - if(!rEntry) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race); - continue; - } - - if(current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class); - continue; - } - - if(!sChrClassesStore.LookupEntry(current_class)) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class); - continue; - } - - // accept DB data only for valid position (and non instanceable) - if( !MapManager::IsValidMapCoord(mapId,positionX,positionY,positionZ) ) - { - sLog.outErrorDb("Wrong home position for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race); - continue; - } - - if( sMapStore.LookupEntry(mapId)->Instanceable() ) - { - sLog.outErrorDb("Home position in instanceable map for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race); - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - - pInfo->mapId = mapId; - pInfo->zoneId = zoneId; - pInfo->positionX = positionX; - pInfo->positionY = positionY; - pInfo->positionZ = positionZ; - - pInfo->displayId_m = rEntry->model_m; - pInfo->displayId_f = rEntry->model_f; - - bar.step(); - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u player create definitions", count ); - } - - // Load playercreate items - { - // 0 1 2 3 - QueryResult *result = WorldDatabase.Query("SELECT race, class, itemid, amount FROM playercreateinfo_item"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar( 1 ); - - sLog.outString(); - sLog.outString( ">> Loaded %u player create items", count ); - sLog.outErrorDb( "Error loading `playercreateinfo_item` table or empty table."); - } - else - { - barGoLink bar( result->GetRowCount() ); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - if(current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo_item` table, ignoring.",current_race); - continue; - } - - uint32 current_class = fields[1].GetUInt32(); - if(current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo_item` table, ignoring.",current_class); - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - - uint32 item_id = fields[2].GetUInt32(); - - if(!GetItemPrototype(item_id)) - { - sLog.outErrorDb("Item id %u (race %u class %u) in `playercreateinfo_item` table but not listed in `item_template`, ignoring.",item_id,current_race,current_class); - continue; - } - - uint32 amount = fields[3].GetUInt32(); - - if(!amount) - { - sLog.outErrorDb("Item id %u (class %u race %u) have amount==0 in `playercreateinfo_item` table, ignoring.",item_id,current_race,current_class); - continue; - } - - pInfo->item.push_back(PlayerCreateInfoItem( item_id, amount)); - - bar.step(); - ++count; - } - while(result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u player create items", count ); - } - } - - // Load playercreate spells - { - // 0 1 2 3 - QueryResult *result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar( 1 ); - - sLog.outString(); - sLog.outString( ">> Loaded %u player create spells", count ); - sLog.outErrorDb( "Error loading `playercreateinfo_spell` table or empty table."); - } - else - { - barGoLink bar( result->GetRowCount() ); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - if(current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo_spell` table, ignoring.",current_race); - continue; - } - - uint32 current_class = fields[1].GetUInt32(); - if(current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo_spell` table, ignoring.",current_class); - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - pInfo->spell.push_back(CreateSpellPair(fields[2].GetUInt16(), fields[3].GetUInt8())); - - bar.step(); - ++count; - } - while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u player create spells", count ); - } - } - - // Load playercreate actions - { - // 0 1 2 3 4 5 - QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type, misc FROM playercreateinfo_action"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar( 1 ); - - sLog.outString(); - sLog.outString( ">> Loaded %u player create actions", count ); - sLog.outErrorDb( "Error loading `playercreateinfo_action` table or empty table."); - } - else - { - barGoLink bar( result->GetRowCount() ); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - if(current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo_action` table, ignoring.",current_race); - continue; - } - - uint32 current_class = fields[1].GetUInt32(); - if(current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo_action` table, ignoring.",current_class); - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - pInfo->action[0].push_back(fields[2].GetUInt16()); - pInfo->action[1].push_back(fields[3].GetUInt16()); - pInfo->action[2].push_back(fields[4].GetUInt16()); - pInfo->action[3].push_back(fields[5].GetUInt16()); - - bar.step(); - ++count; - } - while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u player create actions", count ); - } - } - - // Loading levels data (class only dependent) - { - // 0 1 2 3 - QueryResult *result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar( 1 ); - - sLog.outString(); - sLog.outString( ">> Loaded %u level health/mana definitions", count ); - sLog.outErrorDb( "Error loading `player_classlevelstats` table or empty table."); - exit(1); - } - - barGoLink bar( result->GetRowCount() ); - - do - { - Field* fields = result->Fetch(); - - uint32 current_class = fields[0].GetUInt32(); - if(current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `player_classlevelstats` table, ignoring.",current_class); - continue; - } - - uint32 current_level = fields[1].GetUInt32(); - if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - if(current_level > 255) // hardcoded level maximum - sLog.outErrorDb("Wrong (> 255) level %u in `player_classlevelstats` table, ignoring.",current_level); - else - sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level); - continue; - } - - PlayerClassInfo* pClassInfo = &playerClassInfo[current_class]; - - if(!pClassInfo->levelInfo) - pClassInfo->levelInfo = new PlayerClassLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; - - PlayerClassLevelInfo* pClassLevelInfo = &pClassInfo->levelInfo[current_level-1]; - - pClassLevelInfo->basehealth = fields[2].GetUInt16(); - pClassLevelInfo->basemana = fields[3].GetUInt16(); - - bar.step(); - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u level health/mana definitions", count ); - } - - // Fill gaps and check integrity - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - { - // skip non existed classes - if(!sChrClassesStore.LookupEntry(class_)) - continue; - - PlayerClassInfo* pClassInfo = &playerClassInfo[class_]; - - // fatal error if no level 1 data - if(!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0 ) - { - sLog.outErrorDb("Class %i Level 1 does not have health/mana data!",class_); - exit(1); - } - - // fill level gaps - for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - { - if(pClassInfo->levelInfo[level].basehealth == 0) - { - sLog.outErrorDb("Class %i Level %i does not have health/mana data. Using stats data of level %i.",class_,level+1, level); - pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level-1]; - } - } - } - - // Loading levels data (class/race dependent) - { - // 0 1 2 3 4 5 6 7 - QueryResult *result = WorldDatabase.Query("SELECT race, class, level, str, agi, sta, inte, spi FROM player_levelstats"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar( 1 ); - - sLog.outString(); - sLog.outString( ">> Loaded %u level stats definitions", count ); - sLog.outErrorDb( "Error loading `player_levelstats` table or empty table."); - exit(1); - } - - barGoLink bar( result->GetRowCount() ); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - if(current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `player_levelstats` table, ignoring.",current_race); - continue; - } - - uint32 current_class = fields[1].GetUInt32(); - if(current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `player_levelstats` table, ignoring.",current_class); - continue; - } - - uint32 current_level = fields[2].GetUInt32(); - if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - if(current_level > 255) // hardcoded level maximum - sLog.outErrorDb("Wrong (> 255) level %u in `player_levelstats` table, ignoring.",current_level); - else - sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_levelstats` table, ignoring.",current_level); - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - - if(!pInfo->levelInfo) - pInfo->levelInfo = new PlayerLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; - - PlayerLevelInfo* pLevelInfo = &pInfo->levelInfo[current_level-1]; - - for (int i = 0; i < MAX_STATS; i++) - { - pLevelInfo->stats[i] = fields[i+3].GetUInt8(); - } - - bar.step(); - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u level stats definitions", count ); - } - - // Fill gaps and check integrity - for (int race = 0; race < MAX_RACES; ++race) - { - // skip non existed races - if(!sChrRacesStore.LookupEntry(race)) - continue; - - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - { - // skip non existed classes - if(!sChrClassesStore.LookupEntry(class_)) - continue; - - PlayerInfo* pInfo = &playerInfo[race][class_]; - - // skip non loaded combinations - if(!pInfo->displayId_m || !pInfo->displayId_f) - continue; - - // skip expansion races if not playing with expansion - if (sWorld.getConfig(CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI)) - continue; - - // fatal error if no level 1 data - if(!pInfo->levelInfo || pInfo->levelInfo[0].stats[0] == 0 ) - { - sLog.outErrorDb("Race %i Class %i Level 1 does not have stats data!",race,class_); - exit(1); - } - - // fill level gaps - for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - { - if(pInfo->levelInfo[level].stats[0] == 0) - { - sLog.outErrorDb("Race %i Class %i Level %i does not have stats data. Using stats data of level %i.",race,class_,level+1, level); - pInfo->levelInfo[level] = pInfo->levelInfo[level-1]; - } - } - } - } -} - -void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const -{ - if(level < 1 || class_ >= MAX_CLASSES) - return; - - PlayerClassInfo const* pInfo = &playerClassInfo[class_]; - - if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); - - *info = pInfo->levelInfo[level-1]; -} - -void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint32 level, PlayerLevelInfo* info) const -{ - if(level < 1 || race >= MAX_RACES || class_ >= MAX_CLASSES) - return; - - PlayerInfo const* pInfo = &playerInfo[race][class_]; - if(pInfo->displayId_m==0 || pInfo->displayId_f==0) - return; - - if(level <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - *info = pInfo->levelInfo[level-1]; - else - BuildPlayerLevelInfo(race,class_,level,info); -} - -void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, PlayerLevelInfo* info) const -{ - // base data (last known level) - *info = playerInfo[race][_class].levelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1]; - - for(int lvl = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1; lvl < level; ++lvl) - { - switch(_class) - { - case CLASS_WARRIOR: - info->stats[STAT_STRENGTH] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_STAMINA] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_AGILITY] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 9 && !(lvl%2) ? 1: 0); - break; - case CLASS_PALADIN: - info->stats[STAT_STRENGTH] += (lvl > 3 ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 7 ? 1: 0); - break; - case CLASS_HUNTER: - info->stats[STAT_STRENGTH] += (lvl > 4 ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0)); - break; - case CLASS_ROGUE: - info->stats[STAT_STRENGTH] += (lvl > 5 ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0)); - break; - case CLASS_PRIEST: - info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_SPIRIT] += (lvl > 3 ? 1: 0); - break; - case CLASS_SHAMAN: - info->stats[STAT_STRENGTH] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0)); - info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 7 && !(lvl%2) ? 1: 0); - info->stats[STAT_INTELLECT] += (lvl > 5 ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 4 ? 1: 0); - break; - case CLASS_MAGE: - info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_SPIRIT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0)); - break; - case CLASS_WARLOCK: - info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0)); - info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0)); - info->stats[STAT_SPIRIT] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0)); - break; - case CLASS_DRUID: - info->stats[STAT_STRENGTH] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0)); - info->stats[STAT_STAMINA] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0)); - info->stats[STAT_AGILITY] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0)); - info->stats[STAT_SPIRIT] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0)); - } - } -} - -void ObjectMgr::LoadGuilds() -{ - Guild *newguild; - uint32 count = 0; - - QueryResult *result = CharacterDatabase.Query( "SELECT guildid FROM guild" ); - - if( !result ) - { - - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u guild definitions", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - Field *fields = result->Fetch(); - - bar.step(); - ++count; - - newguild = new Guild; - if(!newguild->LoadGuildFromDB(fields[0].GetUInt32())) - { - newguild->Disband(); - delete newguild; - continue; - } - AddGuild(newguild); - - }while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u guild definitions", count ); -} - -void ObjectMgr::LoadArenaTeams() -{ - uint32 count = 0; - - QueryResult *result = CharacterDatabase.Query( "SELECT arenateamid FROM arena_team" ); - - if( !result ) - { - - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u arenateam definitions", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - Field *fields = result->Fetch(); - - bar.step(); - ++count; - - ArenaTeam *newarenateam = new ArenaTeam; - if(!newarenateam->LoadArenaTeamFromDB(fields[0].GetUInt32())) - { - delete newarenateam; - continue; - } - AddArenaTeam(newarenateam); - }while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u arenateam definitions", count ); -} - -void ObjectMgr::LoadGroups() -{ - // -- loading groups -- - Group *group = NULL; - uint64 leaderGuid = 0; - uint32 count = 0; - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - QueryResult *result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty, leaderGuid FROM groups"); - - if( !result ) - { - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u group definitions", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - bar.step(); - Field *fields = result->Fetch(); - ++count; - leaderGuid = MAKE_NEW_GUID(fields[15].GetUInt32(),0,HIGHGUID_PLAYER); - - group = new Group; - if(!group->LoadGroupFromDB(leaderGuid, result, false)) - { - group->Disband(); - delete group; - continue; - } - AddGroup(group); - }while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u group definitions", count ); - - // -- loading members -- - count = 0; - group = NULL; - leaderGuid = 0; - // 0 1 2 3 - result = CharacterDatabase.PQuery("SELECT memberGuid, assistant, subgroup, leaderGuid FROM group_member ORDER BY leaderGuid"); - if(!result) - { - barGoLink bar( 1 ); - bar.step(); - } - else - { - barGoLink bar( result->GetRowCount() ); - do - { - bar.step(); - Field *fields = result->Fetch(); - count++; - leaderGuid = MAKE_NEW_GUID(fields[3].GetUInt32(), 0, HIGHGUID_PLAYER); - if(!group || group->GetLeaderGUID() != leaderGuid) - { - group = GetGroupByLeader(leaderGuid); - if(!group) - { - sLog.outErrorDb("Incorrect entry in group_member table : no group with leader %d for member %d!", fields[3].GetUInt32(), fields[0].GetUInt32()); - CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32()); - continue; - } - } - - if(!group->LoadMemberFromDB(fields[0].GetUInt32(), fields[2].GetUInt8(), fields[1].GetBool())) - { - sLog.outErrorDb("Incorrect entry in group_member table : member %d cannot be added to player %d's group!", fields[0].GetUInt32(), fields[3].GetUInt32()); - CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32()); - } - }while( result->NextRow() ); - delete result; - } - - // clean groups - // TODO: maybe delete from the DB before loading in this case - for(GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end();) - { - if((*itr)->GetMembersCount() < 2) - { - (*itr)->Disband(); - delete *itr; - mGroupSet.erase(itr++); - } - else - ++itr; - } - - // -- loading instances -- - count = 0; - group = NULL; - leaderGuid = 0; - result = CharacterDatabase.PQuery( - // 0 1 2 3 4 5 - "SELECT leaderGuid, map, instance, permanent, difficulty, resettime, " - // 6 - "(SELECT COUNT(*) FROM character_instance WHERE guid = leaderGuid AND instance = group_instance.instance AND permanent = 1 LIMIT 1) " - "FROM group_instance LEFT JOIN instance ON instance = id ORDER BY leaderGuid" - ); - - if(!result) - { - barGoLink bar( 1 ); - bar.step(); - } - else - { - barGoLink bar( result->GetRowCount() ); - do - { - bar.step(); - Field *fields = result->Fetch(); - count++; - leaderGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - if(!group || group->GetLeaderGUID() != leaderGuid) - { - group = GetGroupByLeader(leaderGuid); - if(!group) - { - sLog.outErrorDb("Incorrect entry in group_instance table : no group with leader %d", fields[0].GetUInt32()); - continue; - } - } - - InstanceSave *save = sInstanceSaveManager.AddInstanceSave(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true); - group->BindToInstance(save, fields[3].GetBool(), true); - }while( result->NextRow() ); - delete result; - } - - sLog.outString(); - sLog.outString( ">> Loaded %u group-instance binds total", count ); - - sLog.outString(); - sLog.outString( ">> Loaded %u group members total", count ); -} - -void ObjectMgr::LoadQuests() -{ - // For reload case - for(QuestMap::const_iterator itr=mQuestTemplates.begin(); itr != mQuestTemplates.end(); ++itr) - delete itr->second; - mQuestTemplates.clear(); - - mExclusiveQuestGroups.clear(); - - // 0 1 2 3 4 5 6 7 - QueryResult *result = WorldDatabase.Query("SELECT entry, ZoneOrSort, SkillOrClass, MinLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue," - // 8 9 10 11 12 13 14 15 - "RepObjectiveFaction, RepObjectiveValue, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime," - // 16 17 18 19 20 21 22 23 24 25 - "QuestFlags, SpecialFlags, CharTitleId, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell," - // 26 27 28 29 30 31 32 33 34 35 - "Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4," - // 36 37 38 39 40 41 42 43 - "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4," - // 44 45 46 47 48 49 50 51 52 53 54 55 - "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4, ReqSourceRef1, ReqSourceRef2, ReqSourceRef3, ReqSourceRef4," - // 56 57 58 59 60 61 62 63 - "ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4," - // 64 65 66 67 - "ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4," - // 68 69 70 71 72 73 - "RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6," - // 74 75 76 77 78 79 - "RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6," - // 80 81 82 83 84 85 86 87 - "RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4," - // 88 89 90 91 92 93 94 95 96 97 - "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5," - // 98 99 100 101 102 103 104 105 106 107 - "RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt," - // 108 109 110 111 112 113 114 115 116 117 - "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4," - // 118 119 - "StartScript, CompleteScript" - " FROM quest_template"); - if(result == NULL) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded 0 quests definitions" ); - sLog.outErrorDb("`quest_template` table is empty!"); - return; - } - - // create multimap previous quest for each existed quest - // some quests can have many previous maps set by NextQuestId in previous quest - // for example set of race quests can lead to single not race specific quest - barGoLink bar( result->GetRowCount() ); - do - { - bar.step(); - Field *fields = result->Fetch(); - - Quest * newQuest = new Quest(fields); - mQuestTemplates[newQuest->GetQuestId()] = newQuest; - } while( result->NextRow() ); - - delete result; - - // Post processing - for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); iter++) - { - Quest * qinfo = iter->second; - - // additional quest integrity checks (GO, creature_template and item_template must be loaded already) - - if (qinfo->QuestFlags & ~QUEST_MANGOS_FLAGS_DB_ALLOWED) - { - sLog.outErrorDb("Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u", - qinfo->GetQuestId(),qinfo->QuestFlags,QUEST_MANGOS_FLAGS_DB_ALLOWED >> 16); - qinfo->QuestFlags &= QUEST_MANGOS_FLAGS_DB_ALLOWED; - } - - if(qinfo->QuestFlags & QUEST_FLAGS_DAILY) - { - if(!(qinfo->QuestFlags & QUEST_MANGOS_FLAGS_REPEATABLE)) - { - sLog.outErrorDb("Daily Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId()); - qinfo->QuestFlags |= QUEST_MANGOS_FLAGS_REPEATABLE; - } - } - - if(qinfo->QuestFlags & QUEST_FLAGS_AUTO_REWARDED) - { - // at auto-reward can be rewarded only RewChoiceItemId[0] - for(int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j ) - { - if(uint32 id = qinfo->RewChoiceItemId[j]) - { - sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item from `RewChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes, quest ignore this data - } - } - } - - // client quest log visual (area case) - if( qinfo->ZoneOrSort > 0 ) - { - if(!GetAreaEntryByAreaID(qinfo->ZoneOrSort)) - { - sLog.outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.", - qinfo->GetQuestId(),qinfo->ZoneOrSort); - // no changes, quest not dependent from this value but can have problems at client - } - } - // client quest log visual (sort case) - if( qinfo->ZoneOrSort < 0 ) - { - QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort)); - if( !qSort ) - { - sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.", - qinfo->GetQuestId(),qinfo->ZoneOrSort); - // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check) - } - //check SkillOrClass value (class case). - if( ClassByQuestSort(-int32(qinfo->ZoneOrSort)) ) - { - // SkillOrClass should not have class case when class case already set in ZoneOrSort. - if(qinfo->SkillOrClass < 0) - { - sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClass` = %i (class case), redundant.", - qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClass); - } - } - //check for proper SkillOrClass value (skill case) - if(int32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort))) - { - // skill is positive value in SkillOrClass - if(qinfo->SkillOrClass != skill_id ) - { - sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClass` does not have a corresponding value (%i).", - qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id); - //override, and force proper value here? - } - } - } - - // SkillOrClass (class case) - if( qinfo->SkillOrClass < 0 ) - { - if( !sChrClassesStore.LookupEntry(-int32(qinfo->SkillOrClass)) ) - { - sLog.outErrorDb("Quest %u has `SkillOrClass` = %i (class case) but class (%i) does not exist", - qinfo->GetQuestId(),qinfo->SkillOrClass,-qinfo->SkillOrClass); - } - } - // SkillOrClass (skill case) - if( qinfo->SkillOrClass > 0 ) - { - if( !sSkillLineStore.LookupEntry(qinfo->SkillOrClass) ) - { - sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist", - qinfo->GetQuestId(),qinfo->SkillOrClass,qinfo->SkillOrClass); - } - } - - if( qinfo->RequiredSkillValue ) - { - if( qinfo->RequiredSkillValue > sWorld.GetConfigMaxSkillValue() ) - { - sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but max possible skill is %u, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue()); - // no changes, quest can't be done for this requirement - } - - if( qinfo->SkillOrClass <= 0 ) - { - sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.", - qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClass); - // no changes, quest can't be done for this requirement (fail at wrong skill id) - } - } - // else Skill quests can have 0 skill level, this is ok - - if(qinfo->RepObjectiveFaction && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction)) - { - sLog.outErrorDb("Quest %u has `RepObjectiveFaction` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->RepObjectiveFaction,qinfo->RepObjectiveFaction); - // no changes, quest can't be done for this requirement - } - - if(qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction)) - { - sLog.outErrorDb("Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredMinRepFaction,qinfo->RequiredMinRepFaction); - // no changes, quest can't be done for this requirement - } - - if(qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction)) - { - sLog.outErrorDb("Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredMaxRepFaction,qinfo->RequiredMaxRepFaction); - // no changes, quest can't be done for this requirement - } - - if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > Player::Reputation_Cap) - { - sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredMinRepValue,Player::Reputation_Cap); - // no changes, quest can't be done for this requirement - } - - if(qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue) - { - sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredMaxRepValue,qinfo->RequiredMinRepValue); - // no changes, quest can't be done for this requirement - } - - if(!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0 ) - { - sLog.outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect", - qinfo->GetQuestId(),qinfo->RepObjectiveValue); - // warning - } - - if(!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0 ) - { - sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect", - qinfo->GetQuestId(),qinfo->RequiredMinRepValue); - // warning - } - - if(!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0 ) - { - sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect", - qinfo->GetQuestId(),qinfo->RequiredMaxRepValue); - // warning - } - - if(qinfo->CharTitleId && !sCharTitlesStore.LookupEntry(qinfo->CharTitleId)) - { - sLog.outErrorDb("Quest %u has `CharTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.", - qinfo->GetQuestId(),qinfo->GetCharTitleId(),qinfo->GetCharTitleId()); - qinfo->CharTitleId = 0; - // quest can't reward this title - } - - if(qinfo->SrcItemId) - { - if(!sItemStorage.LookupEntry(qinfo->SrcItemId)) - { - sLog.outErrorDb("Quest %u has `SrcItemId` = %u but item with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->SrcItemId,qinfo->SrcItemId); - qinfo->SrcItemId = 0; // quest can't be done for this requirement - } - else if(qinfo->SrcItemCount==0) - { - sLog.outErrorDb("Quest %u has `SrcItemId` = %u but `SrcItemCount` = 0, set to 1 but need fix in DB.", - qinfo->GetQuestId(),qinfo->SrcItemId); - qinfo->SrcItemCount = 1; // update to 1 for allow quest work for backward comptibility with DB - } - } - else if(qinfo->SrcItemCount>0) - { - sLog.outErrorDb("Quest %u has `SrcItemId` = 0 but `SrcItemCount` = %u, useless value.", - qinfo->GetQuestId(),qinfo->SrcItemCount); - qinfo->SrcItemCount=0; // no quest work changes in fact - } - - if(qinfo->SrcSpell) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->SrcSpell); - if(!spellInfo) - { - sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u doesn't exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell); - qinfo->SrcSpell = 0; // quest can't be done for this requirement - } - else if(!SpellMgr::IsSpellValid(spellInfo)) - { - sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u is broken, quest can't be done.", - qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell); - qinfo->SrcSpell = 0; // quest can't be done for this requirement - } - } - - for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j ) - { - uint32 id = qinfo->ReqItemId[j]; - if(id) - { - if(qinfo->ReqItemCount[j]==0) - { - sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but `ReqItemCount%d` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes, quest can't be done for this requirement - } - - qinfo->SetFlag(QUEST_MANGOS_FLAGS_DELIVER); - - if(!sItemStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but item with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,id); - qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest - } - } - else if(qinfo->ReqItemCount[j]>0) - { - sLog.outErrorDb("Quest %u has `ReqItemId%d` = 0 but `ReqItemCount%d` = %u, quest can't be done.", - qinfo->GetQuestId(),j+1,j+1,qinfo->ReqItemCount[j]); - qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest - } - } - - for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j ) - { - uint32 id = qinfo->ReqSourceId[j]; - if(id) - { - if(!sItemStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but item with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,id); - // no changes, quest can't be done for this requirement - } - - if(!qinfo->ReqSourceCount[j]) - { - sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1); - qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest - } - - if(!qinfo->ReqSourceRef[j]) - { - sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1); - qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest - } - } - else - { - if(qinfo->ReqSourceCount[j]>0) - { - sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceCount%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]); - // no changes, quest ignore this data - } - - if(qinfo->ReqSourceRef[j]>0) - { - sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]); - // no changes, quest ignore this data - } - } - } - - for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j ) - { - uint32 ref = qinfo->ReqSourceRef[j]; - if(ref) - { - if(ref > QUEST_OBJECTIVES_COUNT) - { - sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.", - qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT); - // no changes, quest can't be done for this requirement - } - else - if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1]) - { - sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,ref,ref,ref); - // no changes, quest can't be done for this requirement - } - else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1]) - { - sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.", - qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]); - // no changes, quest can't be done for this requirement - qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest - } - } - } - - for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j ) - { - uint32 id = qinfo->ReqSpell[j]; - if(id) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(id); - if(!spellInfo) - { - sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,id); - // no changes, quest can't be done for this requirement - } - - if(!qinfo->ReqCreatureOrGOId[j]) - { - bool found = false; - for(int k = 0; k < 3; ++k) - { - if( spellInfo->Effect[k]==SPELL_EFFECT_QUEST_COMPLETE && uint32(spellInfo->EffectMiscValue[k])==qinfo->QuestId || - spellInfo->Effect[k]==SPELL_EFFECT_SEND_EVENT) - { - found = true; - break; - } - } - - if(found) - { - if(!qinfo->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT)) - { - sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT for quest %u and ReqCreatureOrGOId%d = 0, but quest not have flag QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT. Quest flags or ReqCreatureOrGOId%d must be fixed, quest modified to enable objective.",spellInfo->Id,qinfo->QuestId,j+1,j+1); - - // this will prevent quest completing without objective - const_cast(qinfo)->SetFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT); - } - } - else - { - sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u and ReqCreatureOrGOId%d = 0 but spell %u does not have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT effect for this quest, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1,id); - // no changes, quest can't be done for this requirement - } - } - } - } - - for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j ) - { - int32 id = qinfo->ReqCreatureOrGOId[j]; - if(id < 0 && !sGOStorage.LookupEntry(-id)) - { - sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but gameobject %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,uint32(-id)); - qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement - } - - if(id > 0 && !sCreatureStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but creature with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,uint32(id)); - qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement - } - - if(id) - { - // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast - - qinfo->SetFlag(QUEST_MANGOS_FLAGS_KILL_OR_CAST | QUEST_MANGOS_FLAGS_SPEAKTO); - - if(!qinfo->ReqCreatureOrGOCount[j]) - { - sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %u but `ReqCreatureOrGOCount%d` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes, quest can be incorrectly done, but we already report this - } - } - else if(qinfo->ReqCreatureOrGOCount[j]>0) - { - sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = 0 but `ReqCreatureOrGOCount%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->ReqCreatureOrGOCount[j]); - // no changes, quest ignore this data - } - } - - for(int j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j ) - { - uint32 id = qinfo->RewChoiceItemId[j]; - if(id) - { - if(!sItemStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.", - qinfo->GetQuestId(),j+1,id,id); - qinfo->RewChoiceItemId[j] = 0; // no changes, quest will not reward this - } - - if(!qinfo->RewChoiceItemCount[j]) - { - sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but `RewChoiceItemCount%d` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes, quest can't be done - } - } - else if(qinfo->RewChoiceItemCount[j]>0) - { - sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = 0 but `RewChoiceItemCount%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->RewChoiceItemCount[j]); - // no changes, quest ignore this data - } - } - - for(int j = 0; j < QUEST_REWARDS_COUNT; ++j ) - { - uint32 id = qinfo->RewItemId[j]; - if(id) - { - if(!sItemStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.", - qinfo->GetQuestId(),j+1,id,id); - qinfo->RewItemId[j] = 0; // no changes, quest will not reward this item - } - - if(!qinfo->RewItemCount[j]) - { - sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but `RewItemCount%d` = 0, quest will not reward this item.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes - } - } - else if(qinfo->RewItemCount[j]>0) - { - sLog.outErrorDb("Quest %u has `RewItemId%d` = 0 but `RewItemCount%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->RewItemCount[j]); - // no changes, quest ignore this data - } - } - - for(int j = 0; j < QUEST_REPUTATIONS_COUNT; ++j) - { - if(qinfo->RewRepFaction[j]) - { - if(!qinfo->RewRepValue[j]) - { - sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but `RewRepValue%d` = 0, quest will not reward this reputation.", - qinfo->GetQuestId(),j+1,qinfo->RewRepValue[j],j+1); - // no changes - } - - if(!sFactionStore.LookupEntry(qinfo->RewRepFaction[j])) - { - sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but raw faction (faction.dbc) %u does not exist, quest will not reward reputation for this faction.", - qinfo->GetQuestId(),j+1,qinfo->RewRepFaction[j] ,qinfo->RewRepFaction[j] ); - qinfo->RewRepFaction[j] = 0; // quest will not reward this - } - } - else if(qinfo->RewRepValue[j]!=0) - { - sLog.outErrorDb("Quest %u has `RewRepFaction%d` = 0 but `RewRepValue%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->RewRepValue[j]); - // no changes, quest ignore this data - } - } - - if(qinfo->RewSpell) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpell); - - if(!spellInfo) - { - sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u does not exist, spell removed as display reward.", - qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); - qinfo->RewSpell = 0; // no spell reward will display for this quest - } - - else if(!SpellMgr::IsSpellValid(spellInfo)) - { - sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.", - qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); - qinfo->RewSpell = 0; // no spell reward will display for this quest - } - - } - - if(qinfo->RewSpellCast) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpellCast); - - if(!spellInfo) - { - sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.", - qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); - qinfo->RewSpellCast = 0; // no spell will be casted on player - } - - else if(!SpellMgr::IsSpellValid(spellInfo)) - { - sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.", - qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); - qinfo->RewSpellCast = 0; // no spell will be casted on player - } - - } - - if(qinfo->RewMailTemplateId) - { - if(!sMailTemplateStore.LookupEntry(qinfo->RewMailTemplateId)) - { - sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template %u does not exist, quest will not have a mail reward.", - qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId); - qinfo->RewMailTemplateId = 0; // no mail will send to player - qinfo->RewMailDelaySecs = 0; // no mail will send to player - } - } - - if(qinfo->NextQuestInChain) - { - if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end()) - { - sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.", - qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain ); - qinfo->NextQuestInChain = 0; - } - else - mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId()); - } - - // fill additional data stores - if(qinfo->PrevQuestId) - { - if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end()) - { - sLog.outErrorDb("Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId()); - } - else - { - qinfo->prevQuests.push_back(qinfo->PrevQuestId); - } - } - - if(qinfo->NextQuestId) - { - if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end()) - { - sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId()); - } - else - { - int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId()); - mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId); - } - } - - if(qinfo->ExclusiveGroup) - mExclusiveQuestGroups.insert(std::pair(qinfo->ExclusiveGroup, qinfo->GetQuestId())); - if(qinfo->LimitTime) - qinfo->SetFlag(QUEST_MANGOS_FLAGS_TIMED); - } - - // check QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE - for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(i); - if(!spellInfo) - continue; - - for(int j = 0; j < 3; ++j) - { - if(spellInfo->Effect[j] != SPELL_EFFECT_QUEST_COMPLETE) - continue; - - uint32 quest_id = spellInfo->EffectMiscValue[j]; - - Quest const* quest = GetQuestTemplate(quest_id); - - // some quest referenced in spells not exist (outdataed spells) - if(!quest) - continue; - - if(!quest->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT)) - { - sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE for quest %u , but quest not have flag QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.",spellInfo->Id,quest_id); - - // this will prevent quest completing without objective - const_cast(quest)->SetFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT); - } - } - } - - sLog.outString(); - sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() ); -} - -void ObjectMgr::LoadQuestLocales() -{ - QueryResult *result = WorldDatabase.Query("SELECT entry," - "Title_loc1,Details_loc1,Objectives_loc1,OfferRewardText_loc1,RequestItemsText_loc1,EndText_loc1,ObjectiveText1_loc1,ObjectiveText2_loc1,ObjectiveText3_loc1,ObjectiveText4_loc1," - "Title_loc2,Details_loc2,Objectives_loc2,OfferRewardText_loc2,RequestItemsText_loc2,EndText_loc2,ObjectiveText1_loc2,ObjectiveText2_loc2,ObjectiveText3_loc2,ObjectiveText4_loc2," - "Title_loc3,Details_loc3,Objectives_loc3,OfferRewardText_loc3,RequestItemsText_loc3,EndText_loc3,ObjectiveText1_loc3,ObjectiveText2_loc3,ObjectiveText3_loc3,ObjectiveText4_loc3," - "Title_loc4,Details_loc4,Objectives_loc4,OfferRewardText_loc4,RequestItemsText_loc4,EndText_loc4,ObjectiveText1_loc4,ObjectiveText2_loc4,ObjectiveText3_loc4,ObjectiveText4_loc4," - "Title_loc5,Details_loc5,Objectives_loc5,OfferRewardText_loc5,RequestItemsText_loc5,EndText_loc5,ObjectiveText1_loc5,ObjectiveText2_loc5,ObjectiveText3_loc5,ObjectiveText4_loc5," - "Title_loc6,Details_loc6,Objectives_loc6,OfferRewardText_loc6,RequestItemsText_loc6,EndText_loc6,ObjectiveText1_loc6,ObjectiveText2_loc6,ObjectiveText3_loc6,ObjectiveText4_loc6," - "Title_loc7,Details_loc7,Objectives_loc7,OfferRewardText_loc7,RequestItemsText_loc7,EndText_loc7,ObjectiveText1_loc7,ObjectiveText2_loc7,ObjectiveText3_loc7,ObjectiveText4_loc7," - "Title_loc8,Details_loc8,Objectives_loc8,OfferRewardText_loc8,RequestItemsText_loc8,EndText_loc8,ObjectiveText1_loc8,ObjectiveText2_loc8,ObjectiveText3_loc8,ObjectiveText4_loc8" - " FROM locales_quest" - ); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - QuestLocale& data = mQuestLocaleMap[entry]; - - for(int i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[1+10*(i-1)].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Title.size() <= idx) - data.Title.resize(idx+1); - - data.Title[idx] = str; - } - } - str = fields[1+10*(i-1)+1].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Details.size() <= idx) - data.Details.resize(idx+1); - - data.Details[idx] = str; - } - } - str = fields[1+10*(i-1)+2].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Objectives.size() <= idx) - data.Objectives.resize(idx+1); - - data.Objectives[idx] = str; - } - } - str = fields[1+10*(i-1)+3].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.OfferRewardText.size() <= idx) - data.OfferRewardText.resize(idx+1); - - data.OfferRewardText[idx] = str; - } - } - str = fields[1+10*(i-1)+4].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.RequestItemsText.size() <= idx) - data.RequestItemsText.resize(idx+1); - - data.RequestItemsText[idx] = str; - } - } - str = fields[1+10*(i-1)+5].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.EndText.size() <= idx) - data.EndText.resize(idx+1); - - data.EndText[idx] = str; - } - } - for(int k = 0; k < 4; ++k) - { - str = fields[1+10*(i-1)+6+k].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.ObjectiveText[k].size() <= idx) - data.ObjectiveText[k].resize(idx+1); - - data.ObjectiveText[k][idx] = str; - } - } - } - } - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() ); -} - -void ObjectMgr::LoadPetCreateSpells() -{ - QueryResult *result = WorldDatabase.PQuery("SELECT entry, Spell1, Spell2, Spell3, Spell4 FROM petcreateinfo_spell"); - if(!result) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded 0 pet create spells" ); - sLog.outErrorDb("`petcreateinfo_spell` table is empty!"); - return; - } - - uint32 count = 0; - - barGoLink bar( result->GetRowCount() ); - - mPetCreateSpell.clear(); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 creature_id = fields[0].GetUInt32(); - - if(!creature_id || !sCreatureStorage.LookupEntry(creature_id)) - continue; - - PetCreateSpellEntry PetCreateSpell; - for(int i = 0; i < 4; i++) - { - PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32(); - - if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i])) - sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]); - } - - mPetCreateSpell[creature_id] = PetCreateSpell; - - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u pet create spells", count ); -} - -void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename) -{ - if(sWorld.IsScriptScheduled()) // function don't must be called in time scripts use. - return; - - sLog.outString( "%s :", tablename); - - scripts.clear(); // need for reload support - - QueryResult *result = WorldDatabase.PQuery( "SELECT id,delay,command,datalong,datalong2,datatext, x, y, z, o FROM %s", tablename ); - - uint32 count = 0; - - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u script definitions", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - ScriptInfo tmp; - tmp.id = fields[0].GetUInt32(); - tmp.delay = fields[1].GetUInt32(); - tmp.command = fields[2].GetUInt32(); - tmp.datalong = fields[3].GetUInt32(); - tmp.datalong2 = fields[4].GetUInt32(); - tmp.datatext = fields[5].GetCppString(); - tmp.x = fields[6].GetFloat(); - tmp.y = fields[7].GetFloat(); - tmp.z = fields[8].GetFloat(); - tmp.o = fields[9].GetFloat(); - - // generic command args check - switch(tmp.command) - { - case SCRIPT_COMMAND_TALK: - { - if(tmp.datalong > 3) - { - sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - break; - } - - case SCRIPT_COMMAND_TELEPORT_TO: - { - if(!sMapStore.LookupEntry(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - - if(!MaNGOS::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) - { - sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.x,tmp.y,tmp.id); - continue; - } - break; - } - - case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: - { - if(!MaNGOS::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) - { - sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.x,tmp.y,tmp.id); - continue; - } - - if(!GetCreatureTemplate(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - break; - } - - case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: - { - GameObjectData const* data = GetGOData(tmp.datalong); - if(!data) - { - sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - - GameObjectInfo const* info = GetGameObjectInfo(data->id); - if(!info) - { - sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,data->id,tmp.id); - continue; - } - - if( info->type==GAMEOBJECT_TYPE_FISHINGNODE || - info->type==GAMEOBJECT_TYPE_FISHINGHOLE || - info->type==GAMEOBJECT_TYPE_DOOR || - info->type==GAMEOBJECT_TYPE_BUTTON || - info->type==GAMEOBJECT_TYPE_TRAP ) - { - sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,info->id,tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_OPEN_DOOR: - case SCRIPT_COMMAND_CLOSE_DOOR: - { - GameObjectData const* data = GetGOData(tmp.datalong); - if(!data) - { - sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",tablename,tmp.datalong,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); - continue; - } - - GameObjectInfo const* info = GetGameObjectInfo(data->id); - if(!info) - { - sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",tablename,tmp.datalong,data->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); - continue; - } - - if( info->type!=GAMEOBJECT_TYPE_DOOR) - { - sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",tablename,info->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); - continue; - } - - break; - } - case SCRIPT_COMMAND_QUEST_EXPLORED: - { - Quest const* quest = objmgr.GetQuestTemplate(tmp.datalong); - if(!quest) - { - sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - - if(!quest->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT)) - { - sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",tablename,tmp.datalong,tmp.id); - - // this will prevent quest completing without objective - const_cast(quest)->SetFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT); - - // continue; - quest objective requiremet set and command can be allowed - } - - if(float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) - { - sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong2,tmp.id); - continue; - } - - if(tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) - { - sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %u or 0 for disable distance check",tablename,tmp.datalong2,tmp.id,uint32(DEFAULT_VISIBILITY_DISTANCE)); - continue; - } - - if(tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE) - { - sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %u or 0 for disable distance check",tablename,tmp.datalong2,tmp.id,uint32(INTERACTION_DISTANCE)); - continue; - } - - break; - } - - case SCRIPT_COMMAND_REMOVE_AURA: - case SCRIPT_COMMAND_CAST_SPELL: - { - if(!sSpellStore.LookupEntry(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - break; - } - } - - if (scripts.find(tmp.id) == scripts.end()) - { - ScriptMap emptyMap; - scripts[tmp.id] = emptyMap; - } - scripts[tmp.id].insert(std::pair(tmp.delay, tmp)); - - ++count; - } while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u script definitions", count ); -} - -void ObjectMgr::LoadGameObjectScripts() -{ - LoadScripts(sGameObjectScripts, "gameobject_scripts"); - - // check ids - for(ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr) - { - if(!GetGOData(itr->first)) - sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id",itr->first); - } -} - -void ObjectMgr::LoadQuestEndScripts() -{ - objmgr.LoadScripts(sQuestEndScripts, "quest_end_scripts"); - - // check ids - for(ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr) - { - if(!GetQuestTemplate(itr->first)) - sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id",itr->first); - } -} - -void ObjectMgr::LoadQuestStartScripts() -{ - objmgr.LoadScripts(sQuestStartScripts,"quest_start_scripts"); - - // check ids - for(ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr) - { - if(!GetQuestTemplate(itr->first)) - sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id",itr->first); - } -} - -void ObjectMgr::LoadSpellScripts() -{ - objmgr.LoadScripts(sSpellScripts, "spell_scripts"); - - // check ids - for(ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); - - if(!spellInfo) - { - sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id",itr->first); - continue; - } - - //check for correct spellEffect - bool found = false; - for(int i=0; i<3; ++i) - { - // skip empty effects - if( !spellInfo->Effect[i] ) - continue; - - if( spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT ) - { - found = true; - break; - } - } - - if(!found) - sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect",itr->first,SPELL_EFFECT_SCRIPT_EFFECT); - } -} - -void ObjectMgr::LoadEventScripts() -{ - objmgr.LoadScripts(sEventScripts, "event_scripts"); - - std::set evt_scripts; - // Load all possible script entries from gameobjects - for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i) - { - GameObjectInfo const * goInfo = sGOStorage.LookupEntry(i); - if (goInfo) - { - switch(goInfo->type) - { - case GAMEOBJECT_TYPE_GOOBER: - if(goInfo->goober.eventId) - evt_scripts.insert(goInfo->goober.eventId); - break; - case GAMEOBJECT_TYPE_CHEST: - if(goInfo->chest.eventId) - evt_scripts.insert(goInfo->chest.eventId); - break; - default: - break; - } - } - } - // Load all possible script entries from spells - for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) - { - SpellEntry const * spell = sSpellStore.LookupEntry(i); - if (spell) - { - for(int j=0; j<3; ++j) - { - if( spell->Effect[j] == SPELL_EFFECT_SEND_EVENT ) - { - if (spell->EffectMiscValue[j]) - evt_scripts.insert(spell->EffectMiscValue[j]); - } - } - } - } - // Then check if all scripts are in above list of possible script entries - for(ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr) - { - std::set::const_iterator itr2 = evt_scripts.find(itr->first); - if (itr2 == evt_scripts.end()) - sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not refering to any gameobject_template type 10 data2 field or type 3 data6 field or any spell effect %u", itr->first, SPELL_EFFECT_SEND_EVENT); - } -} - -void ObjectMgr::LoadItemTexts() -{ - QueryResult *result = CharacterDatabase.PQuery("SELECT id, text FROM item_text"); - - uint32 count = 0; - - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u item pages", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - Field* fields; - do - { - bar.step(); - - fields = result->Fetch(); - - mItemTexts[ fields[0].GetUInt32() ] = fields[1].GetCppString(); - - ++count; - - } while ( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u item texts", count ); -} - -void ObjectMgr::LoadPageTexts() -{ - sPageTextStore.Free(); // for reload case - - sPageTextStore.Load(); - sLog.outString( ">> Loaded %u page texts", sPageTextStore.RecordCount ); - sLog.outString(); - - for(uint32 i = 1; i < sPageTextStore.MaxEntry; ++i) - { - // check data correctness - PageText const* page = sPageTextStore.LookupEntry(i); - if(!page) - continue; - - if(page->Next_Page && !sPageTextStore.LookupEntry(page->Next_Page)) - { - sLog.outErrorDb("Page text (Id: %u) has not existing next page (Id:%u)", i,page->Next_Page); - continue; - } - - // detect circular reference - std::set checkedPages; - for(PageText const* pageItr = page; pageItr; pageItr = sPageTextStore.LookupEntry(pageItr->Next_Page)) - { - if(!pageItr->Next_Page) - break; - checkedPages.insert(pageItr->Page_ID); - if(checkedPages.find(pageItr->Next_Page)!=checkedPages.end()) - { - std::ostringstream ss; - ss<< "The text page(s) "; - for (std::set::iterator itr= checkedPages.begin();itr!=checkedPages.end(); itr++) - ss << *itr << " "; - ss << "create(s) a circular reference, which can cause the server to freeze. Changing Next_Page of page " - << pageItr->Page_ID <<" to 0"; - sLog.outErrorDb(ss.str().c_str()); - const_cast(pageItr)->Next_Page = 0; - break; - } - } - } -} - -void ObjectMgr::LoadPageTextLocales() -{ - QueryResult *result = WorldDatabase.PQuery("SELECT entry,text_loc1,text_loc2,text_loc3,text_loc4,text_loc5,text_loc6,text_loc7,text_loc8 FROM locales_page_text"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - sLog.outString(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - PageTextLocale& data = mPageTextLocaleMap[entry]; - - for(int i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[i].GetCppString(); - if(str.empty()) - continue; - - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Text.size() <= idx) - data.Text.resize(idx+1); - - data.Text[idx] = str; - } - } - - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() ); -} - -void ObjectMgr::LoadInstanceTemplate() -{ - sInstanceTemplate.Load(); - - for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) - { - InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i); - if(!temp) continue; - const MapEntry* entry = sMapStore.LookupEntry(temp->map); - if(!entry) - { - sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map); - continue; - } - else if(!entry->HasResetTime()) - continue; - - if(temp->reset_delay == 0) - { - // use defaults from the DBC - if(entry->SupportsHeroicMode()) - { - temp->reset_delay = entry->resetTimeHeroic / DAY; - } - else if (entry->resetTimeRaid && entry->map_type == MAP_RAID) - { - temp->reset_delay = entry->resetTimeRaid / DAY; - } - } - - // the reset_delay must be atleast one day - temp->reset_delay = std::max((uint32)1, (uint32)(temp->reset_delay * sWorld.getRate(RATE_INSTANCE_RESET_TIME))); - } - - sLog.outString( ">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount ); - sLog.outString(); -} - -void ObjectMgr::AddGossipText(GossipText *pGText) -{ - ASSERT( pGText->Text_ID ); - ASSERT( mGossipText.find(pGText->Text_ID) == mGossipText.end() ); - mGossipText[pGText->Text_ID] = pGText; -} - -GossipText *ObjectMgr::GetGossipText(uint32 Text_ID) -{ - GossipTextMap::const_iterator itr; - for (itr = mGossipText.begin(); itr != mGossipText.end(); itr++) - { - if(itr->second->Text_ID == Text_ID) - return itr->second; - } - return NULL; -} - -void ObjectMgr::LoadGossipText() -{ - GossipText *pGText; - QueryResult *result = WorldDatabase.Query( "SELECT * FROM npc_text" ); - - int count = 0; - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u npc texts", count ); - return; - } - - int cic; - - barGoLink bar( result->GetRowCount() ); - - do - { - ++count; - cic = 0; - - Field *fields = result->Fetch(); - - bar.step(); - - pGText = new GossipText; - pGText->Text_ID = fields[cic++].GetUInt32(); - - for (int i=0; i< 8; i++) - { - pGText->Options[i].Text_0 = fields[cic++].GetCppString(); - pGText->Options[i].Text_1 = fields[cic++].GetCppString(); - - pGText->Options[i].Language = fields[cic++].GetUInt32(); - pGText->Options[i].Probability = fields[cic++].GetFloat(); - - pGText->Options[i].Emotes[0]._Delay = fields[cic++].GetUInt32(); - pGText->Options[i].Emotes[0]._Emote = fields[cic++].GetUInt32(); - - pGText->Options[i].Emotes[1]._Delay = fields[cic++].GetUInt32(); - pGText->Options[i].Emotes[1]._Emote = fields[cic++].GetUInt32(); - - pGText->Options[i].Emotes[2]._Delay = fields[cic++].GetUInt32(); - pGText->Options[i].Emotes[2]._Emote = fields[cic++].GetUInt32(); - } - - if ( !pGText->Text_ID ) continue; - AddGossipText( pGText ); - - } while( result->NextRow() ); - - sLog.outString(); - sLog.outString( ">> Loaded %u npc texts", count ); - delete result; -} - -void ObjectMgr::LoadNpcTextLocales() -{ - QueryResult *result = WorldDatabase.Query("SELECT entry," - "Text0_0_loc1,Text0_1_loc1,Text1_0_loc1,Text1_1_loc1,Text2_0_loc1,Text2_1_loc1,Text3_0_loc1,Text3_1_loc1,Text4_0_loc1,Text4_1_loc1,Text5_0_loc1,Text5_1_loc1,Text6_0_loc1,Text6_1_loc1,Text7_0_loc1,Text7_1_loc1," - "Text0_0_loc2,Text0_1_loc2,Text1_0_loc2,Text1_1_loc2,Text2_0_loc2,Text2_1_loc2,Text3_0_loc2,Text3_1_loc1,Text4_0_loc2,Text4_1_loc2,Text5_0_loc2,Text5_1_loc2,Text6_0_loc2,Text6_1_loc2,Text7_0_loc2,Text7_1_loc2," - "Text0_0_loc3,Text0_1_loc3,Text1_0_loc3,Text1_1_loc3,Text2_0_loc3,Text2_1_loc3,Text3_0_loc3,Text3_1_loc1,Text4_0_loc3,Text4_1_loc3,Text5_0_loc3,Text5_1_loc3,Text6_0_loc3,Text6_1_loc3,Text7_0_loc3,Text7_1_loc3," - "Text0_0_loc4,Text0_1_loc4,Text1_0_loc4,Text1_1_loc4,Text2_0_loc4,Text2_1_loc4,Text3_0_loc4,Text3_1_loc1,Text4_0_loc4,Text4_1_loc4,Text5_0_loc4,Text5_1_loc4,Text6_0_loc4,Text6_1_loc4,Text7_0_loc4,Text7_1_loc4," - "Text0_0_loc5,Text0_1_loc5,Text1_0_loc5,Text1_1_loc5,Text2_0_loc5,Text2_1_loc5,Text3_0_loc5,Text3_1_loc1,Text4_0_loc5,Text4_1_loc5,Text5_0_loc5,Text5_1_loc5,Text6_0_loc5,Text6_1_loc5,Text7_0_loc5,Text7_1_loc5," - "Text0_0_loc6,Text0_1_loc6,Text1_0_loc6,Text1_1_loc6,Text2_0_loc6,Text2_1_loc6,Text3_0_loc6,Text3_1_loc1,Text4_0_loc6,Text4_1_loc6,Text5_0_loc6,Text5_1_loc6,Text6_0_loc6,Text6_1_loc6,Text7_0_loc6,Text7_1_loc6," - "Text0_0_loc7,Text0_1_loc7,Text1_0_loc7,Text1_1_loc7,Text2_0_loc7,Text2_1_loc7,Text3_0_loc7,Text3_1_loc1,Text4_0_loc7,Text4_1_loc7,Text5_0_loc7,Text5_1_loc7,Text6_0_loc7,Text6_1_loc7,Text7_0_loc7,Text7_1_loc7, " - "Text0_0_loc8,Text0_1_loc8,Text1_0_loc8,Text1_1_loc8,Text2_0_loc8,Text2_1_loc8,Text3_0_loc8,Text3_1_loc1,Text4_0_loc8,Text4_1_loc8,Text5_0_loc8,Text5_1_loc8,Text6_0_loc8,Text6_1_loc8,Text7_0_loc8,Text7_1_loc8 " - " FROM locales_npc_text"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - NpcTextLocale& data = mNpcTextLocaleMap[entry]; - - for(int i=1; i= 0) - { - if(data.Text_0[j].size() <= idx) - data.Text_0[j].resize(idx+1); - - data.Text_0[j][idx] = str0; - } - } - std::string str1 = fields[1+8*2*(i-1)+2*j+1].GetCppString(); - if(!str1.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Text_1[j].size() <= idx) - data.Text_1[j].resize(idx+1); - - data.Text_1[j][idx] = str1; - } - } - } - } - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() ); -} - -//not very fast function but it is called only once a day, or on starting-up -void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) -{ - time_t basetime = time(NULL); - sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec); - //delete all old mails without item and without body immediately, if starting server - if (!serverUp) - CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" I64FMTD "' AND has_items = '0' AND itemTextId = 0", (uint64)basetime); - // 0 1 2 3 4 5 6 7 8 9 - QueryResult* result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,itemTextId,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" I64FMTD "'", (uint64)basetime); - if ( !result ) - return; // any mails need to be returned or deleted - Field *fields; - //std::ostringstream delitems, delmails; //will be here for optimization - //bool deletemail = false, deleteitem = false; - //delitems << "DELETE FROM item_instance WHERE guid IN ( "; - //delmails << "DELETE FROM mail WHERE id IN ( " - do - { - fields = result->Fetch(); - Mail *m = new Mail; - m->messageID = fields[0].GetUInt32(); - m->messageType = fields[1].GetUInt8(); - m->sender = fields[2].GetUInt32(); - m->receiver = fields[3].GetUInt32(); - m->itemTextId = fields[4].GetUInt32(); - bool has_items = fields[5].GetBool(); - m->expire_time = (time_t)fields[6].GetUInt64(); - m->deliver_time = 0; - m->COD = fields[7].GetUInt32(); - m->checked = fields[8].GetUInt32(); - m->mailTemplateId = fields[9].GetInt16(); - - Player *pl = 0; - if (serverUp) - pl = objmgr.GetPlayer((uint64)m->receiver); - if (pl && pl->m_mailsLoaded) - { //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail - //his in mailbox and he has already listed his mails ) - delete m; - continue; - } - //delete or return mail: - if (has_items) - { - QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", m->messageID); - if(resultItems) - { - do - { - Field *fields2 = resultItems->Fetch(); - - uint32 item_guid_low = fields2[0].GetUInt32(); - uint32 item_template = fields2[1].GetUInt32(); - - m->AddItem(item_guid_low, item_template); - } - while (resultItems->NextRow()); - - delete resultItems; - } - //if it is mail from AH, it shouldn't be returned, but deleted - if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_AUCTION | MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED))) - { - // mail open and then not returned - for(std::vector::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid); - } - else - { - //mail will be returned: - CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" I64FMTD "', deliver_time = '" I64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID); - delete m; - continue; - } - } - - if (m->itemTextId) - CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId); - - //deletemail = true; - //delmails << m->messageID << ", "; - CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID); - delete m; - } while (result->NextRow()); - delete result; -} - -void ObjectMgr::LoadQuestAreaTriggers() -{ - mQuestAreaTriggerMap.clear(); // need for reload case - - QueryResult *result = WorldDatabase.Query( "SELECT id,quest FROM areatrigger_involvedrelation" ); - - uint32 count = 0; - - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u quest trigger points", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 trigger_ID = fields[0].GetUInt32(); - uint32 quest_ID = fields[1].GetUInt32(); - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID); - if(!atEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",trigger_ID); - continue; - } - - Quest const* quest = GetQuestTemplate(quest_ID); - - if(!quest) - { - sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u",trigger_ID,quest_ID); - continue; - } - - if(!quest->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT)) - { - sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not quest %u, but quest not have flag QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.",trigger_ID,quest_ID); - - // this will prevent quest completing without objective - const_cast(quest)->SetFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT); - - // continue; - quest modified to required obkective and trigger can be allowed. - } - - mQuestAreaTriggerMap[trigger_ID] = quest_ID; - - } while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u quest trigger points", count ); -} - -void ObjectMgr::LoadTavernAreaTriggers() -{ - mTavernAreaTriggerSet.clear(); // need for reload case - - QueryResult *result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern"); - - uint32 count = 0; - - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u tavern triggers", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 Trigger_ID = fields[0].GetUInt32(); - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); - if(!atEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); - continue; - } - - mTavernAreaTriggerSet.insert(Trigger_ID); - } while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u tavern triggers", count ); -} - -void ObjectMgr::LoadAreaTriggerScripts() -{ - mAreaTriggerScripts.clear(); // need for reload case - QueryResult *result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts"); - - uint32 count = 0; - - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u areatrigger scripts", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 Trigger_ID = fields[0].GetUInt32(); - std::string scriptName = fields[1].GetCppString(); - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); - if(!atEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); - continue; - } - mAreaTriggerScripts[Trigger_ID] = scriptName; - } while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u areatrigger scripts", count ); -} -uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid ) -{ - bool found = false; - float dist; - uint32 id = 0; - - for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i) - { - TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i); - if(node && node->map_id == mapid) - { - float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z); - if(found) - { - if(dist2 < dist) - { - dist = dist2; - id = i; - } - } - else - { - found = true; - dist = dist2; - id = i; - } - } - } - - return id; -} - -void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost) -{ - TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source); - if(src_i==sTaxiPathSetBySource.end()) - { - path = 0; - cost = 0; - return; - } - - TaxiPathSetForSource& pathSet = src_i->second; - - TaxiPathSetForSource::iterator dest_i = pathSet.find(destination); - if(dest_i==pathSet.end()) - { - path = 0; - cost = 0; - return; - } - - cost = dest_i->second.price; - path = dest_i->second.ID; -} - -uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team ) -{ - uint16 mount_entry = 0; - uint16 mount_id = 0; - - TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id); - if(node) - { - if (team == ALLIANCE) - { - mount_entry = node->alliance_mount_type; - CreatureInfo const *ci = objmgr.GetCreatureTemplate(mount_entry); - if(ci) - mount_id = ci->DisplayID_A; - } - if (team == HORDE) - { - mount_entry = node->horde_mount_type; - CreatureInfo const *ci = objmgr.GetCreatureTemplate(mount_entry); - if(ci) - mount_id = ci->DisplayID_H; - } - } - - CreatureModelInfo const *minfo = objmgr.GetCreatureModelInfo(mount_id); - if(!minfo) - { - sLog.outErrorDb("Taxi mount (Entry: %u) for taxi node (Id: %u) for team %u has model %u not found in table `creature_model_info`, can't load. ", - mount_entry,id,team,mount_id); - - return false; - } - if(minfo->modelid_other_gender!=0) - mount_id = urand(0,1) ? mount_id : minfo->modelid_other_gender; - - return mount_id; -} - -void ObjectMgr::GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector& mapIds) -{ - if(path >= sTaxiPathNodesByPath.size()) - return; - - TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path]; - - pathnodes.Resize(nodeList.size()); - mapIds.resize(nodeList.size()); - - for(size_t i = 0; i < nodeList.size(); ++i) - { - pathnodes[ i ].x = nodeList[i].x; - pathnodes[ i ].y = nodeList[i].y; - pathnodes[ i ].z = nodeList[i].z; - - mapIds[i] = nodeList[i].mapid; - } -} - -void ObjectMgr::GetTransportPathNodes( uint32 path, TransportPath &pathnodes ) -{ - if(path >= sTaxiPathNodesByPath.size()) - return; - - TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path]; - - pathnodes.Resize(nodeList.size()); - - for(size_t i = 0; i < nodeList.size(); ++i) - { - pathnodes[ i ].mapid = nodeList[i].mapid; - pathnodes[ i ].x = nodeList[i].x; - pathnodes[ i ].y = nodeList[i].y; - pathnodes[ i ].z = nodeList[i].z; - pathnodes[ i ].actionFlag = nodeList[i].actionFlag; - pathnodes[ i ].delay = nodeList[i].delay; - } -} - -void ObjectMgr::LoadGraveyardZones() -{ - mGraveYardMap.clear(); // need for reload case - - QueryResult *result = WorldDatabase.Query("SELECT id,ghost_zone,faction FROM game_graveyard_zone"); - - uint32 count = 0; - - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u graveyard-zone links", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 safeLocId = fields[0].GetUInt32(); - uint32 zoneId = fields[1].GetUInt32(); - uint32 team = fields[2].GetUInt32(); - - WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId); - if(!entry) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",safeLocId); - continue; - } - - AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId); - if(!areaEntry) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing zone id (%u), skipped.",zoneId); - continue; - } - - if(areaEntry->zone != 0) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record subzone id (%u) instead of zone, skipped.",zoneId); - continue; - } - - if(team!=0 && team!=HORDE && team!=ALLIANCE) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for non player faction (%u), skipped.",team); - continue; - } - - if(entry->map_id != areaEntry->mapid && team != 0) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for ghost zone (%u) at map %u and graveyard (%u) at map %u for team %u, but in case maps are different, player faction setting is ignored. Use faction 0 instead.",zoneId,areaEntry->mapid, safeLocId, entry->map_id, team); - team = 0; - } - - if(!AddGraveYardLink(safeLocId,zoneId,team,false)) - sLog.outErrorDb("Table `game_graveyard_zone` has a duplicate record for Garveyard (ID: %u) and Zone (ID: %u), skipped.",safeLocId,zoneId); - } while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u graveyard-zone links", count ); -} - -WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team) -{ - // search for zone associated closest graveyard - uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y); - - // Simulate std. algorithm: - // found some graveyard associated to (ghost_zone,ghost_map) - // - // if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map - // then check faction - // if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated - // then skip check faction - GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId); - GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId); - if(graveLow==graveUp) - { - sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team); - return NULL; - } - - bool foundNear = false; - float distNear; - WorldSafeLocsEntry const* entryNear = NULL; - WorldSafeLocsEntry const* entryFar = NULL; - - for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr) - { - GraveYardData const& data = itr->second; - - WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId); - if(!entry) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",data.safeLocId); - continue; - } - - // remember first graveyard at another map and ignore other - if(MapId != entry->map_id) - { - if(!entryFar) - entryFar = entry; - continue; - } - - // skip enemy faction graveyard at same map (normal area, city, or battleground) - // team == 0 case can be at call from .neargrave - if(data.team != 0 && team != 0 && data.team != team) - continue; - - // find now nearest graveyard at same map - float dist2 = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y)+(entry->z - z)*(entry->z - z); - if(foundNear) - { - if(dist2 < distNear) - { - distNear = dist2; - entryNear = entry; - } - } - else - { - foundNear = true; - distNear = dist2; - entryNear = entry; - } - } - - if(entryNear) - return entryNear; - - return entryFar; -} - -GraveYardData const* ObjectMgr::FindGraveYardData(uint32 id, uint32 zoneId) -{ - GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId); - GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId); - - for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr) - { - if(itr->second.safeLocId==id) - return &itr->second; - } - - return NULL; -} - -bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB) -{ - if(FindGraveYardData(id,zoneId)) - return false; - - // add link to loaded data - GraveYardData data; - data.safeLocId = id; - data.team = team; - - mGraveYardMap.insert(GraveYardMap::value_type(zoneId,data)); - - // add link to DB - if(inDB) - { - WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone ( id,ghost_zone,faction) " - "VALUES ('%u', '%u','%u')",id,zoneId,team); - } - - return true; -} - -void ObjectMgr::LoadAreaTriggerTeleports() -{ - mAreaTriggers.clear(); // need for reload case - - uint32 count = 0; - - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - QueryResult *result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport"); - if( !result ) - { - - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u area trigger teleport definitions", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - Field *fields = result->Fetch(); - - bar.step(); - - ++count; - - uint32 Trigger_ID = fields[0].GetUInt32(); - - AreaTrigger at; - - at.requiredLevel = fields[1].GetUInt8(); - at.requiredItem = fields[2].GetUInt32(); - at.requiredItem2 = fields[3].GetUInt32(); - at.heroicKey = fields[4].GetUInt32(); - at.heroicKey2 = fields[5].GetUInt32(); - at.requiredQuest = fields[6].GetUInt32(); - at.requiredFailedText = fields[7].GetCppString(); - at.target_mapId = fields[8].GetUInt32(); - at.target_X = fields[9].GetFloat(); - at.target_Y = fields[10].GetFloat(); - at.target_Z = fields[11].GetFloat(); - at.target_Orientation = fields[12].GetFloat(); - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); - if(!atEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); - continue; - } - - if(at.requiredItem) - { - ItemPrototype const *pProto = objmgr.GetItemPrototype(at.requiredItem); - if(!pProto) - { - sLog.outError("Key item %u does not exist for trigger %u, removing key requirement.", at.requiredItem, Trigger_ID); - at.requiredItem = 0; - } - } - if(at.requiredItem2) - { - ItemPrototype const *pProto = objmgr.GetItemPrototype(at.requiredItem2); - if(!pProto) - { - sLog.outError("Second item %u not exist for trigger %u, remove key requirement.", at.requiredItem2, Trigger_ID); - at.requiredItem2 = 0; - } - } - - if(at.heroicKey) - { - ItemPrototype const *pProto = objmgr.GetItemPrototype(at.heroicKey); - if(!pProto) - { - sLog.outError("Heroic key item %u not exist for trigger %u, remove key requirement.", at.heroicKey, Trigger_ID); - at.heroicKey = 0; - } - } - - if(at.heroicKey2) - { - ItemPrototype const *pProto = objmgr.GetItemPrototype(at.heroicKey2); - if(!pProto) - { - sLog.outError("Heroic second key item %u not exist for trigger %u, remove key requirement.", at.heroicKey2, Trigger_ID); - at.heroicKey2 = 0; - } - } - - if(at.requiredQuest) - { - if(!mQuestTemplates[at.requiredQuest]) - { - sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",at.requiredQuest,Trigger_ID); - at.requiredQuest = 0; - } - } - - MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId); - if(!mapEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Trigger_ID,at.target_mapId); - continue; - } - - if(at.target_X==0 && at.target_Y==0 && at.target_Z==0) - { - sLog.outErrorDb("Area trigger (ID:%u) target coordinates not provided.",Trigger_ID); - continue; - } - - mAreaTriggers[Trigger_ID] = at; - - } while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u area trigger teleport definitions", count ); -} - -AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const -{ - const MapEntry *mapEntry = sMapStore.LookupEntry(Map); - if(!mapEntry) return NULL; - for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); itr++) - { - if(itr->second.target_mapId == mapEntry->parent_map) - { - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first); - if(atEntry && atEntry->mapid == Map) - return &itr->second; - } - } - return NULL; -} - -void ObjectMgr::SetHighestGuids() -{ - QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" ); - if( result ) - { - m_hiCharGuid = (*result)[0].GetUInt32()+1; - - delete result; - } - - result = WorldDatabase.Query( "SELECT MAX(guid) FROM creature" ); - if( result ) - { - m_hiCreatureGuid = (*result)[0].GetUInt32()+1; - - delete result; - } - - result = CharacterDatabase.Query( "SELECT MAX(id) FROM character_pet" ); - if( result ) - { - m_hiPetGuid = (*result)[0].GetUInt32()+1; - - delete result; - } - - result = CharacterDatabase.Query( "SELECT MAX(guid) FROM item_instance" ); - if( result ) - { - m_hiItemGuid = (*result)[0].GetUInt32()+1; - - delete result; - } - - // Cleanup other tables from not existed guids (>=m_hiItemGuid) - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", m_hiItemGuid); - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_hiItemGuid); - CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", m_hiItemGuid); - CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_hiItemGuid); - - result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" ); - if( result ) - { - m_hiGoGuid = (*result)[0].GetUInt32()+1; - - delete result; - } - - result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse" ); - if( result ) - { - m_auctionid = (*result)[0].GetUInt32()+1; - - delete result; - } - else - { - m_auctionid = 0; - } - result = CharacterDatabase.Query( "SELECT MAX(id) FROM mail" ); - if( result ) - { - m_mailid = (*result)[0].GetUInt32()+1; - - delete result; - } - else - { - m_mailid = 0; - } - result = CharacterDatabase.Query( "SELECT MAX(id) FROM item_text" ); - if( result ) - { - m_ItemTextId = (*result)[0].GetUInt32(); - - delete result; - } - else - m_ItemTextId = 0; - - result = CharacterDatabase.Query( "SELECT MAX(guid) FROM corpse" ); - if( result ) - { - m_hiCorpseGuid = (*result)[0].GetUInt32()+1; - - delete result; - } -} - -uint32 ObjectMgr::GenerateAuctionID() -{ - ++m_auctionid; - if(m_auctionid>=0xFFFFFFFF) - { - sLog.outError("Auctions ids overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_auctionid; -} - -uint32 ObjectMgr::GenerateMailID() -{ - ++m_mailid; - if(m_mailid>=0xFFFFFFFF) - { - sLog.outError("Mail ids overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_mailid; -} - -uint32 ObjectMgr::GenerateItemTextID() -{ - ++m_ItemTextId; - if(m_ItemTextId>=0xFFFFFFFF) - { - sLog.outError("Item text ids overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_ItemTextId; -} - -uint32 ObjectMgr::CreateItemText(std::string text) -{ - uint32 newItemTextId = GenerateItemTextID(); - //insert new itempage to container - mItemTexts[ newItemTextId ] = text; - //save new itempage - CharacterDatabase.escape_string(text); - //any Delete query needed, itemTextId is maximum of all ids - std::ostringstream query; - query << "INSERT INTO item_text (id,text) VALUES ( '" << newItemTextId << "', '" << text << "')"; - CharacterDatabase.Execute(query.str().c_str()); //needs to be run this way, because mail body may be more than 1024 characters - return newItemTextId; -} - -uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh) -{ - switch(guidhigh) - { - case HIGHGUID_ITEM: - ++m_hiItemGuid; - if(m_hiItemGuid>=0xFFFFFFFF) - { - sLog.outError("Item guid overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_hiItemGuid; - case HIGHGUID_UNIT: - ++m_hiCreatureGuid; - if(m_hiCreatureGuid>=0x00FFFFFF) - { - sLog.outError("Creature guid overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_hiCreatureGuid; - case HIGHGUID_PET: - ++m_hiPetGuid; - if(m_hiPetGuid>=0x00FFFFFF) - { - sLog.outError("Pet guid overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_hiPetGuid; - case HIGHGUID_PLAYER: - ++m_hiCharGuid; - if(m_hiCharGuid>=0xFFFFFFFF) - { - sLog.outError("Players guid overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_hiCharGuid; - case HIGHGUID_GAMEOBJECT: - ++m_hiGoGuid; - if(m_hiGoGuid>=0x00FFFFFF) - { - sLog.outError("Gameobject guid overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_hiGoGuid; - case HIGHGUID_CORPSE: - ++m_hiCorpseGuid; - if(m_hiCorpseGuid>=0xFFFFFFFF) - { - sLog.outError("Corpse guid overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_hiCorpseGuid; - case HIGHGUID_DYNAMICOBJECT: - ++m_hiDoGuid; - if(m_hiDoGuid>=0xFFFFFFFF) - { - sLog.outError("DynamicObject guid overflow!! Can't continue, shuting down server. "); - sWorld.m_stopEvent = true; - } - return m_hiDoGuid; - default: - ASSERT(0); - } - - ASSERT(0); - return 0; -} - -void ObjectMgr::LoadGameObjectLocales() -{ - QueryResult *result = WorldDatabase.Query("SELECT entry," - "name_loc1,name_loc2,name_loc3,name_loc4,name_loc5,name_loc6,name_loc7,name_loc8," - "castbarcaption_loc1,castbarcaption_loc2,castbarcaption_loc3,castbarcaption_loc4," - "castbarcaption_loc5,castbarcaption_loc6,castbarcaption_loc7,castbarcaption_loc8 FROM locales_gameobject"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - sLog.outString(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - GameObjectLocale& data = mGameObjectLocaleMap[entry]; - - for(int i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[i].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.Name.size() <= idx) - data.Name.resize(idx+1); - - data.Name[idx] = str; - } - } - } - - for(int i = MAX_LOCALE; i < MAX_LOCALE*2-1; ++i) - { - std::string str = fields[i].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - if(data.CastBarCaption.size() <= idx) - data.CastBarCaption.resize(idx+1); - - data.CastBarCaption[idx] = str; - } - } - } - - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() ); -} - -void ObjectMgr::LoadGameobjectInfo() -{ - sGOStorage.Load(); - - // some checks - for(uint32 id = 1; id < sGOStorage.MaxEntry; id++) - { - GameObjectInfo const* goInfo = sGOStorage.LookupEntry(id); - if(!goInfo) - continue; - - switch(goInfo->type) - { - case GAMEOBJECT_TYPE_DOOR: //0 - { - if(goInfo->door.lockId) - { - if(!sLockStore.LookupEntry(goInfo->door.lockId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.", - id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId); - } - break; - } - case GAMEOBJECT_TYPE_BUTTON: //1 - { - if(goInfo->button.lockId) - { - if(!sLockStore.LookupEntry(goInfo->button.lockId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.", - id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId); - } - break; - } - case GAMEOBJECT_TYPE_CHEST: //3 - { - if(goInfo->chest.lockId) - { - if(!sLockStore.LookupEntry(goInfo->chest.lockId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.", - id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId); - } - if(goInfo->chest.linkedTrapId) // linked trap - { - if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry(goInfo->chest.linkedTrapId)) - { - if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", - id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP); - } - /* disable check for while - else - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.", - id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId); - */ - } - break; - } - case GAMEOBJECT_TYPE_TRAP: //6 - { - /* disable check for while - if(goInfo->trap.spellId) // spell - { - if(!sSpellStore.LookupEntry(goInfo->trap.spellId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.", - id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId); - } - */ - break; - } - case GAMEOBJECT_TYPE_CHAIR: //7 - if(goInfo->chair.height > 2) - { - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..2.", - id,goInfo->type,goInfo->chair.height); - - // prevent client and server unexpected work - const_cast(goInfo)->chair.height = 0; - } - break; - case GAMEOBJECT_TYPE_SPELL_FOCUS: //8 - { - if(goInfo->spellFocus.focusId) - { - if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.", - id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId); - } - - if(goInfo->spellFocus.linkedTrapId) // linked trap - { - if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry(goInfo->spellFocus.linkedTrapId)) - { - if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", - id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP); - } - /* disable check for while - else - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.", - id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId); - */ - } - break; - } - case GAMEOBJECT_TYPE_GOOBER: //10 - { - if(goInfo->goober.pageId) // pageId - { - if(!sPageTextStore.LookupEntry(goInfo->goober.pageId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.", - id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId); - } - /* disable check for while - if(goInfo->goober.spellId) // spell - { - if(!sSpellStore.LookupEntry(goInfo->goober.spellId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.", - id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId); - } - */ - if(goInfo->goober.linkedTrapId) // linked trap - { - if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry(goInfo->goober.linkedTrapId)) - { - if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", - id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP); - } - /* disable check for while - else - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.", - id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId); - */ - } - break; - } - case GAMEOBJECT_TYPE_MO_TRANSPORT: //15 - { - if(goInfo->moTransport.taxiPathId) - { - if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty()) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.", - id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId); - } - break; - } - case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18 - { - /* disabled - if(goInfo->summoningRitual.spellId) - { - if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.", - id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId); - } - */ - break; - } - case GAMEOBJECT_TYPE_SPELLCASTER: //22 - { - if(goInfo->spellcaster.spellId) // spell - { - if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.", - id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId); - } - break; - } - } - } - - sLog.outString( ">> Loaded %u game object templates", sGOStorage.RecordCount ); - sLog.outString(); -} - -void ObjectMgr::LoadExplorationBaseXP() -{ - uint32 count = 0; - QueryResult *result = WorldDatabase.Query("SELECT level,basexp FROM exploration_basexp"); - - if( !result ) - { - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u BaseXP definitions", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - uint32 level = fields[0].GetUInt32(); - uint32 basexp = fields[1].GetUInt32(); - mBaseXPTable[level] = basexp; - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u BaseXP definitions", count ); -} - -uint32 ObjectMgr::GetBaseXP(uint32 level) -{ - return mBaseXPTable[level] ? mBaseXPTable[level] : 0; -} - -void ObjectMgr::LoadPetNames() -{ - uint32 count = 0; - QueryResult *result = WorldDatabase.Query("SELECT word,entry,half FROM pet_name_generation"); - - if( !result ) - { - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u pet name parts", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - std::string word = fields[0].GetString(); - uint32 entry = fields[1].GetUInt32(); - bool half = fields[2].GetBool(); - if(half) - PetHalfName1[entry].push_back(word); - else - PetHalfName0[entry].push_back(word); - ++count; - } - while (result->NextRow()); - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u pet name parts", count ); -} - -void ObjectMgr::LoadPetNumber() -{ - QueryResult* result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet"); - if(result) - { - Field *fields = result->Fetch(); - m_hiPetNumber = fields[0].GetUInt32()+1; - delete result; - } - - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded the max pet number: %d", m_hiPetNumber-1); -} - -std::string ObjectMgr::GeneratePetName(uint32 entry) -{ - std::vector & list0 = PetHalfName0[entry]; - std::vector & list1 = PetHalfName1[entry]; - - if(list0.empty() || list1.empty()) - { - CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(entry); - char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale()); - if(!petname) - petname = cinfo->Name; - return std::string(petname); - } - - return *(list0.begin()+urand(0, list0.size()-1)) + *(list1.begin()+urand(0, list1.size()-1)); -} - -uint32 ObjectMgr::GeneratePetNumber() -{ - return ++m_hiPetNumber; -} - -void ObjectMgr::LoadCorpses() -{ - uint32 count = 0; - // 0 1 2 3 4 5 6 7 8 10 - QueryResult *result = CharacterDatabase.PQuery("SELECT position_x, position_y, position_z, orientation, map, data, time, corpse_type, instance, guid FROM corpse WHERE corpse_type <> 0"); - - if( !result ) - { - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u corpses", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - - uint32 guid = fields[result->GetFieldCount()-1].GetUInt32(); - - Corpse *corpse = new Corpse; - if(!corpse->LoadFromDB(guid,fields)) - { - delete corpse; - continue; - } - - ObjectAccessor::Instance().AddCorpse(corpse); - - ++count; - } - while (result->NextRow()); - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u corpses", count ); -} - -void ObjectMgr::LoadReputationOnKill() -{ - uint32 count = 0; - - // 0 1 2 - QueryResult *result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2," - // 3 4 5 6 7 8 9 - "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent " - "FROM creature_onkill_reputation"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 creature_id = fields[0].GetUInt32(); - - ReputationOnKillEntry repOnKill; - repOnKill.repfaction1 = fields[1].GetUInt32(); - repOnKill.repfaction2 = fields[2].GetUInt32(); - repOnKill.is_teamaward1 = fields[3].GetBool(); - repOnKill.reputration_max_cap1 = fields[4].GetUInt32(); - repOnKill.repvalue1 = fields[5].GetInt32(); - repOnKill.is_teamaward2 = fields[6].GetBool(); - repOnKill.reputration_max_cap2 = fields[7].GetUInt32(); - repOnKill.repvalue2 = fields[8].GetInt32(); - repOnKill.team_dependent = fields[9].GetUInt8(); - - if(!GetCreatureTemplate(creature_id)) - { - sLog.outErrorDb("Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped",creature_id); - continue; - } - - if(repOnKill.repfaction1) - { - FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repOnKill.repfaction1); - if(!factionEntry1) - { - sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction1); - continue; - } - } - - if(repOnKill.repfaction2) - { - FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repOnKill.repfaction2); - if(!factionEntry2) - { - sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction2); - continue; - } - } - - mRepOnKill[creature_id] = repOnKill; - - ++count; - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString(">> Loaded %u creature award reputation definitions", count); -} - -void ObjectMgr::LoadWeatherZoneChances() -{ - uint32 count = 0; - - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - QueryResult *result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather"); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 zone_id = fields[0].GetUInt32(); - - WeatherZoneChances& wzc = mWeatherZoneMap[zone_id]; - - for(int season = 0; season < WEATHER_SEASONS; ++season) - { - wzc.data[season].rainChance = fields[season * (MAX_WEATHER_TYPE-1) + 1].GetUInt32(); - wzc.data[season].snowChance = fields[season * (MAX_WEATHER_TYPE-1) + 2].GetUInt32(); - wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE-1) + 3].GetUInt32(); - - if(wzc.data[season].rainChance > 100) - { - wzc.data[season].rainChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%",zone_id,season); - } - - if(wzc.data[season].snowChance > 100) - { - wzc.data[season].snowChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%",zone_id,season); - } - - if(wzc.data[season].stormChance > 100) - { - wzc.data[season].stormChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%",zone_id,season); - } - } - - ++count; - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString(">> Loaded %u weather definitions", count); -} - -void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t) -{ - mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t; - WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); - if(t) - WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance); -} - -void ObjectMgr::DeleteCreatureData(uint32 guid) -{ - // remove mapid*cellid -> guid_set map - CreatureData const* data = GetCreatureData(guid); - if(data) - RemoveCreatureFromGrid(guid, data); - - mCreatureDataMap.erase(guid); -} - -void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t) -{ - mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t; - WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); - if(t) - WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance); -} - -void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance) -{ - RespawnTimes::iterator next; - - for(RespawnTimes::iterator itr = mGORespawnTimes.begin(); itr != mGORespawnTimes.end(); itr = next) - { - next = itr; - ++next; - - if(GUID_HIPART(itr->first)==instance) - mGORespawnTimes.erase(itr); - } - - for(RespawnTimes::iterator itr = mCreatureRespawnTimes.begin(); itr != mCreatureRespawnTimes.end(); itr = next) - { - next = itr; - ++next; - - if(GUID_HIPART(itr->first)==instance) - mCreatureRespawnTimes.erase(itr); - } - - WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", instance); - WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", instance); -} - -void ObjectMgr::DeleteGOData(uint32 guid) -{ - // remove mapid*cellid -> guid_set map - GameObjectData const* data = GetGOData(guid); - if(data) - RemoveGameobjectFromGrid(guid, data); - - mGameObjectDataMap.erase(guid); -} - -void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance) -{ - // corpses are always added to spawn mode 0 and they are spawned by their instance id - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid]; - cell_guids.corpses[player_guid] = instance; -} - -void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid) -{ - // corpses are always added to spawn mode 0 and they are spawned by their instance id - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid]; - cell_guids.corpses.erase(player_guid); -} - -void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map,char const* table) -{ - map.clear(); // need for reload case - - uint32 count = 0; - - QueryResult *result = WorldDatabase.PQuery("SELECT id,quest FROM %s",table); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 quest relations from %s. DB table `%s` is empty.",table,table); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 id = fields[0].GetUInt32(); - uint32 quest = fields[1].GetUInt32(); - - if(mQuestTemplates.find(quest) == mQuestTemplates.end()) - { - sLog.outErrorDb("Table `%s: Quest %u listed for entry %u does not exist.",table,quest,id); - continue; - } - - map.insert(QuestRelations::value_type(id,quest)); - - ++count; - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString(">> Loaded %u quest relations from %s", count,table); -} - -void ObjectMgr::LoadGameobjectQuestRelations() -{ - LoadQuestRelationsHelper(mGOQuestRelations,"gameobject_questrelation"); - - for(QuestRelations::iterator itr = mGOQuestRelations.begin(); itr != mGOQuestRelations.end(); ++itr) - { - GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first); - if(!goInfo) - sLog.outErrorDb("Table `gameobject_questrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second); - else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER) - sLog.outErrorDb("Table `gameobject_questrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second); - } -} - -void ObjectMgr::LoadGameobjectInvolvedRelations() -{ - LoadQuestRelationsHelper(mGOQuestInvolvedRelations,"gameobject_involvedrelation"); - - for(QuestRelations::iterator itr = mGOQuestInvolvedRelations.begin(); itr != mGOQuestInvolvedRelations.end(); ++itr) - { - GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first); - if(!goInfo) - sLog.outErrorDb("Table `gameobject_involvedrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second); - else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER) - sLog.outErrorDb("Table `gameobject_involvedrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second); - } -} - -void ObjectMgr::LoadCreatureQuestRelations() -{ - LoadQuestRelationsHelper(mCreatureQuestRelations,"creature_questrelation"); - - for(QuestRelations::iterator itr = mCreatureQuestRelations.begin(); itr != mCreatureQuestRelations.end(); ++itr) - { - CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); - if(!cInfo) - sLog.outErrorDb("Table `creature_questrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second); - else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) - sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second); - } -} - -void ObjectMgr::LoadCreatureInvolvedRelations() -{ - LoadQuestRelationsHelper(mCreatureQuestInvolvedRelations,"creature_involvedrelation"); - - for(QuestRelations::iterator itr = mCreatureQuestInvolvedRelations.begin(); itr != mCreatureQuestInvolvedRelations.end(); ++itr) - { - CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); - if(!cInfo) - sLog.outErrorDb("Table `creature_involvedrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second); - else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) - sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second); - } -} - -void ObjectMgr::LoadReservedPlayersNames() -{ - m_ReservedNames.clear(); // need for reload case - - QueryResult *result = WorldDatabase.PQuery("SELECT name FROM reserved_name"); - - uint32 count = 0; - - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u reserved player names", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - Field* fields; - do - { - bar.step(); - fields = result->Fetch(); - std::string name= fields[0].GetCppString(); - if(normalizePlayerName(name)) - { - m_ReservedNames.insert(name); - ++count; - } - } while ( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u reserved player names", count ); -} - -enum LanguageType -{ - LT_BASIC_LATIN = 0x0000, - LT_EXTENDEN_LATIN = 0x0001, - LT_CYRILLIC = 0x0002, - LT_EAST_ASIA = 0x0004, - LT_ANY = 0xFFFF -}; - -static LanguageType GetRealmLanguageType(bool create) -{ - switch(sWorld.getConfig(CONFIG_REALM_ZONE)) - { - case REALM_ZONE_UNKNOWN: // any language - case REALM_ZONE_DEVELOPMENT: - case REALM_ZONE_TEST_SERVER: - case REALM_ZONE_QA_SERVER: - return LT_ANY; - case REALM_ZONE_UNITED_STATES: // extended-Latin - case REALM_ZONE_OCEANIC: - case REALM_ZONE_LATIN_AMERICA: - case REALM_ZONE_ENGLISH: - case REALM_ZONE_GERMAN: - case REALM_ZONE_FRENCH: - case REALM_ZONE_SPANISH: - return LT_EXTENDEN_LATIN; - case REALM_ZONE_KOREA: // East-Asian - case REALM_ZONE_TAIWAN: - case REALM_ZONE_CHINA: - return LT_EAST_ASIA; - case REALM_ZONE_RUSSIAN: // Cyrillic - return LT_CYRILLIC; - default: - return create ? LT_BASIC_LATIN : LT_ANY; // basic-Latin at create, any at login - } -} - -bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bool create = false) -{ - if(strictMask==0) // any language, ignore realm - { - if(isExtendedLatinString(wstr,numericOrSpace)) - return true; - if(isCyrillicString(wstr,numericOrSpace)) - return true; - if(isEastAsianString(wstr,numericOrSpace)) - return true; - return false; - } - - if(strictMask & 0x2) // realm zone specific - { - LanguageType lt = GetRealmLanguageType(create); - if(lt & LT_EXTENDEN_LATIN) - if(isExtendedLatinString(wstr,numericOrSpace)) - return true; - if(lt & LT_CYRILLIC) - if(isCyrillicString(wstr,numericOrSpace)) - return true; - if(lt & LT_EAST_ASIA) - if(isEastAsianString(wstr,numericOrSpace)) - return true; - } - - if(strictMask & 0x1) // basic latin - { - if(isBasicLatinString(wstr,numericOrSpace)) - return true; - } - - return false; -} - -bool ObjectMgr::IsValidName( std::string name, bool create ) -{ - std::wstring wname; - if(!Utf8toWStr(name,wname)) - return false; - - if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME) - return false; - - uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES); - - return isValidString(wname,strictMask,false,create); -} - -bool ObjectMgr::IsValidCharterName( std::string name ) -{ - std::wstring wname; - if(!Utf8toWStr(name,wname)) - return false; - - if(wname.size() < 1) - return false; - - uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES); - - return isValidString(wname,strictMask,true); -} - -bool ObjectMgr::IsValidPetName( std::string name ) -{ - std::wstring wname; - if(!Utf8toWStr(name,wname)) - return false; - - if(wname.size() < 1) - return false; - - uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES); - - return isValidString(wname,strictMask,false); -} - -int ObjectMgr::GetIndexForLocale( LocaleConstant loc ) -{ - if(loc==LOCALE_enUS) - return -1; - - for(size_t i=0;i < m_LocalForIndex.size(); ++i) - if(m_LocalForIndex[i]==loc) - return i; - - return -1; -} - -LocaleConstant ObjectMgr::GetLocaleForIndex(int i) -{ - if (i<0 || i>=m_LocalForIndex.size()) - return LOCALE_enUS; - - return m_LocalForIndex[i]; -} - -int ObjectMgr::GetOrNewIndexForLocale( LocaleConstant loc ) -{ - if(loc==LOCALE_enUS) - return -1; - - for(size_t i=0;i < m_LocalForIndex.size(); ++i) - if(m_LocalForIndex[i]==loc) - return i; - - m_LocalForIndex.push_back(loc); - return m_LocalForIndex.size()-1; -} - -void ObjectMgr::LoadBattleMastersEntry() -{ - mBattleMastersMap.clear(); // need for reload case - - QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" ); - - uint32 count = 0; - - if( !result ) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 entry = fields[0].GetUInt32(); - uint32 bgTypeId = fields[1].GetUInt32(); - - mBattleMastersMap[entry] = bgTypeId; - - } while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u battlemaster entries", count ); -} - -void ObjectMgr::LoadGameObjectForQuests() -{ - mGameObjectForQuestSet.clear(); // need for reload case - - uint32 count = 0; - - // collect GO entries for GO that must activated - for(uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry) - { - GameObjectInfo const* goInfo = sGOStorage.LookupEntry(go_entry); - if(!goInfo) - continue; - - switch(goInfo->type) - { - // scan GO chest with loot including quest items - case GAMEOBJECT_TYPE_CHEST: - { - uint32 loot_id = GameObject::GetLootId(goInfo); - - // find quest loot for GO - if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id)) - { - mGameObjectForQuestSet.insert(go_entry); - ++count; - } - break; - } - case GAMEOBJECT_TYPE_GOOBER: - { - if(goInfo->goober.questId) //quests objects - { - mGameObjectForQuestSet.insert(go_entry); - count++; - } - break; - } - default: - break; - } - } - - sLog.outString(); - sLog.outString( ">> Loaded %u GameObject for quests", count ); -} - -bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, bool positive_entries) -{ - // cleanup affected map part for reloading case - for(MangosStringLocaleMap::iterator itr = mMangosStringLocaleMap.begin(); itr != mMangosStringLocaleMap.end();) - { - if(itr->first > 0 && positive_entries || itr->first < 0 && !positive_entries) - { - MangosStringLocaleMap::iterator itr2 = itr; - ++itr; - mMangosStringLocaleMap.erase(itr2); - } - else - ++itr; - } - - QueryResult *result = db.PQuery("SELECT entry,content_default,content_loc1,content_loc2,content_loc3,content_loc4,content_loc5,content_loc6,content_loc7,content_loc8 FROM %s",table); - - if(!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - if(positive_entries) // error only in case internal strings - sLog.outErrorDb(">> Loaded 0 mangos strings. DB table `%s` is empty. Cannot continue.",table); - else - sLog.outString(">> Loaded 0 mangos strings. DB table `%s` is empty.",table); - return false; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - int32 entry = fields[0].GetInt32(); - - if(entry==0) - { - sLog.outString("Table `%s` contain reserved entry 0, ignored.",table); - continue; - } - else if(entry < 0) - { - if(positive_entries) - { - sLog.outString("Table `%s` contain unexpected negative entry %i, ignored.",table,entry); - continue; - } - } - else - { - if(!positive_entries) - { - sLog.outString("Table `%s` contain unexpected positive entry %i, ignored.",table,entry); - continue; - } - } - - MangosStringLocale& data = mMangosStringLocaleMap[entry]; - - if(data.Content.size() < 1) - data.Content.resize(1); - - // 0 -> default, idx in to idx+1 - data.Content[0] = fields[1].GetCppString(); - - for(int i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[i+1].GetCppString(); - if(!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) - { - // 0 -> default, idx in to idx+1 - if(data.Content.size() <= idx+1) - data.Content.resize(idx+2); - - data.Content[idx+1] = str; - } - } - } - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u MaNGOS strings from table %s", mMangosStringLocaleMap.size(),table); - return true; -} - -const char *ObjectMgr::GetMangosString(int32 entry, int locale_idx) const -{ - // locale_idx==-1 -> default, locale_idx >= 0 in to idx+1 - // Content[0] always exist if exist MangosStringLocale - if(MangosStringLocale const *msl = GetMangosStringLocale(entry)) - { - if(msl->Content.size() > locale_idx+1 && !msl->Content[locale_idx+1].empty()) - return msl->Content[locale_idx+1].c_str(); - else - return msl->Content[0].c_str(); - } - - if(entry > 0) - sLog.outErrorDb("Entry %i not found in `mangos_string` table.",entry); - else - sLog.outErrorDb("Mangos string entry %i not found in DB.",entry); - return ""; -} - -void ObjectMgr::LoadFishingBaseSkillLevel() -{ - mFishingBaseForArea.clear(); // for relaod case - - uint32 count = 0; - QueryResult *result = WorldDatabase.Query("SELECT entry,skill FROM skill_fishing_base_level"); - - if( !result ) - { - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `skill_fishing_base_level`, table is empty!"); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - uint32 entry = fields[0].GetUInt32(); - int32 skill = fields[1].GetInt32(); - - AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry); - if(!fArea) - { - sLog.outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist",entry); - continue; - } - - mFishingBaseForArea[entry] = skill; - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u areas for fishing base skill level", count ); -} - -// Searches for the same condition already in Conditions store -// Returns Id if found, else adds it to Conditions and returns Id -uint16 ObjectMgr::GetConditionId( ConditionType condition, uint32 value1, uint32 value2 ) -{ - PlayerCondition lc = PlayerCondition(condition, value1, value2); - for (uint16 i=0; i < mConditions.size(); ++i) - { - if (lc == mConditions[i]) - return i; - } - - mConditions.push_back(lc); - - if(mConditions.size() > 0xFFFF) - { - sLog.outError("Conditions store overflow! Current and later loaded conditions will ignored!"); - return 0; - } - - return mConditions.size() - 1; -} - -bool ObjectMgr::CheckDeclinedNames( std::wstring mainpart, DeclinedName const& names ) -{ - for(int i =0; i < MAX_DECLINED_NAME_CASES; ++i) - { - std::wstring wname; - if(!Utf8toWStr(names.name[i],wname)) - return false; - - if(mainpart!=GetMainPartOfName(wname,i+1)) - return false; - } - return true; -} - -const char* ObjectMgr::GetAreaTriggerScriptName(uint32 id) -{ - AreaTriggerScriptMap::const_iterator i = mAreaTriggerScripts.find(id); - if(i!= mAreaTriggerScripts.end()) - return i->second.c_str(); - return ""; -} - -// Checks if player meets the condition -bool PlayerCondition::Meets(Player const * player) const -{ - if( !player ) - return false; // player not present, return false - - switch (condition) - { - case CONDITION_NONE: - return true; // empty condition, always met - case CONDITION_AURA: - return player->HasAura(value1, value2); - case CONDITION_ITEM: - return player->HasItemCount(value1, value2); - case CONDITION_ITEM_EQUIPPED: - return player->GetItemOrItemWithGemEquipped(value1) != NULL; - case CONDITION_ZONEID: - return player->GetZoneId() == value1; - case CONDITION_REPUTATION_RANK: - { - FactionEntry const* faction = sFactionStore.LookupEntry(value1); - return faction && player->GetReputationRank(faction) >= value2; - } - case CONDITION_TEAM: - return player->GetTeam() == value1; - case CONDITION_SKILL: - return player->HasSkill(value1) && player->GetBaseSkillValue(value1) >= value2; - case CONDITION_QUESTREWARDED: - return player->GetQuestRewardStatus(value1); - case CONDITION_QUESTTAKEN: - { - QuestStatus status = player->GetQuestStatus(value1); - return (status == QUEST_STATUS_INCOMPLETE); - } - case CONDITION_AD_COMMISSION_AURA: - { - Unit::AuraMap const& auras = player->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual==3580) - return true; - return false; - } - default: - return false; - } -} - -// Verification of condition values validity -bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 value2) -{ - if( condition >= MAX_CONDITION) // Wrong condition type - { - sLog.outErrorDb("Condition has bad type of %u, skipped ", condition ); - return false; - } - - switch (condition) - { - case CONDITION_AURA: - { - if(!sSpellStore.LookupEntry(value1)) - { - sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1); - return false; - } - if(value2 > 2) - { - sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2); - return false; - } - break; - } - case CONDITION_ITEM: - { - ItemPrototype const *proto = objmgr.GetItemPrototype(value1); - if(!proto) - { - sLog.outErrorDb("Item condition requires to have non existing item (%u), skipped", value1); - return false; - } - break; - } - case CONDITION_ITEM_EQUIPPED: - { - ItemPrototype const *proto = objmgr.GetItemPrototype(value1); - if(!proto) - { - sLog.outErrorDb("ItemEquipped condition requires to have non existing item (%u) equipped, skipped", value1); - return false; - } - break; - } - case CONDITION_ZONEID: - { - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(value1); - if(!areaEntry) - { - sLog.outErrorDb("Zone condition requires to be in non existing area (%u), skipped", value1); - return false; - } - if(areaEntry->zone != 0) - { - sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", value1); - return false; - } - break; - } - case CONDITION_REPUTATION_RANK: - { - FactionEntry const* factionEntry = sFactionStore.LookupEntry(value1); - if(!factionEntry) - { - sLog.outErrorDb("Reputation condition requires to have reputation non existing faction (%u), skipped", value1); - return false; - } - break; - } - case CONDITION_TEAM: - { - if (value1 != ALLIANCE && value1 != HORDE) - { - sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", value1); - return false; - } - break; - } - case CONDITION_SKILL: - { - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(value1); - if (!pSkill) - { - sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", value1); - return false; - } - if (value2 < 1 || value2 > sWorld.GetConfigMaxSkillValue() ) - { - sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", value2); - return false; - } - break; - } - case CONDITION_QUESTREWARDED: - case CONDITION_QUESTTAKEN: - { - Quest const *Quest = objmgr.GetQuestTemplate(value1); - if (!Quest) - { - sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", value1); - return false; - } - if(value2) - sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2); - break; - } - case CONDITION_AD_COMMISSION_AURA: - { - if(value1) - sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", value1); - if(value2) - sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2); - break; - } - } - return true; -} - -SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial) -{ - switch(pSkill->categoryId) - { - case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE; - case SKILL_CATEGORY_WEAPON: - if(pSkill->id!=SKILL_FIST_WEAPONS) - return SKILL_RANGE_LEVEL; - else - return SKILL_RANGE_MONO; - case SKILL_CATEGORY_ARMOR: - case SKILL_CATEGORY_CLASS: - if(pSkill->id != SKILL_POISONS && pSkill->id != SKILL_LOCKPICKING) - return SKILL_RANGE_MONO; - else - return SKILL_RANGE_LEVEL; - case SKILL_CATEGORY_SECONDARY: - case SKILL_CATEGORY_PROFESSION: - // not set skills for professions and racial abilities - if(IsProfessionSkill(pSkill->id)) - return SKILL_RANGE_RANK; - else if(racial) - return SKILL_RANGE_NONE; - else - return SKILL_RANGE_MONO; - default: - case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc - case SKILL_CATEGORY_NOT_DISPLAYED: //only GENEREC(DND) - return SKILL_RANGE_NONE; - } -} - -const char* GetAreaTriggerScriptNameById(uint32 id) -{ - return objmgr.GetAreaTriggerScriptName(id); -} - - -bool LoadMangosStrings(DatabaseType& db, char const* table) -{ - // for scripting localized strings allowed use _only_ negative entries - return objmgr.LoadMangosStrings(db,table,false); -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "Database/SQLStorage.h" + +#include "Log.h" +#include "MapManager.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "UpdateMask.h" +#include "World.h" +#include "WorldSession.h" +#include "Group.h" +#include "Guild.h" +#include "ArenaTeam.h" +#include "Transports.h" +#include "ProgressBar.h" +#include "Policies/SingletonImp.h" +#include "Language.h" +#include "GameEvent.h" +#include "Spell.h" +#include "Chat.h" +#include "InstanceSaveMgr.h" +#include "SpellAuras.h" +#include "Util.h" + +INSTANTIATE_SINGLETON_1(ObjectMgr); + +ScriptMapMap sQuestEndScripts; +ScriptMapMap sQuestStartScripts; +ScriptMapMap sSpellScripts; +ScriptMapMap sGameObjectScripts; +ScriptMapMap sEventScripts; + +bool normalizePlayerName(std::string& name) +{ + if(name.empty()) + return false; + + wchar_t wstr_buf[MAX_INTERNAL_PLAYER_NAME+1]; + size_t wstr_len = MAX_INTERNAL_PLAYER_NAME; + + if(!Utf8toWStr(name,&wstr_buf[0],wstr_len)) + return false; + + wstr_buf[0] = wcharToUpper(wstr_buf[0]); + for(size_t i = 1; i < wstr_len; ++i) + wstr_buf[i] = wcharToLower(wstr_buf[i]); + + if(!WStrToUtf8(wstr_buf,wstr_len,name)) + return false; + + return true; +} + +ObjectMgr::ObjectMgr() +{ + m_hiCharGuid = 1; + m_hiCreatureGuid = 1; + m_hiPetGuid = 1; + m_hiItemGuid = 1; + m_hiGoGuid = 1; + m_hiDoGuid = 1; + m_hiCorpseGuid = 1; + + m_hiPetNumber = 1; + + mGuildBankTabPrice.resize(GUILD_BANK_MAX_TABS); + mGuildBankTabPrice[0] = 100; + mGuildBankTabPrice[1] = 250; + mGuildBankTabPrice[2] = 500; + mGuildBankTabPrice[3] = 1000; + mGuildBankTabPrice[4] = 2500; + mGuildBankTabPrice[5] = 5000; + + // Only zero condition left, others will be added while loading DB tables + mConditions.resize(1); +} + +ObjectMgr::~ObjectMgr() +{ + for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++ i ) + { + delete i->second; + } + mQuestTemplates.clear( ); + + for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++ i ) + { + delete i->second; + } + mGossipText.clear( ); + + mAreaTriggers.clear(); + + for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++ i ) + { + delete[] i->second; + } + petInfo.clear(); + + // free only if loaded + for (int class_ = 0; class_ < MAX_CLASSES; ++class_) + delete[] playerClassInfo[class_].levelInfo; + + for (int race = 0; race < MAX_RACES; ++race) + for (int class_ = 0; class_ < MAX_CLASSES; ++class_) + delete[] playerInfo[race][class_].levelInfo; + + // free group and guild objects + for (GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) + delete (*itr); + for (GuildSet::iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr) + delete (*itr); + + for(ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr) + delete itr->second; + + for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) + for (VendorItemList::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + delete (*itr2); + + for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) + itr->second.Clear(); +} + +Group * ObjectMgr::GetGroupByLeader(const uint64 &guid) const +{ + for(GroupSet::const_iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) + if ((*itr)->GetLeaderGUID() == guid) + return *itr; + + return NULL; +} + +Guild * ObjectMgr::GetGuildById(const uint32 GuildId) const +{ + for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++) + if ((*itr)->GetId() == GuildId) + return *itr; + + return NULL; +} + +Guild * ObjectMgr::GetGuildByName(std::string guildname) const +{ + for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++) + if ((*itr)->GetName() == guildname) + return *itr; + + return NULL; +} + +std::string ObjectMgr::GetGuildNameById(const uint32 GuildId) const +{ + for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++) + if ((*itr)->GetId() == GuildId) + return (*itr)->GetName(); + + return ""; +} + +Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const +{ + for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr) + if( (*itr)->GetLeader() == guid) + return *itr; + + return NULL; +} + +ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 ArenaTeamId) const +{ + for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++) + if ((*itr)->GetId() == ArenaTeamId) + return *itr; + + return NULL; +} + +ArenaTeam* ObjectMgr::GetArenaTeamByName(std::string arenateamname) const +{ + for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++) + if ((*itr)->GetName() == arenateamname) + return *itr; + + return NULL; +} + +ArenaTeam* ObjectMgr::GetArenaTeamByCapitan(uint64 const& guid) const +{ + for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++) + if ((*itr)->GetCaptain() == guid) + return *itr; + + return NULL; +} + +AuctionHouseObject * ObjectMgr::GetAuctionsMap( uint32 location ) +{ + switch ( location ) + { + case 6: //horde + return & mHordeAuctions; + break; + case 2: //alliance + return & mAllianceAuctions; + break; + default: //neutral + return & mNeutralAuctions; + } +} + +uint32 ObjectMgr::GetAuctionCut(uint32 location, uint32 highBid) +{ + if (location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + return (uint32) (0.15f * highBid * sWorld.getRate(RATE_AUCTION_CUT)); + else + return (uint32) (0.05f * highBid * sWorld.getRate(RATE_AUCTION_CUT)); +} + +uint32 ObjectMgr::GetAuctionDeposit(uint32 location, uint32 time, Item *pItem) +{ + float percentance; // in 0..1 + if ( location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + percentance = 0.75f; + else + percentance = 0.15f; + + percentance *= sWorld.getRate(RATE_AUCTION_DEPOSIT); + + return uint32( percentance * pItem->GetProto()->SellPrice * pItem->GetCount() * (time / MIN_AUCTION_TIME ) ); +} + +/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c +uint32 ObjectMgr::GetAuctionOutBid(uint32 currentBid) +{ + uint32 outbid = (currentBid / 100) * 5; + if (!outbid) + outbid = 1; + return outbid; +} + +//does not clear ram +void ObjectMgr::SendAuctionWonMail( AuctionEntry *auction ) +{ + Item *pItem = GetAItem(auction->item_guidlow); + if(!pItem) + return; + + uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); + Player *bidder = GetPlayer(bidder_guid); + + uint32 bidder_accId = 0; + + // data for gm.log + if( sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) + { + uint32 bidder_security = 0; + std::string bidder_name; + if (bidder) + { + bidder_accId = bidder->GetSession()->GetAccountId(); + bidder_security = bidder->GetSession()->GetSecurity(); + bidder_name = bidder->GetName(); + } + else + { + bidder_accId = GetPlayerAccountIdByGUID(bidder_guid); + bidder_security = GetSecurityByAccount(bidder_accId); + + if(bidder_security > SEC_PLAYER ) // not do redundant DB requests + { + if(!GetPlayerNameByGUID(bidder_guid,bidder_name)) + bidder_name = GetMangosStringForDBCLocale(LANG_UNKNOWN); + } + } + + if( bidder_security > SEC_PLAYER ) + { + std::string owner_name; + if(!GetPlayerNameByGUID(auction->owner,owner_name)) + owner_name = GetMangosStringForDBCLocale(LANG_UNKNOWN); + + uint32 owner_accid = GetPlayerAccountIdByGUID(auction->owner); + + sLog.outCommand("GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", + bidder_name.c_str(),bidder_accId,pItem->GetProto()->Name1,pItem->GetEntry(),pItem->GetCount(),auction->bid,owner_name.c_str(),owner_accid); + } + } + else if(!bidder) + bidder_accId = GetPlayerAccountIdByGUID(bidder_guid); + + // receiver exist + if(bidder || bidder_accId) + { + std::ostringstream msgAuctionWonSubject; + msgAuctionWonSubject << auction->item_template << ":0:" << AUCTION_WON; + + std::ostringstream msgAuctionWonBody; + msgAuctionWonBody.width(16); + msgAuctionWonBody << std::right << std::hex << auction->owner; + msgAuctionWonBody << std::dec << ":" << auction->bid << ":" << auction->buyout; + sLog.outDebug( "AuctionWon body string : %s", msgAuctionWonBody.str().c_str() ); + + //prepare mail data... : + uint32 itemTextId = this->CreateItemText( msgAuctionWonBody.str() ); + + // set owner to bidder (to prevent delete item with sender char deleting) + // owner in `data` will set at mail receive and item extracting + CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'",auction->bidder,pItem->GetGUIDLow()); + CharacterDatabase.CommitTransaction(); + + MailItemsInfo mi; + mi.AddItem(auction->item_guidlow, auction->item_template, pItem); + + if (bidder) + bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, bidder_guid, 0, 0, auction->item_template); + else + RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! + + // will delete item or place to receiver mail list + WorldSession::SendMailTo(bidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionWonSubject.str(), itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_AUCTION); + } + // receiver not exist + else + { + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", pItem->GetGUIDLow()); + RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! + delete pItem; + } +} + +void ObjectMgr::SendAuctionSalePendingMail( AuctionEntry * auction ) +{ + uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); + Player *owner = GetPlayer(owner_guid); + + // owner exist (online or offline) + if(owner || GetPlayerAccountIdByGUID(owner_guid)) + { + std::ostringstream msgAuctionSalePendingSubject; + msgAuctionSalePendingSubject << auction->item_template << ":0:" << AUCTION_SALE_PENDING; + + std::ostringstream msgAuctionSalePendingBody; + uint32 auctionCut = GetAuctionCut(auction->location, auction->bid); + + time_t distrTime = time(NULL) + HOUR; + + msgAuctionSalePendingBody.width(16); + msgAuctionSalePendingBody << std::right << std::hex << auction->bidder; + msgAuctionSalePendingBody << std::dec << ":" << auction->bid << ":" << auction->buyout; + msgAuctionSalePendingBody << ":" << auction->deposit << ":" << auctionCut << ":0:"; + msgAuctionSalePendingBody << secsToTimeBitFields(distrTime); + + sLog.outDebug("AuctionSalePending body string : %s", msgAuctionSalePendingBody.str().c_str()); + + uint32 itemTextId = this->CreateItemText( msgAuctionSalePendingBody.str() ); + + WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSalePendingSubject.str(), itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_AUCTION); + } +} + +//call this method to send mail to auction owner, when auction is successful, it does not clear ram +void ObjectMgr::SendAuctionSuccessfulMail( AuctionEntry * auction ) +{ + uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); + Player *owner = GetPlayer(owner_guid); + + uint32 owner_accId = 0; + if(!owner) + owner_accId = GetPlayerAccountIdByGUID(owner_guid); + + // owner exist + if(owner || owner_accId) + { + std::ostringstream msgAuctionSuccessfulSubject; + msgAuctionSuccessfulSubject << auction->item_template << ":0:" << AUCTION_SUCCESSFUL; + + std::ostringstream auctionSuccessfulBody; + uint32 auctionCut = GetAuctionCut(auction->location, auction->bid); + + auctionSuccessfulBody.width(16); + auctionSuccessfulBody << std::right << std::hex << auction->bidder; + auctionSuccessfulBody << std::dec << ":" << auction->bid << ":" << auction->buyout; + auctionSuccessfulBody << ":" << auction->deposit << ":" << auctionCut; + + sLog.outDebug("AuctionSuccessful body string : %s", auctionSuccessfulBody.str().c_str()); + + uint32 itemTextId = this->CreateItemText( auctionSuccessfulBody.str() ); + + uint32 profit = auction->bid + auction->deposit - auctionCut; + + if (owner) + { + //send auction owner notification, bidder must be current! + owner->GetSession()->SendAuctionOwnerNotification( auction ); + } + + WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSuccessfulSubject.str(), itemTextId, NULL, profit, 0, MAIL_CHECK_MASK_AUCTION, HOUR); + } +} + +//does not clear ram +void ObjectMgr::SendAuctionExpiredMail( AuctionEntry * auction ) +{ //return an item in auction to its owner by mail + Item *pItem = GetAItem(auction->item_guidlow); + if(!pItem) + { + sLog.outError("Auction item (GUID: %u) not found, and lost.",auction->item_guidlow); + return; + } + + uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); + Player *owner = GetPlayer(owner_guid); + + uint32 owner_accId = 0; + if(!owner) + owner_accId = GetPlayerAccountIdByGUID(owner_guid); + + // owner exist + if(owner || owner_accId) + { + std::ostringstream subject; + subject << auction->item_template << ":0:" << AUCTION_EXPIRED; + + if ( owner ) + owner->GetSession()->SendAuctionOwnerNotification( auction ); + else + RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! + + MailItemsInfo mi; + mi.AddItem(auction->item_guidlow, auction->item_template, pItem); + + // will delete item or place to receiver mail list + WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, GUID_LOPART(owner_guid), subject.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE); + + } + // owner not found + else + { + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'",pItem->GetGUIDLow()); + RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! + delete pItem; + } +} + +CreatureInfo const* ObjectMgr::GetCreatureTemplate(uint32 id) +{ + return sCreatureStorage.LookupEntry(id); +} + +void ObjectMgr::LoadCreatureLocales() +{ + QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,subname_loc1,name_loc2,subname_loc2,name_loc3,subname_loc3,name_loc4,subname_loc4,name_loc5,subname_loc5,name_loc6,subname_loc6,name_loc7,subname_loc7,name_loc8,subname_loc8 FROM locales_creature"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outString(">> Loaded 0 creature locale strings. DB table `locales_creature` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + CreatureLocale& data = mCreatureLocaleMap[entry]; + + for(int i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[1+2*(i-1)].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Name.size() <= idx) + data.Name.resize(idx+1); + + data.Name[idx] = str; + } + } + str = fields[1+2*(i-1)+1].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.SubName.size() <= idx) + data.SubName.resize(idx+1); + + data.SubName[idx] = str; + } + } + } + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() ); +} + +void ObjectMgr::LoadCreatureTemplates() +{ + sCreatureStorage.Load(); + + sLog.outString( ">> Loaded %u creature definitions", sCreatureStorage.RecordCount ); + sLog.outString(); + + std::set heroicEntries; // already loaded heroic value in creatures + std::set hasHeroicEntries; // already loaded creatures with heroic entry values + + // check data correctness + for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i) + { + CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i); + if(!cInfo) + continue; + + if(cInfo->HeroicEntry) + { + CreatureInfo const* heroicInfo = GetCreatureTemplate(cInfo->HeroicEntry); + if(!heroicInfo) + { + sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u not exist.",cInfo->HeroicEntry,cInfo->HeroicEntry); + continue; + } + + if(heroicEntries.find(i)!=heroicEntries.end()) + { + sLog.outErrorDb("Creature (Entry: %u) listed as heroic but have value in `heroic_entry`.",i); + continue; + } + + if(heroicEntries.find(cInfo->HeroicEntry)!=heroicEntries.end()) + { + sLog.outErrorDb("Creature (Entry: %u) already listed as heroic for another entry.",cInfo->HeroicEntry); + continue; + } + + if(hasHeroicEntries.find(cInfo->HeroicEntry)!=hasHeroicEntries.end()) + { + sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u have heroic entry also.",i,cInfo->HeroicEntry,cInfo->HeroicEntry); + continue; + } + + if(cInfo->npcflag != heroicInfo->npcflag) + { + sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `npcflag` in heroic mode.",i); + continue; + } + + if(cInfo->classNum != heroicInfo->classNum) + { + sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `classNum` in heroic mode.",i); + continue; + } + + if(cInfo->race != heroicInfo->race) + { + sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `race` in heroic mode.",i); + continue; + } + + if(cInfo->trainer_type != heroicInfo->trainer_type) + { + sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_type` in heroic mode.",i); + continue; + } + + if(cInfo->trainer_spell != heroicInfo->trainer_spell) + { + sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_spell` in heroic mode.",i); + continue; + } + + hasHeroicEntries.insert(i); + heroicEntries.insert(cInfo->HeroicEntry); + } + + FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A); + if(!factionTemplate) + sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A); + + factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H); + if(!factionTemplate) + sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H); + + CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->DisplayID_A); + if (!minfo) + sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_A (%u)", cInfo->Entry, cInfo->DisplayID_A); + minfo = sCreatureModelStorage.LookupEntry(cInfo->DisplayID_H); + if (!minfo) + sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_H (%u)", cInfo->Entry, cInfo->DisplayID_H); + + if(cInfo->dmgschool >= MAX_SPELL_SCHOOL) + { + sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool); + const_cast(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL; + } + + if(cInfo->baseattacktime == 0) + const_cast(cInfo)->baseattacktime = BASE_ATTACK_TIME; + + if(cInfo->rangeattacktime == 0) + const_cast(cInfo)->rangeattacktime = BASE_ATTACK_TIME; + + if((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE) + sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type); + + if(cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE) + { + sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType); + const_cast(cInfo)->InhabitType = INHABIT_ANYWHERE; + } + + if(cInfo->PetSpellDataId) + { + CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId); + if(!spellDataId) + sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId); + } + + if(cInfo->MovementType >= MAX_DB_MOTION_TYPE) + { + sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType); + const_cast(cInfo)->MovementType = IDLE_MOTION_TYPE; + } + + if(cInfo->equipmentId > 0) // 0 no equipment + { + if(!GetEquipmentInfo(cInfo->equipmentId)) + { + sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId); + const_cast(cInfo)->equipmentId = 0; + } + } + + /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc + if(cInfo->scale <= 0.0f) + { + CreatureDisplayInfoEntry const* ScaleEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->DisplayID_A); + const_cast(cInfo)->scale = ScaleEntry ? ScaleEntry->scale : 1.0f; + } + } +} + +void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr) +{ + // Now add the auras, format "spellid effectindex spellid effectindex..." + char *p,*s; + std::vector val; + s=p=(char*)reinterpret_cast(addon->auras); + if(p) + { + while (p[0]!=0) + { + ++p; + if (p[0]==' ') + { + val.push_back(atoi(s)); + s=++p; + } + } + if (p!=s) + val.push_back(atoi(s)); + + // free char* loaded memory + delete[] (char*)reinterpret_cast(addon->auras); + + // wrong list + if (val.size()%2) + { + addon->auras = NULL; + sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`.",guidEntryStr,addon->guidOrEntry,table); + return; + } + } + + // empty list + if(val.empty()) + { + addon->auras = NULL; + return; + } + + // replace by new strucutres array + const_cast(addon->auras) = new CreatureDataAddonAura[val.size()/2+1]; + + int i=0; + for(int j=0;j(addon->auras[i]); + cAura.spell_id = (uint32)val[2*j+0]; + cAura.effect_idx = (uint32)val[2*j+1]; + if ( cAura.effect_idx > 2 ) + { + sLog.outErrorDb("Creature (%s: %u) has wrong effect %u for spell %u in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table); + continue; + } + SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura.spell_id); + if (!AdditionalSpellInfo) + { + sLog.outErrorDb("Creature (%s: %u) has wrong spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table); + continue; + } + + if (!AdditionalSpellInfo->Effect[cAura.effect_idx] || !AdditionalSpellInfo->EffectApplyAuraName[cAura.effect_idx]) + { + sLog.outErrorDb("Creature (%s: %u) has not aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table); + continue; + } + + ++i; + } + + // fill terminator element (after last added) + CreatureDataAddonAura& endAura = const_cast(addon->auras[i]); + endAura.spell_id = 0; + endAura.effect_idx = 0; +} + +void ObjectMgr::LoadCreatureAddons() +{ + sCreatureInfoAddonStorage.Load(); + + sLog.outString( ">> Loaded %u creature template addons", sCreatureInfoAddonStorage.RecordCount ); + sLog.outString(); + + // check data correctness and convert 'auras' + for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i) + { + CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry(i); + if(!addon) + continue; + + ConvertCreatureAddonAuras(const_cast(addon), "creature_template_addon", "Entry"); + + if(!sCreatureStorage.LookupEntry(addon->guidOrEntry)) + sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `creature_template_addon`",addon->guidOrEntry); + } + + sCreatureDataAddonStorage.Load(); + + sLog.outString( ">> Loaded %u creature addons", sCreatureDataAddonStorage.RecordCount ); + sLog.outString(); + + // check data correctness and convert 'auras' + for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i) + { + CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry(i); + if(!addon) + continue; + + ConvertCreatureAddonAuras(const_cast(addon), "creature_addon", "GUIDLow"); + + if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end()) + sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry); + } +} + +EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry) +{ + return sEquipmentStorage.LookupEntry(entry); +} + +void ObjectMgr::LoadEquipmentTemplates() +{ + sEquipmentStorage.Load(); + + sLog.outString( ">> Loaded %u equipment template", sEquipmentStorage.RecordCount ); + sLog.outString(); +} + +CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid) +{ + return sCreatureModelStorage.LookupEntry(modelid); +} + +uint32 ObjectMgr::ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data) +{ + // Load creature model (display id) + uint32 display_id; + if (!data || data->displayid == 0) // use defaults from the template + { + // DisplayID_A is used if no team is given + if (team == HORDE) + display_id = (cinfo->DisplayID_H2 != 0 && urand(0,1) == 0) ? cinfo->DisplayID_H2 : cinfo->DisplayID_H; + else + display_id = (cinfo->DisplayID_A2 != 0 && urand(0,1) == 0) ? cinfo->DisplayID_A2 : cinfo->DisplayID_A; + } + else // overriden in creature data + display_id = data->displayid; + + return display_id; +} + +CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_id) +{ + CreatureModelInfo const *minfo = GetCreatureModelInfo(display_id); + if(!minfo) + return NULL; + + // If a model for another gender exists, 50% chance to use it + if(minfo->modelid_other_gender != 0 && urand(0,1) == 0) + { + CreatureModelInfo const *minfo_tmp = GetCreatureModelInfo(minfo->modelid_other_gender); + if(!minfo_tmp) + { + sLog.outErrorDb("Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", minfo->modelid, minfo->modelid_other_gender); + return minfo; // not fatal, just use the previous one + } + else + return minfo_tmp; + } + else + return minfo; +} + +void ObjectMgr::LoadCreatureModelInfo() +{ + sCreatureModelStorage.Load(); + + sLog.outString( ">> Loaded %u creature model based info", sCreatureModelStorage.RecordCount ); + sLog.outString(); +} + +void ObjectMgr::LoadCreatures() +{ + uint32 count = 0; + // 0 1 2 3 + QueryResult *result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid," + // 4 5 6 7 8 9 10 11 + "equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint," + // 12 13 14 15 16 17 + "curhealth, curmana, DeathState, MovementType, spawnMask, event " + "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty."); + return; + } + + // build single time for check creature data + std::set heroicCreatures; + for(uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i) + if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) + if(cInfo->HeroicEntry) + heroicCreatures.insert(cInfo->HeroicEntry); + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 guid = fields[0].GetUInt32(); + + CreatureData& data = mCreatureDataMap[guid]; + + data.id = fields[ 1].GetUInt32(); + data.mapid = fields[ 2].GetUInt32(); + data.displayid = fields[ 3].GetUInt32(); + data.equipmentId = fields[ 4].GetUInt32(); + data.posX = fields[ 5].GetFloat(); + data.posY = fields[ 6].GetFloat(); + data.posZ = fields[ 7].GetFloat(); + data.orientation = fields[ 8].GetFloat(); + data.spawntimesecs = fields[ 9].GetUInt32(); + data.spawndist = fields[10].GetFloat(); + data.currentwaypoint= fields[11].GetUInt32(); + data.curhealth = fields[12].GetUInt32(); + data.curmana = fields[13].GetUInt32(); + data.is_dead = fields[14].GetBool(); + data.movementType = fields[15].GetUInt8(); + data.spawnMask = fields[16].GetUInt8(); + int16 gameEvent = fields[17].GetInt16(); + + CreatureInfo const* cInfo = GetCreatureTemplate(data.id); + if(!cInfo) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u) with not existed creature entry %u, skipped.",guid,data.id ); + continue; + } + + if(heroicCreatures.find(data.id)!=heroicCreatures.end()) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template in `creature_template_substitution`, skipped.",guid,data.id ); + continue; + } + + if(data.equipmentId > 0) // -1 no equipment, 0 use default + { + if(!GetEquipmentInfo(data.equipmentId)) + { + sLog.outErrorDb("Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId); + data.equipmentId = -1; + } + } + + if(cInfo->RegenHealth && data.curhealth < cInfo->minhealth) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.",guid,data.id,data.curhealth, cInfo->minhealth ); + data.curhealth = cInfo->minhealth; + } + + if(data.curmana < cInfo->minmana) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana ); + data.curmana = cInfo->minmana; + } + + if(data.spawndist < 0.0f) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.",guid,data.id ); + data.spawndist = 0.0f; + } + else if(data.movementType == RANDOM_MOTION_TYPE) + { + if(data.spawndist == 0.0f) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=1 (random movement) but with `spawndist`=0, replace by idle movement type (0).",guid,data.id ); + data.movementType = IDLE_MOTION_TYPE; + } + } + else if(data.movementType == IDLE_MOTION_TYPE) + { + if(data.spawndist != 0.0f) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=0 (idle) have `spawndist`<>0, set to 0.",guid,data.id ); + data.spawndist = 0.0f; + } + } + + if (gameEvent==0) // if not this is to be managed by GameEvent System + AddCreatureToGrid(guid, &data); + ++count; + + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u creatures", mCreatureDataMap.size() ); +} + +void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data) +{ + uint8 mask = data->spawnMask; + for(uint8 i = 0; mask != 0; i++, mask >>= 1) + { + if(mask & 1) + { + CellPair cell_pair = MaNGOS::ComputeCellPair(data->posX, data->posY); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; + cell_guids.creatures.insert(guid); + } + } +} + +void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data) +{ + uint8 mask = data->spawnMask; + for(uint8 i = 0; mask != 0; i++, mask >>= 1) + { + if(mask & 1) + { + CellPair cell_pair = MaNGOS::ComputeCellPair(data->posX, data->posY); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; + cell_guids.creatures.erase(guid); + } + } +} + +void ObjectMgr::LoadGameobjects() +{ + uint32 count = 0; + + // 0 1 2 3 4 5 6 + QueryResult *result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation," + // 7 8 9 10 11 12 13 14 15 + "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, event " + "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 gameobjects. DB table `gameobject` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 guid = fields[0].GetUInt32(); + + GameObjectData& data = mGameObjectDataMap[guid]; + + data.id = fields[ 1].GetUInt32(); + data.mapid = fields[ 2].GetUInt32(); + data.posX = fields[ 3].GetFloat(); + data.posY = fields[ 4].GetFloat(); + data.posZ = fields[ 5].GetFloat(); + data.orientation = fields[ 6].GetFloat(); + data.rotation0 = fields[ 7].GetFloat(); + data.rotation1 = fields[ 8].GetFloat(); + data.rotation2 = fields[ 9].GetFloat(); + data.rotation3 = fields[10].GetFloat(); + data.spawntimesecs = fields[11].GetInt32(); + data.animprogress = fields[12].GetUInt32(); + data.go_state = fields[13].GetUInt32(); + data.spawnMask = fields[14].GetUInt8(); + int16 gameEvent = fields[15].GetInt16(); + + GameObjectInfo const* gInfo = GetGameObjectInfo(data.id); + if(!gInfo) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u) with not existed gameobject entry %u, skipped.",guid,data.id ); + continue; + } + + if (gameEvent==0) // if not this is to be managed by GameEvent System + AddGameobjectToGrid(guid, &data); + ++count; + + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u gameobjects", mGameObjectDataMap.size()); +} + +void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data) +{ + uint8 mask = data->spawnMask; + for(uint8 i = 0; mask != 0; i++, mask >>= 1) + { + if(mask & 1) + { + CellPair cell_pair = MaNGOS::ComputeCellPair(data->posX, data->posY); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; + cell_guids.gameobjects.insert(guid); + } + } +} + +void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data) +{ + uint8 mask = data->spawnMask; + for(uint8 i = 0; mask != 0; i++, mask >>= 1) + { + if(mask & 1) + { + CellPair cell_pair = MaNGOS::ComputeCellPair(data->posX, data->posY); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; + cell_guids.gameobjects.erase(guid); + } + } +} + +void ObjectMgr::LoadCreatureRespawnTimes() +{ + // remove outdated data + WorldDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); + + uint32 count = 0; + + QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM creature_respawn"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded 0 creature respawn time."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 loguid = fields[0].GetUInt32(); + uint64 respawn_time = fields[1].GetUInt64(); + uint32 instance = fields[2].GetUInt32(); + + mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time); + + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString( ">> Loaded %u creature respawn times", mCreatureRespawnTimes.size() ); + sLog.outString(); +} + +void ObjectMgr::LoadGameobjectRespawnTimes() +{ + // remove outdated data + WorldDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); + + uint32 count = 0; + + QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM gameobject_respawn"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded 0 gameobject respawn time."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 loguid = fields[0].GetUInt32(); + uint64 respawn_time = fields[1].GetUInt64(); + uint32 instance = fields[2].GetUInt32(); + + mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time); + + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString( ">> Loaded %u gameobject respawn times", mGORespawnTimes.size() ); + sLog.outString(); +} + +// name must be checked to correctness (if received) before call this function +uint64 ObjectMgr::GetPlayerGUIDByName(std::string name) const +{ + uint64 guid = 0; + + CharacterDatabase.escape_string(name); + + // Player name safe to sending to DB (checked at login) and this function using + QueryResult *result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE name = '%s'", name.c_str()); + if(result) + { + guid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); + + delete result; + } + + return guid; +} + +bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const +{ + // prevent DB access for online player + if(Player* player = GetPlayer(guid)) + { + name = player->GetName(); + return true; + } + + QueryResult *result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); + + if(result) + { + name = (*result)[0].GetCppString(); + delete result; + return true; + } + + return false; +} + +uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const +{ + QueryResult *result = CharacterDatabase.PQuery("SELECT race FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); + + if(result) + { + uint8 race = (*result)[0].GetUInt8(); + delete result; + return Player::TeamForRace(race); + } + + return 0; +} + +uint32 ObjectMgr::GetPlayerAccountIdByGUID(const uint64 &guid) const +{ + QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); + if(result) + { + uint32 acc = (*result)[0].GetUInt32(); + delete result; + return acc; + } + + return 0; +} + +uint32 ObjectMgr::GetSecurityByAccount(uint32 acc_id) const +{ + QueryResult *result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id); + if(result) + { + uint32 sec = (*result)[0].GetUInt32(); + delete result; + return sec; + } + + return 0; +} + +bool ObjectMgr::GetAccountNameByAccount(uint32 acc_id, std::string &name) const +{ + QueryResult *result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id); + if(result) + { + name = (*result)[0].GetCppString(); + delete result; + return true; + } + + return false; +} + +uint32 ObjectMgr::GetAccountByAccountName(std::string name) const +{ + loginDatabase.escape_string(name); + QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", name.c_str()); + if(result) + { + uint32 id = (*result)[0].GetUInt32(); + delete result; + return id; + } + + return 0; +} + +void ObjectMgr::LoadAuctions() +{ + QueryResult *result = CharacterDatabase.Query("SELECT COUNT(*) FROM auctionhouse"); + if( !result ) + return; + + Field *fields = result->Fetch(); + uint32 AuctionCount=fields[0].GetUInt32(); + delete result; + + if(!AuctionCount) + return; + + result = CharacterDatabase.Query( "SELECT id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit,location FROM auctionhouse" ); + if( !result ) + return; + + barGoLink bar( AuctionCount ); + + AuctionEntry *aItem; + + do + { + fields = result->Fetch(); + + bar.step(); + + aItem = new AuctionEntry; + aItem->Id = fields[0].GetUInt32(); + aItem->auctioneer = fields[1].GetUInt32(); + aItem->item_guidlow = fields[2].GetUInt32(); + aItem->item_template = fields[3].GetUInt32(); + aItem->owner = fields[4].GetUInt32(); + aItem->buyout = fields[5].GetUInt32(); + aItem->time = fields[6].GetUInt32(); + aItem->bidder = fields[7].GetUInt32(); + aItem->bid = fields[8].GetUInt32(); + aItem->startbid = fields[9].GetUInt32(); + aItem->deposit = fields[10].GetUInt32(); + aItem->location = fields[11].GetUInt8(); + //check if sold item exists + if ( this->GetAItem( aItem->item_guidlow ) ) + { + GetAuctionsMap( aItem->location )->AddAuction(aItem); + } + else + { + CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",aItem->Id); + sLog.outError("Auction %u has not a existing item : %u", aItem->Id, aItem->item_guidlow); + delete aItem; + } + } while (result->NextRow()); + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u auctions", AuctionCount ); + sLog.outString(); +} + +void ObjectMgr::LoadItemLocales() +{ + QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,description_loc1,name_loc2,description_loc2,name_loc3,description_loc3,name_loc4,description_loc4,name_loc5,description_loc5,name_loc6,description_loc6,name_loc7,description_loc7,name_loc8,description_loc8 FROM locales_item"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outString(">> Loaded 0 Item locale strings. DB table `locales_item` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + ItemLocale& data = mItemLocaleMap[entry]; + + for(int i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[1+2*(i-1)].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Name.size() <= idx) + data.Name.resize(idx+1); + + data.Name[idx] = str; + } + } + + str = fields[1+2*(i-1)+1].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Description.size() <= idx) + data.Description.resize(idx+1); + + data.Description[idx] = str; + } + } + } + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u Item locale strings", mItemLocaleMap.size() ); +} + +void ObjectMgr::LoadItemPrototypes() +{ + sItemStorage.Load (); + sLog.outString( ">> Loaded %u item prototypes", sItemStorage.RecordCount ); + sLog.outString(); + + // check data correctness + for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i) + { + ItemPrototype const* proto = sItemStorage.LookupEntry(i); + ItemEntry const *dbcitem = sItemStore.LookupEntry(i); + if(!proto) + { + /* to many errors, and possible not all items really used in game + if (dbcitem) + sLog.outErrorDb("Item (Entry: %u) doesn't exists in DB, but must exist.",i); + */ + continue; + } + + if(dbcitem) + { + if(proto->InventoryType != dbcitem->InventoryType) + { + sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType); + // It safe let use InventoryType from DB + } + + if(proto->DisplayInfoID != dbcitem->DisplayId) + { + sLog.outErrorDb("Item (Entry: %u) not correct %u display id, must be %u (using it).",i,proto->DisplayInfoID,dbcitem->DisplayId); + const_cast(proto)->DisplayInfoID = dbcitem->DisplayId; + } + if(proto->Sheath != dbcitem->Sheath) + { + sLog.outErrorDb("Item (Entry: %u) not correct %u sheath, must be %u (using it).",i,proto->Sheath,dbcitem->Sheath); + const_cast(proto)->Sheath = dbcitem->Sheath; + } + } + else + { + sLog.outErrorDb("Item (Entry: %u) not correct (not listed in list of existed items).",i); + } + + if(proto->Class >= MAX_ITEM_CLASS) + { + sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class); + const_cast(proto)->Class = ITEM_CLASS_JUNK; + } + + if(proto->SubClass >= MaxItemSubclassValues[proto->Class]) + { + sLog.outErrorDb("Item (Entry: %u) has wrong Subclass value (%u) for class %u",i,proto->SubClass,proto->Class); + const_cast(proto)->SubClass = 0;// exist for all item classes + } + + if(proto->Quality >= MAX_ITEM_QUALITY) + { + sLog.outErrorDb("Item (Entry: %u) has wrong Quality value (%u)",i,proto->Quality); + const_cast(proto)->Quality = ITEM_QUALITY_NORMAL; + } + + if(proto->BuyCount <= 0) + { + sLog.outErrorDb("Item (Entry: %u) has wrong BuyCount value (%u), set to default(1).",i,proto->BuyCount); + const_cast(proto)->BuyCount = 1; + } + + if(proto->InventoryType >= MAX_INVTYPE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong InventoryType value (%u)",i,proto->InventoryType); + const_cast(proto)->InventoryType = INVTYPE_NON_EQUIP; + } + + if(proto->RequiredSkill >= MAX_SKILL_TYPE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill); + const_cast(proto)->RequiredSkill = 0; + } + + if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE)) + { + sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped.",i,proto->AllowableClass); + } + + if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE)) + { + sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped.",i,proto->AllowableRace); + } + + if(proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell)) + { + sLog.outErrorDb("Item (Entry: %u) have wrong (non-existed) spell in RequiredSpell (%u)",i,proto->RequiredSpell); + const_cast(proto)->RequiredSpell = 0; + } + + if(proto->RequiredReputationRank >= MAX_REPUTATION_RANK) + sLog.outErrorDb("Item (Entry: %u) has wrong reputation rank in RequiredReputationRank (%u), item can't be used.",i,proto->RequiredReputationRank); + + if(proto->RequiredReputationFaction) + { + if(!sFactionStore.LookupEntry(proto->RequiredReputationFaction)) + { + sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) faction in RequiredReputationFaction (%u)",i,proto->RequiredReputationFaction); + const_cast(proto)->RequiredReputationFaction = 0; + } + + if(proto->RequiredReputationRank == MIN_REPUTATION_RANK) + sLog.outErrorDb("Item (Entry: %u) has min. reputation rank in RequiredReputationRank (0) but RequiredReputationFaction > 0, faction setting is useless.",i); + } + else if(proto->RequiredReputationRank > MIN_REPUTATION_RANK) + sLog.outErrorDb("Item (Entry: %u) has RequiredReputationFaction ==0 but RequiredReputationRank > 0, rank setting is useless.",i); + + if(proto->Stackable==0) + { + sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%u), replace by default 1.",i,proto->Stackable); + const_cast(proto)->Stackable = 1; + } + else if(proto->Stackable > 255) + { + sLog.outErrorDb("Item (Entry: %u) has too large value in stackable (%u), replace by hardcoded upper limit (255).",i,proto->Stackable); + const_cast(proto)->Stackable = 255; + } + + for (int j = 0; j < 10; j++) + { + // for ItemStatValue != 0 + if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD) + { + sLog.outErrorDb("Item (Entry: %u) has wrong stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType); + const_cast(proto)->ItemStat[j].ItemStatType = 0; + } + } + + for (int j = 0; j < 5; j++) + { + if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL) + { + sLog.outErrorDb("Item (Entry: %u) has wrong dmg_type%d (%u)",i,j+1,proto->Damage[j].DamageType); + const_cast(proto)->Damage[j].DamageType = 0; + } + } + + // special format + if(proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN) + { + // spell_1 + if(proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format",i,0+1,proto->Spells[0].SpellTrigger); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[0].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + const_cast(proto)->Spells[1].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + + // spell_2 have learning spell + if(proto->Spells[1].SpellTrigger != ITEM_SPELLTRIGGER_LEARN_SPELL_ID) + { + sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format.",i,1+1,proto->Spells[1].SpellTrigger); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[1].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + else if(!proto->Spells[1].SpellId) + { + sLog.outErrorDb("Item (Entry: %u) not has expected spell in spellid_%d in special learning format.",i,1+1); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + else + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[1].SpellId); + if(!spellInfo) + { + sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[1].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + // allowed only in special format + else if(proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN) + { + sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[1].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + } + + // spell_3*,spell_4*,spell_5* is empty + for (int j = 2; j < 5; j++) + { + if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger); + const_cast(proto)->Spells[j].SpellId = 0; + const_cast(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + else if(proto->Spells[j].SpellId != 0) + { + sLog.outErrorDb("Item (Entry: %u) has wrong spell in spellid_%d (%u) for learning special format",i,j+1,proto->Spells[j].SpellId); + const_cast(proto)->Spells[j].SpellId = 0; + } + } + } + // normal spell list + else + { + for (int j = 0; j < 5; j++) + { + if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID) + { + sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger); + const_cast(proto)->Spells[j].SpellId = 0; + const_cast(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + + if(proto->Spells[j].SpellId) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId); + if(!spellInfo) + { + sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId); + const_cast(proto)->Spells[j].SpellId = 0; + } + // allowed only in special format + else if(proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN) + { + sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId); + const_cast(proto)->Spells[j].SpellId = 0; + } + } + } + } + + if(proto->Bonding >= MAX_BIND_TYPE) + sLog.outErrorDb("Item (Entry: %u) has wrong Bonding value (%u)",i,proto->Bonding); + + if(proto->PageText && !sPageTextStore.LookupEntry(proto->PageText)) + sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText); + + if(proto->LockID && !sLockStore.LookupEntry(proto->LockID)) + sLog.outErrorDb("Item (Entry: %u) has wrong LockID (%u)",i,proto->LockID); + + if(proto->Sheath >= MAX_SHEATHETYPE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong Sheath (%u)",i,proto->Sheath); + const_cast(proto)->Sheath = SHEATHETYPE_NONE; + } + + if(proto->RandomProperty && !sItemRandomPropertiesStore.LookupEntry(GetItemEnchantMod(proto->RandomProperty))) + { + sLog.outErrorDb("Item (Entry: %u) has unknown (wrong or not listed in `item_enchantment_template`) RandomProperty (%u)",i,proto->RandomProperty); + const_cast(proto)->RandomProperty = 0; + } + + if(proto->RandomSuffix && !sItemRandomSuffixStore.LookupEntry(GetItemEnchantMod(proto->RandomSuffix))) + { + sLog.outErrorDb("Item (Entry: %u) has wrong RandomSuffix (%u)",i,proto->RandomSuffix); + const_cast(proto)->RandomSuffix = 0; + } + + if(proto->ItemSet && !sItemSetStore.LookupEntry(proto->ItemSet)) + { + sLog.outErrorDb("Item (Entry: %u) have wrong ItemSet (%u)",i,proto->ItemSet); + const_cast(proto)->ItemSet = 0; + } + + if(proto->Area && !GetAreaEntryByAreaID(proto->Area)) + sLog.outErrorDb("Item (Entry: %u) has wrong Area (%u)",i,proto->Area); + + if(proto->Map && !sMapStore.LookupEntry(proto->Map)) + sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map); + + if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory)) + sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory); + + for (int j = 0; j < 3; j++) + { + if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color) + { + sLog.outErrorDb("Item (Entry: %u) has wrong socketColor_%d (%u)",i,j+1,proto->Socket[j].Color); + const_cast(proto)->Socket[j].Color = 0; + } + } + + if(proto->GemProperties && !sGemPropertiesStore.LookupEntry(proto->GemProperties)) + sLog.outErrorDb("Item (Entry: %u) has wrong GemProperties (%u)",i,proto->GemProperties); + + if(proto->FoodType >= MAX_PET_DIET) + { + sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType); + const_cast(proto)->FoodType = 0; + } + } + + // this DBC used currently only for check item templates in DB. + sItemStore.Clear(); +} + +void ObjectMgr::LoadAuctionItems() +{ + QueryResult *result = CharacterDatabase.Query( "SELECT itemguid,item_template FROM auctionhouse" ); + + if( !result ) + return; + + barGoLink bar( result->GetRowCount() ); + + uint32 count = 0; + + Field *fields; + do + { + bar.step(); + + fields = result->Fetch(); + uint32 item_guid = fields[0].GetUInt32(); + uint32 item_template = fields[1].GetUInt32(); + + ItemPrototype const *proto = GetItemPrototype(item_template); + + if(!proto) + { + sLog.outError( "ObjectMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped.", item_guid,item_template); + continue; + } + + Item *item = NewItemOrBag(proto); + + if(!item->LoadFromDB(item_guid,0)) + { + delete item; + continue; + } + AddAItem(item); + + ++count; + } + while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u auction items", count ); +} + +void ObjectMgr::LoadPetLevelInfo() +{ + // Loading levels data + { + // 0 1 2 3 4 5 6 7 8 9 + QueryResult *result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar( 1 ); + + sLog.outString(); + sLog.outString( ">> Loaded %u level pet stats definitions", count ); + sLog.outErrorDb( "Error loading `pet_levelstats` table or empty table."); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field* fields = result->Fetch(); + + uint32 creature_id = fields[0].GetUInt32(); + if(!sCreatureStorage.LookupEntry(creature_id)) + { + sLog.outErrorDb("Wrong creature id %u in `pet_levelstats` table, ignoring.",creature_id); + continue; + } + + uint32 current_level = fields[1].GetUInt32(); + if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + if(current_level > 255) // hardcoded level maximum + sLog.outErrorDb("Wrong (> 255) level %u in `pet_levelstats` table, ignoring.",current_level); + else + sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `pet_levelstats` table, ignoring.",current_level); + continue; + } + else if(current_level < 1) + { + sLog.outErrorDb("Wrong (<1) level %u in `pet_levelstats` table, ignoring.",current_level); + continue; + } + + PetLevelInfo*& pInfoMapEntry = petInfo[creature_id]; + + if(pInfoMapEntry==NULL) + pInfoMapEntry = new PetLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; + + // data for level 1 stored in [0] array element, ... + PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level-1]; + + pLevelInfo->health = fields[2].GetUInt16(); + pLevelInfo->mana = fields[3].GetUInt16(); + pLevelInfo->armor = fields[9].GetUInt16(); + + for (int i = 0; i < MAX_STATS; i++) + { + pLevelInfo->stats[i] = fields[i+4].GetUInt16(); + } + + bar.step(); + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u level pet stats definitions", count ); + } + + // Fill gaps and check integrity + for (PetLevelInfoMap::iterator itr = petInfo.begin(); itr != petInfo.end(); ++itr) + { + PetLevelInfo* pInfo = itr->second; + + // fatal error if no level 1 data + if(!pInfo || pInfo[0].health == 0 ) + { + sLog.outErrorDb("Creature %u does not have pet stats data for Level 1!",itr->first); + exit(1); + } + + // fill level gaps + for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) + { + if(pInfo[level].health == 0) + { + sLog.outErrorDb("Creature %u has no data for Level %i pet stats data, using data of Level %i.",itr->first,level+1, level); + pInfo[level] = pInfo[level-1]; + } + } + } +} + +PetLevelInfo const* ObjectMgr::GetPetLevelInfo(uint32 creature_id, uint32 level) const +{ + if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); + + PetLevelInfoMap::const_iterator itr = petInfo.find(creature_id); + if(itr == petInfo.end()) + return NULL; + + return &itr->second[level-1]; // data for level 1 stored in [0] array element, ... +} + +void ObjectMgr::LoadPlayerInfo() +{ + // Load playercreate + { + // 0 1 2 3 4 5 6 + QueryResult *result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z FROM playercreateinfo"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar( 1 ); + + sLog.outString(); + sLog.outString( ">> Loaded %u player create definitions", count ); + sLog.outErrorDb( "Error loading `playercreateinfo` table or empty table."); + exit(1); + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + uint32 current_class = fields[1].GetUInt32(); + uint32 mapId = fields[2].GetUInt32(); + uint32 zoneId = fields[3].GetUInt32(); + float positionX = fields[4].GetFloat(); + float positionY = fields[5].GetFloat(); + float positionZ = fields[6].GetFloat(); + + if(current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race); + continue; + } + + ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(current_race); + if(!rEntry) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race); + continue; + } + + if(current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class); + continue; + } + + if(!sChrClassesStore.LookupEntry(current_class)) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class); + continue; + } + + // accept DB data only for valid position (and non instanceable) + if( !MapManager::IsValidMapCoord(mapId,positionX,positionY,positionZ) ) + { + sLog.outErrorDb("Wrong home position for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race); + continue; + } + + if( sMapStore.LookupEntry(mapId)->Instanceable() ) + { + sLog.outErrorDb("Home position in instanceable map for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race); + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + + pInfo->mapId = mapId; + pInfo->zoneId = zoneId; + pInfo->positionX = positionX; + pInfo->positionY = positionY; + pInfo->positionZ = positionZ; + + pInfo->displayId_m = rEntry->model_m; + pInfo->displayId_f = rEntry->model_f; + + bar.step(); + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u player create definitions", count ); + } + + // Load playercreate items + { + // 0 1 2 3 + QueryResult *result = WorldDatabase.Query("SELECT race, class, itemid, amount FROM playercreateinfo_item"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar( 1 ); + + sLog.outString(); + sLog.outString( ">> Loaded %u player create items", count ); + sLog.outErrorDb( "Error loading `playercreateinfo_item` table or empty table."); + } + else + { + barGoLink bar( result->GetRowCount() ); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + if(current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo_item` table, ignoring.",current_race); + continue; + } + + uint32 current_class = fields[1].GetUInt32(); + if(current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo_item` table, ignoring.",current_class); + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + + uint32 item_id = fields[2].GetUInt32(); + + if(!GetItemPrototype(item_id)) + { + sLog.outErrorDb("Item id %u (race %u class %u) in `playercreateinfo_item` table but not listed in `item_template`, ignoring.",item_id,current_race,current_class); + continue; + } + + uint32 amount = fields[3].GetUInt32(); + + if(!amount) + { + sLog.outErrorDb("Item id %u (class %u race %u) have amount==0 in `playercreateinfo_item` table, ignoring.",item_id,current_race,current_class); + continue; + } + + pInfo->item.push_back(PlayerCreateInfoItem( item_id, amount)); + + bar.step(); + ++count; + } + while(result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u player create items", count ); + } + } + + // Load playercreate spells + { + // 0 1 2 3 + QueryResult *result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar( 1 ); + + sLog.outString(); + sLog.outString( ">> Loaded %u player create spells", count ); + sLog.outErrorDb( "Error loading `playercreateinfo_spell` table or empty table."); + } + else + { + barGoLink bar( result->GetRowCount() ); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + if(current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo_spell` table, ignoring.",current_race); + continue; + } + + uint32 current_class = fields[1].GetUInt32(); + if(current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo_spell` table, ignoring.",current_class); + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + pInfo->spell.push_back(CreateSpellPair(fields[2].GetUInt16(), fields[3].GetUInt8())); + + bar.step(); + ++count; + } + while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u player create spells", count ); + } + } + + // Load playercreate actions + { + // 0 1 2 3 4 5 + QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type, misc FROM playercreateinfo_action"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar( 1 ); + + sLog.outString(); + sLog.outString( ">> Loaded %u player create actions", count ); + sLog.outErrorDb( "Error loading `playercreateinfo_action` table or empty table."); + } + else + { + barGoLink bar( result->GetRowCount() ); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + if(current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo_action` table, ignoring.",current_race); + continue; + } + + uint32 current_class = fields[1].GetUInt32(); + if(current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo_action` table, ignoring.",current_class); + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + pInfo->action[0].push_back(fields[2].GetUInt16()); + pInfo->action[1].push_back(fields[3].GetUInt16()); + pInfo->action[2].push_back(fields[4].GetUInt16()); + pInfo->action[3].push_back(fields[5].GetUInt16()); + + bar.step(); + ++count; + } + while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u player create actions", count ); + } + } + + // Loading levels data (class only dependent) + { + // 0 1 2 3 + QueryResult *result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar( 1 ); + + sLog.outString(); + sLog.outString( ">> Loaded %u level health/mana definitions", count ); + sLog.outErrorDb( "Error loading `player_classlevelstats` table or empty table."); + exit(1); + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field* fields = result->Fetch(); + + uint32 current_class = fields[0].GetUInt32(); + if(current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `player_classlevelstats` table, ignoring.",current_class); + continue; + } + + uint32 current_level = fields[1].GetUInt32(); + if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + if(current_level > 255) // hardcoded level maximum + sLog.outErrorDb("Wrong (> 255) level %u in `player_classlevelstats` table, ignoring.",current_level); + else + sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level); + continue; + } + + PlayerClassInfo* pClassInfo = &playerClassInfo[current_class]; + + if(!pClassInfo->levelInfo) + pClassInfo->levelInfo = new PlayerClassLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; + + PlayerClassLevelInfo* pClassLevelInfo = &pClassInfo->levelInfo[current_level-1]; + + pClassLevelInfo->basehealth = fields[2].GetUInt16(); + pClassLevelInfo->basemana = fields[3].GetUInt16(); + + bar.step(); + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u level health/mana definitions", count ); + } + + // Fill gaps and check integrity + for (int class_ = 0; class_ < MAX_CLASSES; ++class_) + { + // skip non existed classes + if(!sChrClassesStore.LookupEntry(class_)) + continue; + + PlayerClassInfo* pClassInfo = &playerClassInfo[class_]; + + // fatal error if no level 1 data + if(!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0 ) + { + sLog.outErrorDb("Class %i Level 1 does not have health/mana data!",class_); + exit(1); + } + + // fill level gaps + for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) + { + if(pClassInfo->levelInfo[level].basehealth == 0) + { + sLog.outErrorDb("Class %i Level %i does not have health/mana data. Using stats data of level %i.",class_,level+1, level); + pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level-1]; + } + } + } + + // Loading levels data (class/race dependent) + { + // 0 1 2 3 4 5 6 7 + QueryResult *result = WorldDatabase.Query("SELECT race, class, level, str, agi, sta, inte, spi FROM player_levelstats"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar( 1 ); + + sLog.outString(); + sLog.outString( ">> Loaded %u level stats definitions", count ); + sLog.outErrorDb( "Error loading `player_levelstats` table or empty table."); + exit(1); + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + if(current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `player_levelstats` table, ignoring.",current_race); + continue; + } + + uint32 current_class = fields[1].GetUInt32(); + if(current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `player_levelstats` table, ignoring.",current_class); + continue; + } + + uint32 current_level = fields[2].GetUInt32(); + if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + if(current_level > 255) // hardcoded level maximum + sLog.outErrorDb("Wrong (> 255) level %u in `player_levelstats` table, ignoring.",current_level); + else + sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_levelstats` table, ignoring.",current_level); + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + + if(!pInfo->levelInfo) + pInfo->levelInfo = new PlayerLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; + + PlayerLevelInfo* pLevelInfo = &pInfo->levelInfo[current_level-1]; + + for (int i = 0; i < MAX_STATS; i++) + { + pLevelInfo->stats[i] = fields[i+3].GetUInt8(); + } + + bar.step(); + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u level stats definitions", count ); + } + + // Fill gaps and check integrity + for (int race = 0; race < MAX_RACES; ++race) + { + // skip non existed races + if(!sChrRacesStore.LookupEntry(race)) + continue; + + for (int class_ = 0; class_ < MAX_CLASSES; ++class_) + { + // skip non existed classes + if(!sChrClassesStore.LookupEntry(class_)) + continue; + + PlayerInfo* pInfo = &playerInfo[race][class_]; + + // skip non loaded combinations + if(!pInfo->displayId_m || !pInfo->displayId_f) + continue; + + // skip expansion races if not playing with expansion + if (sWorld.getConfig(CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI)) + continue; + + // fatal error if no level 1 data + if(!pInfo->levelInfo || pInfo->levelInfo[0].stats[0] == 0 ) + { + sLog.outErrorDb("Race %i Class %i Level 1 does not have stats data!",race,class_); + exit(1); + } + + // fill level gaps + for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) + { + if(pInfo->levelInfo[level].stats[0] == 0) + { + sLog.outErrorDb("Race %i Class %i Level %i does not have stats data. Using stats data of level %i.",race,class_,level+1, level); + pInfo->levelInfo[level] = pInfo->levelInfo[level-1]; + } + } + } + } +} + +void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const +{ + if(level < 1 || class_ >= MAX_CLASSES) + return; + + PlayerClassInfo const* pInfo = &playerClassInfo[class_]; + + if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); + + *info = pInfo->levelInfo[level-1]; +} + +void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint32 level, PlayerLevelInfo* info) const +{ + if(level < 1 || race >= MAX_RACES || class_ >= MAX_CLASSES) + return; + + PlayerInfo const* pInfo = &playerInfo[race][class_]; + if(pInfo->displayId_m==0 || pInfo->displayId_f==0) + return; + + if(level <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + *info = pInfo->levelInfo[level-1]; + else + BuildPlayerLevelInfo(race,class_,level,info); +} + +void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, PlayerLevelInfo* info) const +{ + // base data (last known level) + *info = playerInfo[race][_class].levelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1]; + + for(int lvl = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1; lvl < level; ++lvl) + { + switch(_class) + { + case CLASS_WARRIOR: + info->stats[STAT_STRENGTH] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_STAMINA] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_AGILITY] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 9 && !(lvl%2) ? 1: 0); + break; + case CLASS_PALADIN: + info->stats[STAT_STRENGTH] += (lvl > 3 ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 7 ? 1: 0); + break; + case CLASS_HUNTER: + info->stats[STAT_STRENGTH] += (lvl > 4 ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0)); + break; + case CLASS_ROGUE: + info->stats[STAT_STRENGTH] += (lvl > 5 ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0)); + break; + case CLASS_PRIEST: + info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_SPIRIT] += (lvl > 3 ? 1: 0); + break; + case CLASS_SHAMAN: + info->stats[STAT_STRENGTH] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0)); + info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 7 && !(lvl%2) ? 1: 0); + info->stats[STAT_INTELLECT] += (lvl > 5 ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 4 ? 1: 0); + break; + case CLASS_MAGE: + info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_SPIRIT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0)); + break; + case CLASS_WARLOCK: + info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0)); + info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0)); + info->stats[STAT_SPIRIT] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0)); + break; + case CLASS_DRUID: + info->stats[STAT_STRENGTH] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0)); + info->stats[STAT_STAMINA] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0)); + info->stats[STAT_AGILITY] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0)); + info->stats[STAT_SPIRIT] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0)); + } + } +} + +void ObjectMgr::LoadGuilds() +{ + Guild *newguild; + uint32 count = 0; + + QueryResult *result = CharacterDatabase.Query( "SELECT guildid FROM guild" ); + + if( !result ) + { + + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u guild definitions", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field *fields = result->Fetch(); + + bar.step(); + ++count; + + newguild = new Guild; + if(!newguild->LoadGuildFromDB(fields[0].GetUInt32())) + { + newguild->Disband(); + delete newguild; + continue; + } + AddGuild(newguild); + + }while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u guild definitions", count ); +} + +void ObjectMgr::LoadArenaTeams() +{ + uint32 count = 0; + + QueryResult *result = CharacterDatabase.Query( "SELECT arenateamid FROM arena_team" ); + + if( !result ) + { + + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u arenateam definitions", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field *fields = result->Fetch(); + + bar.step(); + ++count; + + ArenaTeam *newarenateam = new ArenaTeam; + if(!newarenateam->LoadArenaTeamFromDB(fields[0].GetUInt32())) + { + delete newarenateam; + continue; + } + AddArenaTeam(newarenateam); + }while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u arenateam definitions", count ); +} + +void ObjectMgr::LoadGroups() +{ + // -- loading groups -- + Group *group = NULL; + uint64 leaderGuid = 0; + uint32 count = 0; + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + QueryResult *result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty, leaderGuid FROM groups"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u group definitions", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + bar.step(); + Field *fields = result->Fetch(); + ++count; + leaderGuid = MAKE_NEW_GUID(fields[15].GetUInt32(),0,HIGHGUID_PLAYER); + + group = new Group; + if(!group->LoadGroupFromDB(leaderGuid, result, false)) + { + group->Disband(); + delete group; + continue; + } + AddGroup(group); + }while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u group definitions", count ); + + // -- loading members -- + count = 0; + group = NULL; + leaderGuid = 0; + // 0 1 2 3 + result = CharacterDatabase.PQuery("SELECT memberGuid, assistant, subgroup, leaderGuid FROM group_member ORDER BY leaderGuid"); + if(!result) + { + barGoLink bar( 1 ); + bar.step(); + } + else + { + barGoLink bar( result->GetRowCount() ); + do + { + bar.step(); + Field *fields = result->Fetch(); + count++; + leaderGuid = MAKE_NEW_GUID(fields[3].GetUInt32(), 0, HIGHGUID_PLAYER); + if(!group || group->GetLeaderGUID() != leaderGuid) + { + group = GetGroupByLeader(leaderGuid); + if(!group) + { + sLog.outErrorDb("Incorrect entry in group_member table : no group with leader %d for member %d!", fields[3].GetUInt32(), fields[0].GetUInt32()); + CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32()); + continue; + } + } + + if(!group->LoadMemberFromDB(fields[0].GetUInt32(), fields[2].GetUInt8(), fields[1].GetBool())) + { + sLog.outErrorDb("Incorrect entry in group_member table : member %d cannot be added to player %d's group!", fields[0].GetUInt32(), fields[3].GetUInt32()); + CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32()); + } + }while( result->NextRow() ); + delete result; + } + + // clean groups + // TODO: maybe delete from the DB before loading in this case + for(GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end();) + { + if((*itr)->GetMembersCount() < 2) + { + (*itr)->Disband(); + delete *itr; + mGroupSet.erase(itr++); + } + else + ++itr; + } + + // -- loading instances -- + count = 0; + group = NULL; + leaderGuid = 0; + result = CharacterDatabase.PQuery( + // 0 1 2 3 4 5 + "SELECT leaderGuid, map, instance, permanent, difficulty, resettime, " + // 6 + "(SELECT COUNT(*) FROM character_instance WHERE guid = leaderGuid AND instance = group_instance.instance AND permanent = 1 LIMIT 1) " + "FROM group_instance LEFT JOIN instance ON instance = id ORDER BY leaderGuid" + ); + + if(!result) + { + barGoLink bar( 1 ); + bar.step(); + } + else + { + barGoLink bar( result->GetRowCount() ); + do + { + bar.step(); + Field *fields = result->Fetch(); + count++; + leaderGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + if(!group || group->GetLeaderGUID() != leaderGuid) + { + group = GetGroupByLeader(leaderGuid); + if(!group) + { + sLog.outErrorDb("Incorrect entry in group_instance table : no group with leader %d", fields[0].GetUInt32()); + continue; + } + } + + InstanceSave *save = sInstanceSaveManager.AddInstanceSave(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true); + group->BindToInstance(save, fields[3].GetBool(), true); + }while( result->NextRow() ); + delete result; + } + + sLog.outString(); + sLog.outString( ">> Loaded %u group-instance binds total", count ); + + sLog.outString(); + sLog.outString( ">> Loaded %u group members total", count ); +} + +void ObjectMgr::LoadQuests() +{ + // For reload case + for(QuestMap::const_iterator itr=mQuestTemplates.begin(); itr != mQuestTemplates.end(); ++itr) + delete itr->second; + mQuestTemplates.clear(); + + mExclusiveQuestGroups.clear(); + + // 0 1 2 3 4 5 6 7 + QueryResult *result = WorldDatabase.Query("SELECT entry, ZoneOrSort, SkillOrClass, MinLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue," + // 8 9 10 11 12 13 14 15 + "RepObjectiveFaction, RepObjectiveValue, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime," + // 16 17 18 19 20 21 22 23 24 25 + "QuestFlags, SpecialFlags, CharTitleId, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell," + // 26 27 28 29 30 31 32 33 34 35 + "Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4," + // 36 37 38 39 40 41 42 43 + "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4," + // 44 45 46 47 48 49 50 51 52 53 54 55 + "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4, ReqSourceRef1, ReqSourceRef2, ReqSourceRef3, ReqSourceRef4," + // 56 57 58 59 60 61 62 63 + "ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4," + // 64 65 66 67 + "ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4," + // 68 69 70 71 72 73 + "RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6," + // 74 75 76 77 78 79 + "RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6," + // 80 81 82 83 84 85 86 87 + "RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4," + // 88 89 90 91 92 93 94 95 96 97 + "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5," + // 98 99 100 101 102 103 104 105 106 107 + "RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt," + // 108 109 110 111 112 113 114 115 116 117 + "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4," + // 118 119 + "StartScript, CompleteScript" + " FROM quest_template"); + if(result == NULL) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded 0 quests definitions" ); + sLog.outErrorDb("`quest_template` table is empty!"); + return; + } + + // create multimap previous quest for each existed quest + // some quests can have many previous maps set by NextQuestId in previous quest + // for example set of race quests can lead to single not race specific quest + barGoLink bar( result->GetRowCount() ); + do + { + bar.step(); + Field *fields = result->Fetch(); + + Quest * newQuest = new Quest(fields); + mQuestTemplates[newQuest->GetQuestId()] = newQuest; + } while( result->NextRow() ); + + delete result; + + // Post processing + for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); iter++) + { + Quest * qinfo = iter->second; + + // additional quest integrity checks (GO, creature_template and item_template must be loaded already) + + if (qinfo->QuestFlags & ~QUEST_MANGOS_FLAGS_DB_ALLOWED) + { + sLog.outErrorDb("Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u", + qinfo->GetQuestId(),qinfo->QuestFlags,QUEST_MANGOS_FLAGS_DB_ALLOWED >> 16); + qinfo->QuestFlags &= QUEST_MANGOS_FLAGS_DB_ALLOWED; + } + + if(qinfo->QuestFlags & QUEST_FLAGS_DAILY) + { + if(!(qinfo->QuestFlags & QUEST_MANGOS_FLAGS_REPEATABLE)) + { + sLog.outErrorDb("Daily Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId()); + qinfo->QuestFlags |= QUEST_MANGOS_FLAGS_REPEATABLE; + } + } + + if(qinfo->QuestFlags & QUEST_FLAGS_AUTO_REWARDED) + { + // at auto-reward can be rewarded only RewChoiceItemId[0] + for(int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j ) + { + if(uint32 id = qinfo->RewChoiceItemId[j]) + { + sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item from `RewChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes, quest ignore this data + } + } + } + + // client quest log visual (area case) + if( qinfo->ZoneOrSort > 0 ) + { + if(!GetAreaEntryByAreaID(qinfo->ZoneOrSort)) + { + sLog.outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.", + qinfo->GetQuestId(),qinfo->ZoneOrSort); + // no changes, quest not dependent from this value but can have problems at client + } + } + // client quest log visual (sort case) + if( qinfo->ZoneOrSort < 0 ) + { + QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort)); + if( !qSort ) + { + sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.", + qinfo->GetQuestId(),qinfo->ZoneOrSort); + // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check) + } + //check SkillOrClass value (class case). + if( ClassByQuestSort(-int32(qinfo->ZoneOrSort)) ) + { + // SkillOrClass should not have class case when class case already set in ZoneOrSort. + if(qinfo->SkillOrClass < 0) + { + sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClass` = %i (class case), redundant.", + qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClass); + } + } + //check for proper SkillOrClass value (skill case) + if(int32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort))) + { + // skill is positive value in SkillOrClass + if(qinfo->SkillOrClass != skill_id ) + { + sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClass` does not have a corresponding value (%i).", + qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id); + //override, and force proper value here? + } + } + } + + // SkillOrClass (class case) + if( qinfo->SkillOrClass < 0 ) + { + if( !sChrClassesStore.LookupEntry(-int32(qinfo->SkillOrClass)) ) + { + sLog.outErrorDb("Quest %u has `SkillOrClass` = %i (class case) but class (%i) does not exist", + qinfo->GetQuestId(),qinfo->SkillOrClass,-qinfo->SkillOrClass); + } + } + // SkillOrClass (skill case) + if( qinfo->SkillOrClass > 0 ) + { + if( !sSkillLineStore.LookupEntry(qinfo->SkillOrClass) ) + { + sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist", + qinfo->GetQuestId(),qinfo->SkillOrClass,qinfo->SkillOrClass); + } + } + + if( qinfo->RequiredSkillValue ) + { + if( qinfo->RequiredSkillValue > sWorld.GetConfigMaxSkillValue() ) + { + sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but max possible skill is %u, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue()); + // no changes, quest can't be done for this requirement + } + + if( qinfo->SkillOrClass <= 0 ) + { + sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.", + qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClass); + // no changes, quest can't be done for this requirement (fail at wrong skill id) + } + } + // else Skill quests can have 0 skill level, this is ok + + if(qinfo->RepObjectiveFaction && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction)) + { + sLog.outErrorDb("Quest %u has `RepObjectiveFaction` = %u but faction template %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->RepObjectiveFaction,qinfo->RepObjectiveFaction); + // no changes, quest can't be done for this requirement + } + + if(qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction)) + { + sLog.outErrorDb("Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredMinRepFaction,qinfo->RequiredMinRepFaction); + // no changes, quest can't be done for this requirement + } + + if(qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction)) + { + sLog.outErrorDb("Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredMaxRepFaction,qinfo->RequiredMaxRepFaction); + // no changes, quest can't be done for this requirement + } + + if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > Player::Reputation_Cap) + { + sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredMinRepValue,Player::Reputation_Cap); + // no changes, quest can't be done for this requirement + } + + if(qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue) + { + sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredMaxRepValue,qinfo->RequiredMinRepValue); + // no changes, quest can't be done for this requirement + } + + if(!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0 ) + { + sLog.outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect", + qinfo->GetQuestId(),qinfo->RepObjectiveValue); + // warning + } + + if(!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0 ) + { + sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect", + qinfo->GetQuestId(),qinfo->RequiredMinRepValue); + // warning + } + + if(!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0 ) + { + sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect", + qinfo->GetQuestId(),qinfo->RequiredMaxRepValue); + // warning + } + + if(qinfo->CharTitleId && !sCharTitlesStore.LookupEntry(qinfo->CharTitleId)) + { + sLog.outErrorDb("Quest %u has `CharTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.", + qinfo->GetQuestId(),qinfo->GetCharTitleId(),qinfo->GetCharTitleId()); + qinfo->CharTitleId = 0; + // quest can't reward this title + } + + if(qinfo->SrcItemId) + { + if(!sItemStorage.LookupEntry(qinfo->SrcItemId)) + { + sLog.outErrorDb("Quest %u has `SrcItemId` = %u but item with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->SrcItemId,qinfo->SrcItemId); + qinfo->SrcItemId = 0; // quest can't be done for this requirement + } + else if(qinfo->SrcItemCount==0) + { + sLog.outErrorDb("Quest %u has `SrcItemId` = %u but `SrcItemCount` = 0, set to 1 but need fix in DB.", + qinfo->GetQuestId(),qinfo->SrcItemId); + qinfo->SrcItemCount = 1; // update to 1 for allow quest work for backward comptibility with DB + } + } + else if(qinfo->SrcItemCount>0) + { + sLog.outErrorDb("Quest %u has `SrcItemId` = 0 but `SrcItemCount` = %u, useless value.", + qinfo->GetQuestId(),qinfo->SrcItemCount); + qinfo->SrcItemCount=0; // no quest work changes in fact + } + + if(qinfo->SrcSpell) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->SrcSpell); + if(!spellInfo) + { + sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u doesn't exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell); + qinfo->SrcSpell = 0; // quest can't be done for this requirement + } + else if(!SpellMgr::IsSpellValid(spellInfo)) + { + sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u is broken, quest can't be done.", + qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell); + qinfo->SrcSpell = 0; // quest can't be done for this requirement + } + } + + for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j ) + { + uint32 id = qinfo->ReqItemId[j]; + if(id) + { + if(qinfo->ReqItemCount[j]==0) + { + sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but `ReqItemCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes, quest can't be done for this requirement + } + + qinfo->SetFlag(QUEST_MANGOS_FLAGS_DELIVER); + + if(!sItemStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but item with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,id); + qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest + } + } + else if(qinfo->ReqItemCount[j]>0) + { + sLog.outErrorDb("Quest %u has `ReqItemId%d` = 0 but `ReqItemCount%d` = %u, quest can't be done.", + qinfo->GetQuestId(),j+1,j+1,qinfo->ReqItemCount[j]); + qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest + } + } + + for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j ) + { + uint32 id = qinfo->ReqSourceId[j]; + if(id) + { + if(!sItemStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but item with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,id); + // no changes, quest can't be done for this requirement + } + + if(!qinfo->ReqSourceCount[j]) + { + sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1); + qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest + } + + if(!qinfo->ReqSourceRef[j]) + { + sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1); + qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest + } + } + else + { + if(qinfo->ReqSourceCount[j]>0) + { + sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceCount%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]); + // no changes, quest ignore this data + } + + if(qinfo->ReqSourceRef[j]>0) + { + sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]); + // no changes, quest ignore this data + } + } + } + + for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j ) + { + uint32 ref = qinfo->ReqSourceRef[j]; + if(ref) + { + if(ref > QUEST_OBJECTIVES_COUNT) + { + sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.", + qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT); + // no changes, quest can't be done for this requirement + } + else + if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1]) + { + sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,ref,ref,ref); + // no changes, quest can't be done for this requirement + } + else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1]) + { + sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.", + qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]); + // no changes, quest can't be done for this requirement + qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest + } + } + } + + for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j ) + { + uint32 id = qinfo->ReqSpell[j]; + if(id) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(id); + if(!spellInfo) + { + sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,id); + // no changes, quest can't be done for this requirement + } + + if(!qinfo->ReqCreatureOrGOId[j]) + { + bool found = false; + for(int k = 0; k < 3; ++k) + { + if( spellInfo->Effect[k]==SPELL_EFFECT_QUEST_COMPLETE && uint32(spellInfo->EffectMiscValue[k])==qinfo->QuestId || + spellInfo->Effect[k]==SPELL_EFFECT_SEND_EVENT) + { + found = true; + break; + } + } + + if(found) + { + if(!qinfo->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT)) + { + sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT for quest %u and ReqCreatureOrGOId%d = 0, but quest not have flag QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT. Quest flags or ReqCreatureOrGOId%d must be fixed, quest modified to enable objective.",spellInfo->Id,qinfo->QuestId,j+1,j+1); + + // this will prevent quest completing without objective + const_cast(qinfo)->SetFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT); + } + } + else + { + sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u and ReqCreatureOrGOId%d = 0 but spell %u does not have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT effect for this quest, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1,id); + // no changes, quest can't be done for this requirement + } + } + } + } + + for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j ) + { + int32 id = qinfo->ReqCreatureOrGOId[j]; + if(id < 0 && !sGOStorage.LookupEntry(-id)) + { + sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but gameobject %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,uint32(-id)); + qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement + } + + if(id > 0 && !sCreatureStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but creature with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,uint32(id)); + qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement + } + + if(id) + { + // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast + + qinfo->SetFlag(QUEST_MANGOS_FLAGS_KILL_OR_CAST | QUEST_MANGOS_FLAGS_SPEAKTO); + + if(!qinfo->ReqCreatureOrGOCount[j]) + { + sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %u but `ReqCreatureOrGOCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes, quest can be incorrectly done, but we already report this + } + } + else if(qinfo->ReqCreatureOrGOCount[j]>0) + { + sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = 0 but `ReqCreatureOrGOCount%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->ReqCreatureOrGOCount[j]); + // no changes, quest ignore this data + } + } + + for(int j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j ) + { + uint32 id = qinfo->RewChoiceItemId[j]; + if(id) + { + if(!sItemStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.", + qinfo->GetQuestId(),j+1,id,id); + qinfo->RewChoiceItemId[j] = 0; // no changes, quest will not reward this + } + + if(!qinfo->RewChoiceItemCount[j]) + { + sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but `RewChoiceItemCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes, quest can't be done + } + } + else if(qinfo->RewChoiceItemCount[j]>0) + { + sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = 0 but `RewChoiceItemCount%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->RewChoiceItemCount[j]); + // no changes, quest ignore this data + } + } + + for(int j = 0; j < QUEST_REWARDS_COUNT; ++j ) + { + uint32 id = qinfo->RewItemId[j]; + if(id) + { + if(!sItemStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.", + qinfo->GetQuestId(),j+1,id,id); + qinfo->RewItemId[j] = 0; // no changes, quest will not reward this item + } + + if(!qinfo->RewItemCount[j]) + { + sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but `RewItemCount%d` = 0, quest will not reward this item.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes + } + } + else if(qinfo->RewItemCount[j]>0) + { + sLog.outErrorDb("Quest %u has `RewItemId%d` = 0 but `RewItemCount%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->RewItemCount[j]); + // no changes, quest ignore this data + } + } + + for(int j = 0; j < QUEST_REPUTATIONS_COUNT; ++j) + { + if(qinfo->RewRepFaction[j]) + { + if(!qinfo->RewRepValue[j]) + { + sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but `RewRepValue%d` = 0, quest will not reward this reputation.", + qinfo->GetQuestId(),j+1,qinfo->RewRepValue[j],j+1); + // no changes + } + + if(!sFactionStore.LookupEntry(qinfo->RewRepFaction[j])) + { + sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but raw faction (faction.dbc) %u does not exist, quest will not reward reputation for this faction.", + qinfo->GetQuestId(),j+1,qinfo->RewRepFaction[j] ,qinfo->RewRepFaction[j] ); + qinfo->RewRepFaction[j] = 0; // quest will not reward this + } + } + else if(qinfo->RewRepValue[j]!=0) + { + sLog.outErrorDb("Quest %u has `RewRepFaction%d` = 0 but `RewRepValue%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->RewRepValue[j]); + // no changes, quest ignore this data + } + } + + if(qinfo->RewSpell) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpell); + + if(!spellInfo) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u does not exist, spell removed as display reward.", + qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); + qinfo->RewSpell = 0; // no spell reward will display for this quest + } + + else if(!SpellMgr::IsSpellValid(spellInfo)) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.", + qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); + qinfo->RewSpell = 0; // no spell reward will display for this quest + } + + } + + if(qinfo->RewSpellCast) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpellCast); + + if(!spellInfo) + { + sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); + qinfo->RewSpellCast = 0; // no spell will be casted on player + } + + else if(!SpellMgr::IsSpellValid(spellInfo)) + { + sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.", + qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); + qinfo->RewSpellCast = 0; // no spell will be casted on player + } + + } + + if(qinfo->RewMailTemplateId) + { + if(!sMailTemplateStore.LookupEntry(qinfo->RewMailTemplateId)) + { + sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template %u does not exist, quest will not have a mail reward.", + qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId); + qinfo->RewMailTemplateId = 0; // no mail will send to player + qinfo->RewMailDelaySecs = 0; // no mail will send to player + } + } + + if(qinfo->NextQuestInChain) + { + if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end()) + { + sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.", + qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain ); + qinfo->NextQuestInChain = 0; + } + else + mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId()); + } + + // fill additional data stores + if(qinfo->PrevQuestId) + { + if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end()) + { + sLog.outErrorDb("Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId()); + } + else + { + qinfo->prevQuests.push_back(qinfo->PrevQuestId); + } + } + + if(qinfo->NextQuestId) + { + if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end()) + { + sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId()); + } + else + { + int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId()); + mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId); + } + } + + if(qinfo->ExclusiveGroup) + mExclusiveQuestGroups.insert(std::pair(qinfo->ExclusiveGroup, qinfo->GetQuestId())); + if(qinfo->LimitTime) + qinfo->SetFlag(QUEST_MANGOS_FLAGS_TIMED); + } + + // check QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE + for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(i); + if(!spellInfo) + continue; + + for(int j = 0; j < 3; ++j) + { + if(spellInfo->Effect[j] != SPELL_EFFECT_QUEST_COMPLETE) + continue; + + uint32 quest_id = spellInfo->EffectMiscValue[j]; + + Quest const* quest = GetQuestTemplate(quest_id); + + // some quest referenced in spells not exist (outdataed spells) + if(!quest) + continue; + + if(!quest->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT)) + { + sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE for quest %u , but quest not have flag QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.",spellInfo->Id,quest_id); + + // this will prevent quest completing without objective + const_cast(quest)->SetFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT); + } + } + } + + sLog.outString(); + sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() ); +} + +void ObjectMgr::LoadQuestLocales() +{ + QueryResult *result = WorldDatabase.Query("SELECT entry," + "Title_loc1,Details_loc1,Objectives_loc1,OfferRewardText_loc1,RequestItemsText_loc1,EndText_loc1,ObjectiveText1_loc1,ObjectiveText2_loc1,ObjectiveText3_loc1,ObjectiveText4_loc1," + "Title_loc2,Details_loc2,Objectives_loc2,OfferRewardText_loc2,RequestItemsText_loc2,EndText_loc2,ObjectiveText1_loc2,ObjectiveText2_loc2,ObjectiveText3_loc2,ObjectiveText4_loc2," + "Title_loc3,Details_loc3,Objectives_loc3,OfferRewardText_loc3,RequestItemsText_loc3,EndText_loc3,ObjectiveText1_loc3,ObjectiveText2_loc3,ObjectiveText3_loc3,ObjectiveText4_loc3," + "Title_loc4,Details_loc4,Objectives_loc4,OfferRewardText_loc4,RequestItemsText_loc4,EndText_loc4,ObjectiveText1_loc4,ObjectiveText2_loc4,ObjectiveText3_loc4,ObjectiveText4_loc4," + "Title_loc5,Details_loc5,Objectives_loc5,OfferRewardText_loc5,RequestItemsText_loc5,EndText_loc5,ObjectiveText1_loc5,ObjectiveText2_loc5,ObjectiveText3_loc5,ObjectiveText4_loc5," + "Title_loc6,Details_loc6,Objectives_loc6,OfferRewardText_loc6,RequestItemsText_loc6,EndText_loc6,ObjectiveText1_loc6,ObjectiveText2_loc6,ObjectiveText3_loc6,ObjectiveText4_loc6," + "Title_loc7,Details_loc7,Objectives_loc7,OfferRewardText_loc7,RequestItemsText_loc7,EndText_loc7,ObjectiveText1_loc7,ObjectiveText2_loc7,ObjectiveText3_loc7,ObjectiveText4_loc7," + "Title_loc8,Details_loc8,Objectives_loc8,OfferRewardText_loc8,RequestItemsText_loc8,EndText_loc8,ObjectiveText1_loc8,ObjectiveText2_loc8,ObjectiveText3_loc8,ObjectiveText4_loc8" + " FROM locales_quest" + ); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + QuestLocale& data = mQuestLocaleMap[entry]; + + for(int i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[1+10*(i-1)].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Title.size() <= idx) + data.Title.resize(idx+1); + + data.Title[idx] = str; + } + } + str = fields[1+10*(i-1)+1].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Details.size() <= idx) + data.Details.resize(idx+1); + + data.Details[idx] = str; + } + } + str = fields[1+10*(i-1)+2].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Objectives.size() <= idx) + data.Objectives.resize(idx+1); + + data.Objectives[idx] = str; + } + } + str = fields[1+10*(i-1)+3].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.OfferRewardText.size() <= idx) + data.OfferRewardText.resize(idx+1); + + data.OfferRewardText[idx] = str; + } + } + str = fields[1+10*(i-1)+4].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.RequestItemsText.size() <= idx) + data.RequestItemsText.resize(idx+1); + + data.RequestItemsText[idx] = str; + } + } + str = fields[1+10*(i-1)+5].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.EndText.size() <= idx) + data.EndText.resize(idx+1); + + data.EndText[idx] = str; + } + } + for(int k = 0; k < 4; ++k) + { + str = fields[1+10*(i-1)+6+k].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.ObjectiveText[k].size() <= idx) + data.ObjectiveText[k].resize(idx+1); + + data.ObjectiveText[k][idx] = str; + } + } + } + } + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() ); +} + +void ObjectMgr::LoadPetCreateSpells() +{ + QueryResult *result = WorldDatabase.PQuery("SELECT entry, Spell1, Spell2, Spell3, Spell4 FROM petcreateinfo_spell"); + if(!result) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded 0 pet create spells" ); + sLog.outErrorDb("`petcreateinfo_spell` table is empty!"); + return; + } + + uint32 count = 0; + + barGoLink bar( result->GetRowCount() ); + + mPetCreateSpell.clear(); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 creature_id = fields[0].GetUInt32(); + + if(!creature_id || !sCreatureStorage.LookupEntry(creature_id)) + continue; + + PetCreateSpellEntry PetCreateSpell; + for(int i = 0; i < 4; i++) + { + PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32(); + + if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i])) + sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]); + } + + mPetCreateSpell[creature_id] = PetCreateSpell; + + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u pet create spells", count ); +} + +void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename) +{ + if(sWorld.IsScriptScheduled()) // function don't must be called in time scripts use. + return; + + sLog.outString( "%s :", tablename); + + scripts.clear(); // need for reload support + + QueryResult *result = WorldDatabase.PQuery( "SELECT id,delay,command,datalong,datalong2,datatext, x, y, z, o FROM %s", tablename ); + + uint32 count = 0; + + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u script definitions", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + ScriptInfo tmp; + tmp.id = fields[0].GetUInt32(); + tmp.delay = fields[1].GetUInt32(); + tmp.command = fields[2].GetUInt32(); + tmp.datalong = fields[3].GetUInt32(); + tmp.datalong2 = fields[4].GetUInt32(); + tmp.datatext = fields[5].GetCppString(); + tmp.x = fields[6].GetFloat(); + tmp.y = fields[7].GetFloat(); + tmp.z = fields[8].GetFloat(); + tmp.o = fields[9].GetFloat(); + + // generic command args check + switch(tmp.command) + { + case SCRIPT_COMMAND_TALK: + { + if(tmp.datalong > 3) + { + sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + break; + } + + case SCRIPT_COMMAND_TELEPORT_TO: + { + if(!sMapStore.LookupEntry(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + + if(!MaNGOS::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) + { + sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.x,tmp.y,tmp.id); + continue; + } + break; + } + + case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: + { + if(!MaNGOS::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) + { + sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.x,tmp.y,tmp.id); + continue; + } + + if(!GetCreatureTemplate(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + break; + } + + case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: + { + GameObjectData const* data = GetGOData(tmp.datalong); + if(!data) + { + sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + + GameObjectInfo const* info = GetGameObjectInfo(data->id); + if(!info) + { + sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,data->id,tmp.id); + continue; + } + + if( info->type==GAMEOBJECT_TYPE_FISHINGNODE || + info->type==GAMEOBJECT_TYPE_FISHINGHOLE || + info->type==GAMEOBJECT_TYPE_DOOR || + info->type==GAMEOBJECT_TYPE_BUTTON || + info->type==GAMEOBJECT_TYPE_TRAP ) + { + sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,info->id,tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_OPEN_DOOR: + case SCRIPT_COMMAND_CLOSE_DOOR: + { + GameObjectData const* data = GetGOData(tmp.datalong); + if(!data) + { + sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",tablename,tmp.datalong,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); + continue; + } + + GameObjectInfo const* info = GetGameObjectInfo(data->id); + if(!info) + { + sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",tablename,tmp.datalong,data->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); + continue; + } + + if( info->type!=GAMEOBJECT_TYPE_DOOR) + { + sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",tablename,info->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); + continue; + } + + break; + } + case SCRIPT_COMMAND_QUEST_EXPLORED: + { + Quest const* quest = GetQuestTemplate(tmp.datalong); + if(!quest) + { + sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + + if(!quest->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT)) + { + sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",tablename,tmp.datalong,tmp.id); + + // this will prevent quest completing without objective + const_cast(quest)->SetFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT); + + // continue; - quest objective requiremet set and command can be allowed + } + + if(float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) + { + sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong2,tmp.id); + continue; + } + + if(tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) + { + sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %u or 0 for disable distance check",tablename,tmp.datalong2,tmp.id,uint32(DEFAULT_VISIBILITY_DISTANCE)); + continue; + } + + if(tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE) + { + sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %u or 0 for disable distance check",tablename,tmp.datalong2,tmp.id,uint32(INTERACTION_DISTANCE)); + continue; + } + + break; + } + + case SCRIPT_COMMAND_REMOVE_AURA: + case SCRIPT_COMMAND_CAST_SPELL: + { + if(!sSpellStore.LookupEntry(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + break; + } + } + + if (scripts.find(tmp.id) == scripts.end()) + { + ScriptMap emptyMap; + scripts[tmp.id] = emptyMap; + } + scripts[tmp.id].insert(std::pair(tmp.delay, tmp)); + + ++count; + } while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u script definitions", count ); +} + +void ObjectMgr::LoadGameObjectScripts() +{ + LoadScripts(sGameObjectScripts, "gameobject_scripts"); + + // check ids + for(ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr) + { + if(!GetGOData(itr->first)) + sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id",itr->first); + } +} + +void ObjectMgr::LoadQuestEndScripts() +{ + LoadScripts(sQuestEndScripts, "quest_end_scripts"); + + // check ids + for(ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr) + { + if(!GetQuestTemplate(itr->first)) + sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id",itr->first); + } +} + +void ObjectMgr::LoadQuestStartScripts() +{ + LoadScripts(sQuestStartScripts,"quest_start_scripts"); + + // check ids + for(ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr) + { + if(!GetQuestTemplate(itr->first)) + sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id",itr->first); + } +} + +void ObjectMgr::LoadSpellScripts() +{ + LoadScripts(sSpellScripts, "spell_scripts"); + + // check ids + for(ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); + + if(!spellInfo) + { + sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id",itr->first); + continue; + } + + //check for correct spellEffect + bool found = false; + for(int i=0; i<3; ++i) + { + // skip empty effects + if( !spellInfo->Effect[i] ) + continue; + + if( spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT ) + { + found = true; + break; + } + } + + if(!found) + sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect",itr->first,SPELL_EFFECT_SCRIPT_EFFECT); + } +} + +void ObjectMgr::LoadEventScripts() +{ + LoadScripts(sEventScripts, "event_scripts"); + + std::set evt_scripts; + // Load all possible script entries from gameobjects + for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i) + { + GameObjectInfo const * goInfo = sGOStorage.LookupEntry(i); + if (goInfo) + { + switch(goInfo->type) + { + case GAMEOBJECT_TYPE_GOOBER: + if(goInfo->goober.eventId) + evt_scripts.insert(goInfo->goober.eventId); + break; + case GAMEOBJECT_TYPE_CHEST: + if(goInfo->chest.eventId) + evt_scripts.insert(goInfo->chest.eventId); + break; + default: + break; + } + } + } + // Load all possible script entries from spells + for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) + { + SpellEntry const * spell = sSpellStore.LookupEntry(i); + if (spell) + { + for(int j=0; j<3; ++j) + { + if( spell->Effect[j] == SPELL_EFFECT_SEND_EVENT ) + { + if (spell->EffectMiscValue[j]) + evt_scripts.insert(spell->EffectMiscValue[j]); + } + } + } + } + // Then check if all scripts are in above list of possible script entries + for(ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr) + { + std::set::const_iterator itr2 = evt_scripts.find(itr->first); + if (itr2 == evt_scripts.end()) + sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not refering to any gameobject_template type 10 data2 field or type 3 data6 field or any spell effect %u", itr->first, SPELL_EFFECT_SEND_EVENT); + } +} + +void ObjectMgr::LoadItemTexts() +{ + QueryResult *result = CharacterDatabase.PQuery("SELECT id, text FROM item_text"); + + uint32 count = 0; + + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u item pages", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + Field* fields; + do + { + bar.step(); + + fields = result->Fetch(); + + mItemTexts[ fields[0].GetUInt32() ] = fields[1].GetCppString(); + + ++count; + + } while ( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u item texts", count ); +} + +void ObjectMgr::LoadPageTexts() +{ + sPageTextStore.Free(); // for reload case + + sPageTextStore.Load(); + sLog.outString( ">> Loaded %u page texts", sPageTextStore.RecordCount ); + sLog.outString(); + + for(uint32 i = 1; i < sPageTextStore.MaxEntry; ++i) + { + // check data correctness + PageText const* page = sPageTextStore.LookupEntry(i); + if(!page) + continue; + + if(page->Next_Page && !sPageTextStore.LookupEntry(page->Next_Page)) + { + sLog.outErrorDb("Page text (Id: %u) has not existing next page (Id:%u)", i,page->Next_Page); + continue; + } + + // detect circular reference + std::set checkedPages; + for(PageText const* pageItr = page; pageItr; pageItr = sPageTextStore.LookupEntry(pageItr->Next_Page)) + { + if(!pageItr->Next_Page) + break; + checkedPages.insert(pageItr->Page_ID); + if(checkedPages.find(pageItr->Next_Page)!=checkedPages.end()) + { + std::ostringstream ss; + ss<< "The text page(s) "; + for (std::set::iterator itr= checkedPages.begin();itr!=checkedPages.end(); itr++) + ss << *itr << " "; + ss << "create(s) a circular reference, which can cause the server to freeze. Changing Next_Page of page " + << pageItr->Page_ID <<" to 0"; + sLog.outErrorDb(ss.str().c_str()); + const_cast(pageItr)->Next_Page = 0; + break; + } + } + } +} + +void ObjectMgr::LoadPageTextLocales() +{ + QueryResult *result = WorldDatabase.PQuery("SELECT entry,text_loc1,text_loc2,text_loc3,text_loc4,text_loc5,text_loc6,text_loc7,text_loc8 FROM locales_page_text"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outString(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + PageTextLocale& data = mPageTextLocaleMap[entry]; + + for(int i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[i].GetCppString(); + if(str.empty()) + continue; + + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Text.size() <= idx) + data.Text.resize(idx+1); + + data.Text[idx] = str; + } + } + + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() ); +} + +void ObjectMgr::LoadInstanceTemplate() +{ + sInstanceTemplate.Load(); + + for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) + { + InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i); + if(!temp) continue; + const MapEntry* entry = sMapStore.LookupEntry(temp->map); + if(!entry) + { + sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map); + continue; + } + else if(!entry->HasResetTime()) + continue; + + if(temp->reset_delay == 0) + { + // use defaults from the DBC + if(entry->SupportsHeroicMode()) + { + temp->reset_delay = entry->resetTimeHeroic / DAY; + } + else if (entry->resetTimeRaid && entry->map_type == MAP_RAID) + { + temp->reset_delay = entry->resetTimeRaid / DAY; + } + } + + // the reset_delay must be atleast one day + temp->reset_delay = std::max((uint32)1, (uint32)(temp->reset_delay * sWorld.getRate(RATE_INSTANCE_RESET_TIME))); + } + + sLog.outString( ">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount ); + sLog.outString(); +} + +void ObjectMgr::AddGossipText(GossipText *pGText) +{ + ASSERT( pGText->Text_ID ); + ASSERT( mGossipText.find(pGText->Text_ID) == mGossipText.end() ); + mGossipText[pGText->Text_ID] = pGText; +} + +GossipText *ObjectMgr::GetGossipText(uint32 Text_ID) +{ + GossipTextMap::const_iterator itr; + for (itr = mGossipText.begin(); itr != mGossipText.end(); itr++) + { + if(itr->second->Text_ID == Text_ID) + return itr->second; + } + return NULL; +} + +void ObjectMgr::LoadGossipText() +{ + GossipText *pGText; + QueryResult *result = WorldDatabase.Query( "SELECT * FROM npc_text" ); + + int count = 0; + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u npc texts", count ); + return; + } + + int cic; + + barGoLink bar( result->GetRowCount() ); + + do + { + ++count; + cic = 0; + + Field *fields = result->Fetch(); + + bar.step(); + + pGText = new GossipText; + pGText->Text_ID = fields[cic++].GetUInt32(); + + for (int i=0; i< 8; i++) + { + pGText->Options[i].Text_0 = fields[cic++].GetCppString(); + pGText->Options[i].Text_1 = fields[cic++].GetCppString(); + + pGText->Options[i].Language = fields[cic++].GetUInt32(); + pGText->Options[i].Probability = fields[cic++].GetFloat(); + + pGText->Options[i].Emotes[0]._Delay = fields[cic++].GetUInt32(); + pGText->Options[i].Emotes[0]._Emote = fields[cic++].GetUInt32(); + + pGText->Options[i].Emotes[1]._Delay = fields[cic++].GetUInt32(); + pGText->Options[i].Emotes[1]._Emote = fields[cic++].GetUInt32(); + + pGText->Options[i].Emotes[2]._Delay = fields[cic++].GetUInt32(); + pGText->Options[i].Emotes[2]._Emote = fields[cic++].GetUInt32(); + } + + if ( !pGText->Text_ID ) continue; + AddGossipText( pGText ); + + } while( result->NextRow() ); + + sLog.outString(); + sLog.outString( ">> Loaded %u npc texts", count ); + delete result; +} + +void ObjectMgr::LoadNpcTextLocales() +{ + QueryResult *result = WorldDatabase.Query("SELECT entry," + "Text0_0_loc1,Text0_1_loc1,Text1_0_loc1,Text1_1_loc1,Text2_0_loc1,Text2_1_loc1,Text3_0_loc1,Text3_1_loc1,Text4_0_loc1,Text4_1_loc1,Text5_0_loc1,Text5_1_loc1,Text6_0_loc1,Text6_1_loc1,Text7_0_loc1,Text7_1_loc1," + "Text0_0_loc2,Text0_1_loc2,Text1_0_loc2,Text1_1_loc2,Text2_0_loc2,Text2_1_loc2,Text3_0_loc2,Text3_1_loc1,Text4_0_loc2,Text4_1_loc2,Text5_0_loc2,Text5_1_loc2,Text6_0_loc2,Text6_1_loc2,Text7_0_loc2,Text7_1_loc2," + "Text0_0_loc3,Text0_1_loc3,Text1_0_loc3,Text1_1_loc3,Text2_0_loc3,Text2_1_loc3,Text3_0_loc3,Text3_1_loc1,Text4_0_loc3,Text4_1_loc3,Text5_0_loc3,Text5_1_loc3,Text6_0_loc3,Text6_1_loc3,Text7_0_loc3,Text7_1_loc3," + "Text0_0_loc4,Text0_1_loc4,Text1_0_loc4,Text1_1_loc4,Text2_0_loc4,Text2_1_loc4,Text3_0_loc4,Text3_1_loc1,Text4_0_loc4,Text4_1_loc4,Text5_0_loc4,Text5_1_loc4,Text6_0_loc4,Text6_1_loc4,Text7_0_loc4,Text7_1_loc4," + "Text0_0_loc5,Text0_1_loc5,Text1_0_loc5,Text1_1_loc5,Text2_0_loc5,Text2_1_loc5,Text3_0_loc5,Text3_1_loc1,Text4_0_loc5,Text4_1_loc5,Text5_0_loc5,Text5_1_loc5,Text6_0_loc5,Text6_1_loc5,Text7_0_loc5,Text7_1_loc5," + "Text0_0_loc6,Text0_1_loc6,Text1_0_loc6,Text1_1_loc6,Text2_0_loc6,Text2_1_loc6,Text3_0_loc6,Text3_1_loc1,Text4_0_loc6,Text4_1_loc6,Text5_0_loc6,Text5_1_loc6,Text6_0_loc6,Text6_1_loc6,Text7_0_loc6,Text7_1_loc6," + "Text0_0_loc7,Text0_1_loc7,Text1_0_loc7,Text1_1_loc7,Text2_0_loc7,Text2_1_loc7,Text3_0_loc7,Text3_1_loc1,Text4_0_loc7,Text4_1_loc7,Text5_0_loc7,Text5_1_loc7,Text6_0_loc7,Text6_1_loc7,Text7_0_loc7,Text7_1_loc7, " + "Text0_0_loc8,Text0_1_loc8,Text1_0_loc8,Text1_1_loc8,Text2_0_loc8,Text2_1_loc8,Text3_0_loc8,Text3_1_loc1,Text4_0_loc8,Text4_1_loc8,Text5_0_loc8,Text5_1_loc8,Text6_0_loc8,Text6_1_loc8,Text7_0_loc8,Text7_1_loc8 " + " FROM locales_npc_text"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + NpcTextLocale& data = mNpcTextLocaleMap[entry]; + + for(int i=1; i= 0) + { + if(data.Text_0[j].size() <= idx) + data.Text_0[j].resize(idx+1); + + data.Text_0[j][idx] = str0; + } + } + std::string str1 = fields[1+8*2*(i-1)+2*j+1].GetCppString(); + if(!str1.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Text_1[j].size() <= idx) + data.Text_1[j].resize(idx+1); + + data.Text_1[j][idx] = str1; + } + } + } + } + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() ); +} + +//not very fast function but it is called only once a day, or on starting-up +void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) +{ + time_t basetime = time(NULL); + sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec); + //delete all old mails without item and without body immediately, if starting server + if (!serverUp) + CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" I64FMTD "' AND has_items = '0' AND itemTextId = 0", (uint64)basetime); + // 0 1 2 3 4 5 6 7 8 9 + QueryResult* result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,itemTextId,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" I64FMTD "'", (uint64)basetime); + if ( !result ) + return; // any mails need to be returned or deleted + Field *fields; + //std::ostringstream delitems, delmails; //will be here for optimization + //bool deletemail = false, deleteitem = false; + //delitems << "DELETE FROM item_instance WHERE guid IN ( "; + //delmails << "DELETE FROM mail WHERE id IN ( " + do + { + fields = result->Fetch(); + Mail *m = new Mail; + m->messageID = fields[0].GetUInt32(); + m->messageType = fields[1].GetUInt8(); + m->sender = fields[2].GetUInt32(); + m->receiver = fields[3].GetUInt32(); + m->itemTextId = fields[4].GetUInt32(); + bool has_items = fields[5].GetBool(); + m->expire_time = (time_t)fields[6].GetUInt64(); + m->deliver_time = 0; + m->COD = fields[7].GetUInt32(); + m->checked = fields[8].GetUInt32(); + m->mailTemplateId = fields[9].GetInt16(); + + Player *pl = 0; + if (serverUp) + pl = GetPlayer((uint64)m->receiver); + if (pl && pl->m_mailsLoaded) + { //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail + //his in mailbox and he has already listed his mails ) + delete m; + continue; + } + //delete or return mail: + if (has_items) + { + QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", m->messageID); + if(resultItems) + { + do + { + Field *fields2 = resultItems->Fetch(); + + uint32 item_guid_low = fields2[0].GetUInt32(); + uint32 item_template = fields2[1].GetUInt32(); + + m->AddItem(item_guid_low, item_template); + } + while (resultItems->NextRow()); + + delete resultItems; + } + //if it is mail from AH, it shouldn't be returned, but deleted + if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_AUCTION | MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED))) + { + // mail open and then not returned + for(std::vector::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid); + } + else + { + //mail will be returned: + CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" I64FMTD "', deliver_time = '" I64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID); + delete m; + continue; + } + } + + if (m->itemTextId) + CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId); + + //deletemail = true; + //delmails << m->messageID << ", "; + CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID); + delete m; + } while (result->NextRow()); + delete result; +} + +void ObjectMgr::LoadQuestAreaTriggers() +{ + mQuestAreaTriggerMap.clear(); // need for reload case + + QueryResult *result = WorldDatabase.Query( "SELECT id,quest FROM areatrigger_involvedrelation" ); + + uint32 count = 0; + + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u quest trigger points", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 trigger_ID = fields[0].GetUInt32(); + uint32 quest_ID = fields[1].GetUInt32(); + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID); + if(!atEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",trigger_ID); + continue; + } + + Quest const* quest = GetQuestTemplate(quest_ID); + + if(!quest) + { + sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u",trigger_ID,quest_ID); + continue; + } + + if(!quest->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT)) + { + sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not quest %u, but quest not have flag QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.",trigger_ID,quest_ID); + + // this will prevent quest completing without objective + const_cast(quest)->SetFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT); + + // continue; - quest modified to required obkective and trigger can be allowed. + } + + mQuestAreaTriggerMap[trigger_ID] = quest_ID; + + } while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u quest trigger points", count ); +} + +void ObjectMgr::LoadTavernAreaTriggers() +{ + mTavernAreaTriggerSet.clear(); // need for reload case + + QueryResult *result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern"); + + uint32 count = 0; + + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u tavern triggers", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 Trigger_ID = fields[0].GetUInt32(); + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); + if(!atEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); + continue; + } + + mTavernAreaTriggerSet.insert(Trigger_ID); + } while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u tavern triggers", count ); +} + +void ObjectMgr::LoadAreaTriggerScripts() +{ + mAreaTriggerScripts.clear(); // need for reload case + QueryResult *result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts"); + + uint32 count = 0; + + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u areatrigger scripts", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 Trigger_ID = fields[0].GetUInt32(); + std::string scriptName = fields[1].GetCppString(); + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); + if(!atEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); + continue; + } + mAreaTriggerScripts[Trigger_ID] = scriptName; + } while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u areatrigger scripts", count ); +} +uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid ) +{ + bool found = false; + float dist; + uint32 id = 0; + + for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i) + { + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i); + if(node && node->map_id == mapid) + { + float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z); + if(found) + { + if(dist2 < dist) + { + dist = dist2; + id = i; + } + } + else + { + found = true; + dist = dist2; + id = i; + } + } + } + + return id; +} + +void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost) +{ + TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source); + if(src_i==sTaxiPathSetBySource.end()) + { + path = 0; + cost = 0; + return; + } + + TaxiPathSetForSource& pathSet = src_i->second; + + TaxiPathSetForSource::iterator dest_i = pathSet.find(destination); + if(dest_i==pathSet.end()) + { + path = 0; + cost = 0; + return; + } + + cost = dest_i->second.price; + path = dest_i->second.ID; +} + +uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team ) +{ + uint16 mount_entry = 0; + uint16 mount_id = 0; + + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id); + if(node) + { + if (team == ALLIANCE) + { + mount_entry = node->alliance_mount_type; + CreatureInfo const *ci = GetCreatureTemplate(mount_entry); + if(ci) + mount_id = ci->DisplayID_A; + } + if (team == HORDE) + { + mount_entry = node->horde_mount_type; + CreatureInfo const *ci = GetCreatureTemplate(mount_entry); + if(ci) + mount_id = ci->DisplayID_H; + } + } + + CreatureModelInfo const *minfo = GetCreatureModelInfo(mount_id); + if(!minfo) + { + sLog.outErrorDb("Taxi mount (Entry: %u) for taxi node (Id: %u) for team %u has model %u not found in table `creature_model_info`, can't load. ", + mount_entry,id,team,mount_id); + + return false; + } + if(minfo->modelid_other_gender!=0) + mount_id = urand(0,1) ? mount_id : minfo->modelid_other_gender; + + return mount_id; +} + +void ObjectMgr::GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector& mapIds) +{ + if(path >= sTaxiPathNodesByPath.size()) + return; + + TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path]; + + pathnodes.Resize(nodeList.size()); + mapIds.resize(nodeList.size()); + + for(size_t i = 0; i < nodeList.size(); ++i) + { + pathnodes[ i ].x = nodeList[i].x; + pathnodes[ i ].y = nodeList[i].y; + pathnodes[ i ].z = nodeList[i].z; + + mapIds[i] = nodeList[i].mapid; + } +} + +void ObjectMgr::GetTransportPathNodes( uint32 path, TransportPath &pathnodes ) +{ + if(path >= sTaxiPathNodesByPath.size()) + return; + + TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path]; + + pathnodes.Resize(nodeList.size()); + + for(size_t i = 0; i < nodeList.size(); ++i) + { + pathnodes[ i ].mapid = nodeList[i].mapid; + pathnodes[ i ].x = nodeList[i].x; + pathnodes[ i ].y = nodeList[i].y; + pathnodes[ i ].z = nodeList[i].z; + pathnodes[ i ].actionFlag = nodeList[i].actionFlag; + pathnodes[ i ].delay = nodeList[i].delay; + } +} + +void ObjectMgr::LoadGraveyardZones() +{ + mGraveYardMap.clear(); // need for reload case + + QueryResult *result = WorldDatabase.Query("SELECT id,ghost_zone,faction FROM game_graveyard_zone"); + + uint32 count = 0; + + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u graveyard-zone links", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 safeLocId = fields[0].GetUInt32(); + uint32 zoneId = fields[1].GetUInt32(); + uint32 team = fields[2].GetUInt32(); + + WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId); + if(!entry) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",safeLocId); + continue; + } + + AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId); + if(!areaEntry) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing zone id (%u), skipped.",zoneId); + continue; + } + + if(areaEntry->zone != 0) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record subzone id (%u) instead of zone, skipped.",zoneId); + continue; + } + + if(team!=0 && team!=HORDE && team!=ALLIANCE) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for non player faction (%u), skipped.",team); + continue; + } + + if(entry->map_id != areaEntry->mapid && team != 0) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for ghost zone (%u) at map %u and graveyard (%u) at map %u for team %u, but in case maps are different, player faction setting is ignored. Use faction 0 instead.",zoneId,areaEntry->mapid, safeLocId, entry->map_id, team); + team = 0; + } + + if(!AddGraveYardLink(safeLocId,zoneId,team,false)) + sLog.outErrorDb("Table `game_graveyard_zone` has a duplicate record for Garveyard (ID: %u) and Zone (ID: %u), skipped.",safeLocId,zoneId); + } while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u graveyard-zone links", count ); +} + +WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team) +{ + // search for zone associated closest graveyard + uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y); + + // Simulate std. algorithm: + // found some graveyard associated to (ghost_zone,ghost_map) + // + // if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map + // then check faction + // if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated + // then skip check faction + GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId); + GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId); + if(graveLow==graveUp) + { + sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team); + return NULL; + } + + bool foundNear = false; + float distNear; + WorldSafeLocsEntry const* entryNear = NULL; + WorldSafeLocsEntry const* entryFar = NULL; + + for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr) + { + GraveYardData const& data = itr->second; + + WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId); + if(!entry) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",data.safeLocId); + continue; + } + + // remember first graveyard at another map and ignore other + if(MapId != entry->map_id) + { + if(!entryFar) + entryFar = entry; + continue; + } + + // skip enemy faction graveyard at same map (normal area, city, or battleground) + // team == 0 case can be at call from .neargrave + if(data.team != 0 && team != 0 && data.team != team) + continue; + + // find now nearest graveyard at same map + float dist2 = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y)+(entry->z - z)*(entry->z - z); + if(foundNear) + { + if(dist2 < distNear) + { + distNear = dist2; + entryNear = entry; + } + } + else + { + foundNear = true; + distNear = dist2; + entryNear = entry; + } + } + + if(entryNear) + return entryNear; + + return entryFar; +} + +GraveYardData const* ObjectMgr::FindGraveYardData(uint32 id, uint32 zoneId) +{ + GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId); + GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId); + + for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr) + { + if(itr->second.safeLocId==id) + return &itr->second; + } + + return NULL; +} + +bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB) +{ + if(FindGraveYardData(id,zoneId)) + return false; + + // add link to loaded data + GraveYardData data; + data.safeLocId = id; + data.team = team; + + mGraveYardMap.insert(GraveYardMap::value_type(zoneId,data)); + + // add link to DB + if(inDB) + { + WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone ( id,ghost_zone,faction) " + "VALUES ('%u', '%u','%u')",id,zoneId,team); + } + + return true; +} + +void ObjectMgr::LoadAreaTriggerTeleports() +{ + mAreaTriggers.clear(); // need for reload case + + uint32 count = 0; + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + QueryResult *result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport"); + if( !result ) + { + + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u area trigger teleport definitions", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field *fields = result->Fetch(); + + bar.step(); + + ++count; + + uint32 Trigger_ID = fields[0].GetUInt32(); + + AreaTrigger at; + + at.requiredLevel = fields[1].GetUInt8(); + at.requiredItem = fields[2].GetUInt32(); + at.requiredItem2 = fields[3].GetUInt32(); + at.heroicKey = fields[4].GetUInt32(); + at.heroicKey2 = fields[5].GetUInt32(); + at.requiredQuest = fields[6].GetUInt32(); + at.requiredFailedText = fields[7].GetCppString(); + at.target_mapId = fields[8].GetUInt32(); + at.target_X = fields[9].GetFloat(); + at.target_Y = fields[10].GetFloat(); + at.target_Z = fields[11].GetFloat(); + at.target_Orientation = fields[12].GetFloat(); + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); + if(!atEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); + continue; + } + + if(at.requiredItem) + { + ItemPrototype const *pProto = GetItemPrototype(at.requiredItem); + if(!pProto) + { + sLog.outError("Key item %u does not exist for trigger %u, removing key requirement.", at.requiredItem, Trigger_ID); + at.requiredItem = 0; + } + } + if(at.requiredItem2) + { + ItemPrototype const *pProto = GetItemPrototype(at.requiredItem2); + if(!pProto) + { + sLog.outError("Second item %u not exist for trigger %u, remove key requirement.", at.requiredItem2, Trigger_ID); + at.requiredItem2 = 0; + } + } + + if(at.heroicKey) + { + ItemPrototype const *pProto = GetItemPrototype(at.heroicKey); + if(!pProto) + { + sLog.outError("Heroic key item %u not exist for trigger %u, remove key requirement.", at.heroicKey, Trigger_ID); + at.heroicKey = 0; + } + } + + if(at.heroicKey2) + { + ItemPrototype const *pProto = GetItemPrototype(at.heroicKey2); + if(!pProto) + { + sLog.outError("Heroic second key item %u not exist for trigger %u, remove key requirement.", at.heroicKey2, Trigger_ID); + at.heroicKey2 = 0; + } + } + + if(at.requiredQuest) + { + if(!mQuestTemplates[at.requiredQuest]) + { + sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",at.requiredQuest,Trigger_ID); + at.requiredQuest = 0; + } + } + + MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId); + if(!mapEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Trigger_ID,at.target_mapId); + continue; + } + + if(at.target_X==0 && at.target_Y==0 && at.target_Z==0) + { + sLog.outErrorDb("Area trigger (ID:%u) target coordinates not provided.",Trigger_ID); + continue; + } + + mAreaTriggers[Trigger_ID] = at; + + } while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u area trigger teleport definitions", count ); +} + +AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const +{ + const MapEntry *mapEntry = sMapStore.LookupEntry(Map); + if(!mapEntry) return NULL; + for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); itr++) + { + if(itr->second.target_mapId == mapEntry->parent_map) + { + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first); + if(atEntry && atEntry->mapid == Map) + return &itr->second; + } + } + return NULL; +} + +void ObjectMgr::SetHighestGuids() +{ + QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" ); + if( result ) + { + m_hiCharGuid = (*result)[0].GetUInt32()+1; + + delete result; + } + + result = WorldDatabase.Query( "SELECT MAX(guid) FROM creature" ); + if( result ) + { + m_hiCreatureGuid = (*result)[0].GetUInt32()+1; + + delete result; + } + + result = CharacterDatabase.Query( "SELECT MAX(id) FROM character_pet" ); + if( result ) + { + m_hiPetGuid = (*result)[0].GetUInt32()+1; + + delete result; + } + + result = CharacterDatabase.Query( "SELECT MAX(guid) FROM item_instance" ); + if( result ) + { + m_hiItemGuid = (*result)[0].GetUInt32()+1; + + delete result; + } + + // Cleanup other tables from not existed guids (>=m_hiItemGuid) + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", m_hiItemGuid); + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_hiItemGuid); + CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", m_hiItemGuid); + CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_hiItemGuid); + + result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" ); + if( result ) + { + m_hiGoGuid = (*result)[0].GetUInt32()+1; + + delete result; + } + + result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse" ); + if( result ) + { + m_auctionid = (*result)[0].GetUInt32()+1; + + delete result; + } + else + { + m_auctionid = 0; + } + result = CharacterDatabase.Query( "SELECT MAX(id) FROM mail" ); + if( result ) + { + m_mailid = (*result)[0].GetUInt32()+1; + + delete result; + } + else + { + m_mailid = 0; + } + result = CharacterDatabase.Query( "SELECT MAX(id) FROM item_text" ); + if( result ) + { + m_ItemTextId = (*result)[0].GetUInt32(); + + delete result; + } + else + m_ItemTextId = 0; + + result = CharacterDatabase.Query( "SELECT MAX(guid) FROM corpse" ); + if( result ) + { + m_hiCorpseGuid = (*result)[0].GetUInt32()+1; + + delete result; + } +} + +uint32 ObjectMgr::GenerateAuctionID() +{ + ++m_auctionid; + if(m_auctionid>=0xFFFFFFFF) + { + sLog.outError("Auctions ids overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_auctionid; +} + +uint32 ObjectMgr::GenerateMailID() +{ + ++m_mailid; + if(m_mailid>=0xFFFFFFFF) + { + sLog.outError("Mail ids overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_mailid; +} + +uint32 ObjectMgr::GenerateItemTextID() +{ + ++m_ItemTextId; + if(m_ItemTextId>=0xFFFFFFFF) + { + sLog.outError("Item text ids overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_ItemTextId; +} + +uint32 ObjectMgr::CreateItemText(std::string text) +{ + uint32 newItemTextId = GenerateItemTextID(); + //insert new itempage to container + mItemTexts[ newItemTextId ] = text; + //save new itempage + CharacterDatabase.escape_string(text); + //any Delete query needed, itemTextId is maximum of all ids + std::ostringstream query; + query << "INSERT INTO item_text (id,text) VALUES ( '" << newItemTextId << "', '" << text << "')"; + CharacterDatabase.Execute(query.str().c_str()); //needs to be run this way, because mail body may be more than 1024 characters + return newItemTextId; +} + +uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh) +{ + switch(guidhigh) + { + case HIGHGUID_ITEM: + ++m_hiItemGuid; + if(m_hiItemGuid>=0xFFFFFFFF) + { + sLog.outError("Item guid overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_hiItemGuid; + case HIGHGUID_UNIT: + ++m_hiCreatureGuid; + if(m_hiCreatureGuid>=0x00FFFFFF) + { + sLog.outError("Creature guid overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_hiCreatureGuid; + case HIGHGUID_PET: + ++m_hiPetGuid; + if(m_hiPetGuid>=0x00FFFFFF) + { + sLog.outError("Pet guid overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_hiPetGuid; + case HIGHGUID_PLAYER: + ++m_hiCharGuid; + if(m_hiCharGuid>=0xFFFFFFFF) + { + sLog.outError("Players guid overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_hiCharGuid; + case HIGHGUID_GAMEOBJECT: + ++m_hiGoGuid; + if(m_hiGoGuid>=0x00FFFFFF) + { + sLog.outError("Gameobject guid overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_hiGoGuid; + case HIGHGUID_CORPSE: + ++m_hiCorpseGuid; + if(m_hiCorpseGuid>=0xFFFFFFFF) + { + sLog.outError("Corpse guid overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_hiCorpseGuid; + case HIGHGUID_DYNAMICOBJECT: + ++m_hiDoGuid; + if(m_hiDoGuid>=0xFFFFFFFF) + { + sLog.outError("DynamicObject guid overflow!! Can't continue, shuting down server. "); + sWorld.m_stopEvent = true; + } + return m_hiDoGuid; + default: + ASSERT(0); + } + + ASSERT(0); + return 0; +} + +void ObjectMgr::LoadGameObjectLocales() +{ + QueryResult *result = WorldDatabase.Query("SELECT entry," + "name_loc1,name_loc2,name_loc3,name_loc4,name_loc5,name_loc6,name_loc7,name_loc8," + "castbarcaption_loc1,castbarcaption_loc2,castbarcaption_loc3,castbarcaption_loc4," + "castbarcaption_loc5,castbarcaption_loc6,castbarcaption_loc7,castbarcaption_loc8 FROM locales_gameobject"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outString(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + GameObjectLocale& data = mGameObjectLocaleMap[entry]; + + for(int i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[i].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.Name.size() <= idx) + data.Name.resize(idx+1); + + data.Name[idx] = str; + } + } + } + + for(int i = MAX_LOCALE; i < MAX_LOCALE*2-1; ++i) + { + std::string str = fields[i].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + if(data.CastBarCaption.size() <= idx) + data.CastBarCaption.resize(idx+1); + + data.CastBarCaption[idx] = str; + } + } + } + + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() ); +} + +void ObjectMgr::LoadGameobjectInfo() +{ + sGOStorage.Load(); + + // some checks + for(uint32 id = 1; id < sGOStorage.MaxEntry; id++) + { + GameObjectInfo const* goInfo = sGOStorage.LookupEntry(id); + if(!goInfo) + continue; + + switch(goInfo->type) + { + case GAMEOBJECT_TYPE_DOOR: //0 + { + if(goInfo->door.lockId) + { + if(!sLockStore.LookupEntry(goInfo->door.lockId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.", + id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId); + } + break; + } + case GAMEOBJECT_TYPE_BUTTON: //1 + { + if(goInfo->button.lockId) + { + if(!sLockStore.LookupEntry(goInfo->button.lockId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.", + id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId); + } + break; + } + case GAMEOBJECT_TYPE_CHEST: //3 + { + if(goInfo->chest.lockId) + { + if(!sLockStore.LookupEntry(goInfo->chest.lockId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.", + id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId); + } + if(goInfo->chest.linkedTrapId) // linked trap + { + if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry(goInfo->chest.linkedTrapId)) + { + if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", + id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP); + } + /* disable check for while + else + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.", + id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId); + */ + } + break; + } + case GAMEOBJECT_TYPE_TRAP: //6 + { + /* disable check for while + if(goInfo->trap.spellId) // spell + { + if(!sSpellStore.LookupEntry(goInfo->trap.spellId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.", + id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId); + } + */ + break; + } + case GAMEOBJECT_TYPE_CHAIR: //7 + if(goInfo->chair.height > 2) + { + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..2.", + id,goInfo->type,goInfo->chair.height); + + // prevent client and server unexpected work + const_cast(goInfo)->chair.height = 0; + } + break; + case GAMEOBJECT_TYPE_SPELL_FOCUS: //8 + { + if(goInfo->spellFocus.focusId) + { + if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.", + id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId); + } + + if(goInfo->spellFocus.linkedTrapId) // linked trap + { + if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry(goInfo->spellFocus.linkedTrapId)) + { + if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", + id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP); + } + /* disable check for while + else + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.", + id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId); + */ + } + break; + } + case GAMEOBJECT_TYPE_GOOBER: //10 + { + if(goInfo->goober.pageId) // pageId + { + if(!sPageTextStore.LookupEntry(goInfo->goober.pageId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.", + id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId); + } + /* disable check for while + if(goInfo->goober.spellId) // spell + { + if(!sSpellStore.LookupEntry(goInfo->goober.spellId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.", + id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId); + } + */ + if(goInfo->goober.linkedTrapId) // linked trap + { + if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry(goInfo->goober.linkedTrapId)) + { + if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", + id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP); + } + /* disable check for while + else + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.", + id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId); + */ + } + break; + } + case GAMEOBJECT_TYPE_MO_TRANSPORT: //15 + { + if(goInfo->moTransport.taxiPathId) + { + if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty()) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.", + id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId); + } + break; + } + case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18 + { + /* disabled + if(goInfo->summoningRitual.spellId) + { + if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.", + id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId); + } + */ + break; + } + case GAMEOBJECT_TYPE_SPELLCASTER: //22 + { + if(goInfo->spellcaster.spellId) // spell + { + if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.", + id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId); + } + break; + } + } + } + + sLog.outString( ">> Loaded %u game object templates", sGOStorage.RecordCount ); + sLog.outString(); +} + +void ObjectMgr::LoadExplorationBaseXP() +{ + uint32 count = 0; + QueryResult *result = WorldDatabase.Query("SELECT level,basexp FROM exploration_basexp"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u BaseXP definitions", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + uint32 level = fields[0].GetUInt32(); + uint32 basexp = fields[1].GetUInt32(); + mBaseXPTable[level] = basexp; + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u BaseXP definitions", count ); +} + +uint32 ObjectMgr::GetBaseXP(uint32 level) +{ + return mBaseXPTable[level] ? mBaseXPTable[level] : 0; +} + +void ObjectMgr::LoadPetNames() +{ + uint32 count = 0; + QueryResult *result = WorldDatabase.Query("SELECT word,entry,half FROM pet_name_generation"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u pet name parts", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + std::string word = fields[0].GetString(); + uint32 entry = fields[1].GetUInt32(); + bool half = fields[2].GetBool(); + if(half) + PetHalfName1[entry].push_back(word); + else + PetHalfName0[entry].push_back(word); + ++count; + } + while (result->NextRow()); + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u pet name parts", count ); +} + +void ObjectMgr::LoadPetNumber() +{ + QueryResult* result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet"); + if(result) + { + Field *fields = result->Fetch(); + m_hiPetNumber = fields[0].GetUInt32()+1; + delete result; + } + + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded the max pet number: %d", m_hiPetNumber-1); +} + +std::string ObjectMgr::GeneratePetName(uint32 entry) +{ + std::vector & list0 = PetHalfName0[entry]; + std::vector & list1 = PetHalfName1[entry]; + + if(list0.empty() || list1.empty()) + { + CreatureInfo const *cinfo = GetCreatureTemplate(entry); + char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale()); + if(!petname) + petname = cinfo->Name; + return std::string(petname); + } + + return *(list0.begin()+urand(0, list0.size()-1)) + *(list1.begin()+urand(0, list1.size()-1)); +} + +uint32 ObjectMgr::GeneratePetNumber() +{ + return ++m_hiPetNumber; +} + +void ObjectMgr::LoadCorpses() +{ + uint32 count = 0; + // 0 1 2 3 4 5 6 7 8 10 + QueryResult *result = CharacterDatabase.PQuery("SELECT position_x, position_y, position_z, orientation, map, data, time, corpse_type, instance, guid FROM corpse WHERE corpse_type <> 0"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u corpses", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + + uint32 guid = fields[result->GetFieldCount()-1].GetUInt32(); + + Corpse *corpse = new Corpse; + if(!corpse->LoadFromDB(guid,fields)) + { + delete corpse; + continue; + } + + ObjectAccessor::Instance().AddCorpse(corpse); + + ++count; + } + while (result->NextRow()); + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u corpses", count ); +} + +void ObjectMgr::LoadReputationOnKill() +{ + uint32 count = 0; + + // 0 1 2 + QueryResult *result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2," + // 3 4 5 6 7 8 9 + "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent " + "FROM creature_onkill_reputation"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 creature_id = fields[0].GetUInt32(); + + ReputationOnKillEntry repOnKill; + repOnKill.repfaction1 = fields[1].GetUInt32(); + repOnKill.repfaction2 = fields[2].GetUInt32(); + repOnKill.is_teamaward1 = fields[3].GetBool(); + repOnKill.reputation_max_cap1 = fields[4].GetUInt32(); + repOnKill.repvalue1 = fields[5].GetInt32(); + repOnKill.is_teamaward2 = fields[6].GetBool(); + repOnKill.reputation_max_cap2 = fields[7].GetUInt32(); + repOnKill.repvalue2 = fields[8].GetInt32(); + repOnKill.team_dependent = fields[9].GetUInt8(); + + if(!GetCreatureTemplate(creature_id)) + { + sLog.outErrorDb("Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped",creature_id); + continue; + } + + if(repOnKill.repfaction1) + { + FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repOnKill.repfaction1); + if(!factionEntry1) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction1); + continue; + } + } + + if(repOnKill.repfaction2) + { + FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repOnKill.repfaction2); + if(!factionEntry2) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction2); + continue; + } + } + + mRepOnKill[creature_id] = repOnKill; + + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u creature award reputation definitions", count); +} + +void ObjectMgr::LoadWeatherZoneChances() +{ + uint32 count = 0; + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + QueryResult *result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 zone_id = fields[0].GetUInt32(); + + WeatherZoneChances& wzc = mWeatherZoneMap[zone_id]; + + for(int season = 0; season < WEATHER_SEASONS; ++season) + { + wzc.data[season].rainChance = fields[season * (MAX_WEATHER_TYPE-1) + 1].GetUInt32(); + wzc.data[season].snowChance = fields[season * (MAX_WEATHER_TYPE-1) + 2].GetUInt32(); + wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE-1) + 3].GetUInt32(); + + if(wzc.data[season].rainChance > 100) + { + wzc.data[season].rainChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%",zone_id,season); + } + + if(wzc.data[season].snowChance > 100) + { + wzc.data[season].snowChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%",zone_id,season); + } + + if(wzc.data[season].stormChance > 100) + { + wzc.data[season].stormChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%",zone_id,season); + } + } + + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u weather definitions", count); +} + +void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t) +{ + mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t; + WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); + if(t) + WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance); +} + +void ObjectMgr::DeleteCreatureData(uint32 guid) +{ + // remove mapid*cellid -> guid_set map + CreatureData const* data = GetCreatureData(guid); + if(data) + RemoveCreatureFromGrid(guid, data); + + mCreatureDataMap.erase(guid); +} + +void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t) +{ + mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t; + WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); + if(t) + WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance); +} + +void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance) +{ + RespawnTimes::iterator next; + + for(RespawnTimes::iterator itr = mGORespawnTimes.begin(); itr != mGORespawnTimes.end(); itr = next) + { + next = itr; + ++next; + + if(GUID_HIPART(itr->first)==instance) + mGORespawnTimes.erase(itr); + } + + for(RespawnTimes::iterator itr = mCreatureRespawnTimes.begin(); itr != mCreatureRespawnTimes.end(); itr = next) + { + next = itr; + ++next; + + if(GUID_HIPART(itr->first)==instance) + mCreatureRespawnTimes.erase(itr); + } + + WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", instance); + WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", instance); +} + +void ObjectMgr::DeleteGOData(uint32 guid) +{ + // remove mapid*cellid -> guid_set map + GameObjectData const* data = GetGOData(guid); + if(data) + RemoveGameobjectFromGrid(guid, data); + + mGameObjectDataMap.erase(guid); +} + +void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance) +{ + // corpses are always added to spawn mode 0 and they are spawned by their instance id + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid]; + cell_guids.corpses[player_guid] = instance; +} + +void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid) +{ + // corpses are always added to spawn mode 0 and they are spawned by their instance id + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid]; + cell_guids.corpses.erase(player_guid); +} + +void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map,char const* table) +{ + map.clear(); // need for reload case + + uint32 count = 0; + + QueryResult *result = WorldDatabase.PQuery("SELECT id,quest FROM %s",table); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 quest relations from %s. DB table `%s` is empty.",table,table); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 id = fields[0].GetUInt32(); + uint32 quest = fields[1].GetUInt32(); + + if(mQuestTemplates.find(quest) == mQuestTemplates.end()) + { + sLog.outErrorDb("Table `%s: Quest %u listed for entry %u does not exist.",table,quest,id); + continue; + } + + map.insert(QuestRelations::value_type(id,quest)); + + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u quest relations from %s", count,table); +} + +void ObjectMgr::LoadGameobjectQuestRelations() +{ + LoadQuestRelationsHelper(mGOQuestRelations,"gameobject_questrelation"); + + for(QuestRelations::iterator itr = mGOQuestRelations.begin(); itr != mGOQuestRelations.end(); ++itr) + { + GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first); + if(!goInfo) + sLog.outErrorDb("Table `gameobject_questrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second); + else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER) + sLog.outErrorDb("Table `gameobject_questrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second); + } +} + +void ObjectMgr::LoadGameobjectInvolvedRelations() +{ + LoadQuestRelationsHelper(mGOQuestInvolvedRelations,"gameobject_involvedrelation"); + + for(QuestRelations::iterator itr = mGOQuestInvolvedRelations.begin(); itr != mGOQuestInvolvedRelations.end(); ++itr) + { + GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first); + if(!goInfo) + sLog.outErrorDb("Table `gameobject_involvedrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second); + else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER) + sLog.outErrorDb("Table `gameobject_involvedrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second); + } +} + +void ObjectMgr::LoadCreatureQuestRelations() +{ + LoadQuestRelationsHelper(mCreatureQuestRelations,"creature_questrelation"); + + for(QuestRelations::iterator itr = mCreatureQuestRelations.begin(); itr != mCreatureQuestRelations.end(); ++itr) + { + CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); + if(!cInfo) + sLog.outErrorDb("Table `creature_questrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second); + else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) + sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second); + } +} + +void ObjectMgr::LoadCreatureInvolvedRelations() +{ + LoadQuestRelationsHelper(mCreatureQuestInvolvedRelations,"creature_involvedrelation"); + + for(QuestRelations::iterator itr = mCreatureQuestInvolvedRelations.begin(); itr != mCreatureQuestInvolvedRelations.end(); ++itr) + { + CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); + if(!cInfo) + sLog.outErrorDb("Table `creature_involvedrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second); + else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) + sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second); + } +} + +void ObjectMgr::LoadReservedPlayersNames() +{ + m_ReservedNames.clear(); // need for reload case + + QueryResult *result = WorldDatabase.PQuery("SELECT name FROM reserved_name"); + + uint32 count = 0; + + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u reserved player names", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + Field* fields; + do + { + bar.step(); + fields = result->Fetch(); + std::string name= fields[0].GetCppString(); + if(normalizePlayerName(name)) + { + m_ReservedNames.insert(name); + ++count; + } + } while ( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u reserved player names", count ); +} + +enum LanguageType +{ + LT_BASIC_LATIN = 0x0000, + LT_EXTENDEN_LATIN = 0x0001, + LT_CYRILLIC = 0x0002, + LT_EAST_ASIA = 0x0004, + LT_ANY = 0xFFFF +}; + +static LanguageType GetRealmLanguageType(bool create) +{ + switch(sWorld.getConfig(CONFIG_REALM_ZONE)) + { + case REALM_ZONE_UNKNOWN: // any language + case REALM_ZONE_DEVELOPMENT: + case REALM_ZONE_TEST_SERVER: + case REALM_ZONE_QA_SERVER: + return LT_ANY; + case REALM_ZONE_UNITED_STATES: // extended-Latin + case REALM_ZONE_OCEANIC: + case REALM_ZONE_LATIN_AMERICA: + case REALM_ZONE_ENGLISH: + case REALM_ZONE_GERMAN: + case REALM_ZONE_FRENCH: + case REALM_ZONE_SPANISH: + return LT_EXTENDEN_LATIN; + case REALM_ZONE_KOREA: // East-Asian + case REALM_ZONE_TAIWAN: + case REALM_ZONE_CHINA: + return LT_EAST_ASIA; + case REALM_ZONE_RUSSIAN: // Cyrillic + return LT_CYRILLIC; + default: + return create ? LT_BASIC_LATIN : LT_ANY; // basic-Latin at create, any at login + } +} + +bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bool create = false) +{ + if(strictMask==0) // any language, ignore realm + { + if(isExtendedLatinString(wstr,numericOrSpace)) + return true; + if(isCyrillicString(wstr,numericOrSpace)) + return true; + if(isEastAsianString(wstr,numericOrSpace)) + return true; + return false; + } + + if(strictMask & 0x2) // realm zone specific + { + LanguageType lt = GetRealmLanguageType(create); + if(lt & LT_EXTENDEN_LATIN) + if(isExtendedLatinString(wstr,numericOrSpace)) + return true; + if(lt & LT_CYRILLIC) + if(isCyrillicString(wstr,numericOrSpace)) + return true; + if(lt & LT_EAST_ASIA) + if(isEastAsianString(wstr,numericOrSpace)) + return true; + } + + if(strictMask & 0x1) // basic latin + { + if(isBasicLatinString(wstr,numericOrSpace)) + return true; + } + + return false; +} + +bool ObjectMgr::IsValidName( std::string name, bool create ) +{ + std::wstring wname; + if(!Utf8toWStr(name,wname)) + return false; + + if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME) + return false; + + uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES); + + return isValidString(wname,strictMask,false,create); +} + +bool ObjectMgr::IsValidCharterName( std::string name ) +{ + std::wstring wname; + if(!Utf8toWStr(name,wname)) + return false; + + if(wname.size() < 1) + return false; + + uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES); + + return isValidString(wname,strictMask,true); +} + +bool ObjectMgr::IsValidPetName( std::string name ) +{ + std::wstring wname; + if(!Utf8toWStr(name,wname)) + return false; + + if(wname.size() < 1) + return false; + + uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES); + + return isValidString(wname,strictMask,false); +} + +int ObjectMgr::GetIndexForLocale( LocaleConstant loc ) +{ + if(loc==LOCALE_enUS) + return -1; + + for(size_t i=0;i < m_LocalForIndex.size(); ++i) + if(m_LocalForIndex[i]==loc) + return i; + + return -1; +} + +LocaleConstant ObjectMgr::GetLocaleForIndex(int i) +{ + if (i<0 || i>=m_LocalForIndex.size()) + return LOCALE_enUS; + + return m_LocalForIndex[i]; +} + +int ObjectMgr::GetOrNewIndexForLocale( LocaleConstant loc ) +{ + if(loc==LOCALE_enUS) + return -1; + + for(size_t i=0;i < m_LocalForIndex.size(); ++i) + if(m_LocalForIndex[i]==loc) + return i; + + m_LocalForIndex.push_back(loc); + return m_LocalForIndex.size()-1; +} + +void ObjectMgr::LoadBattleMastersEntry() +{ + mBattleMastersMap.clear(); // need for reload case + + QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" ); + + uint32 count = 0; + + if( !result ) + { + barGoLink bar( 1 ); + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 entry = fields[0].GetUInt32(); + uint32 bgTypeId = fields[1].GetUInt32(); + + mBattleMastersMap[entry] = bgTypeId; + + } while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u battlemaster entries", count ); +} + +void ObjectMgr::LoadGameObjectForQuests() +{ + mGameObjectForQuestSet.clear(); // need for reload case + + uint32 count = 0; + + // collect GO entries for GO that must activated + for(uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry) + { + GameObjectInfo const* goInfo = sGOStorage.LookupEntry(go_entry); + if(!goInfo) + continue; + + switch(goInfo->type) + { + // scan GO chest with loot including quest items + case GAMEOBJECT_TYPE_CHEST: + { + uint32 loot_id = GameObject::GetLootId(goInfo); + + // find quest loot for GO + if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id)) + { + mGameObjectForQuestSet.insert(go_entry); + ++count; + } + break; + } + case GAMEOBJECT_TYPE_GOOBER: + { + if(goInfo->goober.questId) //quests objects + { + mGameObjectForQuestSet.insert(go_entry); + count++; + } + break; + } + default: + break; + } + } + + sLog.outString(); + sLog.outString( ">> Loaded %u GameObject for quests", count ); +} + +bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value) +{ + // cleanup affected map part for reloading case + for(MangosStringLocaleMap::iterator itr = mMangosStringLocaleMap.begin(); itr != mMangosStringLocaleMap.end();) + { + if(itr->first >= min_value && itr->first <= max_value) + { + MangosStringLocaleMap::iterator itr2 = itr; + ++itr; + mMangosStringLocaleMap.erase(itr2); + } + else + ++itr; + } + + QueryResult *result = db.PQuery("SELECT entry,content_default,content_loc1,content_loc2,content_loc3,content_loc4,content_loc5,content_loc6,content_loc7,content_loc8 FROM %s",table); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + if(min_value > 0) // error only in case internal strings + sLog.outErrorDb(">> Loaded 0 mangos strings. DB table `%s` is empty. Cannot continue.",table); + else + sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table); + return false; + } + + uint32 count = 0; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + int32 entry = fields[0].GetInt32(); + + if(entry==0) + { + sLog.outString("Table `%s` contain reserved entry 0, ignored.",table); + continue; + } + else if(entry < min_value || entry > max_value) + { + int32 start = min_value > 0 ? min_value : max_value; + int32 end = min_value > 0 ? max_value : min_value; + sLog.outString("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,start,end); + continue; + } + + MangosStringLocale& data = mMangosStringLocaleMap[entry]; + + if(data.Content.size() > 0) + { + sLog.outString("Table `%s` contain data for already loaded entry %i (from another table?), ignored.",table,entry); + continue; + } + + data.Content.resize(1); + ++count; + + // 0 -> default, idx in to idx+1 + data.Content[0] = fields[1].GetCppString(); + + for(int i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[i+1].GetCppString(); + if(!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if(idx >= 0) + { + // 0 -> default, idx in to idx+1 + if(data.Content.size() <= idx+1) + data.Content.resize(idx+2); + + data.Content[idx+1] = str; + } + } + } + } while (result->NextRow()); + + delete result; + + sLog.outString(); + if(min_value > 0) // internal mangos strings + sLog.outString( ">> Loaded %u MaNGOS strings from table %s", count,table); + else + sLog.outString( ">> Loaded %u string templates from %s", count,table); + + return true; +} + +const char *ObjectMgr::GetMangosString(int32 entry, int locale_idx) const +{ + // locale_idx==-1 -> default, locale_idx >= 0 in to idx+1 + // Content[0] always exist if exist MangosStringLocale + if(MangosStringLocale const *msl = GetMangosStringLocale(entry)) + { + if(msl->Content.size() > locale_idx+1 && !msl->Content[locale_idx+1].empty()) + return msl->Content[locale_idx+1].c_str(); + else + return msl->Content[0].c_str(); + } + + if(entry > 0) + sLog.outErrorDb("Entry %i not found in `mangos_string` table.",entry); + else + sLog.outErrorDb("Mangos string entry %i not found in DB.",entry); + return ""; +} + +void ObjectMgr::LoadFishingBaseSkillLevel() +{ + mFishingBaseForArea.clear(); // for relaod case + + uint32 count = 0; + QueryResult *result = WorldDatabase.Query("SELECT entry,skill FROM skill_fishing_base_level"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `skill_fishing_base_level`, table is empty!"); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + uint32 entry = fields[0].GetUInt32(); + int32 skill = fields[1].GetInt32(); + + AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry); + if(!fArea) + { + sLog.outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist",entry); + continue; + } + + mFishingBaseForArea[entry] = skill; + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u areas for fishing base skill level", count ); +} + +// Searches for the same condition already in Conditions store +// Returns Id if found, else adds it to Conditions and returns Id +uint16 ObjectMgr::GetConditionId( ConditionType condition, uint32 value1, uint32 value2 ) +{ + PlayerCondition lc = PlayerCondition(condition, value1, value2); + for (uint16 i=0; i < mConditions.size(); ++i) + { + if (lc == mConditions[i]) + return i; + } + + mConditions.push_back(lc); + + if(mConditions.size() > 0xFFFF) + { + sLog.outError("Conditions store overflow! Current and later loaded conditions will ignored!"); + return 0; + } + + return mConditions.size() - 1; +} + +bool ObjectMgr::CheckDeclinedNames( std::wstring mainpart, DeclinedName const& names ) +{ + for(int i =0; i < MAX_DECLINED_NAME_CASES; ++i) + { + std::wstring wname; + if(!Utf8toWStr(names.name[i],wname)) + return false; + + if(mainpart!=GetMainPartOfName(wname,i+1)) + return false; + } + return true; +} + +const char* ObjectMgr::GetAreaTriggerScriptName(uint32 id) +{ + AreaTriggerScriptMap::const_iterator i = mAreaTriggerScripts.find(id); + if(i!= mAreaTriggerScripts.end()) + return i->second.c_str(); + return ""; +} + +// Checks if player meets the condition +bool PlayerCondition::Meets(Player const * player) const +{ + if( !player ) + return false; // player not present, return false + + switch (condition) + { + case CONDITION_NONE: + return true; // empty condition, always met + case CONDITION_AURA: + return player->HasAura(value1, value2); + case CONDITION_ITEM: + return player->HasItemCount(value1, value2); + case CONDITION_ITEM_EQUIPPED: + return player->GetItemOrItemWithGemEquipped(value1) != NULL; + case CONDITION_ZONEID: + return player->GetZoneId() == value1; + case CONDITION_REPUTATION_RANK: + { + FactionEntry const* faction = sFactionStore.LookupEntry(value1); + return faction && player->GetReputationRank(faction) >= value2; + } + case CONDITION_TEAM: + return player->GetTeam() == value1; + case CONDITION_SKILL: + return player->HasSkill(value1) && player->GetBaseSkillValue(value1) >= value2; + case CONDITION_QUESTREWARDED: + return player->GetQuestRewardStatus(value1); + case CONDITION_QUESTTAKEN: + { + QuestStatus status = player->GetQuestStatus(value1); + return (status == QUEST_STATUS_INCOMPLETE); + } + case CONDITION_AD_COMMISSION_AURA: + { + Unit::AuraMap const& auras = player->GetAuras(); + for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual==3580) + return true; + return false; + } + default: + return false; + } +} + +// Verification of condition values validity +bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 value2) +{ + if( condition >= MAX_CONDITION) // Wrong condition type + { + sLog.outErrorDb("Condition has bad type of %u, skipped ", condition ); + return false; + } + + switch (condition) + { + case CONDITION_AURA: + { + if(!sSpellStore.LookupEntry(value1)) + { + sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1); + return false; + } + if(value2 > 2) + { + sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2); + return false; + } + break; + } + case CONDITION_ITEM: + { + ItemPrototype const *proto = objmgr.GetItemPrototype(value1); + if(!proto) + { + sLog.outErrorDb("Item condition requires to have non existing item (%u), skipped", value1); + return false; + } + break; + } + case CONDITION_ITEM_EQUIPPED: + { + ItemPrototype const *proto = objmgr.GetItemPrototype(value1); + if(!proto) + { + sLog.outErrorDb("ItemEquipped condition requires to have non existing item (%u) equipped, skipped", value1); + return false; + } + break; + } + case CONDITION_ZONEID: + { + AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(value1); + if(!areaEntry) + { + sLog.outErrorDb("Zone condition requires to be in non existing area (%u), skipped", value1); + return false; + } + if(areaEntry->zone != 0) + { + sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", value1); + return false; + } + break; + } + case CONDITION_REPUTATION_RANK: + { + FactionEntry const* factionEntry = sFactionStore.LookupEntry(value1); + if(!factionEntry) + { + sLog.outErrorDb("Reputation condition requires to have reputation non existing faction (%u), skipped", value1); + return false; + } + break; + } + case CONDITION_TEAM: + { + if (value1 != ALLIANCE && value1 != HORDE) + { + sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", value1); + return false; + } + break; + } + case CONDITION_SKILL: + { + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(value1); + if (!pSkill) + { + sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", value1); + return false; + } + if (value2 < 1 || value2 > sWorld.GetConfigMaxSkillValue() ) + { + sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", value2); + return false; + } + break; + } + case CONDITION_QUESTREWARDED: + case CONDITION_QUESTTAKEN: + { + Quest const *Quest = objmgr.GetQuestTemplate(value1); + if (!Quest) + { + sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", value1); + return false; + } + if(value2) + sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2); + break; + } + case CONDITION_AD_COMMISSION_AURA: + { + if(value1) + sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", value1); + if(value2) + sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2); + break; + } + } + return true; +} + +SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial) +{ + switch(pSkill->categoryId) + { + case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE; + case SKILL_CATEGORY_WEAPON: + if(pSkill->id!=SKILL_FIST_WEAPONS) + return SKILL_RANGE_LEVEL; + else + return SKILL_RANGE_MONO; + case SKILL_CATEGORY_ARMOR: + case SKILL_CATEGORY_CLASS: + if(pSkill->id != SKILL_POISONS && pSkill->id != SKILL_LOCKPICKING) + return SKILL_RANGE_MONO; + else + return SKILL_RANGE_LEVEL; + case SKILL_CATEGORY_SECONDARY: + case SKILL_CATEGORY_PROFESSION: + // not set skills for professions and racial abilities + if(IsProfessionSkill(pSkill->id)) + return SKILL_RANGE_RANK; + else if(racial) + return SKILL_RANGE_NONE; + else + return SKILL_RANGE_MONO; + default: + case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc + case SKILL_CATEGORY_NOT_DISPLAYED: //only GENEREC(DND) + return SKILL_RANGE_NONE; + } +} + +void ObjectMgr::LoadGameTele() +{ + m_GameTeleMap.clear(); // for relaod case + + uint32 count = 0; + QueryResult *result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `game_tele`, table is empty!"); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + + uint32 id = fields[0].GetUInt32(); + + GameTele gt; + + gt.position_x = fields[1].GetFloat(); + gt.position_y = fields[2].GetFloat(); + gt.position_z = fields[3].GetFloat(); + gt.orientation = fields[4].GetFloat(); + gt.mapId = fields[5].GetUInt32(); + gt.name = fields[6].GetCppString(); + + if(!MapManager::IsValidMapCoord(gt.mapId,gt.position_x,gt.position_y,gt.position_z,gt.orientation)) + { + sLog.outErrorDb("Wrong position for id %u (name: %s) in `game_tele` table, ignoring.",id,gt.name.c_str()); + continue; + } + + if(!Utf8toWStr(gt.name,gt.wnameLow)) + { + sLog.outErrorDb("Wrong UTF8 name for id %u in `game_tele` table, ignoring.",id); + continue; + } + + wstrToLower( gt.wnameLow ); + + m_GameTeleMap[id] = gt; + + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u game tele's", count ); +} + +GameTele const* ObjectMgr::GetGameTele(std::string name) const +{ + // explicit name case + std::wstring wname; + if(!Utf8toWStr(name,wname)) + return false; + + // converting string that we try to find to lower case + wstrToLower( wname ); + + for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) + if(itr->second.wnameLow == wname) + return &itr->second; + + return NULL; +} + +bool ObjectMgr::AddGameTele(GameTele& tele) +{ + // find max id + uint32 new_id = 0; + for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) + if(itr->first > new_id) + new_id = itr->first; + + // use next + ++new_id; + + if(!Utf8toWStr(tele.name,tele.wnameLow)) + return false; + + wstrToLower( tele.wnameLow ); + + m_GameTeleMap[new_id] = tele; + + return WorldDatabase.PExecuteLog("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')", + new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str()); +} + +bool ObjectMgr::DeleteGameTele(std::string name) +{ + // explicit name case + std::wstring wname; + if(!Utf8toWStr(name,wname)) + return false; + + // converting string that we try to find to lower case + wstrToLower( wname ); + + for(GameTeleMap::iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) + { + if(itr->second.wnameLow == wname) + { + WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str()); + m_GameTeleMap.erase(itr); + return true; + } + } + + return false; +} + +void ObjectMgr::LoadTrainerSpell() +{ + // For reload case + for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) + itr->second.Clear(); + m_mCacheTrainerSpellMap.clear(); + + QueryResult *result = WorldDatabase.PQuery("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!"); + return; + } + + barGoLink bar( result->GetRowCount() ); + + uint32 count = 0,entry,spell; + do + { + bar.step(); + + Field* fields = result->Fetch(); + + entry = fields[0].GetUInt32(); + spell = fields[1].GetUInt32(); + + if(!GetCreatureTemplate(entry)) + { + sLog.outErrorDb("Table `npc_trainer` have entry for not existed creature template (Entry: %u), ignore", entry); + continue; + } + + SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell); + if(!spellinfo) + { + sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u ) has non existing spell %u, ignore", entry,spell); + continue; + } + + if(!SpellMgr::IsSpellValid(spellinfo)) + { + sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell); + continue; + } + + TrainerSpell* pTrainerSpell = new TrainerSpell(); + pTrainerSpell->spell = spell; + pTrainerSpell->spellcost = fields[2].GetUInt32(); + pTrainerSpell->reqskill = fields[3].GetUInt32(); + pTrainerSpell->reqskillvalue = fields[4].GetUInt32(); + pTrainerSpell->reqlevel = fields[5].GetUInt32(); + + if(!pTrainerSpell->reqlevel) + pTrainerSpell->reqlevel = spellinfo->spellLevel; + + + TrainerSpellData& data = m_mCacheTrainerSpellMap[entry]; + + if(SpellMgr::IsProfessionSpell(spell)) + data.trainerType = 2; + + data.spellList.push_back(pTrainerSpell); + ++count; + + } while (result->NextRow()); + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded Trainers %d", count ); +} + +void ObjectMgr::LoadVendors() +{ + // For reload case + for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) + { + for (VendorItemList::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + delete (*itr2); + } + m_mCacheVendorItemMap.clear(); + + QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor"); + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `npc_vendor`, table is empty!"); + return; + } + + barGoLink bar( result->GetRowCount() ); + + uint32 count = 0; + uint32 entry, item_id, ExtendedCost; + do + { + bar.step(); + Field* fields = result->Fetch(); + + entry = fields[0].GetUInt32(); + if(!GetCreatureTemplate(entry)) + { + sLog.outErrorDb("Table `npc_vendor` have data for not existed creature template (Entry: %u), ignore", entry); + continue; + } + + item_id = fields[1].GetUInt32(); + if(!GetItemPrototype(item_id)) + { + sLog.outErrorDb("Table `npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore",entry,item_id); + continue; + } + + ExtendedCost = fields[4].GetUInt32(); + if(ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) + { + sLog.outErrorDb("Table `npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore",item_id,ExtendedCost,entry); + continue; + } + + VendorItemList& vList = m_mCacheVendorItemMap[entry]; + + if(vList.size() >= MAX_VENDOR_ITEMS) + { + sLog.outErrorDb( "Table `npc_vendor` has too many items (%u >= %i) for vendor (Entry: %u), ignore", vList.size(), MAX_VENDOR_ITEMS, entry); + continue; + } + + VendorItem* pVendorItem = new VendorItem(); + pVendorItem->item = item_id; + pVendorItem->maxcount = fields[2].GetUInt32(); + pVendorItem->incrtime = fields[3].GetUInt32(); + pVendorItem->ExtendedCost = ExtendedCost; + + vList.push_back(pVendorItem); + ++count; + + } while (result->NextRow()); + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %d Vendors ", count ); +} + +void ObjectMgr::LoadNpcTextId() +{ + + m_mCacheNpcTextIdMap.clear(); + + QueryResult* result = WorldDatabase.PQuery("SELECT npc_guid, textid FROM npc_gossip"); + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `npc_gossip`, table is empty!"); + return; + } + + barGoLink bar( result->GetRowCount() ); + + uint32 count = 0; + uint32 guid,textid; + do + { + bar.step(); + + Field* fields = result->Fetch(); + + guid = fields[0].GetUInt32(); + textid = fields[1].GetUInt32(); + + if (!GetCreatureData(guid)) + { + sLog.outErrorDb("Table `npc_gossip` have not existed creature (GUID: %u) entry, ignore. ",guid); + continue; + } + if (!GetGossipText(textid)) + { + sLog.outErrorDb("Table `npc_gossip` for creature (GUID: %u) have wrong Textid (%u), ignore. ", guid, textid); + continue; + } + + m_mCacheNpcTextIdMap[guid] = textid ; + ++count; + + } while (result->NextRow()); + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %d NpcTextId ", count ); +} + +// Functions for scripting access +const char* GetAreaTriggerScriptNameById(uint32 id) +{ + return objmgr.GetAreaTriggerScriptName(id); +} + +bool LoadMangosStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value) +{ + if(start_value >= 0 || start_value <= end_value) // start/end reversed for negative values + { + sLog.outError("Table '%s' attempt loaded with invalid range (%d - %d), use (%d - %d) instead.",table,start_value,end_value,-1,std::numeric_limits::min()); + start_value = -1; + end_value = std::numeric_limits::min(); + } + + // for scripting localized strings allowed use _only_ negative entries + return objmgr.LoadMangosStrings(db,table,end_value,start_value); +} diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index f7b7d0a3cca..42d5d85e415 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -1,780 +1,860 @@ -/* - * Copyright (C) 2005-2008 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 _OBJECTMGR_H -#define _OBJECTMGR_H - -#include "Log.h" -#include "Object.h" -#include "Bag.h" -#include "Creature.h" -#include "Player.h" -#include "DynamicObject.h" -#include "GameObject.h" -#include "Corpse.h" -#include "QuestDef.h" -#include "Path.h" -#include "ItemPrototype.h" -#include "NPCHandler.h" -#include "Database/DatabaseEnv.h" -#include "AuctionHouseObject.h" -#include "Mail.h" -#include "Map.h" -#include "ObjectAccessor.h" -#include "ObjectDefines.h" -#include "Policies/Singleton.h" -#include "Database/SQLStorage.h" - -#include -#include - -extern SQLStorage sCreatureStorage; -extern SQLStorage sCreatureDataAddonStorage; -extern SQLStorage sCreatureInfoAddonStorage; -extern SQLStorage sCreatureModelStorage; -extern SQLStorage sEquipmentStorage; -extern SQLStorage sGOStorage; -extern SQLStorage sPageTextStore; -extern SQLStorage sItemStorage; -extern SQLStorage sInstanceTemplate; - -class Group; -class Guild; -class ArenaTeam; -class Path; -class TransportPath; -class Item; - -struct ScriptInfo -{ - uint32 id; - uint32 delay; - uint32 command; - uint32 datalong; - uint32 datalong2; - std::string datatext; - float x; - float y; - float z; - float o; -}; - -typedef std::multimap ScriptMap; -typedef std::map ScriptMapMap; -extern ScriptMapMap sQuestEndScripts; -extern ScriptMapMap sQuestStartScripts; -extern ScriptMapMap sSpellScripts; -extern ScriptMapMap sGameObjectScripts; -extern ScriptMapMap sEventScripts; - -struct AreaTrigger -{ - uint8 requiredLevel; - uint32 requiredItem; - uint32 requiredItem2; - uint32 heroicKey; - uint32 heroicKey2; - uint32 requiredQuest; - std::string requiredFailedText; - uint32 target_mapId; - float target_X; - float target_Y; - float target_Z; - float target_Orientation; -}; - -typedef std::set CellGuidSet; -typedef std::map CellCorpseSet; -struct CellObjectGuids -{ - CellGuidSet creatures; - CellGuidSet gameobjects; - CellCorpseSet corpses; -}; -typedef HM_NAMESPACE::hash_map CellObjectGuidsMap; -typedef HM_NAMESPACE::hash_map MapObjectGuids; - -typedef HM_NAMESPACE::hash_map RespawnTimes; - -struct MangosStringLocale -{ - std::vector Content; // 0 -> default, i -> i-1 locale index -}; - -typedef HM_NAMESPACE::hash_map CreatureDataMap; -typedef HM_NAMESPACE::hash_map GameObjectDataMap; -typedef HM_NAMESPACE::hash_map CreatureLocaleMap; -typedef HM_NAMESPACE::hash_map GameObjectLocaleMap; -typedef HM_NAMESPACE::hash_map ItemLocaleMap; -typedef HM_NAMESPACE::hash_map QuestLocaleMap; -typedef HM_NAMESPACE::hash_map NpcTextLocaleMap; -typedef HM_NAMESPACE::hash_map PageTextLocaleMap; -typedef HM_NAMESPACE::hash_map MangosStringLocaleMap; - -typedef std::multimap QuestRelations; - -struct PetLevelInfo -{ - PetLevelInfo() : health(0), mana(0) { for(int i=0; i < MAX_STATS; ++i ) stats[i] = 0; } - - uint16 stats[MAX_STATS]; - uint16 health; - uint16 mana; - uint16 armor; -}; - -struct ReputationOnKillEntry -{ - uint32 repfaction1; - uint32 repfaction2; - bool is_teamaward1; - uint32 reputration_max_cap1; - int32 repvalue1; - bool is_teamaward2; - uint32 reputration_max_cap2; - int32 repvalue2; - bool team_dependent; -}; - -struct PetCreateSpellEntry -{ - uint32 spellid[4]; -}; - -#define WEATHER_SEASONS 4 -struct WeatherSeasonChances -{ - uint32 rainChance; - uint32 snowChance; - uint32 stormChance; -}; - -struct WeatherZoneChances -{ - WeatherSeasonChances data[WEATHER_SEASONS]; -}; - -struct GraveYardData -{ - uint32 safeLocId; - uint32 team; -}; -typedef std::multimap GraveYardMap; - -enum ConditionType -{ // value1 value2 for the Condition enumed - CONDITION_NONE = 0, // 0 0 - CONDITION_AURA = 1, // spell_id effindex - CONDITION_ITEM = 2, // item_id count - CONDITION_ITEM_EQUIPPED = 3, // item_id 0 - CONDITION_ZONEID = 4, // zone_id 0 - CONDITION_REPUTATION_RANK = 5, // faction_id min_rank - CONDITION_TEAM = 6, // player_team 0, (469 - Alliance 67 - Horde) - CONDITION_SKILL = 7, // skill_id skill_value - CONDITION_QUESTREWARDED = 8, // quest_id 0 - CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active. - CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD ñommission aura active -}; - -#define MAX_CONDITION 11 // maximum value in ConditionType enum - -struct PlayerCondition -{ - ConditionType condition; // additional condition type - uint32 value1; // data for the condition - see ConditionType definition - uint32 value2; - - PlayerCondition(uint8 _condition = 0, uint32 _value1 = 0, uint32 _value2 = 0) - : condition(ConditionType(_condition)), value1(_value1), value2(_value2) {} - - static bool IsValid(ConditionType condition, uint32 value1, uint32 value2); - // Checks correctness of values - bool Meets(Player const * APlayer) const; // Checks if the player meets the condition - bool operator == (PlayerCondition const& lc) const - { - return (lc.condition == condition && lc.value1 == value1 && lc.value2 == value2); - } -}; - -enum SkillRangeType -{ - SKILL_RANGE_LANGUAGE, // 300..300 - SKILL_RANGE_LEVEL, // 1..max skill for level - SKILL_RANGE_MONO, // 1..1, grey monolite bar - SKILL_RANGE_RANK, // 1..skill for known rank - SKILL_RANGE_NONE, // 0..0 always -}; - -SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial); - -#define MAX_PLAYER_NAME 12 // max allowed by client name length -#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length ( > MAX_PLAYER_NAME for support declined names ) - -bool normalizePlayerName(std::string& name); - -class PlayerDumpReader; - -class ObjectMgr -{ - friend class PlayerDumpReader; - - public: - ObjectMgr(); - ~ObjectMgr(); - - typedef HM_NAMESPACE::hash_map ItemMap; - - typedef std::set< Group * > GroupSet; - typedef std::set< Guild * > GuildSet; - typedef std::set< ArenaTeam * > ArenaTeamSet; - - typedef HM_NAMESPACE::hash_map QuestMap; - - typedef HM_NAMESPACE::hash_map AreaTriggerMap; - - typedef HM_NAMESPACE::hash_map AreaTriggerScriptMap; - - typedef HM_NAMESPACE::hash_map RepOnKillMap; - - typedef HM_NAMESPACE::hash_map WeatherZoneMap; - - typedef HM_NAMESPACE::hash_map PetCreateSpellMap; - - Player* GetPlayer(const char* name) const { return ObjectAccessor::Instance().FindPlayerByName(name);} - Player* GetPlayer(uint64 guid) const { return ObjectAccessor::FindPlayer(guid); } - - static GameObjectInfo const *GetGameObjectInfo(uint32 id) { return sGOStorage.LookupEntry(id); } - - void LoadGameobjectInfo(); - void AddGameobjectInfo(GameObjectInfo *goinfo); - - Group * GetGroupByLeader(const uint64 &guid) const; - void AddGroup(Group* group) { mGroupSet.insert( group ); } - void RemoveGroup(Group* group) { mGroupSet.erase( group ); } - - Guild* GetGuildByLeader(uint64 const&guid) const; - Guild* GetGuildById(const uint32 GuildId) const; - Guild* GetGuildByName(std::string guildname) const; - std::string GetGuildNameById(const uint32 GuildId) const; - void AddGuild(Guild* guild) { mGuildSet.insert( guild ); } - void RemoveGuild(Guild* guild) { mGuildSet.erase( guild ); } - - ArenaTeam* GetArenaTeamById(const uint32 ArenaTeamId) const; - ArenaTeam* GetArenaTeamByName(std::string ArenaTeamName) const; - ArenaTeam* GetArenaTeamByCapitan(uint64 const& guid) const; - void AddArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.insert( arenateam ); } - void RemoveArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.erase( arenateam ); } - - static CreatureInfo const *GetCreatureTemplate( uint32 id ); - CreatureModelInfo const *GetCreatureModelInfo( uint32 modelid ); - CreatureModelInfo const* GetCreatureModelRandomGender(uint32 display_id); - uint32 ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data = NULL); - EquipmentInfo const *GetEquipmentInfo( uint32 entry ); - static CreatureDataAddon const *GetCreatureAddon( uint32 lowguid ) - { - return sCreatureDataAddonStorage.LookupEntry(lowguid); - } - - static CreatureDataAddon const *GetCreatureTemplateAddon( uint32 entry ) - { - return sCreatureInfoAddonStorage.LookupEntry(entry); - } - - static ItemPrototype const* GetItemPrototype(uint32 id) { return sItemStorage.LookupEntry(id); } - - static InstanceTemplate const* GetInstanceTemplate(uint32 map) - { - return sInstanceTemplate.LookupEntry(map); - } - - Item* GetAItem(uint32 id) - { - ItemMap::const_iterator itr = mAitems.find(id); - if (itr != mAitems.end()) - { - return itr->second; - } - return NULL; - } - void AddAItem(Item* it) - { - ASSERT( it ); - ASSERT( mAitems.find(it->GetGUIDLow()) == mAitems.end()); - mAitems[it->GetGUIDLow()] = it; - } - bool RemoveAItem(uint32 id) - { - ItemMap::iterator i = mAitems.find(id); - if (i == mAitems.end()) - { - return false; - } - mAitems.erase(i); - return true; - } - AuctionHouseObject * GetAuctionsMap( uint32 location ); - - //auction messages - void SendAuctionWonMail( AuctionEntry * auction ); - void SendAuctionSalePendingMail( AuctionEntry * auction ); - void SendAuctionSuccessfulMail( AuctionEntry * auction ); - void SendAuctionExpiredMail( AuctionEntry * auction ); - static uint32 GetAuctionCut( uint32 location, uint32 highBid ); - static uint32 GetAuctionDeposit(uint32 location, uint32 time, Item *pItem); - static uint32 GetAuctionOutBid(uint32 currentBid); - - PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint32 level) const; - - PlayerClassInfo const* GetPlayerClassInfo(uint32 class_) const - { - if(class_ >= MAX_CLASSES) return NULL; - return &playerClassInfo[class_]; - } - void GetPlayerClassLevelInfo(uint32 class_,uint32 level, PlayerClassLevelInfo* info) const; - - PlayerInfo const* GetPlayerInfo(uint32 race, uint32 class_) const - { - if(race >= MAX_RACES) return NULL; - if(class_ >= MAX_CLASSES) return NULL; - PlayerInfo const* info = &playerInfo[race][class_]; - if(info->displayId_m==0 || info->displayId_f==0) return NULL; - return info; - } - void GetPlayerLevelInfo(uint32 race, uint32 class_,uint32 level, PlayerLevelInfo* info) const; - - uint64 GetPlayerGUIDByName(std::string name) const; - bool GetPlayerNameByGUID(const uint64 &guid, std::string &name) const; - uint32 GetPlayerTeamByGUID(const uint64 &guid) const; - uint32 GetPlayerAccountIdByGUID(const uint64 &guid) const; - uint32 GetSecurityByAccount(uint32 acc_id) const; - bool GetAccountNameByAccount(uint32 acc_id, std::string &name) const; - uint32 GetAccountByAccountName(std::string name) const; - - uint32 GetNearestTaxiNode( float x, float y, float z, uint32 mapid ); - void GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost); - uint16 GetTaxiMount( uint32 id, uint32 team ); - void GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector& mapIds ); - void GetTransportPathNodes( uint32 path, TransportPath &pathnodes ); - - Quest const* GetQuestTemplate(uint32 quest_id) const - { - QuestMap::const_iterator itr = mQuestTemplates.find(quest_id); - return itr != mQuestTemplates.end() ? itr->second : NULL; - } - QuestMap const& GetQuestTemplates() const { return mQuestTemplates; } - - uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const - { - QuestAreaTriggerMap::const_iterator itr = mQuestAreaTriggerMap.find(Trigger_ID); - if(itr != mQuestAreaTriggerMap.end()) - return itr->second; - return 0; - } - bool IsTavernAreaTrigger(uint32 Trigger_ID) const { return mTavernAreaTriggerSet.count(Trigger_ID) != 0; } - bool IsGameObjectForQuests(uint32 entry) const { return mGameObjectForQuestSet.count(entry) != 0; } - bool IsGuildVaultGameObject(Player *player, uint64 guid) const - { - if(GameObject *go = ObjectAccessor::GetGameObject(*player, guid)) - if(go->GetGoType() == GAMEOBJECT_TYPE_GUILD_BANK) - return true; - return false; - } - - uint32 GetBattleMasterBG(uint32 entry) const - { - BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry); - if(itr != mBattleMastersMap.end()) - return itr->second; - return 2; //BATTLEGROUND_WS - i will not add include only for constant usage! - } - - void AddGossipText(GossipText *pGText); - GossipText *GetGossipText(uint32 Text_ID); - - WorldSafeLocsEntry const *GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team); - bool AddGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = true); - void LoadGraveyardZones(); - GraveYardData const* FindGraveYardData(uint32 id, uint32 zone); - - AreaTrigger const* GetAreaTrigger(uint32 trigger) const - { - AreaTriggerMap::const_iterator itr = mAreaTriggers.find( trigger ); - if( itr != mAreaTriggers.end( ) ) - return &itr->second; - return NULL; - } - - AreaTrigger const* GetGoBackTrigger(uint32 Map) const; - - const char* GetAreaTriggerScriptName(uint32 id); - - ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const - { - RepOnKillMap::const_iterator itr = mRepOnKill.find(id); - if(itr != mRepOnKill.end()) - return &itr->second; - return NULL; - } - - PetCreateSpellEntry const* GetPetCreateSpellEntry(uint32 id) const - { - PetCreateSpellMap::const_iterator itr = mPetCreateSpell.find(id); - if(itr != mPetCreateSpell.end()) - return &itr->second; - return NULL; - } - - void LoadGuilds(); - void LoadArenaTeams(); - void LoadGroups(); - void LoadQuests(); - void LoadQuestRelations() - { - LoadGameobjectQuestRelations(); - LoadGameobjectInvolvedRelations(); - LoadCreatureQuestRelations(); - LoadCreatureInvolvedRelations(); - } - void LoadGameobjectQuestRelations(); - void LoadGameobjectInvolvedRelations(); - void LoadCreatureQuestRelations(); - void LoadCreatureInvolvedRelations(); - - QuestRelations mGOQuestRelations; - QuestRelations mGOQuestInvolvedRelations; - QuestRelations mCreatureQuestRelations; - QuestRelations mCreatureQuestInvolvedRelations; - - void LoadGameObjectScripts(); - void LoadQuestEndScripts(); - void LoadQuestStartScripts(); - void LoadEventScripts(); - void LoadSpellScripts(); - - bool LoadMangosStrings(DatabaseType& db, char const* table, bool positive_entries); - bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase,"mangos_string",true); } - void LoadPetCreateSpells(); - void LoadCreatureLocales(); - void LoadCreatureTemplates(); - void LoadCreatures(); - void LoadCreatureRespawnTimes(); - void LoadCreatureAddons(); - void LoadCreatureModelInfo(); - void LoadEquipmentTemplates(); - void LoadGameObjectLocales(); - void LoadGameobjects(); - void LoadGameobjectRespawnTimes(); - void LoadItemPrototypes(); - void LoadItemLocales(); - void LoadQuestLocales(); - void LoadNpcTextLocales(); - void LoadPageTextLocales(); - void LoadInstanceTemplate(); - - void LoadGossipText(); - - void LoadAreaTriggerTeleports(); - void LoadQuestAreaTriggers(); - void LoadAreaTriggerScripts(); - void LoadTavernAreaTriggers(); - void LoadBattleMastersEntry(); - void LoadGameObjectForQuests(); - - void LoadItemTexts(); - void LoadPageTexts(); - - //load first auction items, because of check if item exists, when loading - void LoadAuctionItems(); - void LoadAuctions(); - void LoadPlayerInfo(); - void LoadPetLevelInfo(); - void LoadExplorationBaseXP(); - void LoadPetNames(); - void LoadPetNumber(); - void LoadCorpses(); - void LoadFishingBaseSkillLevel(); - - void LoadReputationOnKill(); - - void LoadWeatherZoneChances(); - - std::string GeneratePetName(uint32 entry); - uint32 GetBaseXP(uint32 level); - - int32 GetFishingBaseSkillLevel(uint32 entry) const - { - FishingBaseSkillMap::const_iterator itr = mFishingBaseForArea.find(entry); - return itr != mFishingBaseForArea.end() ? itr->second : 0; - } - - void ReturnOrDeleteOldMails(bool serverUp); - - void SetHighestGuids(); - uint32 GenerateLowGuid(HighGuid guidhigh); - uint32 GenerateAuctionID(); - uint32 GenerateMailID(); - uint32 GenerateItemTextID(); - uint32 GeneratePetNumber(); - - uint32 CreateItemText(std::string text); - std::string GetItemText( uint32 id ) - { - ItemTextMap::const_iterator itr = mItemTexts.find( id ); - if ( itr != mItemTexts.end() ) - return itr->second; - else - return "There is no info for this item"; - } - - typedef std::multimap ExclusiveQuestGroups; - ExclusiveQuestGroups mExclusiveQuestGroups; - - WeatherZoneChances const* GetWeatherChances(uint32 zone_id) const - { - WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id); - if(itr != mWeatherZoneMap.end()) - return &itr->second; - else - return NULL; - } - - CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id) - { - return mMapObjectGuids[MAKE_PAIR32(mapid,spawnMode)][cell_id]; - } - - CreatureData const* GetCreatureData(uint32 guid) const - { - CreatureDataMap::const_iterator itr = mCreatureDataMap.find(guid); - if(itr==mCreatureDataMap.end()) return NULL; - return &itr->second; - } - CreatureData& NewOrExistCreatureData(uint32 guid) { return mCreatureDataMap[guid]; } - void DeleteCreatureData(uint32 guid); - CreatureLocale const* GetCreatureLocale(uint32 entry) const - { - CreatureLocaleMap::const_iterator itr = mCreatureLocaleMap.find(entry); - if(itr==mCreatureLocaleMap.end()) return NULL; - return &itr->second; - } - GameObjectLocale const* GetGameObjectLocale(uint32 entry) const - { - GameObjectLocaleMap::const_iterator itr = mGameObjectLocaleMap.find(entry); - if(itr==mGameObjectLocaleMap.end()) return NULL; - return &itr->second; - } - ItemLocale const* GetItemLocale(uint32 entry) const - { - ItemLocaleMap::const_iterator itr = mItemLocaleMap.find(entry); - if(itr==mItemLocaleMap.end()) return NULL; - return &itr->second; - } - QuestLocale const* GetQuestLocale(uint32 entry) const - { - QuestLocaleMap::const_iterator itr = mQuestLocaleMap.find(entry); - if(itr==mQuestLocaleMap.end()) return NULL; - return &itr->second; - } - NpcTextLocale const* GetNpcTextLocale(uint32 entry) const - { - NpcTextLocaleMap::const_iterator itr = mNpcTextLocaleMap.find(entry); - if(itr==mNpcTextLocaleMap.end()) return NULL; - return &itr->second; - } - PageTextLocale const* GetPageTextLocale(uint32 entry) const - { - PageTextLocaleMap::const_iterator itr = mPageTextLocaleMap.find(entry); - if(itr==mPageTextLocaleMap.end()) return NULL; - return &itr->second; - } - - GameObjectData const* GetGOData(uint32 guid) const - { - GameObjectDataMap::const_iterator itr = mGameObjectDataMap.find(guid); - if(itr==mGameObjectDataMap.end()) return NULL; - return &itr->second; - } - GameObjectData& NewGOData(uint32 guid) { return mGameObjectDataMap[guid]; } - void DeleteGOData(uint32 guid); - - MangosStringLocale const* GetMangosStringLocale(int32 entry) const - { - MangosStringLocaleMap::const_iterator itr = mMangosStringLocaleMap.find(entry); - if(itr==mMangosStringLocaleMap.end()) return NULL; - return &itr->second; - } - const char *GetMangosString(int32 entry, int locale_idx) const; - const char *GetMangosStringForDBCLocale(int32 entry) const { return GetMangosString(entry,DBCLocaleIndex); } - void SetDBCLocaleIndex(uint32 lang) { DBCLocaleIndex = GetIndexForLocale(LocaleConstant(lang)); } - - void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance); - void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid); - - time_t GetCreatureRespawnTime(uint32 loguid, uint32 instance) { return mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)]; } - void SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t); - time_t GetGORespawnTime(uint32 loguid, uint32 instance) { return mGORespawnTimes[MAKE_PAIR64(loguid,instance)]; } - void SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t); - void DeleteRespawnTimeForInstance(uint32 instance); - - // grid objects - void AddCreatureToGrid(uint32 guid, CreatureData const* data); - void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data); - void AddGameobjectToGrid(uint32 guid, GameObjectData const* data); - void RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data); - - // reserved names - void LoadReservedPlayersNames(); - bool IsReservedName(std::string name) const - { - return m_ReservedNames.find(name) != m_ReservedNames.end(); - } - - // name with valid structure and symbols - static bool IsValidName( std::string name, bool create = false ); - static bool IsValidCharterName( std::string name ); - static bool IsValidPetName( std::string name ); - - static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names); - - int GetIndexForLocale(LocaleConstant loc); - LocaleConstant GetLocaleForIndex(int i); - // guild bank tabs - const uint32 GetGuildBankTabPrice(uint8 Index) { return Index < GUILD_BANK_MAX_TABS ? mGuildBankTabPrice[Index] : 0; } - - uint16 GetConditionId(ConditionType condition, uint32 value1, uint32 value2); - bool IsPlayerMeetToCondition(Player const* player, uint16 condition_id) const - { - if(condition_id >= mConditions.size()) - return false; - - return mConditions[condition_id].Meets(player); - } - protected: - uint32 m_auctionid; - uint32 m_mailid; - uint32 m_ItemTextId; - - uint32 m_hiCharGuid; - uint32 m_hiCreatureGuid; - uint32 m_hiPetGuid; - uint32 m_hiItemGuid; - uint32 m_hiGoGuid; - uint32 m_hiDoGuid; - uint32 m_hiCorpseGuid; - - uint32 m_hiPetNumber; - - QuestMap mQuestTemplates; - - typedef HM_NAMESPACE::hash_map GossipTextMap; - typedef HM_NAMESPACE::hash_map QuestAreaTriggerMap; - typedef HM_NAMESPACE::hash_map BattleMastersMap; - typedef HM_NAMESPACE::hash_map ItemTextMap; - typedef std::set TavernAreaTriggerSet; - typedef std::set GameObjectForQuestSet; - - GroupSet mGroupSet; - GuildSet mGuildSet; - ArenaTeamSet mArenaTeamSet; - - ItemMap mItems; - ItemMap mAitems; - - ItemTextMap mItemTexts; - - AuctionHouseObject mHordeAuctions; - AuctionHouseObject mAllianceAuctions; - AuctionHouseObject mNeutralAuctions; - - QuestAreaTriggerMap mQuestAreaTriggerMap; - BattleMastersMap mBattleMastersMap; - TavernAreaTriggerSet mTavernAreaTriggerSet; - GameObjectForQuestSet mGameObjectForQuestSet; - GossipTextMap mGossipText; - AreaTriggerMap mAreaTriggers; - AreaTriggerScriptMap mAreaTriggerScripts; - - RepOnKillMap mRepOnKill; - - WeatherZoneMap mWeatherZoneMap; - - PetCreateSpellMap mPetCreateSpell; - - //character reserved names - typedef std::set ReservedNamesMap; - ReservedNamesMap m_ReservedNames; - - GraveYardMap mGraveYardMap; - - typedef std::vector LocalForIndex; - LocalForIndex m_LocalForIndex; - int GetOrNewIndexForLocale(LocaleConstant loc); - - int DBCLocaleIndex; - private: - void LoadScripts(ScriptMapMap& scripts, char const* tablename); - void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr); - void LoadQuestRelationsHelper(QuestRelations& map,char const* table); - - typedef std::map PetLevelInfoMap; - // PetLevelInfoMap[creature_id][level] - PetLevelInfoMap petInfo; // [creature_id][level] - - PlayerClassInfo playerClassInfo[MAX_CLASSES]; - - void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const; - PlayerInfo playerInfo[MAX_RACES][MAX_CLASSES]; - - typedef std::map BaseXPMap; // [area level][base xp] - BaseXPMap mBaseXPTable; - - typedef std::map FishingBaseSkillMap; // [areaId][base skill level] - FishingBaseSkillMap mFishingBaseForArea; - - typedef std::map > HalfNameMap; - HalfNameMap PetHalfName0; - HalfNameMap PetHalfName1; - - MapObjectGuids mMapObjectGuids; - CreatureDataMap mCreatureDataMap; - CreatureLocaleMap mCreatureLocaleMap; - GameObjectDataMap mGameObjectDataMap; - GameObjectLocaleMap mGameObjectLocaleMap; - ItemLocaleMap mItemLocaleMap; - QuestLocaleMap mQuestLocaleMap; - NpcTextLocaleMap mNpcTextLocaleMap; - PageTextLocaleMap mPageTextLocaleMap; - MangosStringLocaleMap mMangosStringLocaleMap; - RespawnTimes mCreatureRespawnTimes; - RespawnTimes mGORespawnTimes; - - typedef std::vector GuildBankTabPriceMap; - GuildBankTabPriceMap mGuildBankTabPrice; - - // Storage for Conditions. First element (index 0) is reserved for zero-condition (nothing required) - typedef std::vector ConditionStore; - ConditionStore mConditions; - -}; - -#define objmgr MaNGOS::Singleton::Instance() -#endif - -// scripting access functions -bool MANGOS_DLL_SPEC LoadMangosStrings(DatabaseType& db, char const* table); -MANGOS_DLL_SPEC const char* GetAreaTriggerScriptNameById(uint32 id); +/* + * Copyright (C) 2005-2008 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 _OBJECTMGR_H +#define _OBJECTMGR_H + +#include "Log.h" +#include "Object.h" +#include "Bag.h" +#include "Creature.h" +#include "Player.h" +#include "DynamicObject.h" +#include "GameObject.h" +#include "Corpse.h" +#include "QuestDef.h" +#include "Path.h" +#include "ItemPrototype.h" +#include "NPCHandler.h" +#include "Database/DatabaseEnv.h" +#include "AuctionHouseObject.h" +#include "Mail.h" +#include "Map.h" +#include "ObjectAccessor.h" +#include "ObjectDefines.h" +#include "Policies/Singleton.h" +#include "Database/SQLStorage.h" + +#include +#include +#include + +extern SQLStorage sCreatureStorage; +extern SQLStorage sCreatureDataAddonStorage; +extern SQLStorage sCreatureInfoAddonStorage; +extern SQLStorage sCreatureModelStorage; +extern SQLStorage sEquipmentStorage; +extern SQLStorage sGOStorage; +extern SQLStorage sPageTextStore; +extern SQLStorage sItemStorage; +extern SQLStorage sInstanceTemplate; + +class Group; +class Guild; +class ArenaTeam; +class Path; +class TransportPath; +class Item; + +struct GameTele +{ + float position_x; + float position_y; + float position_z; + float orientation; + uint32 mapId; + std::string name; + std::wstring wnameLow; +}; + +typedef HM_NAMESPACE::hash_map GameTeleMap; + +struct ScriptInfo +{ + uint32 id; + uint32 delay; + uint32 command; + uint32 datalong; + uint32 datalong2; + std::string datatext; + float x; + float y; + float z; + float o; +}; + +typedef std::multimap ScriptMap; +typedef std::map ScriptMapMap; +extern ScriptMapMap sQuestEndScripts; +extern ScriptMapMap sQuestStartScripts; +extern ScriptMapMap sSpellScripts; +extern ScriptMapMap sGameObjectScripts; +extern ScriptMapMap sEventScripts; + +struct AreaTrigger +{ + uint8 requiredLevel; + uint32 requiredItem; + uint32 requiredItem2; + uint32 heroicKey; + uint32 heroicKey2; + uint32 requiredQuest; + std::string requiredFailedText; + uint32 target_mapId; + float target_X; + float target_Y; + float target_Z; + float target_Orientation; +}; + +typedef std::set CellGuidSet; +typedef std::map CellCorpseSet; +struct CellObjectGuids +{ + CellGuidSet creatures; + CellGuidSet gameobjects; + CellCorpseSet corpses; +}; +typedef HM_NAMESPACE::hash_map CellObjectGuidsMap; +typedef HM_NAMESPACE::hash_map MapObjectGuids; + +typedef HM_NAMESPACE::hash_map RespawnTimes; + +struct MangosStringLocale +{ + std::vector Content; // 0 -> default, i -> i-1 locale index +}; + +typedef HM_NAMESPACE::hash_map CreatureDataMap; +typedef HM_NAMESPACE::hash_map GameObjectDataMap; +typedef HM_NAMESPACE::hash_map CreatureLocaleMap; +typedef HM_NAMESPACE::hash_map GameObjectLocaleMap; +typedef HM_NAMESPACE::hash_map ItemLocaleMap; +typedef HM_NAMESPACE::hash_map QuestLocaleMap; +typedef HM_NAMESPACE::hash_map NpcTextLocaleMap; +typedef HM_NAMESPACE::hash_map PageTextLocaleMap; +typedef HM_NAMESPACE::hash_map MangosStringLocaleMap; + +typedef std::multimap QuestRelations; + +struct PetLevelInfo +{ + PetLevelInfo() : health(0), mana(0) { for(int i=0; i < MAX_STATS; ++i ) stats[i] = 0; } + + uint16 stats[MAX_STATS]; + uint16 health; + uint16 mana; + uint16 armor; +}; + +struct ReputationOnKillEntry +{ + uint32 repfaction1; + uint32 repfaction2; + bool is_teamaward1; + uint32 reputation_max_cap1; + int32 repvalue1; + bool is_teamaward2; + uint32 reputation_max_cap2; + int32 repvalue2; + bool team_dependent; +}; + +struct PetCreateSpellEntry +{ + uint32 spellid[4]; +}; + +#define WEATHER_SEASONS 4 +struct WeatherSeasonChances +{ + uint32 rainChance; + uint32 snowChance; + uint32 stormChance; +}; + +struct WeatherZoneChances +{ + WeatherSeasonChances data[WEATHER_SEASONS]; +}; + +struct GraveYardData +{ + uint32 safeLocId; + uint32 team; +}; +typedef std::multimap GraveYardMap; + +enum ConditionType +{ // value1 value2 for the Condition enumed + CONDITION_NONE = 0, // 0 0 + CONDITION_AURA = 1, // spell_id effindex + CONDITION_ITEM = 2, // item_id count + CONDITION_ITEM_EQUIPPED = 3, // item_id 0 + CONDITION_ZONEID = 4, // zone_id 0 + CONDITION_REPUTATION_RANK = 5, // faction_id min_rank + CONDITION_TEAM = 6, // player_team 0, (469 - Alliance 67 - Horde) + CONDITION_SKILL = 7, // skill_id skill_value + CONDITION_QUESTREWARDED = 8, // quest_id 0 + CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active. + CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD ñommission aura active +}; + +#define MAX_CONDITION 11 // maximum value in ConditionType enum + +struct PlayerCondition +{ + ConditionType condition; // additional condition type + uint32 value1; // data for the condition - see ConditionType definition + uint32 value2; + + PlayerCondition(uint8 _condition = 0, uint32 _value1 = 0, uint32 _value2 = 0) + : condition(ConditionType(_condition)), value1(_value1), value2(_value2) {} + + static bool IsValid(ConditionType condition, uint32 value1, uint32 value2); + // Checks correctness of values + bool Meets(Player const * APlayer) const; // Checks if the player meets the condition + bool operator == (PlayerCondition const& lc) const + { + return (lc.condition == condition && lc.value1 == value1 && lc.value2 == value2); + } +}; + +// NPC gossip text id +typedef HM_NAMESPACE::hash_map CacheNpcTextIdMap; + +// Vendors +struct VendorItem +{ + uint32 item; + uint32 maxcount; + uint32 incrtime; + uint32 ExtendedCost; +}; +typedef std::vector VendorItemList; + +typedef HM_NAMESPACE::hash_map CacheVendorItemMap; + +typedef HM_NAMESPACE::hash_map CacheTrainerSpellMap; + +enum SkillRangeType +{ + SKILL_RANGE_LANGUAGE, // 300..300 + SKILL_RANGE_LEVEL, // 1..max skill for level + SKILL_RANGE_MONO, // 1..1, grey monolite bar + SKILL_RANGE_RANK, // 1..skill for known rank + SKILL_RANGE_NONE, // 0..0 always +}; + +SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial); + +#define MAX_PLAYER_NAME 12 // max allowed by client name length +#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length ( > MAX_PLAYER_NAME for support declined names ) + +bool normalizePlayerName(std::string& name); + +class PlayerDumpReader; + +class ObjectMgr +{ + friend class PlayerDumpReader; + + public: + ObjectMgr(); + ~ObjectMgr(); + + typedef HM_NAMESPACE::hash_map ItemMap; + + typedef std::set< Group * > GroupSet; + typedef std::set< Guild * > GuildSet; + typedef std::set< ArenaTeam * > ArenaTeamSet; + + typedef HM_NAMESPACE::hash_map QuestMap; + + typedef HM_NAMESPACE::hash_map AreaTriggerMap; + + typedef HM_NAMESPACE::hash_map AreaTriggerScriptMap; + + typedef HM_NAMESPACE::hash_map RepOnKillMap; + + typedef HM_NAMESPACE::hash_map WeatherZoneMap; + + typedef HM_NAMESPACE::hash_map PetCreateSpellMap; + + Player* GetPlayer(const char* name) const { return ObjectAccessor::Instance().FindPlayerByName(name);} + Player* GetPlayer(uint64 guid) const { return ObjectAccessor::FindPlayer(guid); } + + static GameObjectInfo const *GetGameObjectInfo(uint32 id) { return sGOStorage.LookupEntry(id); } + + void LoadGameobjectInfo(); + void AddGameobjectInfo(GameObjectInfo *goinfo); + + Group * GetGroupByLeader(const uint64 &guid) const; + void AddGroup(Group* group) { mGroupSet.insert( group ); } + void RemoveGroup(Group* group) { mGroupSet.erase( group ); } + + Guild* GetGuildByLeader(uint64 const&guid) const; + Guild* GetGuildById(const uint32 GuildId) const; + Guild* GetGuildByName(std::string guildname) const; + std::string GetGuildNameById(const uint32 GuildId) const; + void AddGuild(Guild* guild) { mGuildSet.insert( guild ); } + void RemoveGuild(Guild* guild) { mGuildSet.erase( guild ); } + + ArenaTeam* GetArenaTeamById(const uint32 ArenaTeamId) const; + ArenaTeam* GetArenaTeamByName(std::string ArenaTeamName) const; + ArenaTeam* GetArenaTeamByCapitan(uint64 const& guid) const; + void AddArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.insert( arenateam ); } + void RemoveArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.erase( arenateam ); } + + static CreatureInfo const *GetCreatureTemplate( uint32 id ); + CreatureModelInfo const *GetCreatureModelInfo( uint32 modelid ); + CreatureModelInfo const* GetCreatureModelRandomGender(uint32 display_id); + uint32 ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data = NULL); + EquipmentInfo const *GetEquipmentInfo( uint32 entry ); + static CreatureDataAddon const *GetCreatureAddon( uint32 lowguid ) + { + return sCreatureDataAddonStorage.LookupEntry(lowguid); + } + + static CreatureDataAddon const *GetCreatureTemplateAddon( uint32 entry ) + { + return sCreatureInfoAddonStorage.LookupEntry(entry); + } + + static ItemPrototype const* GetItemPrototype(uint32 id) { return sItemStorage.LookupEntry(id); } + + static InstanceTemplate const* GetInstanceTemplate(uint32 map) + { + return sInstanceTemplate.LookupEntry(map); + } + + Item* GetAItem(uint32 id) + { + ItemMap::const_iterator itr = mAitems.find(id); + if (itr != mAitems.end()) + { + return itr->second; + } + return NULL; + } + void AddAItem(Item* it) + { + ASSERT( it ); + ASSERT( mAitems.find(it->GetGUIDLow()) == mAitems.end()); + mAitems[it->GetGUIDLow()] = it; + } + bool RemoveAItem(uint32 id) + { + ItemMap::iterator i = mAitems.find(id); + if (i == mAitems.end()) + { + return false; + } + mAitems.erase(i); + return true; + } + AuctionHouseObject * GetAuctionsMap( uint32 location ); + + //auction messages + void SendAuctionWonMail( AuctionEntry * auction ); + void SendAuctionSalePendingMail( AuctionEntry * auction ); + void SendAuctionSuccessfulMail( AuctionEntry * auction ); + void SendAuctionExpiredMail( AuctionEntry * auction ); + static uint32 GetAuctionCut( uint32 location, uint32 highBid ); + static uint32 GetAuctionDeposit(uint32 location, uint32 time, Item *pItem); + static uint32 GetAuctionOutBid(uint32 currentBid); + + PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint32 level) const; + + PlayerClassInfo const* GetPlayerClassInfo(uint32 class_) const + { + if(class_ >= MAX_CLASSES) return NULL; + return &playerClassInfo[class_]; + } + void GetPlayerClassLevelInfo(uint32 class_,uint32 level, PlayerClassLevelInfo* info) const; + + PlayerInfo const* GetPlayerInfo(uint32 race, uint32 class_) const + { + if(race >= MAX_RACES) return NULL; + if(class_ >= MAX_CLASSES) return NULL; + PlayerInfo const* info = &playerInfo[race][class_]; + if(info->displayId_m==0 || info->displayId_f==0) return NULL; + return info; + } + void GetPlayerLevelInfo(uint32 race, uint32 class_,uint32 level, PlayerLevelInfo* info) const; + + uint64 GetPlayerGUIDByName(std::string name) const; + bool GetPlayerNameByGUID(const uint64 &guid, std::string &name) const; + uint32 GetPlayerTeamByGUID(const uint64 &guid) const; + uint32 GetPlayerAccountIdByGUID(const uint64 &guid) const; + uint32 GetSecurityByAccount(uint32 acc_id) const; + bool GetAccountNameByAccount(uint32 acc_id, std::string &name) const; + uint32 GetAccountByAccountName(std::string name) const; + + uint32 GetNearestTaxiNode( float x, float y, float z, uint32 mapid ); + void GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost); + uint16 GetTaxiMount( uint32 id, uint32 team ); + void GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector& mapIds ); + void GetTransportPathNodes( uint32 path, TransportPath &pathnodes ); + + Quest const* GetQuestTemplate(uint32 quest_id) const + { + QuestMap::const_iterator itr = mQuestTemplates.find(quest_id); + return itr != mQuestTemplates.end() ? itr->second : NULL; + } + QuestMap const& GetQuestTemplates() const { return mQuestTemplates; } + + uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const + { + QuestAreaTriggerMap::const_iterator itr = mQuestAreaTriggerMap.find(Trigger_ID); + if(itr != mQuestAreaTriggerMap.end()) + return itr->second; + return 0; + } + bool IsTavernAreaTrigger(uint32 Trigger_ID) const { return mTavernAreaTriggerSet.count(Trigger_ID) != 0; } + bool IsGameObjectForQuests(uint32 entry) const { return mGameObjectForQuestSet.count(entry) != 0; } + bool IsGuildVaultGameObject(Player *player, uint64 guid) const + { + if(GameObject *go = ObjectAccessor::GetGameObject(*player, guid)) + if(go->GetGoType() == GAMEOBJECT_TYPE_GUILD_BANK) + return true; + return false; + } + + uint32 GetBattleMasterBG(uint32 entry) const + { + BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry); + if(itr != mBattleMastersMap.end()) + return itr->second; + return 2; //BATTLEGROUND_WS - i will not add include only for constant usage! + } + + void AddGossipText(GossipText *pGText); + GossipText *GetGossipText(uint32 Text_ID); + + WorldSafeLocsEntry const *GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team); + bool AddGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = true); + void LoadGraveyardZones(); + GraveYardData const* FindGraveYardData(uint32 id, uint32 zone); + + AreaTrigger const* GetAreaTrigger(uint32 trigger) const + { + AreaTriggerMap::const_iterator itr = mAreaTriggers.find( trigger ); + if( itr != mAreaTriggers.end( ) ) + return &itr->second; + return NULL; + } + + AreaTrigger const* GetGoBackTrigger(uint32 Map) const; + + const char* GetAreaTriggerScriptName(uint32 id); + + ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const + { + RepOnKillMap::const_iterator itr = mRepOnKill.find(id); + if(itr != mRepOnKill.end()) + return &itr->second; + return NULL; + } + + PetCreateSpellEntry const* GetPetCreateSpellEntry(uint32 id) const + { + PetCreateSpellMap::const_iterator itr = mPetCreateSpell.find(id); + if(itr != mPetCreateSpell.end()) + return &itr->second; + return NULL; + } + + void LoadGuilds(); + void LoadArenaTeams(); + void LoadGroups(); + void LoadQuests(); + void LoadQuestRelations() + { + LoadGameobjectQuestRelations(); + LoadGameobjectInvolvedRelations(); + LoadCreatureQuestRelations(); + LoadCreatureInvolvedRelations(); + } + void LoadGameobjectQuestRelations(); + void LoadGameobjectInvolvedRelations(); + void LoadCreatureQuestRelations(); + void LoadCreatureInvolvedRelations(); + + QuestRelations mGOQuestRelations; + QuestRelations mGOQuestInvolvedRelations; + QuestRelations mCreatureQuestRelations; + QuestRelations mCreatureQuestInvolvedRelations; + + void LoadGameObjectScripts(); + void LoadQuestEndScripts(); + void LoadQuestStartScripts(); + void LoadEventScripts(); + void LoadSpellScripts(); + + bool LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); + bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase,"mangos_string",1,std::numeric_limits::max()); } + void LoadPetCreateSpells(); + void LoadCreatureLocales(); + void LoadCreatureTemplates(); + void LoadCreatures(); + void LoadCreatureRespawnTimes(); + void LoadCreatureAddons(); + void LoadCreatureModelInfo(); + void LoadEquipmentTemplates(); + void LoadGameObjectLocales(); + void LoadGameobjects(); + void LoadGameobjectRespawnTimes(); + void LoadItemPrototypes(); + void LoadItemLocales(); + void LoadQuestLocales(); + void LoadNpcTextLocales(); + void LoadPageTextLocales(); + void LoadInstanceTemplate(); + + void LoadGossipText(); + + void LoadAreaTriggerTeleports(); + void LoadQuestAreaTriggers(); + void LoadAreaTriggerScripts(); + void LoadTavernAreaTriggers(); + void LoadBattleMastersEntry(); + void LoadGameObjectForQuests(); + + void LoadItemTexts(); + void LoadPageTexts(); + + //load first auction items, because of check if item exists, when loading + void LoadAuctionItems(); + void LoadAuctions(); + void LoadPlayerInfo(); + void LoadPetLevelInfo(); + void LoadExplorationBaseXP(); + void LoadPetNames(); + void LoadPetNumber(); + void LoadCorpses(); + void LoadFishingBaseSkillLevel(); + + void LoadReputationOnKill(); + + void LoadWeatherZoneChances(); + void LoadGameTele(); + + void LoadNpcTextId(); + void LoadVendors(); + void LoadTrainerSpell(); + + std::string GeneratePetName(uint32 entry); + uint32 GetBaseXP(uint32 level); + + int32 GetFishingBaseSkillLevel(uint32 entry) const + { + FishingBaseSkillMap::const_iterator itr = mFishingBaseForArea.find(entry); + return itr != mFishingBaseForArea.end() ? itr->second : 0; + } + + void ReturnOrDeleteOldMails(bool serverUp); + + void SetHighestGuids(); + uint32 GenerateLowGuid(HighGuid guidhigh); + uint32 GenerateAuctionID(); + uint32 GenerateMailID(); + uint32 GenerateItemTextID(); + uint32 GeneratePetNumber(); + + uint32 CreateItemText(std::string text); + std::string GetItemText( uint32 id ) + { + ItemTextMap::const_iterator itr = mItemTexts.find( id ); + if ( itr != mItemTexts.end() ) + return itr->second; + else + return "There is no info for this item"; + } + + typedef std::multimap ExclusiveQuestGroups; + ExclusiveQuestGroups mExclusiveQuestGroups; + + WeatherZoneChances const* GetWeatherChances(uint32 zone_id) const + { + WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id); + if(itr != mWeatherZoneMap.end()) + return &itr->second; + else + return NULL; + } + + CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id) + { + return mMapObjectGuids[MAKE_PAIR32(mapid,spawnMode)][cell_id]; + } + + CreatureData const* GetCreatureData(uint32 guid) const + { + CreatureDataMap::const_iterator itr = mCreatureDataMap.find(guid); + if(itr==mCreatureDataMap.end()) return NULL; + return &itr->second; + } + CreatureData& NewOrExistCreatureData(uint32 guid) { return mCreatureDataMap[guid]; } + void DeleteCreatureData(uint32 guid); + CreatureLocale const* GetCreatureLocale(uint32 entry) const + { + CreatureLocaleMap::const_iterator itr = mCreatureLocaleMap.find(entry); + if(itr==mCreatureLocaleMap.end()) return NULL; + return &itr->second; + } + GameObjectLocale const* GetGameObjectLocale(uint32 entry) const + { + GameObjectLocaleMap::const_iterator itr = mGameObjectLocaleMap.find(entry); + if(itr==mGameObjectLocaleMap.end()) return NULL; + return &itr->second; + } + ItemLocale const* GetItemLocale(uint32 entry) const + { + ItemLocaleMap::const_iterator itr = mItemLocaleMap.find(entry); + if(itr==mItemLocaleMap.end()) return NULL; + return &itr->second; + } + QuestLocale const* GetQuestLocale(uint32 entry) const + { + QuestLocaleMap::const_iterator itr = mQuestLocaleMap.find(entry); + if(itr==mQuestLocaleMap.end()) return NULL; + return &itr->second; + } + NpcTextLocale const* GetNpcTextLocale(uint32 entry) const + { + NpcTextLocaleMap::const_iterator itr = mNpcTextLocaleMap.find(entry); + if(itr==mNpcTextLocaleMap.end()) return NULL; + return &itr->second; + } + PageTextLocale const* GetPageTextLocale(uint32 entry) const + { + PageTextLocaleMap::const_iterator itr = mPageTextLocaleMap.find(entry); + if(itr==mPageTextLocaleMap.end()) return NULL; + return &itr->second; + } + + GameObjectData const* GetGOData(uint32 guid) const + { + GameObjectDataMap::const_iterator itr = mGameObjectDataMap.find(guid); + if(itr==mGameObjectDataMap.end()) return NULL; + return &itr->second; + } + GameObjectData& NewGOData(uint32 guid) { return mGameObjectDataMap[guid]; } + void DeleteGOData(uint32 guid); + + MangosStringLocale const* GetMangosStringLocale(int32 entry) const + { + MangosStringLocaleMap::const_iterator itr = mMangosStringLocaleMap.find(entry); + if(itr==mMangosStringLocaleMap.end()) return NULL; + return &itr->second; + } + const char *GetMangosString(int32 entry, int locale_idx) const; + const char *GetMangosStringForDBCLocale(int32 entry) const { return GetMangosString(entry,DBCLocaleIndex); } + void SetDBCLocaleIndex(uint32 lang) { DBCLocaleIndex = GetIndexForLocale(LocaleConstant(lang)); } + + void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance); + void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid); + + time_t GetCreatureRespawnTime(uint32 loguid, uint32 instance) { return mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)]; } + void SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t); + time_t GetGORespawnTime(uint32 loguid, uint32 instance) { return mGORespawnTimes[MAKE_PAIR64(loguid,instance)]; } + void SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t); + void DeleteRespawnTimeForInstance(uint32 instance); + + // grid objects + void AddCreatureToGrid(uint32 guid, CreatureData const* data); + void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data); + void AddGameobjectToGrid(uint32 guid, GameObjectData const* data); + void RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data); + + // reserved names + void LoadReservedPlayersNames(); + bool IsReservedName(std::string name) const + { + return m_ReservedNames.find(name) != m_ReservedNames.end(); + } + + // name with valid structure and symbols + static bool IsValidName( std::string name, bool create = false ); + static bool IsValidCharterName( std::string name ); + static bool IsValidPetName( std::string name ); + + static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names); + + int GetIndexForLocale(LocaleConstant loc); + LocaleConstant GetLocaleForIndex(int i); + // guild bank tabs + const uint32 GetGuildBankTabPrice(uint8 Index) { return Index < GUILD_BANK_MAX_TABS ? mGuildBankTabPrice[Index] : 0; } + + uint16 GetConditionId(ConditionType condition, uint32 value1, uint32 value2); + bool IsPlayerMeetToCondition(Player const* player, uint16 condition_id) const + { + if(condition_id >= mConditions.size()) + return false; + + return mConditions[condition_id].Meets(player); + } + + GameTele const* GetGameTele(uint32 id) const + { + GameTeleMap::const_iterator itr = m_GameTeleMap.find(id); + if(itr==m_GameTeleMap.end()) return NULL; + return &itr->second; + } + GameTele const* GetGameTele(std::string name) const; + GameTeleMap const& GetGameTeleMap() const { return m_GameTeleMap; } + bool AddGameTele(GameTele& data); + bool DeleteGameTele(std::string name); + + uint32 GetNpcGossip(uint32 entry) const + { + CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry); + if(iter == m_mCacheNpcTextIdMap.end()) + return 0; + + return iter->second; + } + + TrainerSpellData const* GetNpcTrainerSpells(uint32 entry) const + { + CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerSpellMap.find(entry); + if(iter == m_mCacheTrainerSpellMap.end()) + return NULL; + + return &iter->second; + } + + VendorItemList const* GetNpcVendorItemList(uint32 entry) const + { + CacheVendorItemMap::const_iterator iter = m_mCacheVendorItemMap.find(entry); + if(iter == m_mCacheVendorItemMap.end()) + return NULL; + + return &iter->second; + } + protected: + uint32 m_auctionid; + uint32 m_mailid; + uint32 m_ItemTextId; + + uint32 m_hiCharGuid; + uint32 m_hiCreatureGuid; + uint32 m_hiPetGuid; + uint32 m_hiItemGuid; + uint32 m_hiGoGuid; + uint32 m_hiDoGuid; + uint32 m_hiCorpseGuid; + + uint32 m_hiPetNumber; + + QuestMap mQuestTemplates; + + typedef HM_NAMESPACE::hash_map GossipTextMap; + typedef HM_NAMESPACE::hash_map QuestAreaTriggerMap; + typedef HM_NAMESPACE::hash_map BattleMastersMap; + typedef HM_NAMESPACE::hash_map ItemTextMap; + typedef std::set TavernAreaTriggerSet; + typedef std::set GameObjectForQuestSet; + + GroupSet mGroupSet; + GuildSet mGuildSet; + ArenaTeamSet mArenaTeamSet; + + ItemMap mItems; + ItemMap mAitems; + + ItemTextMap mItemTexts; + + AuctionHouseObject mHordeAuctions; + AuctionHouseObject mAllianceAuctions; + AuctionHouseObject mNeutralAuctions; + + QuestAreaTriggerMap mQuestAreaTriggerMap; + BattleMastersMap mBattleMastersMap; + TavernAreaTriggerSet mTavernAreaTriggerSet; + GameObjectForQuestSet mGameObjectForQuestSet; + GossipTextMap mGossipText; + AreaTriggerMap mAreaTriggers; + AreaTriggerScriptMap mAreaTriggerScripts; + + RepOnKillMap mRepOnKill; + + WeatherZoneMap mWeatherZoneMap; + + PetCreateSpellMap mPetCreateSpell; + + //character reserved names + typedef std::set ReservedNamesMap; + ReservedNamesMap m_ReservedNames; + + GraveYardMap mGraveYardMap; + + GameTeleMap m_GameTeleMap; + + typedef std::vector LocalForIndex; + LocalForIndex m_LocalForIndex; + int GetOrNewIndexForLocale(LocaleConstant loc); + + int DBCLocaleIndex; + private: + void LoadScripts(ScriptMapMap& scripts, char const* tablename); + void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr); + void LoadQuestRelationsHelper(QuestRelations& map,char const* table); + + typedef std::map PetLevelInfoMap; + // PetLevelInfoMap[creature_id][level] + PetLevelInfoMap petInfo; // [creature_id][level] + + PlayerClassInfo playerClassInfo[MAX_CLASSES]; + + void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const; + PlayerInfo playerInfo[MAX_RACES][MAX_CLASSES]; + + typedef std::map BaseXPMap; // [area level][base xp] + BaseXPMap mBaseXPTable; + + typedef std::map FishingBaseSkillMap; // [areaId][base skill level] + FishingBaseSkillMap mFishingBaseForArea; + + typedef std::map > HalfNameMap; + HalfNameMap PetHalfName0; + HalfNameMap PetHalfName1; + + MapObjectGuids mMapObjectGuids; + CreatureDataMap mCreatureDataMap; + CreatureLocaleMap mCreatureLocaleMap; + GameObjectDataMap mGameObjectDataMap; + GameObjectLocaleMap mGameObjectLocaleMap; + ItemLocaleMap mItemLocaleMap; + QuestLocaleMap mQuestLocaleMap; + NpcTextLocaleMap mNpcTextLocaleMap; + PageTextLocaleMap mPageTextLocaleMap; + MangosStringLocaleMap mMangosStringLocaleMap; + RespawnTimes mCreatureRespawnTimes; + RespawnTimes mGORespawnTimes; + + typedef std::vector GuildBankTabPriceMap; + GuildBankTabPriceMap mGuildBankTabPrice; + + // Storage for Conditions. First element (index 0) is reserved for zero-condition (nothing required) + typedef std::vector ConditionStore; + ConditionStore mConditions; + + CacheNpcTextIdMap m_mCacheNpcTextIdMap; + CacheVendorItemMap m_mCacheVendorItemMap; + CacheTrainerSpellMap m_mCacheTrainerSpellMap; +}; + +#define objmgr MaNGOS::Singleton::Instance() + +// scripting access functions +bool MANGOS_DLL_SPEC LoadMangosStrings(DatabaseType& db, char const* table,int32 start_value = -1, int32 end_value = std::numeric_limits::min()); +MANGOS_DLL_SPEC const char* GetAreaTriggerScriptNameById(uint32 id); + +#endif diff --git a/src/game/Player.cpp b/src/game/Player.cpp index f93b44ba732..9ba6404cb5f 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -1,18130 +1,18133 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Language.h" -#include "Database/DatabaseEnv.h" -#include "Log.h" -#include "Opcodes.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "UpdateMask.h" -#include "Player.h" -#include "SkillDiscovery.h" -#include "QuestDef.h" -#include "GossipDef.h" -#include "UpdateData.h" -#include "Channel.h" -#include "ChannelMgr.h" -#include "MapManager.h" -#include "MapInstanced.h" -#include "InstanceSaveMgr.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "CellImpl.h" -#include "ObjectMgr.h" -#include "ObjectAccessor.h" -#include "CreatureAI.h" -#include "Formulas.h" -#include "Group.h" -#include "Guild.h" -#include "Pet.h" -#include "SpellAuras.h" -#include "Util.h" -#include "Transports.h" -#include "Weather.h" -#include "BattleGround.h" -#include "BattleGroundMgr.h" -#include "ArenaTeam.h" -#include "Chat.h" -#include "Database/DatabaseImpl.h" -#include "Spell.h" -#include "SocialMgr.h" - -#include - -#define ZONE_UPDATE_INTERVAL 1000 - -#define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3)) -#define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1) -#define PLAYER_SKILL_BONUS_INDEX(x) (PLAYER_SKILL_INDEX(x)+2) - -#define SKILL_VALUE(x) PAIR32_LOPART(x) -#define SKILL_MAX(x) PAIR32_HIPART(x) -#define MAKE_SKILL_VALUE(v, m) MAKE_PAIR32(v,m) - -#define SKILL_TEMP_BONUS(x) int16(PAIR32_LOPART(x)) -#define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x)) -#define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t,p) - -enum CharacterFlags -{ - CHARACTER_FLAG_NONE = 0x00000000, - CHARACTER_FLAG_UNK1 = 0x00000001, - CHARACTER_FLAG_UNK2 = 0x00000002, - CHARACTER_LOCKED_FOR_TRANSFER = 0x00000004, - CHARACTER_FLAG_UNK4 = 0x00000008, - CHARACTER_FLAG_UNK5 = 0x00000010, - CHARACTER_FLAG_UNK6 = 0x00000020, - CHARACTER_FLAG_UNK7 = 0x00000040, - CHARACTER_FLAG_UNK8 = 0x00000080, - CHARACTER_FLAG_UNK9 = 0x00000100, - CHARACTER_FLAG_UNK10 = 0x00000200, - CHARACTER_FLAG_HIDE_HELM = 0x00000400, - CHARACTER_FLAG_HIDE_CLOAK = 0x00000800, - CHARACTER_FLAG_UNK13 = 0x00001000, - CHARACTER_FLAG_GHOST = 0x00002000, - CHARACTER_FLAG_RENAME = 0x00004000, - CHARACTER_FLAG_UNK16 = 0x00008000, - CHARACTER_FLAG_UNK17 = 0x00010000, - CHARACTER_FLAG_UNK18 = 0x00020000, - CHARACTER_FLAG_UNK19 = 0x00040000, - CHARACTER_FLAG_UNK20 = 0x00080000, - CHARACTER_FLAG_UNK21 = 0x00100000, - CHARACTER_FLAG_UNK22 = 0x00200000, - CHARACTER_FLAG_UNK23 = 0x00400000, - CHARACTER_FLAG_UNK24 = 0x00800000, - CHARACTER_FLAG_LOCKED_BY_BILLING = 0x01000000, - CHARACTER_FLAG_DECLINED = 0x02000000, - CHARACTER_FLAG_UNK27 = 0x04000000, - CHARACTER_FLAG_UNK28 = 0x08000000, - CHARACTER_FLAG_UNK29 = 0x10000000, - CHARACTER_FLAG_UNK30 = 0x20000000, - CHARACTER_FLAG_UNK31 = 0x40000000, - CHARACTER_FLAG_UNK32 = 0x80000000 -}; - -// corpse reclaim times -#define DEATH_EXPIRE_STEP (5*MINUTE) -#define MAX_DEATH_COUNT 3 - -static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 }; - -//== PlayerTaxi ================================================ - -PlayerTaxi::PlayerTaxi() -{ - // Taxi nodes - memset(m_taximask, 0, sizeof(m_taximask)); -} - -void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 level) -{ - // capital and taxi hub masks - switch(race) - { - case RACE_HUMAN: SetTaximaskNode(2); break; // Human - case RACE_ORC: SetTaximaskNode(23); break; // Orc - case RACE_DWARF: SetTaximaskNode(6); break; // Dwarf - case RACE_NIGHTELF: SetTaximaskNode(26); - SetTaximaskNode(27); break; // Night Elf - case RACE_UNDEAD_PLAYER: SetTaximaskNode(11); break;// Undead - case RACE_TAUREN: SetTaximaskNode(22); break; // Tauren - case RACE_GNOME: SetTaximaskNode(6); break; // Gnome - case RACE_TROLL: SetTaximaskNode(23); break; // Troll - case RACE_BLOODELF: SetTaximaskNode(82); break; // Blood Elf - case RACE_DRAENEI: SetTaximaskNode(94); break; // Draenei - } - // new continent starting masks (It will be accessible only at new map) - switch(Player::TeamForRace(race)) - { - case ALLIANCE: SetTaximaskNode(100); break; - case HORDE: SetTaximaskNode(99); break; - } - // level dependent taxi hubs - if(level>=68) - SetTaximaskNode(213); //Shattered Sun Staging Area -} - -void PlayerTaxi::LoadTaxiMask(const char* data) -{ - Tokens tokens = StrSplit(data, " "); - - int index; - Tokens::iterator iter; - for (iter = tokens.begin(), index = 0; - (index < TaxiMaskSize) && (iter != tokens.end()); ++iter, ++index) - { - // load and set bits only for existed taxi nodes - m_taximask[index] = sTaxiNodesMask[index] & uint32(atol((*iter).c_str())); - } -} - -void PlayerTaxi::AppendTaximaskTo( ByteBuffer& data, bool all ) -{ - if(all) - { - for (uint8 i=0; ic_str())); - AddTaxiDestination(node); - } - - if(m_TaxiDestinations.empty()) - return true; - - // Check integrity - if(m_TaxiDestinations.size() < 2) - return false; - - for(size_t i = 1; i < m_TaxiDestinations.size(); ++i) - { - uint32 cost; - uint32 path; - objmgr.GetTaxiPath(m_TaxiDestinations[i-1],m_TaxiDestinations[i],path,cost); - if(!path) - return false; - } - - return true; -} - -std::string PlayerTaxi::SaveTaxiDestinationsToString() -{ - if(m_TaxiDestinations.empty()) - return ""; - - std::ostringstream ss; - - for(size_t i=0; i < m_TaxiDestinations.size(); ++i) - ss << m_TaxiDestinations[i] << " "; - - return ss.str(); -} - -uint32 PlayerTaxi::GetCurrentTaxiPath() const -{ - if(m_TaxiDestinations.size() < 2) - return 0; - - uint32 path; - uint32 cost; - - objmgr.GetTaxiPath(m_TaxiDestinations[0],m_TaxiDestinations[1],path,cost); - - return path; -} - -//== Player ==================================================== - -const int32 Player::ReputationRank_Length[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000}; - -UpdateMask Player::updateVisualBits; - -Player::Player (WorldSession *session): Unit() -{ - m_transport = 0; - - m_speakTime = 0; - m_speakCount = 0; - - m_objectType |= TYPEMASK_PLAYER; - m_objectTypeId = TYPEID_PLAYER; - - m_valuesCount = PLAYER_END; - - m_session = session; - - m_divider = 0; - - m_ExtraFlags = 0; - if(GetSession()->GetSecurity() >= SEC_GAMEMASTER) - SetAcceptTicket(true); - - // players always and GM if set in config accept whispers by default - if(GetSession()->GetSecurity() == SEC_PLAYER || sWorld.getConfig(CONFIG_GM_WISPERING_TO)) - SetAcceptWhispers(true); - - m_curSelection = 0; - m_lootGuid = 0; - - m_comboTarget = 0; - m_comboPoints = 0; - - m_usedTalentCount = 0; - - m_regenTimer = 0; - m_weaponChangeTimer = 0; - - m_zoneUpdateId = 0; - m_zoneUpdateTimer = 0; - - m_areaUpdateId = 0; - - m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE); - - // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE] - // this must help in case next save after mass player load after server startup - m_nextSave = urand(m_nextSave/2,m_nextSave*3/2); - - clearResurrectRequestData(); - - m_SpellModRemoveCount = 0; - - memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT); - - m_social = NULL; - - // group is initialized in the reference constructor - SetGroupInvite(NULL); - m_groupUpdateMask = 0; - m_auraUpdateMask = 0; - - duel = NULL; - - m_GuildIdInvited = 0; - m_ArenaTeamIdInvited = 0; - - m_atLoginFlags = AT_LOGIN_NONE; - - m_dontMove = false; - - pTrader = 0; - ClearTrade(); - - m_cinematic = 0; - - PlayerTalkClass = new PlayerMenu( GetSession() ); - m_currentBuybackSlot = BUYBACK_SLOT_START; - - for ( int aX = 0 ; aX < 8 ; aX++ ) - m_Tutorials[ aX ] = 0x00; - m_TutorialsChanged = false; - - m_DailyQuestChanged = false; - m_lastDailyQuestTime = 0; - - m_regenTimer = 0; - m_weaponChangeTimer = 0; - m_breathTimer = 0; - m_isunderwater = 0; - m_isInWater = false; - m_drunkTimer = 0; - m_drunk = 0; - m_restTime = 0; - m_deathTimer = 0; - m_deathExpireTime = 0; - - m_swingErrorMsg = 0; - - m_DetectInvTimer = 1000; - - m_bgBattleGroundID = 0; - for (int j=0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; j++) - { - m_bgBattleGroundQueueID[j].bgType = 0; - m_bgBattleGroundQueueID[j].invited = false; - } - m_bgTeam = 0; - - m_logintime = time(NULL); - m_Last_tick = m_logintime; - m_WeaponProficiency = 0; - m_ArmorProficiency = 0; - m_canParry = false; - m_canDualWield = false; - m_ammoDPS = 0.0f; - - m_temporaryUnsummonedPetNumber = 0; - //cache for UNIT_CREATED_BY_SPELL to allow - //returning reagests for temporarily removed pets - //when dying/logging out - m_oldpetspell = 0; - - ////////////////////Rest System///////////////////// - time_inn_enter=0; - inn_pos_mapid=0; - inn_pos_x=0; - inn_pos_y=0; - inn_pos_z=0; - m_rest_bonus=0; - rest_type=REST_TYPE_NO; - ////////////////////Rest System///////////////////// - - m_mailsLoaded = false; - m_mailsUpdated = false; - unReadMails = 0; - m_nextMailDelivereTime = 0; - - m_resetTalentsCost = 0; - m_resetTalentsTime = 0; - m_itemUpdateQueueBlocked = false; - - for (int i = 0; i < MAX_MOVE_TYPE; ++i) - m_forced_speed_changes[i] = 0; - - m_stableSlots = 0; - - /////////////////// Instance System ///////////////////// - - m_HomebindTimer = 0; - m_InstanceValid = true; - m_dungeonDifficulty = DIFFICULTY_NORMAL; - - for (int i = 0; i < BASEMOD_END; i++) - { - m_auraBaseMod[i][FLAT_MOD] = 0.0f; - m_auraBaseMod[i][PCT_MOD] = 1.0f; - } - - // Honor System - m_lastHonorUpdateTime = time(NULL); - - // Player summoning - m_summon_expire = 0; - m_summon_mapid = 0; - m_summon_x = 0.0f; - m_summon_y = 0.0f; - m_summon_z = 0.0f; - - //Default movement to run mode - m_unit_movement_flags = 0; - - m_miniPet = 0; - m_bgAfkReportedTimer = 0; - m_contestedPvPTimer = 0; - - m_declinedname = NULL; -} - -Player::~Player () -{ - CleanupsBeforeDelete(); - - if(m_uint32Values) // only for fully created Object - { - sSocialMgr.RemovePlayerSocial(GetGUIDLow()); - } - - // Note: buy back item already deleted from DB when player was saved - for(int i = 0; i < PLAYER_SLOTS_COUNT; ++i) - { - if(m_items[i]) - delete m_items[i]; - } - CleanupChannels(); - - for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - delete itr->second; - - //all mailed items should be deleted, also all mail should be deallocated - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end();++itr) - delete *itr; - - for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter) - delete iter->second; //if item is duplicated... then server may crash ... but that item should be deallocated - - delete PlayerTalkClass; - - if (m_transport) - { - m_transport->RemovePassenger(this); - } - - for(size_t x = 0; x < ItemSetEff.size(); x++) - if(ItemSetEff[x]) - delete ItemSetEff[x]; - - // clean up player-instance binds, may unload some instance saves - for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) - for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) - itr->second.save->RemovePlayer(this); - - delete m_declinedname; -} - -void Player::CleanupsBeforeDelete() -{ - if(m_uint32Values) // only for fully created Object - { - TradeCancel(false); - DuelComplete(DUEL_INTERUPTED); - } - Unit::CleanupsBeforeDelete(); -} - -bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair, uint8 outfitId ) -{ - Object::_Create(guidlow, 0, HIGHGUID_PLAYER); - - m_name = name; - - PlayerInfo const* info = objmgr.GetPlayerInfo(race, class_); - if(!info) - { - sLog.outError("Player have incorrect race/class pair. Can't be loaded."); - return false; - } - - for (int i = 0; i < PLAYER_SLOTS_COUNT; i++) - m_items[i] = NULL; - - //for(int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; j++) - //{ - // SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1+j*2,0); - // SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1+j,0); - // SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1+j,0); - //} - - m_race = race; - m_class = class_; - - SetMapId(info->mapId); - Relocate(info->positionX,info->positionY,info->positionZ); - - ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(class_); - if(!cEntry) - { - sLog.outError("Class %u not found in DBC (Wrong DBC files?)",class_); - return false; - } - - uint8 powertype = cEntry->powerType; - - uint32 unitfield; - - switch(powertype) - { - case POWER_ENERGY: - case POWER_MANA: - unitfield = 0x00000000; - break; - case POWER_RAGE: - unitfield = 0x00110000; - break; - default: - sLog.outError("Invalid default powertype %u for player (class %u)",powertype,class_); - return false; - } - - SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE ); - SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f ); - - switch(gender) - { - case GENDER_FEMALE: - SetDisplayId(info->displayId_f ); - SetNativeDisplayId(info->displayId_f ); - break; - case GENDER_MALE: - SetDisplayId(info->displayId_m ); - SetNativeDisplayId(info->displayId_m ); - break; - default: - sLog.outError("Invalid gender %u for player",gender); - return false; - break; - } - - setFactionForRace(m_race); - - SetUInt32Value(UNIT_FIELD_BYTES_0, ( ( race ) | ( class_ << 8 ) | ( gender << 16 ) | ( powertype << 24 ) ) ); - SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield); - SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK3 | UNIT_BYTE2_FLAG_UNK5 ); - SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE ); - SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); // fix cast time showed in spell tooltip on client - - //-1 is default value - SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); - - SetUInt32Value(PLAYER_BYTES, (skin | (face << 8) | (hairStyle << 16) | (hairColor << 24))); - SetUInt32Value(PLAYER_BYTES_2, (facialHair | (0x00 << 8) | (0x00 << 16) | (0x02 << 24))); - SetByteValue(PLAYER_BYTES_3, 0, gender); - - SetUInt32Value( PLAYER_GUILDID, 0 ); - SetUInt32Value( PLAYER_GUILDRANK, 0 ); - SetUInt32Value( PLAYER_GUILD_TIMESTAMP, 0 ); - - SetUInt64Value( PLAYER__FIELD_KNOWN_TITLES, 0 ); // 0=disabled - SetUInt32Value( PLAYER_CHOSEN_TITLE, 0 ); - SetUInt32Value( PLAYER_FIELD_KILLS, 0 ); - SetUInt32Value( PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 0 ); - SetUInt32Value( PLAYER_FIELD_TODAY_CONTRIBUTION, 0 ); - SetUInt32Value( PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0 ); - - // set starting level - SetUInt32Value( UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) ); - - // Played time - m_Last_tick = time(NULL); - m_Played_time[0] = 0; - m_Played_time[1] = 0; - - // base stats and related field values - InitStatsForLevel(); - InitTaxiNodesForLevel(); - InitTalentForLevel(); - InitPrimaryProffesions(); // to max set before any spell added - - // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods() - UpdateMaxHealth(); // Update max Health (for add bonus from stamina) - SetHealth(GetMaxHealth()); - if (getPowerType()==POWER_MANA) - { - UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intelect) - SetPower(POWER_MANA,GetMaxPower(POWER_MANA)); - } - - learnDefaultSpells(true); - - std::list::const_iterator action_itr[4]; - for(int i=0; i<4; i++) - action_itr[i] = info->action[i].begin(); - - for (; action_itr[0]!=info->action[0].end() && action_itr[1]!=info->action[1].end();) - { - uint16 taction[4]; - for(int i=0; i<4 ;i++) - taction[i] = (*action_itr[i]); - - addActionButton((uint8)taction[0], taction[1], (uint8)taction[2], (uint8)taction[3]); - - for(int i=0; i<4 ;i++) - ++action_itr[i]; - } - - UpdateBlockPercentage(); - - for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr!=info->item.end(); ++item_id_itr++) - { - uint32 titem_id = item_id_itr->item_id; - uint32 titem_amount = item_id_itr->item_amount; - - sLog.outDebug("STORAGE: Creating initial item, itemId = %u, count = %u",titem_id, titem_amount); - - // attempt equip - uint16 eDest; - uint8 msg = CanEquipNewItem( NULL_SLOT, eDest, titem_id, titem_amount, false ); - if( msg == EQUIP_ERR_OK ) - { - EquipNewItem( eDest, titem_id, titem_amount, true); - AutoUnequipOffhandIfNeed(); - continue; // equipped, to next - } - - // attempt store - ItemPosCountVec sDest; - // store in main bag to simplify second pass (special bags can be not equipped yet at this moment) - msg = CanStoreNewItem( INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount ); - if( msg == EQUIP_ERR_OK ) - { - StoreNewItem( sDest, titem_id, true, Item::GenerateItemRandomPropertyId(titem_id) ); - continue; // stored, to next - } - - // item can't be added - sLog.outError("STORAGE: Can't equip or store initial item %u for race %u class %u , error msg = %u",titem_id,race,class_,msg); - } - - // bags and main-hand weapon must equipped at this moment - // now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon) - // or ammo not equipped in special bag - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - if(Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - { - uint16 eDest; - // equip offhand weapon/shield if it attempt equipped before main-hand weapon - uint8 msg = CanEquipItem( NULL_SLOT, eDest, pItem, false ); - if( msg == EQUIP_ERR_OK ) - { - RemoveItem(INVENTORY_SLOT_BAG_0, i,true); - EquipItem( eDest, pItem, true); - } - // move other items to more appropriate slots (ammo not equipped in special bag) - else - { - ItemPosCountVec sDest; - msg = CanStoreItem( NULL_BAG, NULL_SLOT, sDest, pItem, false ); - if( msg == EQUIP_ERR_OK ) - { - RemoveItem(INVENTORY_SLOT_BAG_0, i,true); - pItem = StoreItem( sDest, pItem, true); - } - - // if this is ammo then use it - uint8 msg = CanUseAmmo( pItem->GetProto()->ItemId ); - if( msg == EQUIP_ERR_OK ) - SetAmmo( pItem->GetProto()->ItemId ); - } - } - } - // all item positions resolved - - return true; -} - -void Player::StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue) -{ - uint32 BreathRegen = (uint32)-1; - - WorldPacket data(SMSG_START_MIRROR_TIMER, (21)); - data << (uint32)Type; - data << MaxValue; - data << MaxValue; - data << BreathRegen; - data << (uint8)0; - data << (uint32)0; // spell id - GetSession()->SendPacket(&data); -} - -void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen) -{ - if(Type==BREATH_TIMER) - m_breathTimer = ((MaxValue + 1000) - CurrentValue) / Regen; - - WorldPacket data(SMSG_START_MIRROR_TIMER, (21)); - data << (uint32)Type; - data << CurrentValue; - data << MaxValue; - data << Regen; - data << (uint8)0; - data << (uint32)0; // spell id - GetSession()->SendPacket( &data ); -} - -void Player::StopMirrorTimer(MirrorTimerType Type) -{ - if(Type==BREATH_TIMER) - m_breathTimer = 0; - - WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4); - data << (uint32)Type; - GetSession()->SendPacket( &data ); -} - -void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 damage) -{ - WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21)); - data << (uint64)guid; - data << (uint8)(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL); - data << (uint32)damage; - data << (uint32)0; - data << (uint32)0; - //m_session->SendPacket(&data); - //Let other players see that you get damage - SendMessageToSet(&data, true); - DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - if(type==DAMAGE_FALL && !isAlive()) // DealDamage not apply item durability loss at self damage - { - DEBUG_LOG("We are fall to death, loosing 10 percents durability"); - DurabilityLossAll(0.10f,false); - // durability lost message - WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); - GetSession()->SendPacket(&data); - } -} - -void Player::HandleDrowning() -{ - if(!m_isunderwater) - return; - - //if have water breath , then remove bar - if(waterbreath || isGameMaster() || !isAlive()) - { - StopMirrorTimer(BREATH_TIMER); - m_isunderwater = 0; - return; - } - - uint32 UnderWaterTime = 1*MINUTE*1000; // default leangthL 1 min - - AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING); - for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i) - UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f); - - if ((m_isunderwater & 0x01) && !(m_isunderwater & 0x80) && isAlive()) - { - //single trigger timer - if (!(m_isunderwater & 0x02)) - { - m_isunderwater|= 0x02; - m_breathTimer = UnderWaterTime + 1000; - } - //single trigger "Breathbar" - if ( m_breathTimer <= UnderWaterTime && !(m_isunderwater & 0x04)) - { - m_isunderwater|= 0x04; - StartMirrorTimer(BREATH_TIMER, UnderWaterTime); - } - //continius trigger drowning "Damage" - if ((m_breathTimer == 0) && (m_isunderwater & 0x01)) - { - //TODO: Check this formula - uint64 guid = GetGUID(); - uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); - - EnvironmentalDamage(guid, DAMAGE_DROWNING,damage); - m_breathTimer = 2000; - } - } - //single trigger retract bar - else if (!(m_isunderwater & 0x01) && !(m_isunderwater & 0x08) && (m_isunderwater & 0x02) && (m_breathTimer > 0) && isAlive()) - { - m_isunderwater = 0x08; - - uint32 BreathRegen = 10; - ModifyMirrorTimer(BREATH_TIMER, UnderWaterTime, m_breathTimer,BreathRegen); - m_isunderwater = 0x10; - } - //remove bar - else if ((m_breathTimer < 50) && !(m_isunderwater & 0x01) && (m_isunderwater == 0x10)) - { - StopMirrorTimer(BREATH_TIMER); - m_isunderwater = 0; - } -} - -void Player::HandleLava() -{ - bool ValidArea = false; - - if ((m_isunderwater & 0x80) && isAlive()) - { - //Single trigger Set BreathTimer - if (!(m_isunderwater & 0x80)) - { - m_isunderwater|= 0x04; - m_breathTimer = 1000; - } - //Reset BreathTimer and still in the lava - if (!m_breathTimer) - { - uint64 guid = GetGUID(); - uint32 damage = urand(600, 700); // TODO: Get more detailed information about lava damage - uint32 dmgZone = GetZoneId(); // TODO: Find correct "lava dealing zone" flag in Area Table - - // Deal lava damage only in lava zones. - switch(dmgZone) - { - case 0x8D: - ValidArea = false; - break; - case 0x94: - ValidArea = false; - break; - case 0x2CE: - ValidArea = false; - break; - case 0x2CF: - ValidArea = false; - break; - default: - if (dmgZone / 5 & 0x408) - ValidArea = true; - } - - // if is valid area and is not gamemaster then deal damage - if ( ValidArea && !isGameMaster() ) - EnvironmentalDamage(guid, DAMAGE_LAVA, damage); - - m_breathTimer = 1000; - } - - } - //Death timer disabled and WaterFlags reset - else if (m_deathState == DEAD) - { - m_breathTimer = 0; - m_isunderwater = 0; - } -} - -///The player sobers by 256 every 10 seconds -void Player::HandleSobering() -{ - m_drunkTimer = 0; - - uint32 drunk = (m_drunk <= 256) ? 0 : (m_drunk - 256); - SetDrunkValue(drunk); -} - -DrunkenState Player::GetDrunkenstateByValue(uint16 value) -{ - if(value >= 23000) - return DRUNKEN_SMASHED; - if(value >= 12800) - return DRUNKEN_DRUNK; - if(value & 0xFFFE) - return DRUNKEN_TIPSY; - return DRUNKEN_SOBER; -} - -void Player::SetDrunkValue(uint16 newDrunkenValue, uint32 itemId) -{ - uint32 oldDrunkenState = Player::GetDrunkenstateByValue(m_drunk); - - m_drunk = newDrunkenValue; - SetUInt32Value(PLAYER_BYTES_3,(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | (m_drunk & 0xFFFE)); - - uint32 newDrunkenState = Player::GetDrunkenstateByValue(m_drunk); - - // special drunk invisibility detection - if(newDrunkenState >= DRUNKEN_DRUNK) - m_detectInvisibilityMask |= (1<<6); - else - m_detectInvisibilityMask &= ~(1<<6); - - if(newDrunkenState == oldDrunkenState) - return; - - WorldPacket data(SMSG_CROSSED_INEBRIATION_THRESHOLD, (8+4+4)); - data << GetGUID(); - data << uint32(newDrunkenState); - data << uint32(itemId); - - SendMessageToSet(&data, true); -} - -void Player::Update( uint32 p_time ) -{ - if(!IsInWorld()) - return; - - // undelivered mail - if(m_nextMailDelivereTime && m_nextMailDelivereTime <= time(NULL)) - { - SendNewMail(); - ++unReadMails; - - // It will be recalculate at mailbox open (for unReadMails important non-0 until mailbox open, it also will be recalculated) - m_nextMailDelivereTime = 0; - } - - Unit::Update( p_time ); - - // update player only attacks - if(uint32 ranged_att = getAttackTimer(RANGED_ATTACK)) - { - setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time) ); - } - - if(uint32 off_att = getAttackTimer(OFF_ATTACK)) - { - setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time) ); - } - - time_t now = time (NULL); - - UpdatePvPFlag(now); - - UpdateContestedPvP(p_time); - - UpdateDuelFlag(now); - - CheckDuelDistance(now); - - UpdateAfkReport(now); - - CheckExploreSystem(); - - // Update items that have just a limited lifetime - if (now>m_Last_tick) - UpdateItemDuration(uint32(now- m_Last_tick)); - - if (!m_timedquests.empty()) - { - std::set::iterator iter = m_timedquests.begin(); - while (iter != m_timedquests.end()) - { - QuestStatusData& q_status = mQuestStatus[*iter]; - if( q_status.m_timer <= p_time ) - { - uint32 quest_id = *iter; - ++iter; // current iter will be removed in FailTimedQuest - FailTimedQuest( quest_id ); - } - else - { - q_status.m_timer -= p_time; - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - ++iter; - } - } - } - - if (hasUnitState(UNIT_STAT_MELEE_ATTACKING)) - { - Unit *pVictim = getVictim(); - if( !IsNonMeleeSpellCasted(false) && pVictim) - { - // default combat reach 10 - // TODO add weapon,skill check - - float pldistance = ATTACK_DISTANCE; - - if (isAttackReady(BASE_ATTACK)) - { - if(!IsWithinDistInMap(pVictim, pldistance)) - { - setAttackTimer(BASE_ATTACK,100); - if(m_swingErrorMsg != 1) // send single time (client auto repeat) - { - SendAttackSwingNotInRange(); - m_swingErrorMsg = 1; - } - } - //120 degrees of radiant range - else if( !HasInArc( 2*M_PI/3, pVictim )) - { - setAttackTimer(BASE_ATTACK,100); - if(m_swingErrorMsg != 2) // send single time (client auto repeat) - { - SendAttackSwingBadFacingAttack(); - m_swingErrorMsg = 2; - } - } - else - { - m_swingErrorMsg = 0; // reset swing error state - - // prevent base and off attack in same time, delay attack at 0.2 sec - if(haveOffhandWeapon()) - { - uint32 off_att = getAttackTimer(OFF_ATTACK); - if(off_att < ATTACK_DISPLAY_DELAY) - setAttackTimer(OFF_ATTACK,ATTACK_DISPLAY_DELAY); - } - AttackerStateUpdate(pVictim, BASE_ATTACK); - resetAttackTimer(BASE_ATTACK); - } - } - - if ( haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) - { - if(!IsWithinDistInMap(pVictim, pldistance)) - { - setAttackTimer(OFF_ATTACK,100); - } - else if( !HasInArc( 2*M_PI/3, pVictim )) - { - setAttackTimer(OFF_ATTACK,100); - } - else - { - // prevent base and off attack in same time, delay attack at 0.2 sec - uint32 base_att = getAttackTimer(BASE_ATTACK); - if(base_att < ATTACK_DISPLAY_DELAY) - setAttackTimer(BASE_ATTACK,ATTACK_DISPLAY_DELAY); - // do attack - AttackerStateUpdate(pVictim, OFF_ATTACK); - resetAttackTimer(OFF_ATTACK); - } - } - - Unit *owner = pVictim->GetOwner(); - Unit *u = owner ? owner : pVictim; - if(u->IsPvP() && (!duel || duel->opponent != u)) - { - UpdatePvP(true); - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - } - } - } - - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) - { - if(roll_chance_i(3) && GetTimeInnEnter() > 0) //freeze update - { - int time_inn = time(NULL)-GetTimeInnEnter(); - if (time_inn >= 10) //freeze update - { - float bubble = 0.125*sWorld.getRate(RATE_REST_INGAME); - //speed collect rest bonus (section/in hour) - SetRestBonus( GetRestBonus()+ time_inn*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble ); - UpdateInnerTime(time(NULL)); - } - } - } - - if(m_regenTimer > 0) - { - if(p_time >= m_regenTimer) - m_regenTimer = 0; - else - m_regenTimer -= p_time; - } - - if (m_weaponChangeTimer > 0) - { - if(p_time >= m_weaponChangeTimer) - m_weaponChangeTimer = 0; - else - m_weaponChangeTimer -= p_time; - } - - if (m_zoneUpdateTimer > 0) - { - if(p_time >= m_zoneUpdateTimer) - { - uint32 newzone = GetZoneId(); - if( m_zoneUpdateId != newzone ) - UpdateZone(newzone); // also update area - else - { - // use area updates as well - // needed for free far all arenas for example - uint32 newarea = GetAreaId(); - if( m_areaUpdateId != newarea ) - UpdateArea(newarea); - - m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; - } - } - else - m_zoneUpdateTimer -= p_time; - } - - if (isAlive()) - { - RegenerateAll(); - } - - if (m_deathState == JUST_DIED) - { - KillPlayer(); - } - - if(m_nextSave > 0) - { - if(p_time >= m_nextSave) - { - // m_nextSave reseted in SaveToDB call - SaveToDB(); - sLog.outDetail("Player '%s' (GUID: %u) saved", GetName(), GetGUIDLow()); - } - else - { - m_nextSave -= p_time; - } - } - - //Breathtimer - if(m_breathTimer > 0) - { - if(p_time >= m_breathTimer) - m_breathTimer = 0; - else - m_breathTimer -= p_time; - - } - - //Handle Water/drowning - HandleDrowning(); - - //Handle lava - HandleLava(); - - //Handle detect stealth players - if (m_DetectInvTimer > 0) - { - if (p_time >= m_DetectInvTimer) - { - m_DetectInvTimer = 3000; - HandleStealthedUnitsDetection(); - } - else - m_DetectInvTimer -= p_time; - } - - // Played time - if (now > m_Last_tick) - { - uint32 elapsed = uint32(now - m_Last_tick); - m_Played_time[0] += elapsed; // Total played time - m_Played_time[1] += elapsed; // Level played time - m_Last_tick = now; - } - - if (m_drunk) - { - m_drunkTimer += p_time; - - if (m_drunkTimer > 10000) - HandleSobering(); - } - - // not auto-free ghost from body in instances - if(m_deathTimer > 0 && !GetBaseMap()->Instanceable()) - { - if(p_time >= m_deathTimer) - { - m_deathTimer = 0; - BuildPlayerRepop(); - RepopAtGraveyard(); - } - else - m_deathTimer -= p_time; - } - - UpdateEnchantTime(p_time); - UpdateHomebindTime(p_time); - - // group update - SendUpdateToOutOfRangeGroupMembers(); - - Pet* pet = GetPet(); - if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE)) - { - RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true); - return; - } -} - -void Player::setDeathState(DeathState s) -{ - uint32 ressSpellId = 0; - - bool cur = isAlive(); - - if(s == JUST_DIED && cur) - { - // drunken state is cleared on death - SetDrunkValue(0); - // lost combo points at any target (targeted combo points clear in Unit::setDeathState) - ClearComboPoints(); - - clearResurrectRequestData(); - - // remove form before other mods to prevent incorrect stats calculation - RemoveAurasDueToSpell(m_ShapeShiftFormSpellId); - - //FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequestOpcode and define pet unsummon here with (s == DEAD) - RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); - - // remove uncontrolled pets - RemoveMiniPet(); - RemoveGuardians(); - - // save value before aura remove in Unit::setDeathState - ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL); - - // passive spell - if(!ressSpellId) - ressSpellId = GetResurrectionSpellId(); - } - Unit::setDeathState(s); - - // restore resurrection spell id for player after aura remove - if(s == JUST_DIED && cur && ressSpellId) - SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); - - if(isAlive() && !cur) - { - //clear aura case after resurrection by another way (spells will be applied before next death) - SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); - - // restore default warrior stance - if(getClass()== CLASS_WARRIOR) - CastSpell(this,SPELL_ID_PASSIVE_BATTLE_STANCE,true); - } -} - -void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) -{ - *p_data << GetGUID(); - *p_data << m_name; - - *p_data << getRace(); - uint8 pClass = getClass(); - *p_data << pClass; - *p_data << getGender(); - - uint32 bytes = GetUInt32Value(PLAYER_BYTES); - *p_data << uint8(bytes); - *p_data << uint8(bytes >> 8); - *p_data << uint8(bytes >> 16); - *p_data << uint8(bytes >> 24); - - bytes = GetUInt32Value(PLAYER_BYTES_2); - *p_data << uint8(bytes); - - *p_data << uint8(getLevel()); // player level - // do not use GetMap! it will spawn a new instance since the bound instances are not loaded - uint32 zoneId = MapManager::Instance().GetZoneId(GetMapId(), GetPositionX(),GetPositionY()); - - *p_data << zoneId; - *p_data << GetMapId(); - - *p_data << GetPositionX(); - *p_data << GetPositionY(); - *p_data << GetPositionZ(); - - *p_data << GetUInt32Value(PLAYER_GUILDID); // guild id - - uint32 char_flags = 0; - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) - char_flags |= CHARACTER_FLAG_HIDE_HELM; - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) - char_flags |= CHARACTER_FLAG_HIDE_CLOAK; - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - char_flags |= CHARACTER_FLAG_GHOST; - if(HasAtLoginFlag(AT_LOGIN_RENAME)) - char_flags |= CHARACTER_FLAG_RENAME; - // always send the flag if declined names aren't used - // to let the client select a default method of declining the name - if(!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) || (result && result->Fetch()[12].GetCppString() != "")) - char_flags |= CHARACTER_FLAG_DECLINED; - - *p_data << (uint32)char_flags; // character flags - - *p_data << (uint8)1; // unknown - - // Pets info - { - uint32 petDisplayId = 0; - uint32 petLevel = 0; - uint32 petFamily = 0; - - // show pet at selection character in character list only for non-ghost character - if(result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER)) - { - Field* fields = result->Fetch(); - - uint32 entry = fields[9].GetUInt32(); - CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(entry); - if(cInfo) - { - petDisplayId = fields[10].GetUInt32(); - petLevel = fields[11].GetUInt32(); - petFamily = cInfo->family; - } - } - - *p_data << (uint32)petDisplayId; - *p_data << (uint32)petLevel; - *p_data << (uint32)petFamily; - } - - /*ItemPrototype const *items[EQUIPMENT_SLOT_END]; - for (int i = 0; i < EQUIPMENT_SLOT_END; i++) - items[i] = NULL; - - QueryResult *result = CharacterDatabase.PQuery("SELECT slot,item_template FROM character_inventory WHERE guid = '%u' AND bag = 0",GetGUIDLow()); - if (result) - { - do - { - Field *fields = result->Fetch(); - uint8 slot = fields[0].GetUInt8() & 255; - uint32 item_id = fields[1].GetUInt32(); - if( slot >= EQUIPMENT_SLOT_END ) - continue; - - items[slot] = objmgr.GetItemPrototype(item_id); - if(!items[slot]) - { - sLog.outError( "Player::BuildEnumData: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id ); - continue; - } - } while (result->NextRow()); - delete result; - }*/ - - for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++) - { - uint32 visualbase = PLAYER_VISIBLE_ITEM_1_0 + (slot * MAX_VISIBLE_ITEM_OFFSET); - uint32 item_id = GetUInt32Value(visualbase); - const ItemPrototype * proto = objmgr.GetItemPrototype(item_id); - SpellItemEnchantmentEntry const *enchant = NULL; - - for(uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot<=TEMP_ENCHANTMENT_SLOT; enchantSlot++) - { - uint32 enchantId = GetUInt32Value(visualbase+1+enchantSlot); - if(enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId)) - break; - } - - if (proto != NULL) - { - *p_data << (uint32)proto->DisplayInfoID; - *p_data << (uint8)proto->InventoryType; - *p_data << (uint32)(enchant?enchant->aura_id:0); - } - else - { - *p_data << (uint32)0; - *p_data << (uint8)0; - *p_data << (uint32)0; // enchant? - } - } - *p_data << (uint32)0; // first bag display id - *p_data << (uint8)0; // first bag inventory type - *p_data << (uint32)0; // enchant? -} - -bool Player::ToggleAFK() -{ - ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); - - bool state = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); - - // afk player not allowed in battleground - if(state && InBattleGround()) - LeaveBattleground(); - - return state; -} - -bool Player::ToggleDND() -{ - ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); - - return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); -} - -uint8 Player::chatTag() const -{ - // it's bitmask - // 0x8 - ?? - // 0x4 - gm - // 0x2 - dnd - // 0x1 - afk - if(isGameMaster()) - return 4; - else if(isDND()) - return 3; - if(isAFK()) - return 1; - else - return 0; -} - -bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options) -{ - if(!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) - { - sLog.outError("TeleportTo: invalid map %d or absent instance template.", mapid); - return false; - } - - // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later) - Pet* pet = GetPet(); - - MapEntry const* mEntry = sMapStore.LookupEntry(mapid); - - // don't let enter battlegrounds without assigned battleground id (for example through areatrigger)... - if(!InBattleGround() && mEntry->IsBattleGround() && !GetSession()->GetSecurity()) - return false; - - bool tbc = GetSession()->IsTBC() && sWorld.getConfig(CONFIG_EXPANSION) > 0; - - // normal client and TBC map - if(!tbc && mEntry->IsExpansionMap()) - { - sLog.outDebug("Player %s using Normal client and tried teleport to non existing map %u", GetName(), mapid); - - if(GetTransport()) - RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) - - SendTransferAborted(mapid, TRANSFER_ABORT_INSUF_EXPAN_LVL1); - - return false; // normal client can't teleport to this map... - } - else if(tbc) // can teleport to any existing map - { - sLog.outDebug("Player %s have TBC client and will teleported to map %u", GetName(), mapid); - } - else - { - sLog.outDebug("Player %s have normal client and will teleported to standard map %u", GetName(), mapid); - } - /* - only TBC (no 0x80000 and 0x10 flags...) - 3604590=0x37006E=0x200000 + 0x100000 + 0x40000 + 0x20000 + 0x10000 + 0x40 + 0x20 + 0x8 + 0x4 + 0x2 - - Kharazan (normal/TBC??), but not have 0x10 flag (accessible by normal client?) - 4128878=0x3F006E=0x200000 + 0x100000 + 0x80000 + 0x40000 + 0x20000 + 0x10000 + 0x40 + 0x20 + 0x8 + 0x4 + 0x2 - - normal+TBC maps - 4128894=0x3F007E=0x200000 + 0x100000 + 0x80000 + 0x40000 + 0x20000 + 0x10000 + 0x40 + 0x20 + 0x10 + 0x8 + 0x4 + 0x2 - - normal+TBC maps - 8323198=0x7F007E=0x400000 + 0x200000 + 0x100000 + 0x80000 + 0x40000 + 0x20000 + 0x10000 + 0x40 + 0x20 + 0x10 + 0x8 + 0x4 + 0x2 - */ - - // if we were on a transport, leave - if (!(options & TELE_TO_NOT_LEAVE_TRANSPORT) && m_transport) - { - m_transport->RemovePassenger(this); - m_transport = NULL; - m_movementInfo.t_x = 0.0f; - m_movementInfo.t_y = 0.0f; - m_movementInfo.t_z = 0.0f; - m_movementInfo.t_o = 0.0f; - m_movementInfo.t_time = 0; - } - - SetSemaphoreTeleport(true); - - // The player was ported to another map and looses the duel immediatly. - // We have to perform this check before the teleport, otherwise the - // ObjectAccessor won't find the flag. - if (duel && this->GetMapId()!=mapid) - { - GameObject* obj = ObjectAccessor::GetGameObject(*this, GetUInt64Value(PLAYER_DUEL_ARBITER)); - if (obj) - DuelComplete(DUEL_FLED); - } - - // reset movement flags at teleport, because player will continue move with these flags after teleport - SetUnitMovementFlags(0); - - if ((this->GetMapId() == mapid) && (!m_transport)) - { - // prepare zone change detect - uint32 old_zone = GetZoneId(); - - // near teleport - if(!GetSession()->PlayerLogout()) - { - WorldPacket data; - BuildTeleportAckMsg(&data, x, y, z, orientation); - GetSession()->SendPacket(&data); - SetPosition( x, y, z, orientation, true); - } - else - // this will be used instead of the current location in SaveToDB - m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); - - //BuildHeartBeatMsg(&data); - //SendMessageToSet(&data, true); - if (!(options & TELE_TO_NOT_UNSUMMON_PET)) - { - //same map, only remove pet if out of range - if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE)) - { - if(pet->isControlled() && !pet->isTemporarySummoned() ) - m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); - else - m_temporaryUnsummonedPetNumber = 0; - - RemovePet(pet, PET_SAVE_NOT_IN_SLOT); - } - } - - if(!(options & TELE_TO_NOT_LEAVE_COMBAT)) - CombatStop(); - - if (!(options & TELE_TO_NOT_UNSUMMON_PET)) - { - // resummon pet - if(pet && m_temporaryUnsummonedPetNumber) - { - Pet* NewPet = new Pet; - if(!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true)) - delete NewPet; - - m_temporaryUnsummonedPetNumber = 0; - } - } - - SetSemaphoreTeleport(false); - - if(!GetSession()->PlayerLogout()) - UpdateZone(GetZoneId()); - - // new zone - if(old_zone != GetZoneId()) - { - // honorless target - if(pvpInfo.inHostileArea) - CastSpell(this, 2479, true); - } - } - else - { - // far teleport to another map - Map* oldmap = IsInWorld() ? MapManager::Instance().GetMap(GetMapId(), this) : NULL; - // check if we can enter before stopping combat / removing pet / totems / interrupting spells - - // Check enter rights before map getting to avoid creating instance copy for player - // this check not dependent from map instance copy and same for all instance copies of selected map - if (!MapManager::Instance().CanPlayerEnter(mapid, this)) - { - SetSemaphoreTeleport(false); - return false; - } - - // If the map is not created, assume it is possible to enter it. - // It will be created in the WorldPortAck. - Map *map = MapManager::Instance().FindMap(mapid); - if (!map || map->CanEnter(this)) - { - SetSelection(0); - - CombatStop(); - - ResetContestedPvP(); - - // remove player from battleground on far teleport (when changing maps) - if(BattleGround const* bg = GetBattleGround()) - { - // Note: at battleground join battleground id set before teleport - // and we already will found "current" battleground - // just need check that this is targeted map or leave - if(bg->GetMapId() != mapid) - LeaveBattleground(false); // don't teleport to entry point - } - - // remove pet on map change - if (pet) - { - //leaving map -> delete pet right away (doing this later will cause problems) - if(pet->isControlled() && !pet->isTemporarySummoned()) - m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); - else - m_temporaryUnsummonedPetNumber = 0; - - RemovePet(pet, PET_SAVE_NOT_IN_SLOT); - } - - // remove all dyn objects - RemoveAllDynObjects(); - - // stop spellcasting - // not attempt interrupt teleportation spell at caster teleport - if(!(options & TELE_TO_SPELL)) - if(IsNonMeleeSpellCasted(true)) - InterruptNonMeleeSpells(true); - - if(!GetSession()->PlayerLogout()) - { - // send transfer packets - WorldPacket data(SMSG_TRANSFER_PENDING, (4+4+4)); - data << uint32(mapid); - if (m_transport) - { - data << m_transport->GetEntry() << GetMapId(); - } - GetSession()->SendPacket(&data); - - data.Initialize(SMSG_NEW_WORLD, (20)); - if (m_transport) - { - data << (uint32)mapid << m_movementInfo.t_x << m_movementInfo.t_y << m_movementInfo.t_z << m_movementInfo.t_o; - } - else - { - data << (uint32)mapid << (float)x << (float)y << (float)z << (float)orientation; - } - GetSession()->SendPacket( &data ); - SendSavedInstances(); - - // remove from old map now - if(oldmap) oldmap->Remove(this, false); - } - - // new final coordinates - float final_x = x; - float final_y = y; - float final_z = z; - float final_o = orientation; - - if(m_transport) - { - final_x += m_movementInfo.t_x; - final_y += m_movementInfo.t_y; - final_z += m_movementInfo.t_z; - final_o += m_movementInfo.t_o; - } - - m_teleport_dest = WorldLocation(mapid, final_x, final_y, final_z, final_o); - // if the player is saved before worldportack (at logout for example) - // this will be used instead of the current location in SaveToDB - - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP); - - // move packet sent by client always after far teleport - // SetPosition(final_x, final_y, final_z, final_o, true); - SetDontMove(true); - - // code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet - } - else - return false; - } - return true; -} - -void Player::AddToWorld() -{ - ///- Do not add/remove the player from the object storage - ///- It will crash when updating the ObjectAccessor - ///- The player should only be added when logging in - Unit::AddToWorld(); - - for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++) - { - if(m_items[i]) - m_items[i]->AddToWorld(); - } -} - -void Player::RemoveFromWorld() -{ - // cleanup - if(IsInWorld()) - { - ///- Release charmed creatures, unsummon totems and remove pets/guardians - Uncharm(); - UnsummonAllTotems(); - RemoveMiniPet(); - RemoveGuardians(); - } - - for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++) - { - if(m_items[i]) - m_items[i]->RemoveFromWorld(); - } - - ///- Do not add/remove the player from the object storage - ///- It will crash when updating the ObjectAccessor - ///- The player should only be removed when logging out - Unit::RemoveFromWorld(); -} - -void Player::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ) -{ - float addRage; - - float rageconversion = ((0.0091107836 * getLevel()*getLevel())+3.225598133*getLevel())+4.2652911; - - if(attacker) - { - addRage = ((damage/rageconversion*7.5 + weaponSpeedHitFactor)/2); - - // talent who gave more rage on attack - addRage *= 1.0f + GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT) / 100.0f; - } - else - { - addRage = damage/rageconversion*2.5; - - // Berserker Rage effect - if(HasAura(18499,0)) - addRage *= 1.3; - } - - addRage *= sWorld.getRate(RATE_POWER_RAGE_INCOME); - - ModifyPower(POWER_RAGE, uint32(addRage*10)); -} - -void Player::RegenerateAll() -{ - if (m_regenTimer != 0) - return; - uint32 regenDelay = 2000; - - // Not in combat or they have regeneration - if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) || - HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT) || IsPolymorphed() ) - { - RegenerateHealth(); - if (!isInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN)) - Regenerate(POWER_RAGE); - } - - Regenerate( POWER_ENERGY ); - - Regenerate( POWER_MANA ); - - m_regenTimer = regenDelay; -} - -void Player::Regenerate(Powers power) -{ - uint32 curValue = GetPower(power); - uint32 maxValue = GetMaxPower(power); - - float addvalue = 0.0f; - - switch (power) - { - case POWER_MANA: - { - bool recentCast = IsUnderLastManaUseEffect(); - float ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA); - if (recentCast) - { - // Mangos Updates Mana in intervals of 2s, which is correct - addvalue = GetFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT) * ManaIncreaseRate * 2.00f; - } - else - { - addvalue = GetFloatValue(PLAYER_FIELD_MOD_MANA_REGEN) * ManaIncreaseRate * 2.00f; - } - } break; - case POWER_RAGE: // Regenerate rage - { - float RageDecreaseRate = sWorld.getRate(RATE_POWER_RAGE_LOSS); - addvalue = 30 * RageDecreaseRate; // 3 rage by tick - } break; - case POWER_ENERGY: // Regenerate energy (rogue) - addvalue = 20; - break; - case POWER_FOCUS: - case POWER_HAPPINESS: - break; - } - - // Mana regen calculated in Player::UpdateManaRegen() - // Exist only for POWER_MANA, POWER_ENERGY, POWER_FOCUS auras - if(power != POWER_MANA) - { - AuraList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT); - for(AuraList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i) - if ((*i)->GetModifier()->m_miscvalue == power) - addvalue *= ((*i)->GetModifier()->m_amount + 100) / 100.0f; - } - - if (power != POWER_RAGE) - { - curValue += uint32(addvalue); - if (curValue > maxValue) - curValue = maxValue; - } - else - { - if(curValue <= uint32(addvalue)) - curValue = 0; - else - curValue -= uint32(addvalue); - } - SetPower(power, curValue); -} - -void Player::RegenerateHealth() -{ - uint32 curValue = GetHealth(); - uint32 maxValue = GetMaxHealth(); - - if (curValue >= maxValue) return; - - float HealthIncreaseRate = sWorld.getRate(RATE_HEALTH); - - float addvalue = 0.0f; - - // polymorphed case - if ( IsPolymorphed() ) - addvalue = GetMaxHealth()/3; - // normal regen case (maybe partly in combat case) - else if (!isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) ) - { - addvalue = OCTRegenHPPerSpirit()* HealthIncreaseRate; - if (!isInCombat()) - { - AuraList const& mModHealthRegenPct = GetAurasByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT); - for(AuraList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i) - addvalue *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; - } - else if(HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT)) - addvalue *= GetTotalAuraModifier(SPELL_AURA_MOD_REGEN_DURING_COMBAT) / 100.0f; - - if(!IsStandState()) - addvalue *= 1.5; - } - - // always regeneration bonus (including combat) - addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT); - - if(addvalue < 0) - addvalue = 0; - - ModifyHealth(int32(addvalue)); -} - -bool Player::CanInteractWithNPCs(bool alive) const -{ - if(alive && !isAlive()) - return false; - if(isInFlight()) - return false; - - return true; -} - -bool Player::IsUnderWater() const -{ - return IsInWater() && - GetPositionZ() < (MapManager::Instance().GetBaseMap(GetMapId())->GetWaterLevel(GetPositionX(),GetPositionY())-2); -} - -void Player::SetInWater(bool apply) -{ - if(m_isInWater==apply) - return; - - //define player in water by opcodes - //move player's guid into HateOfflineList of those mobs - //which can't swim and move guid back into ThreatList when - //on surface. - //TODO: exist also swimming mobs, and function must be symmetric to enter/leave water - m_isInWater = apply; - - // remove auras that need water/land - RemoveAurasWithInterruptFlags(apply ? AURA_INTERRUPT_FLAG_NOT_ABOVEWATER : AURA_INTERRUPT_FLAG_NOT_UNDERWATER); - - getHostilRefManager().updateThreatTables(); -} - -void Player::SetGameMaster(bool on) -{ - if(on) - { - m_ExtraFlags |= PLAYER_EXTRA_GM_ON; - setFaction(35); - SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); - - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); - ResetContestedPvP(); - - getHostilRefManager().setOnlineOfflineState(false); - CombatStop(); - } - else - { - m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON; - setFactionForRace(getRace()); - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); - - // restore FFA PvP Server state - if(sWorld.IsFFAPvPRealm()) - SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); - - // restore FFA PvP area state, remove not allowed for GM mounts - UpdateArea(m_areaUpdateId); - - getHostilRefManager().setOnlineOfflineState(true); - } - - ObjectAccessor::UpdateVisibilityForPlayer(this); -} - -void Player::SetGMVisible(bool on) -{ - if(on) - { - m_ExtraFlags &= ~PLAYER_EXTRA_GM_INVISIBLE; //remove flag - - // Reapply stealth/invisibility if active or show if not any - if(HasAuraType(SPELL_AURA_MOD_STEALTH)) - SetVisibility(VISIBILITY_GROUP_STEALTH); - else if(HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) - SetVisibility(VISIBILITY_GROUP_INVISIBILITY); - else - SetVisibility(VISIBILITY_ON); - } - else - { - m_ExtraFlags |= PLAYER_EXTRA_GM_INVISIBLE; //add flag - - SetAcceptWhispers(false); - SetGameMaster(true); - - SetVisibility(VISIBILITY_OFF); - } -} - -bool Player::IsGroupVisibleFor(Player* p) const -{ - switch(sWorld.getConfig(CONFIG_GROUP_VISIBILITY)) - { - default: return IsInSameGroupWith(p); - case 1: return IsInSameRaidWith(p); - case 2: return GetTeam()==p->GetTeam(); - } -} - -bool Player::IsInSameGroupWith(Player const* p) const -{ - return p==this || GetGroup() != NULL && - GetGroup() == p->GetGroup() && - GetGroup()->SameSubGroup((Player*)this, (Player*)p); -} - -///- If the player is invited, remove him. If the group if then only 1 person, disband the group. -/// \todo Shouldn't we also check if there is no other invitees before disbanding the group? -void Player::UninviteFromGroup() -{ - if(GetGroupInvite()) // uninvited invitee - { - Group* group = GetGroupInvite(); - group->RemoveInvite(this); - - if(group->GetMembersCount() <= 1) // group has just 1 member => disband - { - if(group->IsCreated()) - { - group->Disband(true); - objmgr.RemoveGroup(group); - } - else - group->RemoveAllInvites(); - - delete group; - } - } -} - -void Player::RemoveFromGroup(Group* group, uint64 guid) -{ - if(group) - { - if (group->RemoveMember(guid, 0) <= 1) - { - // group->Disband(); already disbanded in RemoveMember - objmgr.RemoveGroup(group); - delete group; - // removemember sets the player's group pointer to NULL - } - } -} - -void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 RestXP) -{ - WorldPacket data(SMSG_LOG_XPGAIN, 21); - data << uint64(victim ? victim->GetGUID() : 0); // guid - data << uint32(GivenXP+RestXP); // given experience - data << uint8(victim ? 0 : 1); // 00-kill_xp type, 01-non_kill_xp type - if(victim) - { - data << uint32(GivenXP); // experience without rested bonus - data << float(1); // 1 - none 0 - 100% group bonus output - } - data << uint8(0); // new 2.4.0 - GetSession()->SendPacket(&data); -} - -void Player::GiveXP(uint32 xp, Unit* victim) -{ - if ( xp < 1 ) - return; - - if(!isAlive()) - return; - - uint32 level = getLevel(); - - // XP to money conversion processed in Player::RewardQuest - if(level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - return; - - // handle SPELL_AURA_MOD_XP_PCT auras - Unit::AuraList const& ModXPPctAuras = GetAurasByType(SPELL_AURA_MOD_XP_PCT); - for(Unit::AuraList::const_iterator i = ModXPPctAuras.begin();i != ModXPPctAuras.end(); ++i) - xp = uint32(xp*(1.0f + (*i)->GetModifier()->m_amount / 100.0f)); - - // XP resting bonus for kill - uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0; - - SendLogXPGain(xp,victim,rested_bonus_xp); - - uint32 curXP = GetUInt32Value(PLAYER_XP); - uint32 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); - uint32 newXP = curXP + xp + rested_bonus_xp; - - while( newXP >= nextLvlXP && level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) - { - newXP -= nextLvlXP; - - if ( level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) - GiveLevel(level + 1); - - level = getLevel(); - nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); - } - - SetUInt32Value(PLAYER_XP, newXP); -} - -// Update player to next level -// Current player experience not update (must be update by caller) -void Player::GiveLevel(uint32 level) -{ - if ( level == getLevel() ) - return; - - PlayerLevelInfo info; - objmgr.GetPlayerLevelInfo(getRace(),getClass(),level,&info); - - PlayerClassLevelInfo classInfo; - objmgr.GetPlayerClassLevelInfo(getClass(),level,&classInfo); - - // send levelup info to client - WorldPacket data(SMSG_LEVELUP_INFO, (4+4+MAX_POWERS*4+MAX_STATS*4)); - data << uint32(level); - data << uint32(int32(classInfo.basehealth) - int32(GetCreateHealth())); - // for(int i = 0; i < MAX_POWERS; ++i) // Powers loop (0-6) - data << uint32(int32(classInfo.basemana) - int32(GetCreateMana())); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - // end for - for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) // Stats loop (0-4) - data << uint32(int32(info.stats[i]) - GetCreateStat(Stats(i))); - - GetSession()->SendPacket(&data); - - SetUInt32Value(PLAYER_NEXT_LEVEL_XP, MaNGOS::XP::xp_to_level(level)); - - //update level, max level of skills - if(getLevel()!= level) - m_Played_time[1] = 0; // Level Played Time reset - SetLevel(level); - UpdateMaxSkills(); - - // save base values (bonuses already included in stored stats - for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) - SetCreateStat(Stats(i), info.stats[i]); - - SetCreateHealth(classInfo.basehealth); - SetCreateMana(classInfo.basemana); - - InitTalentForLevel(); - InitTaxiNodesForLevel(); - - UpdateAllStats(); - - // set current level health and mana/energy to maximum after applying all mods. - SetHealth(GetMaxHealth()); - SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); - SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); - if(GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE)) - SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE)); - SetPower(POWER_FOCUS, 0); - SetPower(POWER_HAPPINESS, 0); - - // give level to summoned pet - Pet* pet = GetPet(); - if(pet && pet->getPetType()==SUMMON_PET) - pet->GivePetLevel(level); -} - -void Player::InitTalentForLevel() -{ - uint32 level = getLevel(); - // talents base at level diff ( talents = level - 9 but some can be used already) - if(level < 10) - { - // Remove all talent points - if(m_usedTalentCount > 0) // Free any used talents - { - resetTalents(true); - SetFreeTalentPoints(0); - } - } - else - { - uint32 talentPointsForLevel = uint32((level-9)*sWorld.getRate(RATE_TALENT)); - // if used more that have then reset - if(m_usedTalentCount > talentPointsForLevel) - { - if (GetSession()->GetSecurity() < SEC_ADMINISTRATOR) - resetTalents(true); - else - SetFreeTalentPoints(0); - } - // else update amount of free points - else - SetFreeTalentPoints(talentPointsForLevel-m_usedTalentCount); - } -} - -void Player::InitStatsForLevel(bool reapplyMods) -{ - if(reapplyMods) //reapply stats values only on .reset stats (level) command - _RemoveAllStatBonuses(); - - PlayerClassLevelInfo classInfo; - objmgr.GetPlayerClassLevelInfo(getClass(),getLevel(),&classInfo); - - PlayerLevelInfo info; - objmgr.GetPlayerLevelInfo(getRace(),getClass(),getLevel(),&info); - - SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ); - SetUInt32Value(PLAYER_NEXT_LEVEL_XP, MaNGOS::XP::xp_to_level(getLevel())); - - UpdateMaxSkills (); - - // set default cast time multiplier - SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); - - // reset size before reapply auras - SetFloatValue(OBJECT_FIELD_SCALE_X,1.0f); - - // save base values (bonuses already included in stored stats - for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) - SetCreateStat(Stats(i), info.stats[i]); - - for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) - SetStat(Stats(i), info.stats[i]); - - SetCreateHealth(classInfo.basehealth); - - //set create powers - SetCreateMana(classInfo.basemana); - - SetArmor(int32(m_createStats[STAT_AGILITY]*2)); - - InitStatBuffMods(); - - //reset rating fields values - for(uint16 index = PLAYER_FIELD_COMBAT_RATING_1; index < PLAYER_FIELD_COMBAT_RATING_1 + MAX_COMBAT_RATING; ++index) - SetUInt32Value(index, 0); - - SetUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS,0); - for (int i = 0; i < 7; i++) - { - SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i, 0); - SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, 0); - SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT+i, 1.00f); - } - - //reset attack power, damage and attack speed fields - SetFloatValue(UNIT_FIELD_BASEATTACKTIME, 2000.0f ); - SetFloatValue(UNIT_FIELD_BASEATTACKTIME + 1, 2000.0f ); // offhand attack time - SetFloatValue(UNIT_FIELD_RANGEDATTACKTIME, 2000.0f ); - - SetFloatValue(UNIT_FIELD_MINDAMAGE, 0.0f ); - SetFloatValue(UNIT_FIELD_MAXDAMAGE, 0.0f ); - SetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, 0.0f ); - SetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, 0.0f ); - SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, 0.0f ); - SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, 0.0f ); - - SetUInt32Value(UNIT_FIELD_ATTACK_POWER, 0 ); - SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, 0 ); - SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER,0.0f); - SetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, 0 ); - SetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS,0 ); - SetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER,0.0f); - - // Base crit values (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset - SetFloatValue(PLAYER_CRIT_PERCENTAGE,0.0f); - SetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE,0.0f); - SetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE,0.0f); - - // Init spell schools (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset - for (uint8 i = 0; i < 7; ++i) - SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1+i, 0.0f); - - // Base parry percents - SetFloatValue(PLAYER_PARRY_PERCENTAGE, 5.0f); - - //Base block percentage - SetFloatValue(PLAYER_BLOCK_PERCENTAGE, 5.0f); - - SetUInt32Value(PLAYER_SHIELD_BLOCK, 0); - - // Dodge percentage - SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.0f); - - // set armor (resistance 0) to original value (create_agility*2) - SetArmor(int32(m_createStats[STAT_AGILITY]*2)); - SetResistanceBuffMods(SpellSchools(0), true, 0.0f); - SetResistanceBuffMods(SpellSchools(0), false, 0.0f); - // set other resistance to original value (0) - for (int i = 1; i < MAX_SPELL_SCHOOL; i++) - { - SetResistance(SpellSchools(i), 0); - SetResistanceBuffMods(SpellSchools(i), true, 0.0f); - SetResistanceBuffMods(SpellSchools(i), false, 0.0f); - } - - SetUInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE,0); - SetUInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE,0); - for(int i = 0; i < MAX_SPELL_SCHOOL; ++i) - { - SetFloatValue(UNIT_FIELD_POWER_COST_MODIFIER+i,0.0f); - SetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+i,0.0f); - } - // Init data for form but skip reapply item mods for form - InitDataForForm(reapplyMods); - - // save new stats - for (int i = POWER_MANA; i < MAX_POWERS; i++) - SetMaxPower(Powers(i), uint32(GetCreatePowers(Powers(i)))); - - SetMaxHealth(classInfo.basehealth); // stamina bonus will applied later - - // cleanup mounted state (it will set correctly at aura loading if player saved at mount. - SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); - - // cleanup unit flags (will be re-applied if need at aura load). - RemoveFlag( UNIT_FIELD_FLAGS, - UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_ATTACKABLE_1 | - UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_SILENCED | UNIT_FLAG_PACIFIED | - UNIT_FLAG_DISABLE_ROTATE | UNIT_FLAG_IN_COMBAT | UNIT_FLAG_DISARMED | - UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING | UNIT_FLAG_NOT_SELECTABLE | - UNIT_FLAG_SKINNABLE | UNIT_FLAG_MOUNT | UNIT_FLAG_TAXI_FLIGHT ); - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE ); // must be set - - // cleanup player flags (will be re-applied if need at aura load), to avoid have ghost flag without ghost aura, for example. - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST | PLAYER_FLAGS_FFA_PVP); - - SetByteValue(UNIT_FIELD_BYTES_1, 2, 0x00); // one form stealth modified bytes - - // restore if need some important flags - SetUInt32Value(PLAYER_FIELD_BYTES2, 0 ); // flags empty by default - - if(reapplyMods) //reapply stats values only on .reset stats (level) command - _ApplyAllStatBonuses(); - - // set current level health and mana/energy to maximum after applying all mods. - SetHealth(GetMaxHealth()); - SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); - SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); - if(GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE)) - SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE)); - SetPower(POWER_FOCUS, 0); - SetPower(POWER_HAPPINESS, 0); -} - -void Player::SendInitialSpells() -{ - uint16 spellCount = 0; - - WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4))); - data << uint8(0); - - size_t countPos = data.wpos(); - data << uint16(spellCount); // spell count placeholder - - for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if(itr->second->state == PLAYERSPELL_REMOVED) - continue; - - if(!itr->second->active || itr->second->disabled) - continue; - - data << uint16(itr->first); - //data << uint16(itr->second->slotId); - data << uint16(0); // it's not slot id - - spellCount +=1; - } - - data.put(countPos,spellCount); // write real count value - - uint16 spellCooldowns = m_spellCooldowns.size(); - data << uint16(spellCooldowns); - for(SpellCooldowns::const_iterator itr=m_spellCooldowns.begin(); itr!=m_spellCooldowns.end(); itr++) - { - SpellEntry const *sEntry = sSpellStore.LookupEntry(itr->first); - if(!sEntry) - continue; - - data << uint16(itr->first); - - time_t cooldown = 0; - time_t curTime = time(NULL); - if(itr->second.end > curTime) - cooldown = (itr->second.end-curTime)*1000; - - data << uint16(itr->second.itemid); // cast item id - data << uint16(sEntry->Category); // spell category - if(sEntry->Category) // may be wrong, but anyway better than nothing... - { - data << uint32(0); - data << uint32(cooldown); - } - else - { - data << uint32(cooldown); - data << uint32(0); - } - } - - GetSession()->SendPacket(&data); - - sLog.outDetail( "CHARACTER: Sent Initial Spells" ); -} - -void Player::RemoveMail(uint32 id) -{ - for(PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end();++itr) - { - if ((*itr)->messageID == id) - { - //do not delete item, because Player::removeMail() is called when returning mail to sender. - m_mail.erase(itr); - return; - } - } -} - -void Player::SendMailResult(uint32 mailId, uint32 mailAction, uint32 mailError, uint32 equipError, uint32 item_guid, uint32 item_count) -{ - WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(mailError == MAIL_ERR_BAG_FULL?4:(mailAction == MAIL_ITEM_TAKEN?4+4:0)))); - data << (uint32) mailId; - data << (uint32) mailAction; - data << (uint32) mailError; - if ( mailError == MAIL_ERR_BAG_FULL ) - data << (uint32) equipError; - else if( mailAction == MAIL_ITEM_TAKEN ) - { - data << (uint32) item_guid; // item guid low? - data << (uint32) item_count; // item count? - } - GetSession()->SendPacket(&data); -} - -void Player::SendNewMail() -{ - // deliver undelivered mail - WorldPacket data(SMSG_RECEIVED_MAIL, 4); - data << (uint32) 0; - GetSession()->SendPacket(&data); -} - -void Player::UpdateNextMailTimeAndUnreads() -{ - // calculate next delivery time (min. from non-delivered mails - // and recalculate unReadMail - time_t cTime = time(NULL); - m_nextMailDelivereTime = 0; - unReadMails = 0; - for(PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) - { - if((*itr)->deliver_time > cTime) - { - if(!m_nextMailDelivereTime || m_nextMailDelivereTime > (*itr)->deliver_time) - m_nextMailDelivereTime = (*itr)->deliver_time; - } - else if(((*itr)->checked & MAIL_CHECK_MASK_READ) == 0) - ++unReadMails; - } -} - -void Player::AddNewMailDeliverTime(time_t deliver_time) -{ - if(deliver_time <= time(NULL)) // ready now - { - ++unReadMails; - SendNewMail(); - } - else // not ready and no have ready mails - { - if(!m_nextMailDelivereTime || m_nextMailDelivereTime > deliver_time) - m_nextMailDelivereTime = deliver_time; - } -} - -bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading, uint16 slot_id, bool disabled) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); - if (!spellInfo) - { - // do character spell book cleanup (all characters) - if(loading && !learning) // spell load case - { - sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.",spell_id); - CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'",spell_id); - } - else - sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id); - - return false; - } - - if(!SpellMgr::IsSpellValid(spellInfo,this,false)) - { - // do character spell book cleanup (all characters) - if(loading && !learning) // spell load case - { - sLog.outError("Player::addSpell: Broken spell #%u learning not allowed, deleting for all characters in `character_spell`.",spell_id); - CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'",spell_id); - } - else - sLog.outError("Player::addSpell: Broken spell #%u learning not allowed.",spell_id); - - return false; - } - - PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED; - - bool disabled_case = false; - bool superceded_old = false; - - PlayerSpellMap::iterator itr = m_spells.find(spell_id); - if (itr != m_spells.end()) - { - // update active state for known spell - if(itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled) - { - itr->second->active = active; - - // loading && !learning == explicitly load from DB and then exist in it already and set correctly - if(loading && !learning) - itr->second->state = PLAYERSPELL_UNCHANGED; - else if(itr->second->state != PLAYERSPELL_NEW) - itr->second->state = PLAYERSPELL_CHANGED; - - if(!active) - { - WorldPacket data(SMSG_REMOVED_SPELL, 4); - data << uint16(spell_id); - GetSession()->SendPacket(&data); - } - return active; // learn (show in spell book if active now) - } - - if(itr->second->disabled != disabled && itr->second->state != PLAYERSPELL_REMOVED) - { - if(itr->second->state != PLAYERSPELL_NEW) - itr->second->state = PLAYERSPELL_CHANGED; - itr->second->disabled = disabled; - - if(disabled) - return false; - - disabled_case = true; - } - else switch(itr->second->state) - { - case PLAYERSPELL_UNCHANGED: // known saved spell - return false; - case PLAYERSPELL_REMOVED: // re-learning removed not saved spell - { - delete itr->second; - m_spells.erase(itr); - state = PLAYERSPELL_CHANGED; - break; // need re-add - } - default: // known not saved yet spell (new or modified) - { - // can be in case spell loading but learned at some previous spell loading - if(loading && !learning) - itr->second->state = PLAYERSPELL_UNCHANGED; - - return false; - } - } - } - - if(!disabled_case) // skip new spell adding if spell already known (disabled spells case) - { - // talent: unlearn all other talent ranks (high and low) - if(TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id)) - { - if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id )) - { - for(int i=0; i <5; ++i) - { - // skip learning spell and no rank spell case - uint32 rankSpellId = talentInfo->RankID[i]; - if(!rankSpellId || rankSpellId==spell_id) - continue; - - // skip unknown ranks - if(!HasSpell(rankSpellId)) - continue; - - removeSpell(rankSpellId); - } - } - } - // non talent spell: learn low ranks (recursive call) - else if(uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id)) - { - if(loading) // at spells loading, no output, but allow save - addSpell(prev_spell,active,true,loading,SPELL_WITHOUT_SLOT_ID,disabled); - else // at normal learning - learnSpell(prev_spell); - } - - PlayerSpell *newspell = new PlayerSpell; - newspell->active = active; - newspell->state = state; - newspell->disabled = disabled; - - // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible - if(newspell->active && !newspell->disabled && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) - { - for( PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr ) - { - if(itr->second->state == PLAYERSPELL_REMOVED) continue; - SpellEntry const *i_spellInfo = sSpellStore.LookupEntry(itr->first); - if(!i_spellInfo) continue; - - if( spellmgr.IsRankSpellDueToSpell(spellInfo,itr->first) ) - { - if(itr->second->active) - { - if(spellmgr.IsHighRankOfSpell(spell_id,itr->first)) - { - if(!loading) // not send spell (re-/over-)learn packets at loading - { - WorldPacket data(SMSG_SUPERCEDED_SPELL, (4)); - data << uint16(itr->first); - data << uint16(spell_id); - GetSession()->SendPacket( &data ); - } - - // mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new) - itr->second->active = false; - itr->second->state = PLAYERSPELL_CHANGED; - superceded_old = true; // new spell replace old in action bars and spell book. - } - else if(spellmgr.IsHighRankOfSpell(itr->first,spell_id)) - { - if(!loading) // not send spell (re-/over-)learn packets at loading - { - WorldPacket data(SMSG_SUPERCEDED_SPELL, (4)); - data << uint16(spell_id); - data << uint16(itr->first); - GetSession()->SendPacket( &data ); - } - - // mark new spell as disable (not learned yet for client and will not learned) - newspell->active = false; - if(newspell->state != PLAYERSPELL_NEW) - newspell->state = PLAYERSPELL_CHANGED; - } - } - } - } - } - - uint16 tmpslot=slot_id; - - if (tmpslot == SPELL_WITHOUT_SLOT_ID) - { - uint16 maxid = 0; - PlayerSpellMap::iterator itr; - for (itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if(itr->second->state == PLAYERSPELL_REMOVED) - continue; - if (itr->second->slotId > maxid) - maxid = itr->second->slotId; - } - tmpslot = maxid + 1; - } - - newspell->slotId = tmpslot; - m_spells[spell_id] = newspell; - - // return false if spell disabled - if (newspell->disabled) - return false; - } - - uint32 talentCost = GetTalentSpellCost(spell_id); - - // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned) - // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive - if( talentCost > 0 && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_LEARN_SPELL) ) - { - // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show) - CastSpell(this, spell_id, true); - } - // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks - else if (IsPassiveSpell(spell_id)) - { - // if spell doesn't require a stance or the player is in the required stance - if( ( !spellInfo->Stances && - spell_id != 5420 && spell_id != 5419 && spell_id != 7376 && - spell_id != 7381 && spell_id != 21156 && spell_id != 21009 && - spell_id != 21178 && spell_id != 33948 && spell_id != 40121 ) || - m_form != 0 && (spellInfo->Stances & (1<<(m_form-1))) || - (spell_id == 5420 && m_form == FORM_TREE) || - (spell_id == 5419 && m_form == FORM_TRAVEL) || - (spell_id == 7376 && m_form == FORM_DEFENSIVESTANCE) || - (spell_id == 7381 && m_form == FORM_BERSERKERSTANCE) || - (spell_id == 21156 && m_form == FORM_BATTLESTANCE)|| - (spell_id == 21178 && (m_form == FORM_BEAR || m_form == FORM_DIREBEAR) ) || - (spell_id == 33948 && m_form == FORM_FLIGHT) || - (spell_id == 40121 && m_form == FORM_FLIGHT_EPIC) ) - //Check CasterAuraStates - if (!spellInfo->CasterAuraState || HasAuraState(AuraState(spellInfo->CasterAuraState))) - CastSpell(this, spell_id, true); - } - else if( IsSpellHaveEffect(spellInfo,SPELL_EFFECT_SKILL_STEP) ) - { - CastSpell(this, spell_id, true); - return false; - } - - // update used talent points count - m_usedTalentCount += talentCost; - - // update free primary prof.points (if any, can be none in case GM .learn prof. learning) - if(uint32 freeProfs = GetFreePrimaryProffesionPoints()) - { - if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) - SetFreePrimaryProffesions(freeProfs-1); - } - - // add dependent skills - uint16 maxskill = GetMaxSkillValueForLevel(); - - SpellLearnSkillNode const* spellLearnSkill = spellmgr.GetSpellLearnSkill(spell_id); - - if(spellLearnSkill) - { - uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill); - uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill); - - if(skill_value < spellLearnSkill->value) - skill_value = spellLearnSkill->value; - - uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? maxskill : spellLearnSkill->maxvalue; - - if(skill_max_value < new_skill_max_value) - skill_max_value = new_skill_max_value; - - SetSkill(spellLearnSkill->skill,skill_value,skill_max_value); - } - else - { - // not ranked skills - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id); - - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId); - if(!pSkill) - continue; - - if(HasSkill(pSkill->id)) - continue; - - if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL || - // poison special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL - pSkill->id==SKILL_POISONS && _spell_idx->second->max_value==0 || - // lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL - pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 ) - { - switch(GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0)) - { - case SKILL_RANGE_LANGUAGE: - SetSkill(pSkill->id, 300, 300 ); - break; - case SKILL_RANGE_LEVEL: - SetSkill(pSkill->id, 1, GetMaxSkillValueForLevel() ); - break; - case SKILL_RANGE_MONO: - SetSkill(pSkill->id, 1, 1 ); - break; - default: - break; - } - } - } - } - - // learn dependent spells - SpellLearnSpellMap::const_iterator spell_begin = spellmgr.GetBeginSpellLearnSpell(spell_id); - SpellLearnSpellMap::const_iterator spell_end = spellmgr.GetEndSpellLearnSpell(spell_id); - - for(SpellLearnSpellMap::const_iterator itr = spell_begin; itr != spell_end; ++itr) - { - if(!itr->second.autoLearned) - { - if(loading) // at spells loading, no output, but allow save - addSpell(itr->second.spell,true,true,loading); - else // at normal learning - learnSpell(itr->second.spell); - } - } - - // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell - return active && !disabled && !superceded_old; -} - -void Player::learnSpell(uint32 spell_id) -{ - PlayerSpellMap::iterator itr = m_spells.find(spell_id); - - bool disabled = (itr != m_spells.end()) ? itr->second->disabled : false; - bool active = disabled ? itr->second->active : true; - - bool learning = addSpell(spell_id,active); - - // learn all disabled higher ranks (recursive) - SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); - for(SpellChainMapNext::const_iterator i = nextMap.lower_bound(spell_id); i != nextMap.upper_bound(spell_id); ++i) - { - PlayerSpellMap::iterator iter = m_spells.find(i->second); - if (disabled && iter != m_spells.end() && iter->second->disabled) - learnSpell(i->second); - } - - // prevent duplicated entires in spell book - if(!learning) - return; - - WorldPacket data(SMSG_LEARNED_SPELL, 4); - data << uint32(spell_id); - GetSession()->SendPacket(&data); -} - -void Player::removeSpell(uint32 spell_id, bool disabled) -{ - PlayerSpellMap::iterator itr = m_spells.find(spell_id); - if (itr == m_spells.end()) - return; - - if(itr->second->state == PLAYERSPELL_REMOVED || disabled && itr->second->disabled) - return; - - // unlearn non talent higher ranks (recursive) - SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); - for(SpellChainMapNext::const_iterator itr2 = nextMap.lower_bound(spell_id); itr2 != nextMap.upper_bound(spell_id); ++itr2) - if(HasSpell(itr2->second) && !GetTalentSpellPos(itr2->second)) - removeSpell(itr2->second,disabled); - - // removing - WorldPacket data(SMSG_REMOVED_SPELL, 4); - data << uint16(spell_id); - GetSession()->SendPacket(&data); - - if (disabled) - { - itr->second->disabled = disabled; - if(itr->second->state != PLAYERSPELL_NEW) - itr->second->state = PLAYERSPELL_CHANGED; - } - else - { - if(itr->second->state == PLAYERSPELL_NEW) - { - delete itr->second; - m_spells.erase(itr); - } - else - itr->second->state = PLAYERSPELL_REMOVED; - } - - RemoveAurasDueToSpell(spell_id); - - // remove pet auras - if(PetAura const* petSpell = spellmgr.GetPetAura(spell_id)) - RemovePetAura(petSpell); - - // free talent points - uint32 talentCosts = GetTalentSpellCost(spell_id); - if(talentCosts > 0) - { - if(talentCosts < m_usedTalentCount) - m_usedTalentCount -= talentCosts; - else - m_usedTalentCount = 0; - } - - // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning) - if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) - { - uint32 freeProfs = GetFreePrimaryProffesionPoints()+1; - if(freeProfs <= sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)) - SetFreePrimaryProffesions(freeProfs); - } - - // remove dependent skill - SpellLearnSkillNode const* spellLearnSkill = spellmgr.GetSpellLearnSkill(spell_id); - if(spellLearnSkill) - { - uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id); - if(!prev_spell) // first rank, remove skill - SetSkill(spellLearnSkill->skill,0,0); - else - { - // search prev. skill setting by spell ranks chain - SpellLearnSkillNode const* prevSkill = spellmgr.GetSpellLearnSkill(prev_spell); - while(!prevSkill && prev_spell) - { - prev_spell = spellmgr.GetPrevSpellInChain(prev_spell); - prevSkill = spellmgr.GetSpellLearnSkill(spellmgr.GetFirstSpellInChain(prev_spell)); - } - - if(!prevSkill) // not found prev skill setting, remove skill - SetSkill(spellLearnSkill->skill,0,0); - else // set to prev. skill setting values - { - uint32 skill_value = GetPureSkillValue(prevSkill->skill); - uint32 skill_max_value = GetPureMaxSkillValue(prevSkill->skill); - - if(skill_value > prevSkill->value) - skill_value = prevSkill->value; - - uint32 new_skill_max_value = prevSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : prevSkill->maxvalue; - - if(skill_max_value > new_skill_max_value) - skill_max_value = new_skill_max_value; - - SetSkill(prevSkill->skill,skill_value,skill_max_value); - } - } - - } - else - { - // not ranked skills - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id); - - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId); - if(!pSkill) - continue; - - if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL || - // poison special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL - pSkill->id==SKILL_POISONS && _spell_idx->second->max_value==0 || - // lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL - pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 ) - { - // not reset skills for professions and racial abilities - if( (pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) && - (IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask!=0) ) - continue; - - SetSkill(pSkill->id, 0, 0 ); - } - } - } - - // remove dependent spells - SpellLearnSpellMap::const_iterator spell_begin = spellmgr.GetBeginSpellLearnSpell(spell_id); - SpellLearnSpellMap::const_iterator spell_end = spellmgr.GetEndSpellLearnSpell(spell_id); - - for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2) - removeSpell(itr2->second.spell, disabled); -} - -void Player::RemoveArenaSpellCooldowns() -{ - // remove cooldowns on spells that has < 15 min CD - SpellCooldowns::iterator itr, next; - // iterate spell cooldowns - for(itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); itr = next) - { - next = itr; - ++next; - SpellEntry const * entry = sSpellStore.LookupEntry(itr->first); - // check if spellentry is present and if the cooldown is less than 15 mins - if( entry && - entry->RecoveryTime <= 15 * MINUTE * 1000 && - entry->CategoryRecoveryTime <= 15 * MINUTE * 1000 ) - { - // notify player - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(itr->first); - data << GetGUID(); - GetSession()->SendPacket(&data); - // remove cooldown - m_spellCooldowns.erase(itr); - } - } -} - -void Player::RemoveAllSpellCooldown() -{ - if(!m_spellCooldowns.empty()) - { - for(SpellCooldowns::const_iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); ++itr) - { - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(itr->first); - data << uint64(GetGUID()); - GetSession()->SendPacket(&data); - } - m_spellCooldowns.clear(); - } -} - -void Player::_LoadSpellCooldowns(QueryResult *result) -{ - m_spellCooldowns.clear(); - - //QueryResult *result = CharacterDatabase.PQuery("SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'",GetGUIDLow()); - - if(result) - { - time_t curTime = time(NULL); - - do - { - Field *fields = result->Fetch(); - - uint32 spell_id = fields[0].GetUInt32(); - uint32 item_id = fields[1].GetUInt32(); - time_t db_time = (time_t)fields[2].GetUInt64(); - - if(!sSpellStore.LookupEntry(spell_id)) - { - sLog.outError("Player %u have unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id); - continue; - } - - // skip outdated cooldown - if(db_time <= curTime) - continue; - - AddSpellCooldown(spell_id, item_id, db_time); - - sLog.outDebug("Player (GUID: %u) spell %u, item %u cooldown loaded (%u secs).", GetGUIDLow(), spell_id, item_id, uint32(db_time-curTime)); - } - while( result->NextRow() ); - - delete result; - } -} - -void Player::_SaveSpellCooldowns() -{ - CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow()); - - time_t curTime = time(NULL); - - // remove outdated and save active - for(SpellCooldowns::iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end();) - { - if(itr->second.end <= curTime) - m_spellCooldowns.erase(itr++); - else - { - CharacterDatabase.PExecute("INSERT INTO character_spell_cooldown (guid,spell,item,time) VALUES ('%u', '%u', '%u', '" I64FMTD "')", GetGUIDLow(), itr->first, itr->second.itemid, uint64(itr->second.end)); - ++itr; - } - } -} - -uint32 Player::resetTalentsCost() const -{ - // The first time reset costs 1 gold - if(m_resetTalentsCost < 1*GOLD) - return 1*GOLD; - // then 5 gold - else if(m_resetTalentsCost < 5*GOLD) - return 5*GOLD; - // After that it increases in increments of 5 gold - else if(m_resetTalentsCost < 10*GOLD) - return 10*GOLD; - else - { - uint32 months = (sWorld.GetGameTime() - m_resetTalentsTime)/MONTH; - if(months > 0) - { - // This cost will be reduced by a rate of 5 gold per month - int32 new_cost = int32(m_resetTalentsCost) - 5*GOLD*months; - // to a minimum of 10 gold. - return (new_cost < 10*GOLD ? 10*GOLD : new_cost); - } - else - { - // After that it increases in increments of 5 gold - int32 new_cost = m_resetTalentsCost + 5*GOLD; - // until it hits a cap of 50 gold. - if(new_cost > 50*GOLD) - new_cost = 50*GOLD; - return new_cost; - } - } -} - -bool Player::resetTalents(bool no_cost) -{ - // not need after this call - if(HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) - { - m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_TALENTS; - CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_TALENTS), GetGUIDLow()); - } - - uint32 level = getLevel(); - uint32 talentPointsForLevel = level < 10 ? 0 : uint32((level-9)*sWorld.getRate(RATE_TALENT)); - - if (m_usedTalentCount == 0) - { - SetFreeTalentPoints(talentPointsForLevel); - return false; - } - - uint32 cost = 0; - - if(!no_cost) - { - cost = resetTalentsCost(); - - if (GetMoney() < cost) - { - SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0); - return false; - } - } - - for (unsigned int i = 0; i < sTalentStore.GetNumRows(); i++) - { - TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); - - if (!talentInfo) continue; - - TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab ); - - if(!talentTabInfo) - continue; - - // unlearn only talents for character class - // some spell learned by one class as normal spells or know at creation but another class learn it as talent, - // to prevent unexpected lost normal learned spell skip another class talents - if( (getClassMask() & talentTabInfo->ClassMask) == 0 ) - continue; - - for (int j = 0; j < 5; j++) - { - for(PlayerSpellMap::iterator itr = GetSpellMap().begin(); itr != GetSpellMap().end();) - { - if(itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) - { - ++itr; - continue; - } - - // remove learned spells (all ranks) - uint32 itrFirstId = spellmgr.GetFirstSpellInChain(itr->first); - - // unlearn if first rank is talent or learned by talent - if (itrFirstId == talentInfo->RankID[j] || spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId)) - { - removeSpell(itr->first,!IsPassiveSpell(itr->first)); - itr = GetSpellMap().begin(); - continue; - } - else - ++itr; - } - } - } - - SetFreeTalentPoints(talentPointsForLevel); - - if(!no_cost) - { - ModifyMoney(-(int32)cost); - - m_resetTalentsCost = cost; - m_resetTalentsTime = time(NULL); - } - - //FIXME: remove pet before or after unlearn spells? for now after unlearn to allow removing of talent related, pet affecting auras - RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true); - - return true; -} - -bool Player::_removeSpell(uint16 spell_id) -{ - PlayerSpellMap::iterator itr = m_spells.find(spell_id); - if (itr != m_spells.end()) - { - delete itr->second; - m_spells.erase(itr); - return true; - } - return false; -} - -Mail* Player::GetMail(uint32 id) -{ - for(PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); itr++) - { - if ((*itr)->messageID == id) - { - return (*itr); - } - } - return NULL; -} - -void Player::_SetCreateBits(UpdateMask *updateMask, Player *target) const -{ - if(target == this) - { - Object::_SetCreateBits(updateMask, target); - } - else - { - for(uint16 index = 0; index < m_valuesCount; index++) - { - if(GetUInt32Value(index) != 0 && updateVisualBits.GetBit(index)) - updateMask->SetBit(index); - } - } -} - -void Player::_SetUpdateBits(UpdateMask *updateMask, Player *target) const -{ - if(target == this) - { - Object::_SetUpdateBits(updateMask, target); - } - else - { - Object::_SetUpdateBits(updateMask, target); - *updateMask &= updateVisualBits; - } -} - -void Player::InitVisibleBits() -{ - updateVisualBits.SetCount(PLAYER_END); - - updateVisualBits.SetBit(OBJECT_FIELD_GUID); - updateVisualBits.SetBit(OBJECT_FIELD_TYPE); - updateVisualBits.SetBit(OBJECT_FIELD_SCALE_X); - - updateVisualBits.SetBit(UNIT_FIELD_CHARM); - updateVisualBits.SetBit(UNIT_FIELD_CHARM+1); - - updateVisualBits.SetBit(UNIT_FIELD_SUMMON); - updateVisualBits.SetBit(UNIT_FIELD_SUMMON+1); - - updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY); - - updateVisualBits.SetBit(UNIT_FIELD_TARGET); - updateVisualBits.SetBit(UNIT_FIELD_TARGET+1); - - updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT); - updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT+1); - - updateVisualBits.SetBit(UNIT_FIELD_HEALTH); - updateVisualBits.SetBit(UNIT_FIELD_POWER1); - updateVisualBits.SetBit(UNIT_FIELD_POWER2); - updateVisualBits.SetBit(UNIT_FIELD_POWER3); - updateVisualBits.SetBit(UNIT_FIELD_POWER4); - updateVisualBits.SetBit(UNIT_FIELD_POWER5); - - updateVisualBits.SetBit(UNIT_FIELD_MAXHEALTH); - updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER1); - updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER2); - updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER3); - updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER4); - updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER5); - - updateVisualBits.SetBit(UNIT_FIELD_LEVEL); - updateVisualBits.SetBit(UNIT_FIELD_FACTIONTEMPLATE); - updateVisualBits.SetBit(UNIT_FIELD_BYTES_0); - updateVisualBits.SetBit(UNIT_FIELD_FLAGS); - updateVisualBits.SetBit(UNIT_FIELD_FLAGS_2); - for(uint16 i = UNIT_FIELD_AURA; i < UNIT_FIELD_AURASTATE; ++i) - updateVisualBits.SetBit(i); - updateVisualBits.SetBit(UNIT_FIELD_AURASTATE); - updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME); - updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME + 1); - updateVisualBits.SetBit(UNIT_FIELD_RANGEDATTACKTIME); - updateVisualBits.SetBit(UNIT_FIELD_BOUNDINGRADIUS); - updateVisualBits.SetBit(UNIT_FIELD_COMBATREACH); - updateVisualBits.SetBit(UNIT_FIELD_DISPLAYID); - updateVisualBits.SetBit(UNIT_FIELD_NATIVEDISPLAYID); - updateVisualBits.SetBit(UNIT_FIELD_MOUNTDISPLAYID); - updateVisualBits.SetBit(UNIT_FIELD_BYTES_1); - updateVisualBits.SetBit(UNIT_FIELD_MOUNTDISPLAYID); - updateVisualBits.SetBit(UNIT_FIELD_PETNUMBER); - updateVisualBits.SetBit(UNIT_FIELD_PET_NAME_TIMESTAMP); - updateVisualBits.SetBit(UNIT_DYNAMIC_FLAGS); - updateVisualBits.SetBit(UNIT_CHANNEL_SPELL); - updateVisualBits.SetBit(UNIT_MOD_CAST_SPEED); - updateVisualBits.SetBit(UNIT_FIELD_BYTES_2); - - updateVisualBits.SetBit(PLAYER_FLAGS); - updateVisualBits.SetBit(PLAYER_BYTES); - updateVisualBits.SetBit(PLAYER_BYTES_2); - updateVisualBits.SetBit(PLAYER_BYTES_3); - updateVisualBits.SetBit(PLAYER_GUILDID); - updateVisualBits.SetBit(PLAYER_GUILDRANK); - updateVisualBits.SetBit(PLAYER_GUILD_TIMESTAMP); - updateVisualBits.SetBit(PLAYER_DUEL_TEAM); - updateVisualBits.SetBit(PLAYER_DUEL_ARBITER); - updateVisualBits.SetBit(PLAYER_DUEL_ARBITER+1); - - // PLAYER_QUEST_LOG_x also visible bit on official (but only on party/raid)... - for(uint16 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_2; i+=4) - updateVisualBits.SetBit(i); - - for(uint16 i = 0; i < INVENTORY_SLOT_BAG_END; i++) - { - updateVisualBits.SetBit((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + i*2)); - updateVisualBits.SetBit((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (i*2) + 1)); - } - //Players visible items are not inventory stuff - //431) = 884 (0x374) = main weapon - for(uint16 i = 0; i < EQUIPMENT_SLOT_END; i++) - { - // item creator - updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + (i*MAX_VISIBLE_ITEM_OFFSET) + 0); - updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + (i*MAX_VISIBLE_ITEM_OFFSET) + 1); - - uint16 visual_base = PLAYER_VISIBLE_ITEM_1_0 + (i*MAX_VISIBLE_ITEM_OFFSET); - - // item entry - updateVisualBits.SetBit(visual_base + 0); - - // item enchantment IDs - for(uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) - updateVisualBits.SetBit(visual_base + 1 + j); - - // random properties - updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 0 + (i*MAX_VISIBLE_ITEM_OFFSET)); - updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 1 + (i*MAX_VISIBLE_ITEM_OFFSET)); - } - - updateVisualBits.SetBit(PLAYER_CHOSEN_TITLE); - - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY); - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + 1); - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + 2); - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO); - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 1); - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 2); - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 3); - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 4); - updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 5); -} - -void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const -{ - for(int i = 0; i < EQUIPMENT_SLOT_END; i++) - { - if(m_items[i] == NULL) - continue; - - m_items[i]->BuildCreateUpdateBlockForPlayer( data, target ); - } - - if(target == this) - { - - for(int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - if(m_items[i] == NULL) - continue; - - m_items[i]->BuildCreateUpdateBlockForPlayer( data, target ); - } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - if(m_items[i] == NULL) - continue; - - m_items[i]->BuildCreateUpdateBlockForPlayer( data, target ); - } - } - - Unit::BuildCreateUpdateBlockForPlayer( data, target ); -} - -void Player::DestroyForPlayer( Player *target ) const -{ - Unit::DestroyForPlayer( target ); - - for(int i = 0; i < INVENTORY_SLOT_BAG_END; i++) - { - if(m_items[i] == NULL) - continue; - - m_items[i]->DestroyForPlayer( target ); - } - - if(target == this) - { - - for(int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - if(m_items[i] == NULL) - continue; - - m_items[i]->DestroyForPlayer( target ); - } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - if(m_items[i] == NULL) - continue; - - m_items[i]->DestroyForPlayer( target ); - } - } -} - -bool Player::HasSpell(uint32 spell) const -{ - PlayerSpellMap::const_iterator itr = m_spells.find((uint16)spell); - return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled); -} - -TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell) const -{ - if (!trainer_spell) - return TRAINER_SPELL_RED; - - if (!trainer_spell->spell) - return TRAINER_SPELL_RED; - - // known spell - if(HasSpell(trainer_spell->spell->Id)) - return TRAINER_SPELL_GRAY; - - // check race/class requirement - if(!IsSpellFitByClassAndRace(trainer_spell->spell->Id)) - return TRAINER_SPELL_RED; - - // check level requirement - if(getLevel() < ( trainer_spell->reqlevel ? trainer_spell->reqlevel : trainer_spell->spell->spellLevel)) - return TRAINER_SPELL_RED; - - if(SpellChainNode const* spell_chain = spellmgr.GetSpellChainNode(trainer_spell->spell->Id)) - { - // check prev.rank requirement - if(spell_chain->prev && !HasSpell(spell_chain->prev)) - return TRAINER_SPELL_RED; - - // check additional spell requirement - if(spell_chain->req && !HasSpell(spell_chain->req)) - return TRAINER_SPELL_RED; - } - - // check skill requirement - if(trainer_spell->reqskill && GetBaseSkillValue(trainer_spell->reqskill) < trainer_spell->reqskillvalue) - return TRAINER_SPELL_RED; - - // secondary prof. or not prof. spell - uint32 skill = trainer_spell->spell->EffectMiscValue[1]; - - if(trainer_spell->spell->Effect[1] != SPELL_EFFECT_SKILL || !IsPrimaryProfessionSkill(skill)) - return TRAINER_SPELL_GREEN; - - // check primary prof. limit - if(spellmgr.IsPrimaryProfessionFirstRankSpell(trainer_spell->spell->Id) && GetFreePrimaryProffesionPoints() == 0) - return TRAINER_SPELL_RED; - - return TRAINER_SPELL_GREEN; -} - -void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars) -{ - uint32 guid = GUID_LOPART(playerguid); - - // convert corpse to bones if exist (to prevent exiting Corpse in World without DB entry) - // bones will be deleted by corpse/bones deleting thread shortly - ObjectAccessor::Instance().ConvertCorpseForPlayer(playerguid); - - // remove from guild - uint32 guildId = GetGuildIdFromDB(playerguid); - if(guildId != 0) - { - Guild* guild = objmgr.GetGuildById(guildId); - if(guild) - guild->DelMember(guid); - } - - // the player was uninvited already on logout so just remove from group - QueryResult *resultGroup = CharacterDatabase.PQuery("SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", guid); - if(resultGroup) - { - uint64 leaderGuid = MAKE_NEW_GUID((*resultGroup)[0].GetUInt32(), 0, HIGHGUID_PLAYER); - delete resultGroup; - Group* group = objmgr.GetGroupByLeader(leaderGuid); - if(group) - { - RemoveFromGroup(group, playerguid); - } - } - - // remove signs from petitions (also remove petitions if owner); - RemovePetitionsAndSigns(playerguid, 10); - - // return back all mails with COD and Item 0 1 2 3 4 5 6 - QueryResult *resultMail = CharacterDatabase.PQuery("SELECT id,mailTemplateId,sender,subject,itemTextId,money,has_items FROM mail WHERE receiver='%u' AND has_items<>0 AND cod<>0", guid); - if(resultMail) - { - do - { - Field *fields = resultMail->Fetch(); - - uint32 mail_id = fields[0].GetUInt32(); - uint16 mailTemplateId= fields[1].GetUInt16(); - uint32 sender = fields[2].GetUInt32(); - std::string subject = fields[3].GetCppString(); - uint32 itemTextId = fields[4].GetUInt32(); - uint32 money = fields[5].GetUInt32(); - bool has_items = fields[6].GetBool(); - - //we can return mail now - //so firstly delete the old one - CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", mail_id); - - MailItemsInfo mi; - if(has_items) - { - QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", mail_id); - if(resultItems) - { - do - { - Field *fields2 = resultItems->Fetch(); - - uint32 item_guidlow = fields2[0].GetUInt32(); - uint32 item_template = fields2[1].GetUInt32(); - - ItemPrototype const* itemProto = objmgr.GetItemPrototype(item_template); - if(!itemProto) - { - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guidlow); - continue; - } - - Item *pItem = NewItemOrBag(itemProto); - if(!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER))) - { - pItem->FSetState(ITEM_REMOVED); - pItem->SaveToDB(); // it also deletes item object ! - continue; - } - - mi.AddItem(item_guidlow, item_template, pItem); - } - while (resultItems->NextRow()); - - delete resultItems; - } - } - - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mail_id); - - uint32 pl_account = objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); - - WorldSession::SendReturnToSender(MAIL_NORMAL, pl_account, guid, sender, subject, itemTextId, &mi, money, 0, mailTemplateId); - } - while (resultMail->NextRow()); - - delete resultMail; - } - - // unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet. - // Get guids of character's pets, will deleted in transaction - QueryResult *resultPets = CharacterDatabase.PQuery("SELECT id FROM character_pet WHERE owner = '%u'",guid); - - // NOW we can finally clear other DB data related to character - CharacterDatabase.BeginTransaction(); - if (resultPets) - { - do - { - Field *fields3 = resultPets->Fetch(); - uint32 petguidlow = fields3[0].GetUInt32(); - Pet::DeleteFromDB(petguidlow); - } while (resultPets->NextRow()); - delete resultPets; - } - - CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_homebind WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_queststatus WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE owner_guid = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' OR friend='%u'",guid,guid); - CharacterDatabase.PExecute("DELETE FROM mail WHERE receiver = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE receiver = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u'",guid); - CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u'",guid); - CharacterDatabase.CommitTransaction(); - - //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID); - if(updateRealmChars) sWorld.UpdateRealmCharCount(accountId); -} - -void Player::SetMovement(PlayerMovementType pType) -{ - WorldPacket data; - switch(pType) - { - case MOVE_ROOT: data.Initialize(SMSG_FORCE_MOVE_ROOT, GetPackGUID().size()+4); break; - case MOVE_UNROOT: data.Initialize(SMSG_FORCE_MOVE_UNROOT, GetPackGUID().size()+4); break; - case MOVE_WATER_WALK: data.Initialize(SMSG_MOVE_WATER_WALK, GetPackGUID().size()+4); break; - case MOVE_LAND_WALK: data.Initialize(SMSG_MOVE_LAND_WALK, GetPackGUID().size()+4); break; - default: - sLog.outError("Player::SetMovement: Unsupported move type (%d), data not sent to client.",pType); - return; - } - data.append(GetPackGUID()); - data << uint32(0); - GetSession()->SendPacket( &data ); -} - -/* Preconditions: - - a resurrectable corpse must not be loaded for the player (only bones) - - the player must be in world -*/ -void Player::BuildPlayerRepop() -{ - if(getRace() == RACE_NIGHTELF) - CastSpell(this, 20584, true); // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) - CastSpell(this, 8326, true); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) - - // there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_WATER_WALK - // there must be SMSG.STOP_MIRROR_TIMER - // there we must send 888 opcode - - // the player cannot have a corpse already, only bones which are not returned by GetCorpse - if(GetCorpse()) - { - sLog.outError("BuildPlayerRepop: player %s(%d) already has a corpse", GetName(), GetGUIDLow()); - assert(false); - } - - // create a corpse and place it at the player's location - CreateCorpse(); - Corpse *corpse = GetCorpse(); - if(!corpse) - { - sLog.outError("Error creating corpse for Player %s [%u]", GetName(), GetGUIDLow()); - return; - } - GetMap()->Add(corpse); - - // convert player body to ghost - SetHealth( 1 ); - - SetMovement(MOVE_WATER_WALK); - if(!GetSession()->isLogingOut()) - SetMovement(MOVE_UNROOT); - - // BG - remove insignia related - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - - SendCorpseReclaimDelay(); - - // to prevent cheating - corpse->ResetGhostTime(); - - StopMirrorTimers(); //disable timers(bars) - - SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, (float)1.0); //see radius of death player? - - SetByteValue(UNIT_FIELD_BYTES_1, 3, PLAYER_STATE_FLAG_ALWAYS_STAND); -} - -void Player::SendDelayResponse(const uint32 ml_seconds) -{ - WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 ); - data << (uint32)time(NULL); - data << (uint32)0; - GetSession()->SendPacket( &data ); -} - -void Player::ResurrectPlayer(float restore_percent, bool updateToWorld, bool applySickness) -{ - WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // remove spirit healer position - data << uint32(-1); - data << float(0); - data << float(0); - data << float(0); - GetSession()->SendPacket(&data); - - // speed change, land walk - - // remove death flag + set aura - SetByteValue(UNIT_FIELD_BYTES_1, 3, 0x00); - if(getRace() == RACE_NIGHTELF) - RemoveAurasDueToSpell(20584); // speed bonuses - RemoveAurasDueToSpell(8326); // SPELL_AURA_GHOST - - setDeathState(ALIVE); - - SetMovement(MOVE_LAND_WALK); - SetMovement(MOVE_UNROOT); - - m_deathTimer = 0; - - // set health/powers (0- will be set in caller) - if(restore_percent>0.0f) - { - SetHealth(uint32(GetMaxHealth()*restore_percent)); - SetPower(POWER_MANA, uint32(GetMaxPower(POWER_MANA)*restore_percent)); - SetPower(POWER_RAGE, 0); - SetPower(POWER_ENERGY, uint32(GetMaxPower(POWER_ENERGY)*restore_percent)); - } - - // update visbility - ObjectAccessor::UpdateVisibilityForPlayer(this); - - // some items limited to specific map - DestroyZoneLimitedItem( true, GetZoneId()); - - if(!applySickness || getLevel() <= 10) - return; - - //Characters from level 1-10 are not affected by resurrection sickness. - //Characters from level 11-19 will suffer from one minute of sickness - //for each level they are above 10. - //Characters level 20 and up suffer from ten minutes of sickness. - int32 startLevel = sWorld.getConfig(CONFIG_DEATH_SICKNESS_LEVEL); - - if(int32(getLevel()) >= startLevel) - { - // set resurrection sickness - CastSpell(this,SPELL_ID_PASSIVE_RESURRECTION_SICKNESS,true); - - // not full duration - if(int32(getLevel()) < startLevel+9) - { - int32 delta = (int32(getLevel()) - startLevel + 1)*MINUTE; - - for(int i =0; i < 3; ++i) - { - if(Aura* Aur = GetAura(SPELL_ID_PASSIVE_RESURRECTION_SICKNESS,i)) - { - Aur->SetAuraDuration(delta*1000); - Aur->UpdateAuraDuration(); - } - } - } - } -} - -void Player::KillPlayer() -{ - SetMovement(MOVE_ROOT); - - StopMirrorTimers(); //disable timers(bars) - - setDeathState(CORPSE); - //SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_IN_PVP ); - - SetFlag(UNIT_DYNAMIC_FLAGS, 0x00); - ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(GetMapId())->Instanceable()); - - // 6 minutes until repop at graveyard - m_deathTimer = 6*MINUTE*1000; - - UpdateCorpseReclaimDelay(); // dependent at use SetDeathPvP() call before kill - - // don't create corpse at this moment, player might be falling - - // update visibility - ObjectAccessor::UpdateObjectVisibility(this); -} - -void Player::CreateCorpse() -{ - // prevent existence 2 corpse for player - SpawnCorpseBones(); - - uint32 _uf, _pb, _pb2, _cfb1, _cfb2; - - Corpse *corpse = new Corpse( (m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) ? CORPSE_RESURRECTABLE_PVP : CORPSE_RESURRECTABLE_PVE ); - SetPvPDeath(false); - - if(!corpse->Create(objmgr.GenerateLowGuid(HIGHGUID_CORPSE), this, GetMapId(), GetPositionX(), - GetPositionY(), GetPositionZ(), GetOrientation())) - { - delete corpse; - return; - } - - _uf = GetUInt32Value(UNIT_FIELD_BYTES_0); - _pb = GetUInt32Value(PLAYER_BYTES); - _pb2 = GetUInt32Value(PLAYER_BYTES_2); - - uint8 race = (uint8)(_uf); - uint8 skin = (uint8)(_pb); - uint8 face = (uint8)(_pb >> 8); - uint8 hairstyle = (uint8)(_pb >> 16); - uint8 haircolor = (uint8)(_pb >> 24); - uint8 facialhair = (uint8)(_pb2); - - _cfb1 = ((0x00) | (race << 8) | (getGender() << 16) | (skin << 24)); - _cfb2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24)); - - corpse->SetUInt32Value( CORPSE_FIELD_BYTES_1, _cfb1 ); - corpse->SetUInt32Value( CORPSE_FIELD_BYTES_2, _cfb2 ); - - uint32 flags = CORPSE_FLAG_UNK2; - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) - flags |= CORPSE_FLAG_HIDE_HELM; - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) - flags |= CORPSE_FLAG_HIDE_CLOAK; - if(InBattleGround()) - flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia - corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, flags ); - - corpse->SetUInt32Value( CORPSE_FIELD_DISPLAY_ID, GetNativeDisplayId() ); - - corpse->SetUInt32Value( CORPSE_FIELD_GUILD, GetGuildId() ); - - uint32 iDisplayID; - uint16 iIventoryType; - uint32 _cfi; - for (int i = 0; i < EQUIPMENT_SLOT_END; i++) - { - if(m_items[i]) - { - iDisplayID = m_items[i]->GetProto()->DisplayInfoID; - iIventoryType = (uint16)m_items[i]->GetProto()->InventoryType; - - _cfi = (uint16(iDisplayID)) | (iIventoryType)<< 24; - corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i,_cfi); - } - } - - // we don't SaveToDB for players in battlegrounds so don't do it for corpses either - const MapEntry *entry = sMapStore.LookupEntry(corpse->GetMapId()); - assert(entry); - if(entry->map_type != MAP_BATTLEGROUND) - corpse->SaveToDB(); - - // register for player, but not show - ObjectAccessor::Instance().AddCorpse(corpse); -} - -void Player::SpawnCorpseBones() -{ - if(ObjectAccessor::Instance().ConvertCorpseForPlayer(GetGUID())) - SaveToDB(); // prevent loading as ghost without corpse -} - -Corpse* Player::GetCorpse() const -{ - return ObjectAccessor::Instance().GetCorpseForPlayerGUID(GetGUID()); -} - -void Player::DurabilityLossAll(double percent, bool inventory) -{ - for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) - if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - DurabilityLoss(pItem,percent); - - if(inventory) - { - // bags not have durability - // for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - DurabilityLoss(pItem,percent); - - // keys not have durability - //for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - if(ItemPrototype const *pBagProto = pBag->GetProto()) - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - if(Item* pItem = GetItemByPos( i, j )) - DurabilityLoss(pItem,percent); - } -} - -void Player::DurabilityLoss(Item* item, double percent) -{ - if(!item ) - return; - - uint32 pMaxDurability = item ->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); - - if(!pMaxDurability) - return; - - uint32 pDurabilityLoss = uint32(pMaxDurability*percent); - - if(pDurabilityLoss < 1 ) - pDurabilityLoss = 1; - - DurabilityPointsLoss(item,pDurabilityLoss); -} - -void Player::DurabilityPointsLossAll(int32 points, bool inventory) -{ - for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) - if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - DurabilityPointsLoss(pItem,points); - - if(inventory) - { - // bags not have durability - // for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - DurabilityPointsLoss(pItem,points); - - // keys not have durability - //for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - if(ItemPrototype const *pBagProto = pBag->GetProto()) - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - if(Item* pItem = GetItemByPos( i, j )) - DurabilityPointsLoss(pItem,points); - } -} - -void Player::DurabilityPointsLoss(Item* item, int32 points) -{ - int32 pMaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); - int32 pOldDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); - int32 pNewDurability = pOldDurability - points; - - if (pNewDurability < 0) - pNewDurability = 0; - else if (pNewDurability > pMaxDurability) - pNewDurability = pMaxDurability; - - if (pOldDurability != pNewDurability) - { - // modify item stats _before_ Durability set to 0 to pass _ApplyItemMods internal check - if ( pNewDurability == 0 && pOldDurability > 0 && item->IsEquipped()) - _ApplyItemMods(item,item->GetSlot(), false); - - item->SetUInt32Value(ITEM_FIELD_DURABILITY, pNewDurability); - - // modify item stats _after_ restore durability to pass _ApplyItemMods internal check - if ( pNewDurability > 0 && pOldDurability == 0 && item->IsEquipped()) - _ApplyItemMods(item,item->GetSlot(), true); - - item->SetState(ITEM_CHANGED, this); - } -} - -void Player::DurabilityPointLossForEquipSlot(EquipmentSlots slot) -{ - if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, slot )) - DurabilityPointsLoss(pItem,1); -} - -uint32 Player::DurabilityRepairAll(bool cost, float discountMod, bool guildBank) -{ - uint32 TotalCost = 0; - // equipped, backpack, bags itself - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) - TotalCost += DurabilityRepair(( (INVENTORY_SLOT_BAG_0 << 8) | i ),cost,discountMod, guildBank); - - // bank, buyback and keys not repaired - - // items in inventory bags - for(int j = INVENTORY_SLOT_BAG_START; j < INVENTORY_SLOT_BAG_END; j++) - for(int i = 0; i < MAX_BAG_SIZE; i++) - TotalCost += DurabilityRepair(( (j << 8) | i ),cost,discountMod, guildBank); - return TotalCost; -} - -uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool guildBank) -{ - Item* item = GetItemByPos(pos); - - uint32 TotalCost = 0; - if(!item) - return TotalCost; - - uint32 maxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); - if(!maxDurability) - return TotalCost; - - uint32 curDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); - - if(cost) - { - uint32 LostDurability = maxDurability - curDurability; - if(LostDurability>0) - { - ItemPrototype const *ditemProto = sItemStorage.LookupEntry(item->GetEntry()); - if(!ditemProto) - { - sLog.outError("ERROR: RepairDurability: Unknown item id %u", ditemProto); - return TotalCost; - } - - DurabilityCostsEntry const *dcost = sDurabilityCostsStore.LookupEntry(ditemProto->ItemLevel); - if(!dcost) - { - sLog.outError("ERROR: RepairDurability: Wrong item lvl %u", dcost); - return TotalCost; - } - - DurabilityQualityEntry const *dQualitymodEntry = sDurabilityQualityStore.LookupEntry((ditemProto->Quality+1)*2); - if(!dQualitymodEntry) - { - sLog.outError("ERROR: RepairDurability: Wrong dQualityModEntry %u", dQualitymodEntry); - return TotalCost; - } - - uint32 dmultiplier = dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class,ditemProto->SubClass)]; - uint32 costs = uint32(LostDurability*dmultiplier*double(dQualitymodEntry->quality_mod)); - - costs = uint32(costs * discountMod); - - if (costs==0) //fix for ITEM_QUALITY_ARTIFACT - costs = 1; - - if (guildBank) - { - if (GetGuildId()==0) - { - DEBUG_LOG("You are not member of a guild"); - return TotalCost; - } - - Guild *pGuild = objmgr.GetGuildById(GetGuildId()); - if (!pGuild) - return TotalCost; - - if (!pGuild->HasRankRight(GetRank(), GR_RIGHT_WITHDRAW_REPAIR)) - { - DEBUG_LOG("You do not have rights to withdraw for repairs"); - return TotalCost; - } - - if (pGuild->GetMemberMoneyWithdrawRem(GetGUIDLow()) < costs) - { - DEBUG_LOG("You do not have enough money withdraw amount remaining"); - return TotalCost; - } - - if (pGuild->GetGuildBankMoney() < costs) - { - DEBUG_LOG("There is not enough money in bank"); - return TotalCost; - } - - pGuild->MemberMoneyWithdraw(costs, GetGUIDLow()); - TotalCost = costs; - } - else if (GetMoney() < costs) - { - DEBUG_LOG("You do not have enough money"); - return TotalCost; - } - else - ModifyMoney( -int32(costs) ); - } - } - - item->SetUInt32Value(ITEM_FIELD_DURABILITY, maxDurability); - item->SetState(ITEM_CHANGED, this); - - // reapply mods for total broken and repaired item if equipped - if(IsEquipmentPos(pos) && !curDurability) - _ApplyItemMods(item,pos & 255, true); - return TotalCost; -} - -void Player::RepopAtGraveyard() -{ - // note: this can be called also when the player is alive - // for example from WorldSession::HandleMovementOpcodes - - AreaTableEntry const *zone = GetAreaEntryByAreaID(GetAreaId()); - - // Such zones are considered unreachable as a ghost and the player must be automatically revived - if(!isAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY || GetTransport()) - { - ResurrectPlayer(0.5f); - SpawnCorpseBones(); - } - - WorldSafeLocsEntry const *ClosestGrave = NULL; - - // Special handle for battleground maps - BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId()); - - if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY)) - ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam()); - else - ClosestGrave = objmgr.GetClosestGraveYard( GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam() ); - - // stop countdown until repop - m_deathTimer = 0; - - // if no grave found, stay at the current location - // and don't show spirit healer location - if(ClosestGrave) - { - TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation()); - if(isDead()) // not send if alive, because it used in TeleportTo() - { - WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // show spirit healer position on minimap - data << ClosestGrave->map_id; - data << ClosestGrave->x; - data << ClosestGrave->y; - data << ClosestGrave->z; - GetSession()->SendPacket(&data); - } - } -} - -void Player::JoinedChannel(Channel *c) -{ - m_channels.push_back(c); -} - -void Player::LeftChannel(Channel *c) -{ - m_channels.remove(c); -} - -void Player::CleanupChannels() -{ - while(!m_channels.empty()) - { - Channel* ch = *m_channels.begin(); - m_channels.erase(m_channels.begin()); // remove from player's channel list - ch->Leave(GetGUID(), false); // not send to client, not remove from player's channel list - if (ChannelMgr* cMgr = channelMgr(GetTeam())) - cMgr->LeftChannel(ch->GetName()); // deleted channel if empty - - } - sLog.outDebug("Player: channels cleaned up!"); -} - -void Player::UpdateLocalChannels(uint32 newZone ) -{ - if(m_channels.empty()) - return; - - AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone); - if(!current_zone) - return; - - ChannelMgr* cMgr = channelMgr(GetTeam()); - if(!cMgr) - return; - - std::string current_zone_name = current_zone->area_name[GetSession()->GetSessionDbcLocale()]; - - for(JoinedChannelsList::iterator i = m_channels.begin(), next; i != m_channels.end(); i = next) - { - next = i; ++next; - - // skip non built-in channels - if(!(*i)->IsConstant()) - continue; - - ChatChannelsEntry const* ch = GetChannelEntryFor((*i)->GetChannelId()); - if(!ch) - continue; - - if((ch->flags & 4) == 4) // global channel without zone name in pattern - continue; - - // new channel - char new_channel_name_buf[100]; - snprintf(new_channel_name_buf,100,ch->pattern[m_session->GetSessionDbcLocale()],current_zone_name.c_str()); - Channel* new_channel = cMgr->GetJoinChannel(new_channel_name_buf,ch->ChannelID); - - if((*i)!=new_channel) - { - new_channel->Join(GetGUID(),""); // will output Changed Channel: N. Name - - // leave old channel - (*i)->Leave(GetGUID(),false); // not send leave channel, it already replaced at client - std::string name = (*i)->GetName(); // stroe name, (*i)erase in LeftChannel - LeftChannel(*i); // remove from player's channel list - cMgr->LeftChannel(name); // delete if empty - } - } - sLog.outDebug("Player: channels cleaned up!"); -} - -void Player::LeaveLFGChannel() -{ - for(JoinedChannelsList::iterator i = m_channels.begin(); i != m_channels.end(); ++i ) - { - if((*i)->IsLFG()) - { - (*i)->Leave(GetGUID()); - break; - } - } -} - -void Player::UpdateDefense() -{ - uint32 defense_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_DEFENSE); - - if(UpdateSkill(SKILL_DEFENSE,defense_skill_gain)) - { - // update dependent from defense skill part - UpdateDefenseBonusesMod(); - } -} - -void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply, bool affectStats) -{ - if(modGroup >= BASEMOD_END || modType >= MOD_END) - { - sLog.outError("ERROR in HandleBaseModValue(): nonexisted BaseModGroup of wrong BaseModType!"); - return; - } - - float val = 1.0f; - - switch(modType) - { - case FLAT_MOD: - m_auraBaseMod[modGroup][modType] += apply ? amount : -amount; - break; - case PCT_MOD: - if(amount <= -100.0f) - amount = -200.0f; - - val = (100.0f + amount) / 100.0f; - m_auraBaseMod[modGroup][modType] *= apply ? val : (1.0f/val); - break; - } - - if(!CanModifyStats()) - return; - - switch(modGroup) - { - case CRIT_PERCENTAGE: UpdateCritPercentage(BASE_ATTACK); break; - case RANGED_CRIT_PERCENTAGE: UpdateCritPercentage(RANGED_ATTACK); break; - case OFFHAND_CRIT_PERCENTAGE: UpdateCritPercentage(OFF_ATTACK); break; - case SHIELD_BLOCK_VALUE: UpdateShieldBlockValue(); break; - default: break; - } -} - -float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const -{ - if(modGroup >= BASEMOD_END || modType > MOD_END) - { - sLog.outError("ERROR: trial to access nonexisted BaseModGroup or wrong BaseModType!"); - return 0.0f; - } - - if(modType == PCT_MOD && m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f) - return 0.0f; - - return m_auraBaseMod[modGroup][modType]; -} - -float Player::GetTotalBaseModValue(BaseModGroup modGroup) const -{ - if(modGroup >= BASEMOD_END) - { - sLog.outError("ERROR: wrong BaseModGroup in GetTotalBaseModValue()!"); - return 0.0f; - } - - if(m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f) - return 0.0f; - - return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD]; -} - -uint32 Player::GetShieldBlockValue() const -{ - BaseModGroup modGroup = SHIELD_BLOCK_VALUE; - - float value = GetTotalBaseModValue(modGroup) + GetStat(STAT_STRENGTH)/20 - 1; - - value = (value < 0) ? 0 : value; - - return uint32(value); -} - -float Player::GetMeleeCritFromAgility() -{ - uint32 level = getLevel(); - uint32 pclass = getClass(); - - if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; - - GtChanceToMeleeCritBaseEntry const *critBase = sGtChanceToMeleeCritBaseStore.LookupEntry(pclass-1); - GtChanceToMeleeCritEntry const *critRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (critBase==NULL || critRatio==NULL) - return 0.0f; - - float crit=critBase->base + GetStat(STAT_AGILITY)*critRatio->ratio; - return crit*100.0f; -} - -float Player::GetDodgeFromAgility() -{ - // Table for base dodge values - float dodge_base[MAX_CLASSES] = { - 0.0075f, // Warrior - 0.00652f, // Paladin - -0.0545f, // Hunter - -0.0059f, // Rogue - 0.03183f, // Priest - 0.0114f, // DK - 0.0167f, // Shaman - 0.034575f, // Mage - 0.02011f, // Warlock - 0.0f, // ?? - -0.0187f // Druid - }; - // Crit/agility to dodge/agility coefficient multipliers - float crit_to_dodge[MAX_CLASSES] = { - 1.1f, // Warrior - 1.0f, // Paladin - 1.6f, // Hunter - 2.0f, // Rogue - 1.0f, // Priest - 1.0f, // DK? - 1.0f, // Shaman - 1.0f, // Mage - 1.0f, // Warlock - 0.0f, // ?? - 1.7f // Druid - }; - - uint32 level = getLevel(); - uint32 pclass = getClass(); - - if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; - - // Dodge per agility for most classes equal crit per agility (but for some classes need apply some multiplier) - GtChanceToMeleeCritEntry const *dodgeRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (dodgeRatio==NULL || pclass > MAX_CLASSES) - return 0.0f; - - float dodge=dodge_base[pclass-1] + GetStat(STAT_AGILITY) * dodgeRatio->ratio * crit_to_dodge[pclass-1]; - return dodge*100.0f; -} - -float Player::GetSpellCritFromIntellect() -{ - uint32 level = getLevel(); - uint32 pclass = getClass(); - - if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; - - GtChanceToSpellCritBaseEntry const *critBase = sGtChanceToSpellCritBaseStore.LookupEntry(pclass-1); - GtChanceToSpellCritEntry const *critRatio = sGtChanceToSpellCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (critBase==NULL || critRatio==NULL) - return 0.0f; - - float crit=critBase->base + GetStat(STAT_INTELLECT)*critRatio->ratio; - return crit*100.0f; -} - -float Player::GetRatingCoefficient(CombatRating cr) const -{ - uint32 level = getLevel(); - - if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; - - GtCombatRatingsEntry const *Rating = sGtCombatRatingsStore.LookupEntry(cr*GT_MAX_LEVEL+level-1); - if (Rating == NULL) - return 1.0f; // By default use minimum coefficient (not must be called) - - return Rating->ratio; -} - -float Player::GetRatingBonusValue(CombatRating cr) const -{ - return float(GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr)) / GetRatingCoefficient(cr); -} - -uint32 Player::GetMeleeCritDamageReduction(uint32 damage) const -{ - float melee = GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*2.0f; - if (melee>25.0f) melee = 25.0f; - return uint32 (melee * damage /100.0f); -} - -uint32 Player::GetRangedCritDamageReduction(uint32 damage) const -{ - float ranged = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED)*2.0f; - if (ranged>25.0f) ranged=25.0f; - return uint32 (ranged * damage /100.0f); -} - -uint32 Player::GetSpellCritDamageReduction(uint32 damage) const -{ - float spell = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2.0f; - // In wow script resilience limited to 25% - if (spell>25.0f) - spell = 25.0f; - return uint32 (spell * damage / 100.0f); -} - -uint32 Player::GetDotDamageReduction(uint32 damage) const -{ - float spellDot = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); - // Dot resilience not limited (limit it by 100%) - if (spellDot > 100.0f) - spellDot = 100.0f; - return uint32 (spellDot * damage / 100.0f); -} - -float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const -{ - switch (attType) - { - case BASE_ATTACK: - return GetUInt32Value(PLAYER_EXPERTISE) / 4.0f; - case OFF_ATTACK: - return GetUInt32Value(PLAYER_OFFHAND_EXPERTISE) / 4.0f; - default: - break; - } - return 0.0f; -} - -float Player::OCTRegenHPPerSpirit() -{ - uint32 level = getLevel(); - uint32 pclass = getClass(); - - if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; - - GtOCTRegenHPEntry const *baseRatio = sGtOCTRegenHPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - GtRegenHPPerSptEntry const *moreRatio = sGtRegenHPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (baseRatio==NULL || moreRatio==NULL) - return 0.0f; - - // Formula from PaperDollFrame script - float spirit = GetStat(STAT_SPIRIT); - float baseSpirit = spirit; - if (baseSpirit>50) baseSpirit = 50; - float moreSpirit = spirit - baseSpirit; - float regen = baseSpirit * baseRatio->ratio + moreSpirit * moreRatio->ratio; - return regen; -} - -float Player::OCTRegenMPPerSpirit() -{ - uint32 level = getLevel(); - uint32 pclass = getClass(); - - if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; - -// GtOCTRegenMPEntry const *baseRatio = sGtOCTRegenMPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - GtRegenMPPerSptEntry const *moreRatio = sGtRegenMPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (moreRatio==NULL) - return 0.0f; - - // Formula get from PaperDollFrame script - float spirit = GetStat(STAT_SPIRIT); - float regen = spirit * moreRatio->ratio; - return regen; -} - -void Player::ApplyRatingMod(CombatRating cr, int32 value, bool apply) -{ - ApplyModUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, value, apply); - - float RatingCoeffecient = GetRatingCoefficient(cr); - float RatingChange = 0.0f; - - bool affectStats = CanModifyStats(); - - switch (cr) - { - case CR_WEAPON_SKILL: // Implemented in Unit::RollMeleeOutcomeAgainst - case CR_DEFENSE_SKILL: - UpdateDefenseBonusesMod(); - break; - case CR_DODGE: - UpdateDodgePercentage(); - break; - case CR_PARRY: - UpdateParryPercentage(); - break; - case CR_BLOCK: - UpdateBlockPercentage(); - break; - case CR_HIT_MELEE: - RatingChange = value / RatingCoeffecient; - m_modMeleeHitChance += apply ? RatingChange : -RatingChange; - break; - case CR_HIT_RANGED: - RatingChange = value / RatingCoeffecient; - m_modRangedHitChance += apply ? RatingChange : -RatingChange; - break; - case CR_HIT_SPELL: - RatingChange = value / RatingCoeffecient; - m_modSpellHitChance += apply ? RatingChange : -RatingChange; - break; - case CR_CRIT_MELEE: - if(affectStats) - { - UpdateCritPercentage(BASE_ATTACK); - UpdateCritPercentage(OFF_ATTACK); - } - break; - case CR_CRIT_RANGED: - if(affectStats) - UpdateCritPercentage(RANGED_ATTACK); - break; - case CR_CRIT_SPELL: - if(affectStats) - UpdateAllSpellCritChances(); - break; - case CR_HIT_TAKEN_MELEE: // Implemented in Unit::MeleeMissChanceCalc - case CR_HIT_TAKEN_RANGED: - break; - case CR_HIT_TAKEN_SPELL: // Implemented in Unit::MagicSpellHitResult - break; - case CR_CRIT_TAKEN_MELEE: // Implemented in Unit::RollMeleeOutcomeAgainst (only for chance to crit) - case CR_CRIT_TAKEN_RANGED: - break; - case CR_CRIT_TAKEN_SPELL: // Implemented in Unit::SpellCriticalBonus (only for chance to crit) - break; - case CR_HASTE_MELEE: - RatingChange = value / RatingCoeffecient; - ApplyAttackTimePercentMod(BASE_ATTACK,RatingChange,apply); - ApplyAttackTimePercentMod(OFF_ATTACK,RatingChange,apply); - break; - case CR_HASTE_RANGED: - RatingChange = value / RatingCoeffecient; - ApplyAttackTimePercentMod(RANGED_ATTACK, RatingChange, apply); - break; - case CR_HASTE_SPELL: - RatingChange = value / RatingCoeffecient; - ApplyCastTimePercentMod(RatingChange,apply); - break; - case CR_WEAPON_SKILL_MAINHAND: // Implemented in Unit::RollMeleeOutcomeAgainst - case CR_WEAPON_SKILL_OFFHAND: - case CR_WEAPON_SKILL_RANGED: - break; - case CR_EXPERTISE: - if(affectStats) - { - UpdateExpertise(BASE_ATTACK); - UpdateExpertise(OFF_ATTACK); - } - break; - } -} - -void Player::SetRegularAttackTime() -{ - for(int i = 0; i < MAX_ATTACK; ++i) - { - Item *tmpitem = GetWeaponForAttack(WeaponAttackType(i)); - if(tmpitem && !tmpitem->IsBroken()) - { - ItemPrototype const *proto = tmpitem->GetProto(); - if(proto->Delay) - SetAttackTime(WeaponAttackType(i), proto->Delay); - else - SetAttackTime(WeaponAttackType(i), BASE_ATTACK_TIME); - } - } -} - -//skill+step, checking for max value -bool Player::UpdateSkill(uint32 skill_id, uint32 step) -{ - if(!skill_id) - return false; - - uint16 i=0; - for (; i < PLAYER_MAX_SKILLS; i++) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill_id) - break; - - if(i>=PLAYER_MAX_SKILLS) - return false; - - uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); - uint32 value = SKILL_VALUE(data); - uint32 max = SKILL_MAX(data); - - if ((!max) || (!value) || (value >= max)) - return false; - - if (value*512 < max*urand(0,512)) - { - uint32 new_value = value+step; - if(new_value > max) - new_value = max; - - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,max)); - return true; - } - - return false; -} - -inline int SkillGainChance(uint32 SkillValue, uint32 GrayLevel, uint32 GreenLevel, uint32 YellowLevel) -{ - if ( SkillValue >= GrayLevel ) - return sWorld.getConfig(CONFIG_SKILL_CHANCE_GREY)*10; - if ( SkillValue >= GreenLevel ) - return sWorld.getConfig(CONFIG_SKILL_CHANCE_GREEN)*10; - if ( SkillValue >= YellowLevel ) - return sWorld.getConfig(CONFIG_SKILL_CHANCE_YELLOW)*10; - return sWorld.getConfig(CONFIG_SKILL_CHANCE_ORANGE)*10; -} - -bool Player::UpdateCraftSkill(uint32 spellid) -{ - sLog.outDebug("UpdateCraftSkill spellid %d", spellid); - - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spellid); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spellid); - - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - if(_spell_idx->second->skillId) - { - uint32 SkillValue = GetPureSkillValue(_spell_idx->second->skillId); - - // Alchemy Discoveries here - SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellid); - if(spellEntry && spellEntry->Mechanic==MECHANIC_DISCOVERY) - { - if(uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this)) - learnSpell(discoveredSpell); - } - - uint32 craft_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_CRAFTING); - - return UpdateSkillPro(_spell_idx->second->skillId, SkillGainChance(SkillValue, - _spell_idx->second->max_value, - (_spell_idx->second->max_value + _spell_idx->second->min_value)/2, - _spell_idx->second->min_value), - craft_skill_gain); - } - } - return false; -} - -bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator ) -{ - sLog.outDebug("UpdateGatherSkill(SkillId %d SkillLevel %d RedLevel %d)", SkillId, SkillValue, RedLevel); - - uint32 gathering_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_GATHERING); - - // For skinning and Mining chance decrease with level. 1-74 - no decrease, 75-149 - 2 times, 225-299 - 8 times - switch (SkillId) - { - case SKILL_HERBALISM: - case SKILL_LOCKPICKING: - case SKILL_JEWELCRAFTING: - return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator,gathering_skill_gain); - case SKILL_SKINNING: - if( sWorld.getConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)==0) - return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator,gathering_skill_gain); - else - return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/sWorld.getConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)), gathering_skill_gain); - case SKILL_MINING: - if (sWorld.getConfig(CONFIG_SKILL_CHANCE_MINING_STEPS)==0) - return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator,gathering_skill_gain); - else - return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/sWorld.getConfig(CONFIG_SKILL_CHANCE_MINING_STEPS)),gathering_skill_gain); - } - return false; -} - -bool Player::UpdateFishingSkill() -{ - sLog.outDebug("UpdateFishingSkill"); - - uint32 SkillValue = GetPureSkillValue(SKILL_FISHING); - - int32 chance = SkillValue < 75 ? 100 : 2500/(SkillValue-50); - - uint32 gathering_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_GATHERING); - - return UpdateSkillPro(SKILL_FISHING,chance*10,gathering_skill_gain); -} - -bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) -{ - sLog.outDebug("UpdateSkillPro(SkillId %d, Chance %3.1f%%)", SkillId, Chance/10.0); - if ( !SkillId ) - return false; - - if(Chance <= 0) // speedup in 0 chance case - { - sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% missed", Chance/10.0); - return false; - } - - uint16 i=0; - for (; i < PLAYER_MAX_SKILLS; i++) - if ( SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_INDEX(i))) == SkillId ) break; - if ( i >= PLAYER_MAX_SKILLS ) - return false; - - uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); - uint16 SkillValue = SKILL_VALUE(data); - uint16 MaxValue = SKILL_MAX(data); - - if ( !MaxValue || !SkillValue || SkillValue >= MaxValue ) - return false; - - int32 Roll = irand(1,1000); - - if ( Roll <= Chance ) - { - uint32 new_value = SkillValue+step; - if(new_value > MaxValue) - new_value = MaxValue; - - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,MaxValue)); - sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% taken", Chance/10.0); - return true; - } - - sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% missed", Chance/10.0); - return false; -} - -void Player::UpdateWeaponSkill (WeaponAttackType attType) -{ - // no skill gain in pvp - Unit *pVictim = getVictim(); - if(pVictim && pVictim->GetTypeId() == TYPEID_PLAYER) - return; - - if(IsInFeralForm()) - return; // always maximized SKILL_FERAL_COMBAT in fact - - if(m_form == FORM_TREE) - return; // use weapon but not skill up - - uint32 weapon_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_WEAPON); - - switch(attType) - { - case BASE_ATTACK: - { - Item *tmpitem = GetWeaponForAttack(attType,true); - - if (!tmpitem) - UpdateSkill(SKILL_UNARMED,weapon_skill_gain); - else if(tmpitem->GetProto()->SubClass != ITEM_SUBCLASS_WEAPON_FISHING_POLE) - UpdateSkill(tmpitem->GetSkill(),weapon_skill_gain); - break; - } - case OFF_ATTACK: - case RANGED_ATTACK: - { - Item *tmpitem = GetWeaponForAttack(attType,true); - if (tmpitem) - UpdateSkill(tmpitem->GetSkill(),weapon_skill_gain); - break; - } - } - UpdateAllCritPercentages(); -} - -void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence) -{ - switch(outcome) - { - case MELEE_HIT_CRIT: - case MELEE_HIT_DODGE: - case MELEE_HIT_PARRY: - case MELEE_HIT_BLOCK: - case MELEE_HIT_BLOCK_CRIT: - return; - - default: - break; - } - - uint32 plevel = getLevel(); // if defense than pVictim == attacker - uint32 greylevel = MaNGOS::XP::GetGrayLevel(plevel); - uint32 moblevel = pVictim->getLevelForTarget(this); - if(moblevel < greylevel) - return; - - if (moblevel > plevel + 5) - moblevel = plevel + 5; - - uint32 lvldif = moblevel - greylevel; - if(lvldif < 3) - lvldif = 3; - - uint32 skilldif = 5 * plevel - (defence ? GetBaseDefenseSkillValue() : GetBaseWeaponSkillValue(attType)); - if(skilldif <= 0) - return; - - float chance = float(3 * lvldif * skilldif) / plevel; - if(!defence) - { - if(getClass() == CLASS_WARRIOR || getClass() == CLASS_ROGUE) - chance *= 0.1f * GetStat(STAT_INTELLECT); - } - - chance = chance < 1.0f ? 1.0f : chance; //minimum chance to increase skill is 1% - - if(roll_chance_f(chance)) - { - if(defence) - UpdateDefense(); - else - UpdateWeaponSkill(attType); - } - else - return; -} - -void Player::ModifySkillBonus(uint32 skillid,int32 val, bool talent) -{ - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skillid) - { - uint32 bonus_val = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); - int16 temp_bonus = SKILL_TEMP_BONUS(bonus_val); - int16 perm_bonus = SKILL_PERM_BONUS(bonus_val); - - if(talent) // permanent bonus stored in high part - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),MAKE_SKILL_BONUS(temp_bonus,perm_bonus+val)); - else // temporary/item bonus stored in low part - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),MAKE_SKILL_BONUS(temp_bonus+val,perm_bonus)); - return; - } -} - -void Player::UpdateMaxSkills() -{ - uint16 maxconfskill = sWorld.GetConfigMaxSkillValue(); - - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - if (GetUInt32Value(PLAYER_SKILL_INDEX(i))) - { - uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; - - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(pskill); - if(!pSkill) - continue; - - if(GetSkillRangeType(pSkill,false) != SKILL_RANGE_LEVEL) - continue; - - uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); - uint32 max = SKILL_MAX(data); - uint32 val = SKILL_VALUE(data); - - // update only level dependent max skill values - if(max!=1 && max != maxconfskill) - { - uint32 max_Skill = GetMaxSkillValueForLevel(); - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(val,max_Skill)); - } - } -} - -void Player::UpdateSkillsToMaxSkillsForLevel() -{ - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - if (GetUInt32Value(PLAYER_SKILL_INDEX(i))) - { - uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; - if( IsProfessionSkill(pskill) || pskill == SKILL_RIDING ) - continue; - uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); - - uint32 max = SKILL_MAX(data); - - if(max > 1) - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(max,max)); - - if(pskill == SKILL_DEFENSE) - { - UpdateBlockPercentage(); - } - } -} - -// This functions sets a skill line value (and adds if doesn't exist yet) -// To "remove" a skill line, set it's values to zero -void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal) -{ - if(!id) - return; - - uint16 i=0; - for (; i < PLAYER_MAX_SKILLS; i++) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == id) break; - - if(isecond->state == PLAYERSPELL_REMOVED) - continue; - - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(itr->first); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(itr->first); - - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - if (_spell_idx->second->skillId == id) - { - // this may remove more than one spell (dependants) - removeSpell(itr->first); - next = m_spells.begin(); - break; - } - } - } - } - } - else if(currVal) //add - { - for (i=0; i < PLAYER_MAX_SKILLS; i++) - if (!GetUInt32Value(PLAYER_SKILL_INDEX(i))) - { - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); - if(!pSkill) - { - sLog.outError("Skill not found in SkillLineStore: skill #%u", id); - return; - } - // enable unlearn button for primary professions only - if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); - else - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(currVal,maxVal)); - - // apply skill bonuses - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); - - // temporary bonuses - AuraList const& mModSkill = GetAurasByType(SPELL_AURA_MOD_SKILL); - for(AuraList::const_iterator i = mModSkill.begin(); i != mModSkill.end(); ++i) - if ((*i)->GetModifier()->m_miscvalue == int32(id)) - (*i)->ApplyModifier(true); - - // permanent bonuses - AuraList const& mModSkillTalent = GetAurasByType(SPELL_AURA_MOD_SKILL_TALENT); - for(AuraList::const_iterator i = mModSkillTalent.begin(); i != mModSkillTalent.end(); ++i) - if ((*i)->GetModifier()->m_miscvalue == int32(id)) - (*i)->ApplyModifier(true); - - // Learn all spells for skill - learnSkillRewardedSpells(id); - return; - } - } -} - -bool Player::HasSkill(uint32 skill) const -{ - if(!skill)return false; - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - return true; - } - } - return false; -} - -uint16 Player::GetSkillValue(uint32 skill) const -{ - if(!skill) - return 0; - - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); - - int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); - result += SKILL_TEMP_BONUS(bonus); - result += SKILL_PERM_BONUS(bonus); - return result < 0 ? 0 : result; - } - } - return 0; -} - -uint16 Player::GetMaxSkillValue(uint32 skill) const -{ - if(!skill)return 0; - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); - - int32 result = int32(SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); - result += SKILL_TEMP_BONUS(bonus); - result += SKILL_PERM_BONUS(bonus); - return result < 0 ? 0 : result; - } - } - return 0; -} - -uint16 Player::GetPureMaxSkillValue(uint32 skill) const -{ - if(!skill)return 0; - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - return SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); - } - } - return 0; -} - -uint16 Player::GetBaseSkillValue(uint32 skill) const -{ - if(!skill)return 0; - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); - result += SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i))); - return result < 0 ? 0 : result; - } - } - return 0; -} - -uint16 Player::GetPureSkillValue(uint32 skill) const -{ - if(!skill)return 0; - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); - } - } - return 0; -} - -int16 Player::GetSkillTempBonusValue(uint32 skill) const -{ - if(!skill) - return 0; - - for (int i = 0; i < PLAYER_MAX_SKILLS; i++) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - return SKILL_TEMP_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i))); - } - } - - return 0; -} - -void Player::SendInitialActionButtons() -{ - sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() ); - - WorldPacket data(SMSG_ACTION_BUTTONS, (MAX_ACTION_BUTTONS*4)); - for(int button = 0; button < MAX_ACTION_BUTTONS; ++button) - { - ActionButtonList::const_iterator itr = m_actionButtons.find(button); - if(itr != m_actionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED) - { - data << uint16(itr->second.action); - data << uint8(itr->second.misc); - data << uint8(itr->second.type); - } - else - { - data << uint32(0); - } - } - - GetSession()->SendPacket( &data ); - sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() ); -} - -void Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc) -{ - if(button >= MAX_ACTION_BUTTONS) - { - sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() ); - return; - } - - // check cheating with adding non-known spells to action bar - if(type==ACTION_BUTTON_SPELL) - { - if(!sSpellStore.LookupEntry(action)) - { - sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() ); - return; - } - - if(!HasSpell(action)) - { - sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() ); - return; - } - } - - ActionButtonList::iterator buttonItr = m_actionButtons.find(button); - - if (buttonItr==m_actionButtons.end()) - { // just add new button - m_actionButtons[button] = ActionButton(action,type,misc); - } - else - { // change state of current button - ActionButtonUpdateState uState = buttonItr->second.uState; - buttonItr->second = ActionButton(action,type,misc); - if (uState != ACTIONBUTTON_NEW) buttonItr->second.uState = ACTIONBUTTON_CHANGED; - }; - - sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button ); -} - -void Player::removeActionButton(uint8 button) -{ - ActionButtonList::iterator buttonItr = m_actionButtons.find(button); - if (buttonItr==m_actionButtons.end()) - return; - - if(buttonItr->second.uState==ACTIONBUTTON_NEW) - m_actionButtons.erase(buttonItr); // new and not saved - else - buttonItr->second.uState = ACTIONBUTTON_DELETED; // saved, will deleted at next save - - sLog.outDetail( "Action Button '%u' Removed from Player '%u'", button, GetGUIDLow() ); -} - -void Player::SetDontMove(bool dontMove) -{ - m_dontMove = dontMove; -} - -bool Player::SetPosition(float x, float y, float z, float orientation, bool teleport) -{ - // prevent crash when a bad coord is sent by the client - if(!MaNGOS::IsValidMapCoord(x,y,z,orientation)) - { - sLog.outDebug("Player::SetPosition(%f, %f, %f, %f, %d) .. bad coordinates for player %d!",x,y,z,orientation,teleport,GetGUIDLow()); - return false; - } - - Map *m = MapManager::Instance().GetMap(GetMapId(), this); - - const float old_x = GetPositionX(); - const float old_y = GetPositionY(); - const float old_z = GetPositionZ(); - const float old_r = GetOrientation(); - - if( teleport || old_x != x || old_y != y || old_z != z || old_r != orientation ) - { - if (teleport || old_x != x || old_y != y || old_z != z) - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING); - else - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); - - // move and update visible state if need - m->PlayerRelocation(this, x, y, z, orientation); - - // reread after Map::Relocation - m = MapManager::Instance().GetMap(GetMapId(), this); - x = GetPositionX(); - y = GetPositionY(); - z = GetPositionZ(); - } - - // code block for underwater state update - UpdateUnderwaterState(m, x, y, z); - - - CheckExploreSystem(); - - // group update - if(GetGroup()) - SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION); - - return true; -} - -void Player::SaveRecallPosition() -{ - m_recallMap = GetMapId(); - m_recallX = GetPositionX(); - m_recallY = GetPositionY(); - m_recallZ = GetPositionZ(); - m_recallO = GetOrientation(); -} - -void Player::SendMessageToSet(WorldPacket *data, bool self) -{ - MapManager::Instance().GetMap(GetMapId(), this)->MessageBroadcast(this, data, self); -} - -void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self) -{ - MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self); -} - -void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only) -{ - MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self,own_team_only); -} - -void Player::SendDirectMessage(WorldPacket *data) -{ - GetSession()->SendPacket(data); -} - -void Player::CheckExploreSystem() -{ - if (!isAlive()) - return; - - if (isInFlight()) - return; - - uint16 areaFlag=MapManager::Instance().GetBaseMap(GetMapId())->GetAreaFlag(GetPositionX(),GetPositionY()); - if(areaFlag==0xffff) - return; - int offset = areaFlag / 32; - - if(offset >= 128) - { - sLog.outError("ERROR: Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < 64 ).",areaFlag,GetPositionX(),GetPositionY(),offset,offset); - return; - } - - uint32 val = (uint32)(1 << (areaFlag % 32)); - uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); - - if( !(currFields & val) ) - { - SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val)); - - AreaTableEntry const *p = GetAreaEntryByAreaFlagAndMap(areaFlag,GetMapId()); - if(!p) - { - sLog.outError("PLAYER: Player %u discovered unknown area (x: %f y: %f map: %u", GetGUIDLow(), GetPositionX(),GetPositionY(),GetMapId()); - } - else if(p->area_level > 0) - { - uint32 area = p->ID; - if (getLevel() >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - SendExplorationExperience(area,0); - } - else - { - int32 diff = int32(getLevel()) - p->area_level; - uint32 XP = 0; - if (diff < -5) - { - XP = uint32(objmgr.GetBaseXP(getLevel()+5)*sWorld.getRate(RATE_XP_EXPLORE)); - } - else if (diff > 5) - { - int32 exploration_percent = (100-((diff-5)*5)); - if (exploration_percent > 100) - exploration_percent = 100; - else if (exploration_percent < 0) - exploration_percent = 0; - - XP = uint32(objmgr.GetBaseXP(p->area_level)*exploration_percent/100*sWorld.getRate(RATE_XP_EXPLORE)); - } - else - { - XP = uint32(objmgr.GetBaseXP(p->area_level)*sWorld.getRate(RATE_XP_EXPLORE)); - } - - GiveXP( XP, NULL ); - SendExplorationExperience(area,XP); - } - sLog.outDetail("PLAYER: Player %u discovered a new area: %u", GetGUIDLow(), area); - } - } -} - -uint32 Player::TeamForRace(uint8 race) -{ - ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race); - if(!rEntry) - { - sLog.outError("Race %u not found in DBC: wrong DBC files?",uint32(race)); - return ALLIANCE; - } - - switch(rEntry->TeamID) - { - case 7: return ALLIANCE; - case 1: return HORDE; - } - - sLog.outError("Race %u have wrong team id in DBC: wrong DBC files?",uint32(race),rEntry->TeamID); - return ALLIANCE; -} - -uint32 Player::getFactionForRace(uint8 race) -{ - ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race); - if(!rEntry) - { - sLog.outError("Race %u not found in DBC: wrong DBC files?",uint32(race)); - return 0; - } - - return rEntry->FactionID; -} - -void Player::setFactionForRace(uint8 race) -{ - m_team = TeamForRace(race); - setFaction( getFactionForRace(race) ); -} - -void Player::UpdateReputation() const -{ - sLog.outDetail( "WORLD: Player::UpdateReputation" ); - - for(FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) - { - SendFactionState(&(itr->second)); - } -} - -void Player::SendFactionState(FactionState const* faction) const -{ - if(faction->Flags & FACTION_FLAG_VISIBLE) //If faction is visible then update it - { - WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0 - data << (float) 0; // unk 2.4.0 - data << (uint32) 1; // count - // for - data << (uint32) faction->ReputationListID; - data << (uint32) faction->Standing; - // end for - GetSession()->SendPacket(&data); - } -} - -void Player::SendInitialReputations() -{ - WorldPacket data(SMSG_INITIALIZE_FACTIONS, (4+128*5)); - data << uint32 (0x00000080); - - RepListID a = 0; - - for (FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); itr++) - { - // fill in absent fields - for (; a != itr->first; a++) - { - data << uint8 (0x00); - data << uint32 (0x00000000); - } - - // fill in encountered data - data << uint8 (itr->second.Flags); - data << uint32 (itr->second.Standing); - - ++a; - } - - // fill in absent fields - for (; a != 128; a++) - { - data << uint8 (0x00); - data << uint32 (0x00000000); - } - - GetSession()->SendPacket(&data); -} - -FactionState const* Player::GetFactionState( FactionEntry const* factionEntry) const -{ - FactionStateList::const_iterator itr = m_factions.find(factionEntry->reputationListID); - if (itr != m_factions.end()) - return &itr->second; - - return NULL; -} - -void Player::SetFactionAtWar(FactionState* faction, bool atWar) -{ - // not allow declare war to own faction - if(atWar && (faction->Flags & FACTION_FLAG_PEACE_FORCED) ) - return; - - // already set - if(((faction->Flags & FACTION_FLAG_AT_WAR) != 0) == atWar) - return; - - if( atWar ) - faction->Flags |= FACTION_FLAG_AT_WAR; - else - faction->Flags &= ~FACTION_FLAG_AT_WAR; - - faction->Changed = true; -} - -void Player::SetFactionInactive(FactionState* faction, bool inactive) -{ - // always invisible or hidden faction can't be inactive - if(inactive && ((faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) || !(faction->Flags & FACTION_FLAG_VISIBLE) ) ) - return; - - // already set - if(((faction->Flags & FACTION_FLAG_INACTIVE) != 0) == inactive) - return; - - if(inactive) - faction->Flags |= FACTION_FLAG_INACTIVE; - else - faction->Flags &= ~FACTION_FLAG_INACTIVE; - - faction->Changed = true; -} - -void Player::SetFactionVisibleForFactionTemplateId(uint32 FactionTemplateId) -{ - FactionTemplateEntry const*factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId); - - if(!factionTemplateEntry) - return; - - SetFactionVisibleForFactionId(factionTemplateEntry->faction); -} - -void Player::SetFactionVisibleForFactionId(uint32 FactionId) -{ - FactionEntry const *factionEntry = sFactionStore.LookupEntry(FactionId); - if(!factionEntry) - return; - - if(factionEntry->reputationListID < 0) - return; - - FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); - if (itr == m_factions.end()) - return; - - SetFactionVisible(&itr->second); -} - -void Player::SetFactionVisible(FactionState* faction) -{ - // always invisible or hidden faction can't be make visible - if(faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) - return; - - // already set - if(faction->Flags & FACTION_FLAG_VISIBLE) - return; - - faction->Flags |= FACTION_FLAG_VISIBLE; - faction->Changed = true; - - if(!m_session->PlayerLoading()) - { - // make faction visible in reputation list at client - WorldPacket data(SMSG_SET_FACTION_VISIBLE, 4); - data << faction->ReputationListID; - GetSession()->SendPacket(&data); - } -} - -void Player::SetInitialFactions() -{ - for(unsigned int i = 1; i < sFactionStore.GetNumRows(); i++) - { - FactionEntry const *factionEntry = sFactionStore.LookupEntry(i); - - if( factionEntry && (factionEntry->reputationListID >= 0)) - { - FactionState newFaction; - newFaction.ID = factionEntry->ID; - newFaction.ReputationListID = factionEntry->reputationListID; - newFaction.Standing = 0; - newFaction.Flags = GetDefaultReputationFlags(factionEntry); - newFaction.Changed = true; - - m_factions[newFaction.ReputationListID] = newFaction; - } - } -} - -uint32 Player::GetDefaultReputationFlags(const FactionEntry *factionEntry) const -{ - if (!factionEntry) - return 0; - - uint32 raceMask = getRaceMask(); - uint32 classMask = getClassMask(); - for (int i=0; i < 4; i++) - { - if( (factionEntry->BaseRepRaceMask[i] & raceMask) && - (factionEntry->BaseRepClassMask[i]==0 || - (factionEntry->BaseRepClassMask[i] & classMask) ) ) - return factionEntry->ReputationFlags[i]; - } - return 0; -} - -int32 Player::GetBaseReputation(const FactionEntry *factionEntry) const -{ - if (!factionEntry) - return 0; - - uint32 raceMask = getRaceMask(); - uint32 classMask = getClassMask(); - for (int i=0; i < 4; i++) - { - if( (factionEntry->BaseRepRaceMask[i] & raceMask) && - (factionEntry->BaseRepClassMask[i]==0 || - (factionEntry->BaseRepClassMask[i] & classMask) ) ) - return factionEntry->BaseRepValue[i]; - } - - // in faction.dbc exist factions with (RepListId >=0, listed in character reputation list) with all BaseRepRaceMask[i]==0 - return 0; -} - -int32 Player::GetReputation(uint32 faction_id) const -{ - FactionEntry const *factionEntry = sFactionStore.LookupEntry(faction_id); - - if (!factionEntry) - { - sLog.outError("Player::GetReputation: Can't get reputation of %s for unknown faction (faction template id) #%u.",GetName(), faction_id); - return 0; - } - - return GetReputation(factionEntry); -} - -int32 Player::GetReputation(const FactionEntry *factionEntry) const -{ - // Faction without recorded reputation. Just ignore. - if(!factionEntry) - return 0; - - FactionStateList::const_iterator itr = m_factions.find(factionEntry->reputationListID); - if (itr != m_factions.end()) - return GetBaseReputation(factionEntry) + itr->second.Standing; - - return 0; -} - -ReputationRank Player::GetReputationRank(uint32 faction) const -{ - FactionEntry const*factionEntry = sFactionStore.LookupEntry(faction); - if(!factionEntry) - return MIN_REPUTATION_RANK; - - return GetReputationRank(factionEntry); -} - -ReputationRank Player::ReputationToRank(int32 standing) const -{ - int32 Limit = Reputation_Cap + 1; - for (int i = MAX_REPUTATION_RANK-1; i >= MIN_REPUTATION_RANK; --i) - { - Limit -= ReputationRank_Length[i]; - if (standing >= Limit ) - return ReputationRank(i); - } - return MIN_REPUTATION_RANK; -} - -ReputationRank Player::GetReputationRank(const FactionEntry *factionEntry) const -{ - int32 Reputation = GetReputation(factionEntry); - return ReputationToRank(Reputation); -} - -ReputationRank Player::GetBaseReputationRank(const FactionEntry *factionEntry) const -{ - int32 Reputation = GetBaseReputation(factionEntry); - return ReputationToRank(Reputation); -} - -bool Player::ModifyFactionReputation(uint32 FactionTemplateId, int32 DeltaReputation) -{ - FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId); - - if(!factionTemplateEntry) - { - sLog.outError("Player::ModifyFactionReputation: Can't update reputation of %s for unknown faction (faction template id) #%u.", GetName(), FactionTemplateId); - return false; - } - - FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction); - - // Faction without recorded reputation. Just ignore. - if(!factionEntry) - return false; - - return ModifyFactionReputation(factionEntry, DeltaReputation); -} - -bool Player::ModifyFactionReputation(FactionEntry const* factionEntry, int32 standing) -{ - SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID); - if (flist) - { - bool res = false; - for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr) - { - FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr); - if(factionEntryCalc) - res = ModifyOneFactionReputation(factionEntryCalc, standing); - } - return res; - } - else - return ModifyOneFactionReputation(factionEntry, standing); -} - -bool Player::ModifyOneFactionReputation(FactionEntry const* factionEntry, int32 standing) -{ - FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); - if (itr != m_factions.end()) - { - int32 BaseRep = GetBaseReputation(factionEntry); - int32 new_rep = BaseRep + itr->second.Standing + standing; - - if (new_rep > Reputation_Cap) - new_rep = Reputation_Cap; - else - if (new_rep < Reputation_Bottom) - new_rep = Reputation_Bottom; - - if(ReputationToRank(new_rep) <= REP_HOSTILE) - SetFactionAtWar(&itr->second,true); - - itr->second.Standing = new_rep - BaseRep; - itr->second.Changed = true; - - SetFactionVisible(&itr->second); - - for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) - { - if(uint32 questid = GetQuestSlotQuestId(i)) - { - Quest const* qInfo = objmgr.GetQuestTemplate(questid); - if( qInfo && qInfo->GetRepObjectiveFaction() == factionEntry->ID ) - { - QuestStatusData& q_status = mQuestStatus[questid]; - if( q_status.m_status == QUEST_STATUS_INCOMPLETE ) - { - if(GetReputation(factionEntry) >= qInfo->GetRepObjectiveValue()) - if ( CanCompleteQuest( questid ) ) - CompleteQuest( questid ); - } - else if( q_status.m_status == QUEST_STATUS_COMPLETE ) - { - if(GetReputation(factionEntry) < qInfo->GetRepObjectiveValue()) - IncompleteQuest( questid ); - } - } - } - } - - SendFactionState(&(itr->second)); - - return true; - } - return false; -} - -bool Player::SetFactionReputation(uint32 FactionTemplateId, int32 standing) -{ - FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId); - - if(!factionTemplateEntry) - { - sLog.outError("Player::SetFactionReputation: Can't set reputation of %s for unknown faction (faction template id) #%u.", GetName(), FactionTemplateId); - return false; - } - - FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction); - - // Faction without recorded reputation. Just ignore. - if(!factionEntry) - return false; - - return SetFactionReputation(factionEntry, standing); -} - -bool Player::SetFactionReputation(FactionEntry const* factionEntry, int32 standing) -{ - SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID); - if (flist) - { - bool res = false; - for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr) - { - FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr); - if(factionEntryCalc) - res = SetOneFactionReputation(factionEntryCalc, standing); - } - return res; - } - else - return SetOneFactionReputation(factionEntry, standing); -} - -bool Player::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing) -{ - FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); - if (itr != m_factions.end()) - { - if (standing > Reputation_Cap) - standing = Reputation_Cap; - else - if (standing < Reputation_Bottom) - standing = Reputation_Bottom; - - int32 BaseRep = GetBaseReputation(factionEntry); - itr->second.Standing = standing - BaseRep; - itr->second.Changed = true; - - SetFactionVisible(&itr->second); - - if(ReputationToRank(standing) <= REP_HOSTILE) - SetFactionAtWar(&itr->second,true); - - SendFactionState(&(itr->second)); - return true; - } - return false; -} - -//Calculate total reputation percent player gain with quest/creature level -int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest) -{ - // for grey creature kill received 20%, in other case 100. - int32 percent = (!for_quest && (creatureOrQuestLevel <= MaNGOS::XP::GetGrayLevel(getLevel()))) ? 20 : 100; - - int32 repMod = GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN); - - percent += rep > 0 ? repMod : -repMod; - - if(percent <=0) - return 0; - - return int32(sWorld.getRate(RATE_REPUTATION_GAIN)*rep*percent/100); -} - -//Calculates how many reputation points player gains in victim's enemy factions -void Player::RewardReputation(Unit *pVictim, float rate) -{ - if(!pVictim || pVictim->GetTypeId() == TYPEID_PLAYER) - return; - - ReputationOnKillEntry const* Rep = objmgr.GetReputationOnKilEntry(pVictim->GetEntry()); - - if(!Rep) - return; - - if(Rep->repfaction1 && (!Rep->team_dependent || GetTeam()==ALLIANCE)) - { - int32 donerep1 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue1,false); - donerep1 = int32(donerep1*rate); - FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(Rep->repfaction1); - uint32 current_reputation_rank1 = GetReputationRank(factionEntry1); - if(factionEntry1 && current_reputation_rank1 <= Rep->reputration_max_cap1) - ModifyFactionReputation(factionEntry1, donerep1); - - // Wiki: Team factions value divided by 2 - if(Rep->is_teamaward1) - { - FactionEntry const *team1_factionEntry = sFactionStore.LookupEntry(factionEntry1->team); - if(team1_factionEntry) - ModifyFactionReputation(team1_factionEntry, donerep1 / 2); - } - } - - if(Rep->repfaction2 && (!Rep->team_dependent || GetTeam()==HORDE)) - { - int32 donerep2 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue2,false); - donerep2 = int32(donerep2*rate); - FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(Rep->repfaction2); - uint32 current_reputation_rank2 = GetReputationRank(factionEntry2); - if(factionEntry2 && current_reputation_rank2 <= Rep->reputration_max_cap2) - ModifyFactionReputation(factionEntry2, donerep2); - - // Wiki: Team factions value divided by 2 - if(Rep->is_teamaward2) - { - FactionEntry const *team2_factionEntry = sFactionStore.LookupEntry(factionEntry2->team); - if(team2_factionEntry) - ModifyFactionReputation(team2_factionEntry, donerep2 / 2); - } - } -} - -//Calculate how many reputation points player gain with the quest -void Player::RewardReputation(Quest const *pQuest) -{ - // quest reputation reward/loss - for(int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - { - if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] ) - { - int32 rep = CalculateReputationGain(pQuest->GetQuestLevel(),pQuest->RewRepValue[i],true); - FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]); - if(factionEntry) - ModifyFactionReputation(factionEntry, rep); - } - } - - // TODO: implement reputation spillover -} - -void Player::UpdateArenaFields(void) -{ - /* arena calcs go here */ -} - -void Player::UpdateHonorFields() -{ - /// called when rewarding honor and at each save - uint64 now = time(NULL); - uint64 today = uint64(time(NULL) / DAY) * DAY; - - if(m_lastHonorUpdateTime < today) - { - uint64 yesterday = today - DAY; - - uint16 kills_today = PAIR32_LOPART(GetUInt32Value(PLAYER_FIELD_KILLS)); - - // update yesterday's contribution - if(m_lastHonorUpdateTime >= yesterday ) - { - SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); - - // this is the first update today, reset today's contribution - SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); - SetUInt32Value(PLAYER_FIELD_KILLS, MAKE_PAIR32(0,kills_today)); - } - else - { - // no honor/kills yesterday or today, reset - SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); - SetUInt32Value(PLAYER_FIELD_KILLS, 0); - } - } - - m_lastHonorUpdateTime = now; -} - -///Calculate the amount of honor gained based on the victim -///and the size of the group for which the honor is divided -///An exact honor value can also be given (overriding the calcs) -bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor) -{ - // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if(GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) - return false; - - uint64 victim_guid = 0; - uint32 victim_rank = 0; - time_t now = time(NULL); - - // need call before fields update to have chance move yesterday data to appropriate fields before today data change. - UpdateHonorFields(); - - if(honor <= 0) - { - if(!uVictim || uVictim == this || uVictim->HasAuraType(SPELL_AURA_NO_PVP_CREDIT)) - return false; - - victim_guid = uVictim->GetGUID(); - - if( uVictim->GetTypeId() == TYPEID_PLAYER ) - { - Player *pVictim = (Player *)uVictim; - - if( GetTeam() == pVictim->GetTeam() && !sWorld.IsFFAPvPRealm() ) - return false; - - float f = 1; //need for total kills (?? need more info) - uint32 k_grey = 0; - uint32 k_level = getLevel(); - uint32 v_level = pVictim->getLevel(); - - { - // PLAYER_CHOSEN_TITLE VALUES DESCRIPTION - // [0] Just name - // [1..14] Alliance honor titles and player name - // [15..28] Horde honor titles and player name - // [29..38] Other title and player name - // [39+] Nothing - uint32 victim_title = pVictim->GetUInt32Value(PLAYER_CHOSEN_TITLE); - // Get Killer titles, CharTitlesEntry::bit_index - // Ranks: - // title[1..14] -> rank[5..18] - // title[15..28] -> rank[5..18] - // title[other] -> 0 - if (victim_title == 0) - victim_guid = 0; // Don't show HK: message, only log. - else if (victim_title < 15) - victim_rank = victim_title + 4; - else if (victim_title < 29) - victim_rank = victim_title - 14 + 4; - else - victim_guid = 0; // Don't show HK: message, only log. - } - - if(k_level <= 5) - k_grey = 0; - else if( k_level <= 39 ) - k_grey = k_level - 5 - k_level/10; - else - k_grey = k_level - 1 - k_level/5; - - if(v_level<=k_grey) - return false; - - float diff_level = (k_level == k_grey) ? 1 : ((float(v_level) - float(k_grey)) / (float(k_level) - float(k_grey))); - - int32 v_rank =1; //need more info - - honor = ((f * diff_level * (190 + v_rank*10))/6); - honor *= ((float)k_level) / 70.0f; //factor of dependence on levels of the killer - - // count the number of playerkills in one day - ApplyModUInt32Value(PLAYER_FIELD_KILLS, 1, true); - // and those in a lifetime - ApplyModUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 1, true); - } - else - { - Creature *cVictim = (Creature *)uVictim; - - if (!cVictim->isRacialLeader()) - return false; - - honor = 100; // ??? need more info - victim_rank = 19; // HK: Leader - } - } - - if (uVictim != NULL) - { - honor *= sWorld.getRate(RATE_HONOR); - - if(groupsize > 1) - honor /= groupsize; - - honor *= (((float)urand(8,12))/10); // approx honor: 80% - 120% of real honor - } - - // honor - for show honor points in log - // victim_guid - for show victim name in log - // victim_rank [1..4] HK: - // victim_rank [5..19] HK: - // victim_rank [0,20+] HK: <> - WorldPacket data(SMSG_PVP_CREDIT,4+8+4); - data << (uint32) honor; - data << (uint64) victim_guid; - data << (uint32) victim_rank; - - GetSession()->SendPacket(&data); - - // add honor points - ModifyHonorPoints(int32(honor)); - - ApplyModUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, uint32(honor), true); - return true; -} - -void Player::ModifyHonorPoints( int32 value ) -{ - if(value < 0) - { - if (GetHonorPoints() > sWorld.getConfig(CONFIG_MAX_HONOR_POINTS)) - SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, sWorld.getConfig(CONFIG_MAX_HONOR_POINTS) + value); - else - SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, GetHonorPoints() > uint32(-value) ? GetHonorPoints() + value : 0); - } - else - SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, GetHonorPoints() < sWorld.getConfig(CONFIG_MAX_HONOR_POINTS) - value ? GetHonorPoints() + value : sWorld.getConfig(CONFIG_MAX_HONOR_POINTS)); -} - -void Player::ModifyArenaPoints( int32 value ) -{ - if(value < 0) - { - if (GetArenaPoints() > sWorld.getConfig(CONFIG_MAX_ARENA_POINTS)) - SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, sWorld.getConfig(CONFIG_MAX_ARENA_POINTS) + value); - else - SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, GetArenaPoints() > uint32(-value) ? GetArenaPoints() + value : 0); - } - else - SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, GetArenaPoints() < sWorld.getConfig(CONFIG_MAX_ARENA_POINTS) - value ? GetArenaPoints() + value : sWorld.getConfig(CONFIG_MAX_ARENA_POINTS)); -} - -uint32 Player::GetGuildIdFromDB(uint64 guid) -{ - std::ostringstream ss; - ss<<"SELECT guildid FROM guild_member WHERE guid='"<Fetch()[0].GetUInt32(); - delete result; - return v; - } - else - return 0; -} - -uint32 Player::GetRankFromDB(uint64 guid) -{ - std::ostringstream ss; - ss<<"SELECT rank FROM guild_member WHERE guid='"<Fetch()[0].GetUInt32(); - delete result; - return v; - } - else - return 0; -} - -uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type) -{ - // need fix it! - QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid FROM arena_team_member WHERE guid='%u'", GUID_LOPART(guid)); - if(result) - { - // init id to 0, check the arena type before assigning a value to id - uint32 id = 0; - do - { - QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM arena_team WHERE arenateamid='%u'", id); - if(result2) - { - uint8 dbtype = (*result2)[0].GetUInt32(); - delete result2; - if(dbtype == type) - { - // if the type matches, we've found the id - id = (*result)[0].GetUInt32(); - break; - } - } - } while(result->NextRow()); - delete result; - return id; - } - // no arenateam for the specified guid, return 0 - return 0; -} - -uint32 Player::GetZoneIdFromDB(uint64 guid) -{ - std::ostringstream ss; - - ss<<"SELECT zone FROM characters WHERE guid='"<Fetch(); - uint32 zone = fields[0].GetUInt32(); - delete result; - - if (!zone) - { - // stored zone is zero, use generic and slow zone detection - ss.str(""); - ss<<"SELECT map,position_x,position_y FROM characters WHERE guid='"<Fetch(); - uint32 map = fields[0].GetUInt32(); - float posx = fields[1].GetFloat(); - float posy = fields[2].GetFloat(); - delete result; - - zone = MapManager::Instance().GetZoneId(map,posx,posy); - - ss.str(""); - ss << "UPDATE characters SET zone='"<flags & AREA_FLAG_ARENA)) - { - if(!isGameMaster()) - SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); - } - else - { - // remove ffa flag only if not ffapvp realm - // removal in sanctuaries and capitals is handled in zone update - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && !sWorld.IsFFAPvPRealm()) - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); - } - - UpdateAreaDependentAuras(newArea); -} - -void Player::UpdateZone(uint32 newZone) -{ - m_zoneUpdateId = newZone; - m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; - - // zone changed, so area changed as well, update it - UpdateArea(GetAreaId()); - - AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone); - if(!zone) - return; - - if (sWorld.getConfig(CONFIG_WEATHER)) - { - Weather *wth = sWorld.FindWeather(zone->ID); - if(wth) - { - wth->SendWeatherUpdateToPlayer(this); - } - else - { - if(!sWorld.AddWeather(zone->ID)) - { - // send fine weather packet to remove old zone's weather - Weather::SendFineWeatherUpdateToPlayer(this); - } - } - } - - pvpInfo.inHostileArea = - GetTeam() == ALLIANCE && zone->team == AREATEAM_HORDE || - GetTeam() == HORDE && zone->team == AREATEAM_ALLY || - sWorld.IsPvPRealm() && zone->team == AREATEAM_NONE || - InBattleGround(); // overwrite for battlegrounds, maybe batter some zone flags but current known not 100% fit to this - - if(pvpInfo.inHostileArea) // in hostile area - { - if(!IsPvP() || pvpInfo.endTimer != 0) - UpdatePvP(true, true); - } - else // in friendly area - { - if(IsPvP() && !HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_IN_PVP) && pvpInfo.endTimer == 0) - pvpInfo.endTimer = time(0); // start toggle-off - } - - if(zone->flags & AREA_FLAG_SANCTUARY) // in sanctuary - { - SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY); - if(sWorld.IsFFAPvPRealm()) - RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); - } - else - { - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY); - } - - if(zone->flags & AREA_FLAG_CAPITAL) // in capital city - { - SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); - SetRestType(REST_TYPE_IN_CITY); - InnEnter(time(0),GetMapId(),0,0,0); - - if(sWorld.IsFFAPvPRealm()) - RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); - } - else // anywhere else - { - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) // but resting (walk from city or maybe in tavern or leave tavern recently) - { - if(GetRestType()==REST_TYPE_IN_TAVERN) // has been in tavern. Is still in? - { - if(GetMapId()!=GetInnPosMapId() || sqrt((GetPositionX()-GetInnPosX())*(GetPositionX()-GetInnPosX())+(GetPositionY()-GetInnPosY())*(GetPositionY()-GetInnPosY())+(GetPositionZ()-GetInnPosZ())*(GetPositionZ()-GetInnPosZ()))>40) - { - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); - SetRestType(REST_TYPE_NO); - - if(sWorld.IsFFAPvPRealm()) - SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); - } - } - else // not in tavern (leave city then) - { - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); - SetRestType(REST_TYPE_NO); - - // Set player to FFA PVP when not in rested enviroment. - if(sWorld.IsFFAPvPRealm()) - SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); - } - } - } - - // remove items with area/map limitations (delete only for alive player to allow back in ghost mode) - // if player resurrected at teleport this will be applied in resurrect code - if(isAlive()) - DestroyZoneLimitedItem( true, newZone ); - - // recent client version not send leave/join channel packets for built-in local channels - UpdateLocalChannels( newZone ); - - // group update - if(GetGroup()) - SetGroupUpdateFlag(GROUP_UPDATE_FLAG_ZONE); - - UpdateZoneDependentAuras(newZone); -} - -//If players are too far way of duel flag... then player loose the duel -void Player::CheckDuelDistance(time_t currTime) -{ - if(!duel) - return; - - uint64 duelFlagGUID = GetUInt64Value(PLAYER_DUEL_ARBITER); - GameObject* obj = ObjectAccessor::GetGameObject(*this, duelFlagGUID); - if(!obj) - return; - - if(duel->outOfBound == 0) - { - if(!IsWithinDistInMap(obj, 50)) - { - duel->outOfBound = currTime; - - WorldPacket data(SMSG_DUEL_OUTOFBOUNDS, 0); - GetSession()->SendPacket(&data); - } - } - else - { - if(IsWithinDistInMap(obj, 40)) - { - duel->outOfBound = 0; - - WorldPacket data(SMSG_DUEL_INBOUNDS, 0); - GetSession()->SendPacket(&data); - } - else if(currTime >= (duel->outOfBound+10)) - { - DuelComplete(DUEL_FLED); - } - } -} - -void Player::DuelComplete(DuelCompleteType type) -{ - // duel not requested - if(!duel) - return; - - WorldPacket data(SMSG_DUEL_COMPLETE, (1)); - data << (uint8)((type != DUEL_INTERUPTED) ? 1 : 0); - GetSession()->SendPacket(&data); - duel->opponent->GetSession()->SendPacket(&data); - - if(type != DUEL_INTERUPTED) - { - data.Initialize(SMSG_DUEL_WINNER, (1+20)); // we guess size - data << (uint8)((type==DUEL_WON) ? 0 : 1); // 0 = just won; 1 = fled - data << duel->opponent->GetName(); - data << GetName(); - SendMessageToSet(&data,true); - } - - // cool-down duel spell - /*data.Initialize(SMSG_SPELL_COOLDOWN, 17); - - data<SendPacket(&data); - data.Initialize(SMSG_SPELL_COOLDOWN, 17); - data<opponent->GetGUID(); - data<opponent->GetSession()->SendPacket(&data);*/ - - //Remove Duel Flag object - GameObject* obj = ObjectAccessor::GetGameObject(*this, GetUInt64Value(PLAYER_DUEL_ARBITER)); - if(obj) - duel->initiator->RemoveGameObject(obj,true); - - /* remove auras */ - std::vector auras2remove; - AuraMap const& vAuras = duel->opponent->GetAuras(); - for (AuraMap::const_iterator i = vAuras.begin(); i != vAuras.end(); i++) - { - if (!i->second->IsPositive() && i->second->GetCasterGUID() == GetGUID() && i->second->GetAuraApplyTime() >= duel->startTime) - auras2remove.push_back(i->second->GetId()); - } - - for(size_t i=0; iopponent->RemoveAurasDueToSpell(auras2remove[i]); - - auras2remove.clear(); - AuraMap const& auras = GetAuras(); - for (AuraMap::const_iterator i = auras.begin(); i != auras.end(); i++) - { - if (!i->second->IsPositive() && i->second->GetCasterGUID() == duel->opponent->GetGUID() && i->second->GetAuraApplyTime() >= duel->startTime) - auras2remove.push_back(i->second->GetId()); - } - for(size_t i=0; iopponent->GetGUID()) - ClearComboPoints(); - else if(GetComboTarget()==duel->opponent->GetPetGUID()) - ClearComboPoints(); - - if(duel->opponent->GetComboTarget()==GetGUID()) - duel->opponent->ClearComboPoints(); - else if(duel->opponent->GetComboTarget()==GetPetGUID()) - duel->opponent->ClearComboPoints(); - - //cleanups - SetUInt64Value(PLAYER_DUEL_ARBITER, 0); - SetUInt32Value(PLAYER_DUEL_TEAM, 0); - duel->opponent->SetUInt64Value(PLAYER_DUEL_ARBITER, 0); - duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 0); - - delete duel->opponent->duel; - duel->opponent->duel = NULL; - delete duel; - duel = NULL; -} - -//---------------------------------------------------------// - -void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply) -{ - if(slot >= INVENTORY_SLOT_BAG_END || !item) - return; - - // not apply/remove mods for broken item - if(item->IsBroken()) - return; - - ItemPrototype const *proto = item->GetProto(); - - if(!proto) - return; - - sLog.outDetail("applying mods for item %u ",item->GetGUIDLow()); - - uint32 attacktype = Player::GetAttackBySlot(slot); - if(attacktype < MAX_ATTACK) - _ApplyWeaponDependentAuraMods(item,WeaponAttackType(attacktype),apply); - - _ApplyItemBonuses(proto,slot,apply); - - if( slot==EQUIPMENT_SLOT_RANGED ) - _ApplyAmmoBonuses(); - - ApplyItemEquipSpell(item,apply); - ApplyEnchantment(item, apply); - - if(proto->Socket[0].Color) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items - CorrectMetaGemEnchants(slot, apply); - - sLog.outDebug("_ApplyItemMods complete."); -} - -void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply) -{ - if(slot >= INVENTORY_SLOT_BAG_END || !proto) - return; - - for (int i = 0; i < 10; i++) - { - float val = float (proto->ItemStat[i].ItemStatValue); - - if(val==0) - continue; - - switch (proto->ItemStat[i].ItemStatType) - { - case ITEM_MOD_MANA: - HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply); - break; - case ITEM_MOD_HEALTH: // modify HP - HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply); - break; - case ITEM_MOD_AGILITY: // modify agility - HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, val, apply); - break; - case ITEM_MOD_STRENGTH: //modify strength - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STRENGTH, val, apply); - break; - case ITEM_MOD_INTELLECT: //modify intellect - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_INTELLECT, val, apply); - break; - case ITEM_MOD_SPIRIT: //modify spirit - HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_SPIRIT, val, apply); - break; - case ITEM_MOD_STAMINA: //modify stamina - HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STAMINA, val, apply); - break; - case ITEM_MOD_DEFENSE_SKILL_RATING: - ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply); - break; - case ITEM_MOD_DODGE_RATING: - ApplyRatingMod(CR_DODGE, int32(val), apply); - break; - case ITEM_MOD_PARRY_RATING: - ApplyRatingMod(CR_PARRY, int32(val), apply); - break; - case ITEM_MOD_BLOCK_RATING: - ApplyRatingMod(CR_BLOCK, int32(val), apply); - break; - case ITEM_MOD_HIT_MELEE_RATING: - ApplyRatingMod(CR_HIT_MELEE, int32(val), apply); - break; - case ITEM_MOD_HIT_RANGED_RATING: - ApplyRatingMod(CR_HIT_RANGED, int32(val), apply); - break; - case ITEM_MOD_HIT_SPELL_RATING: - ApplyRatingMod(CR_HIT_SPELL, int32(val), apply); - break; - case ITEM_MOD_CRIT_MELEE_RATING: - ApplyRatingMod(CR_CRIT_MELEE, int32(val), apply); - break; - case ITEM_MOD_CRIT_RANGED_RATING: - ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply); - break; - case ITEM_MOD_CRIT_SPELL_RATING: - ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply); - break; - case ITEM_MOD_HIT_TAKEN_MELEE_RATING: - ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply); - break; - case ITEM_MOD_HIT_TAKEN_RANGED_RATING: - ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply); - break; - case ITEM_MOD_HIT_TAKEN_SPELL_RATING: - ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply); - break; - case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); - break; - case ITEM_MOD_CRIT_TAKEN_RANGED_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); - break; - case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); - break; - case ITEM_MOD_HASTE_MELEE_RATING: - ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply); - break; - case ITEM_MOD_HASTE_RANGED_RATING: - ApplyRatingMod(CR_HASTE_RANGED, int32(val), apply); - break; - case ITEM_MOD_HASTE_SPELL_RATING: - ApplyRatingMod(CR_HASTE_SPELL, int32(val), apply); - break; - case ITEM_MOD_HIT_RATING: - ApplyRatingMod(CR_HIT_MELEE, int32(val), apply); - ApplyRatingMod(CR_HIT_RANGED, int32(val), apply); - ApplyRatingMod(CR_HIT_SPELL, int32(val), apply); - break; - case ITEM_MOD_CRIT_RATING: - ApplyRatingMod(CR_CRIT_MELEE, int32(val), apply); - ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply); - ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply); - break; - case ITEM_MOD_HIT_TAKEN_RATING: - ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply); - ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply); - ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply); - break; - case ITEM_MOD_CRIT_TAKEN_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); - ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); - ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); - break; - case ITEM_MOD_RESILIENCE_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); - ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); - ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); - break; - case ITEM_MOD_HASTE_RATING: - ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply); - ApplyRatingMod(CR_HASTE_RANGED, int32(val), apply); - ApplyRatingMod(CR_HASTE_SPELL, int32(val), apply); - break; - case ITEM_MOD_EXPERTISE_RATING: - ApplyRatingMod(CR_EXPERTISE, int32(val), apply); - break; - } - } - - if (proto->Armor) - HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(proto->Armor), apply); - - if (proto->Block) - HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply); - - if (proto->HolyRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply); - - if (proto->FireRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply); - - if (proto->NatureRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply); - - if (proto->FrostRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply); - - if (proto->ShadowRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply); - - if (proto->ArcaneRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply); - - WeaponAttackType attType = BASE_ATTACK; - float damage = 0.0f; - - if( slot == EQUIPMENT_SLOT_RANGED && ( - proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN || - proto->InventoryType == INVTYPE_RANGEDRIGHT )) - { - attType = RANGED_ATTACK; - } - else if(slot==EQUIPMENT_SLOT_OFFHAND) - { - attType = OFF_ATTACK; - } - - if (proto->Damage[0].DamageMin > 0 ) - { - damage = apply ? proto->Damage[0].DamageMin : BASE_MINDAMAGE; - SetBaseWeaponDamage(attType, MINDAMAGE, damage); - //sLog.outError("applying mindam: assigning %f to weapon mindamage, now is: %f", damage, GetWeaponDamageRange(attType, MINDAMAGE)); - } - - if (proto->Damage[0].DamageMax > 0 ) - { - damage = apply ? proto->Damage[0].DamageMax : BASE_MAXDAMAGE; - SetBaseWeaponDamage(attType, MAXDAMAGE, damage); - } - - if(!IsUseEquipedWeapon(slot==EQUIPMENT_SLOT_MAINHAND)) - return; - - if (proto->Delay) - { - if(slot == EQUIPMENT_SLOT_RANGED) - SetAttackTime(RANGED_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME); - else if(slot==EQUIPMENT_SLOT_MAINHAND) - SetAttackTime(BASE_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME); - else if(slot==EQUIPMENT_SLOT_OFFHAND) - SetAttackTime(OFF_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME); - } - - if(CanModifyStats() && (damage || proto->Delay)) - UpdateDamagePhysical(attType); -} - -void Player::_ApplyWeaponDependentAuraMods(Item *item,WeaponAttackType attackType,bool apply) -{ - AuraList const& auraCritList = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT); - for(AuraList::const_iterator itr = auraCritList.begin(); itr!=auraCritList.end();++itr) - _ApplyWeaponDependentAuraCritMod(item,attackType,*itr,apply); - - AuraList const& auraDamageFlatList = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); - for(AuraList::const_iterator itr = auraDamageFlatList.begin(); itr!=auraDamageFlatList.end();++itr) - _ApplyWeaponDependentAuraDamageMod(item,attackType,*itr,apply); - - AuraList const& auraDamagePCTList = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for(AuraList::const_iterator itr = auraDamagePCTList.begin(); itr!=auraDamagePCTList.end();++itr) - _ApplyWeaponDependentAuraDamageMod(item,attackType,*itr,apply); -} - -void Player::_ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply) -{ - // generic not weapon specific case processes in aura code - if(aura->GetSpellProto()->EquippedItemClass == -1) - return; - - BaseModGroup mod = BASEMOD_END; - switch(attackType) - { - case BASE_ATTACK: mod = CRIT_PERCENTAGE; break; - case OFF_ATTACK: mod = OFFHAND_CRIT_PERCENTAGE;break; - case RANGED_ATTACK: mod = RANGED_CRIT_PERCENTAGE; break; - default: return; - } - - if (item->IsFitToSpellRequirements(aura->GetSpellProto())) - { - HandleBaseModValue(mod, FLAT_MOD, float (aura->GetModifier()->m_amount), apply); - } -} - -void Player::_ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply) -{ - // ignore spell mods for not wands - Modifier const* modifier = aura->GetModifier(); - if((modifier->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)==0 && (getClassMask() & CLASSMASK_WAND_USERS)==0) - return; - - // generic not weapon specific case processes in aura code - if(aura->GetSpellProto()->EquippedItemClass == -1) - return; - - UnitMods unitMod = UNIT_MOD_END; - switch(attackType) - { - case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; - case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; - case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; - default: return; - } - - UnitModifierType unitModType = TOTAL_VALUE; - switch(modifier->m_auraname) - { - case SPELL_AURA_MOD_DAMAGE_DONE: unitModType = TOTAL_VALUE; break; - case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: unitModType = TOTAL_PCT; break; - default: return; - } - - if (item->IsFitToSpellRequirements(aura->GetSpellProto())) - { - HandleStatModifier(unitMod, unitModType, float(modifier->m_amount),apply); - } -} - -void Player::ApplyItemEquipSpell(Item *item, bool apply, bool form_change) -{ - if(!item) - return; - - ItemPrototype const *proto = item->GetProto(); - if(!proto) - return; - - for (int i = 0; i < 5; i++) - { - _Spell const& spellData = proto->Spells[i]; - - // no spell - if(!spellData.SpellId ) - continue; - - // wrong triggering type - if(apply && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_EQUIP) - continue; - - // check if it is valid spell - SpellEntry const* spellproto = sSpellStore.LookupEntry(spellData.SpellId); - if(!spellproto) - continue; - - ApplyEquipSpell(spellproto,item,apply,form_change); - } -} - -void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply, bool form_change) -{ - if(apply) - { - // Cannot be used in this stance/form - if(GetErrorAtShapeshiftedCast(spellInfo, m_form)!=0) - return; - - if(form_change) // check aura active state from other form - { - bool found = false; - for (int k=0; k < 3; ++k) - { - spellEffectPair spair = spellEffectPair(spellInfo->Id, k); - for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair); ++iter) - { - if(!item || iter->second->GetCastItemGUID() == item->GetGUID()) - { - found = true; - break; - } - } - if(found) - break; - } - - if(found) // and skip re-cast already active aura at form change - return; - } - - DEBUG_LOG("WORLD: cast %s Equip spellId - %i", (item ? "item" : "itemset"), spellInfo->Id); - - CastSpell(this,spellInfo,true,item); - } - else - { - if(form_change) // check aura compatibility - { - // Cannot be used in this stance/form - if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==0) - return; // and remove only not compatible at form change - } - - if(item) - RemoveAurasDueToItemSpell(item,spellInfo->Id); // un-apply all spells , not only at-equipped - else - RemoveAurasDueToSpell(spellInfo->Id); // un-apply spell (item set case) - } -} - -void Player::UpdateEquipSpellsAtFormChange() -{ - for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) - { - if(m_items[i] && !m_items[i]->IsBroken()) - { - ApplyItemEquipSpell(m_items[i],false,true); // remove spells that not fit to form - ApplyItemEquipSpell(m_items[i],true,true); // add spells that fit form but not active - } - } - - // item set bonuses not dependent from item broken state - for(size_t setindex = 0; setindex < ItemSetEff.size(); ++setindex) - { - ItemSetEffect* eff = ItemSetEff[setindex]; - if(!eff) - continue; - - for(uint32 y=0;y<8; ++y) - { - SpellEntry const* spellInfo = eff->spells[y]; - if(!spellInfo) - continue; - - ApplyEquipSpell(spellInfo,NULL,false,true); // remove spells that not fit to form - ApplyEquipSpell(spellInfo,NULL,true,true); // add spells that fit form but not active - } - } -} - -void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attType) -{ - if(!item || item->IsBroken()) - return; - - ItemPrototype const *proto = item->GetProto(); - if(!proto) - return; - - if (!Target || Target == this ) - return; - - for (int i = 0; i < 5; i++) - { - _Spell const& spellData = proto->Spells[i]; - - // no spell - if(!spellData.SpellId ) - continue; - - // wrong triggering type - if(spellData.SpellTrigger != ITEM_SPELLTRIGGER_CHANCE_ON_HIT) - continue; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId); - if(!spellInfo) - { - sLog.outError("WORLD: unknown Item spellid %i", spellData.SpellId); - continue; - } - - // not allow proc extra attack spell at extra attack - if( m_extraAttacks && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_ADD_EXTRA_ATTACKS) ) - return; - - float chance = spellInfo->procChance; - - if(spellData.SpellPPMRate) - { - uint32 WeaponSpeed = GetAttackTime(attType); - chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate); - } - else if(chance > 100.0f) - { - chance = GetWeaponProcChance(); - } - - if (roll_chance_f(chance)) - this->CastSpell(Target, spellInfo->Id, true, item); - } - - // item combat enchantments - for(int e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot) - { - uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot)); - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) continue; - for (int s=0;s<3;s++) - { - if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) - continue; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(pEnchant->spellid[s]); - if (!spellInfo) - { - sLog.outError("Player::CastItemCombatSpell Enchant %i, cast unknown spell %i", pEnchant->ID, pEnchant->spellid[s]); - continue; - } - - float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance(); - if (roll_chance_f(chance)) - { - if(IsPositiveSpell(pEnchant->spellid[s])) - CastSpell(this, pEnchant->spellid[s], true, item); - else - CastSpell(Target, pEnchant->spellid[s], true, item); - } - } - } -} - -void Player::_RemoveAllItemMods() -{ - sLog.outDebug("_RemoveAllItemMods start."); - - for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) - { - if(m_items[i]) - { - ItemPrototype const *proto = m_items[i]->GetProto(); - if(!proto) - continue; - - // item set bonuses not dependent from item broken state - if(proto->ItemSet) - RemoveItemsSetItem(this,proto); - - if(m_items[i]->IsBroken()) - continue; - - ApplyItemEquipSpell(m_items[i],false); - ApplyEnchantment(m_items[i], false); - } - } - - for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) - { - if(m_items[i]) - { - if(m_items[i]->IsBroken()) - continue; - ItemPrototype const *proto = m_items[i]->GetProto(); - if(!proto) - continue; - - uint32 attacktype = Player::GetAttackBySlot(i); - if(attacktype < MAX_ATTACK) - _ApplyWeaponDependentAuraMods(m_items[i],WeaponAttackType(attacktype),false); - - _ApplyItemBonuses(proto,i, false); - - if( i == EQUIPMENT_SLOT_RANGED ) - _ApplyAmmoBonuses(); - } - } - - sLog.outDebug("_RemoveAllItemMods complete."); -} - -void Player::_ApplyAllItemMods() -{ - sLog.outDebug("_ApplyAllItemMods start."); - - for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) - { - if(m_items[i]) - { - if(m_items[i]->IsBroken()) - continue; - - ItemPrototype const *proto = m_items[i]->GetProto(); - if(!proto) - continue; - - uint32 attacktype = Player::GetAttackBySlot(i); - if(attacktype < MAX_ATTACK) - _ApplyWeaponDependentAuraMods(m_items[i],WeaponAttackType(attacktype),true); - - _ApplyItemBonuses(proto,i, true); - - if( i == EQUIPMENT_SLOT_RANGED ) - _ApplyAmmoBonuses(); - } - } - - for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) - { - if(m_items[i]) - { - ItemPrototype const *proto = m_items[i]->GetProto(); - if(!proto) - continue; - - // item set bonuses not dependent from item broken state - if(proto->ItemSet) - AddItemsSetItem(this,m_items[i]); - - if(m_items[i]->IsBroken()) - continue; - - ApplyItemEquipSpell(m_items[i],true); - ApplyEnchantment(m_items[i], true); - } - } - - sLog.outDebug("_ApplyAllItemMods complete."); -} - -void Player::_ApplyAmmoBonuses() -{ - // check ammo - uint32 ammo_id = GetUInt32Value(PLAYER_AMMO_ID); - if(!ammo_id) - return; - - float currentAmmoDPS; - - ItemPrototype const *ammo_proto = objmgr.GetItemPrototype( ammo_id ); - if( !ammo_proto || ammo_proto->Class!=ITEM_CLASS_PROJECTILE || !CheckAmmoCompatibility(ammo_proto)) - currentAmmoDPS = 0.0f; - else - currentAmmoDPS = ammo_proto->Damage[0].DamageMin; - - if(currentAmmoDPS == GetAmmoDPS()) - return; - - m_ammoDPS = currentAmmoDPS; - - if(CanModifyStats()) - UpdateDamagePhysical(RANGED_ATTACK); -} - -bool Player::CheckAmmoCompatibility(const ItemPrototype *ammo_proto) const -{ - if(!ammo_proto) - return false; - - // check ranged weapon - Item *weapon = GetWeaponForAttack( RANGED_ATTACK ); - if(!weapon || weapon->IsBroken() ) - return false; - - ItemPrototype const* weapon_proto = weapon->GetProto(); - if(!weapon_proto || weapon_proto->Class!=ITEM_CLASS_WEAPON ) - return false; - - // check ammo ws. weapon compatibility - switch(weapon_proto->SubClass) - { - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - if(ammo_proto->SubClass!=ITEM_SUBCLASS_ARROW) - return false; - break; - case ITEM_SUBCLASS_WEAPON_GUN: - if(ammo_proto->SubClass!=ITEM_SUBCLASS_BULLET) - return false; - break; - default: - return false; - } - - return true; -} - -/* If in a battleground a player dies, and an enemy removes the insignia, the player's bones is lootable - Called by remove insignia spell effect */ -void Player::RemovedInsignia(Player* looterPlr) -{ - if (!GetBattleGroundId()) - return; - - // If not released spirit, do it ! - if(m_deathTimer > 0) - { - m_deathTimer = 0; - BuildPlayerRepop(); - RepopAtGraveyard(); - } - - Corpse *corpse = GetCorpse(); - if (!corpse) - return; - - // We have to convert player corpse to bones, not to be able to resurrect there - // SpawnCorpseBones isn't handy, 'cos it saves player while he in BG - Corpse *bones = ObjectAccessor::Instance().ConvertCorpseForPlayer(GetGUID()); - if (!bones) - return; - - // Now we must make bones lootable, and send player loot - bones->SetFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); - - // We store the level of our player in the gold field - // We retrieve this information at Player::SendLoot() - bones->loot.gold = getLevel(); - bones->lootRecipient = looterPlr; - looterPlr->SendLoot(bones->GetGUID(), LOOT_INSIGNIA); -} - -/*Loot type MUST be -1-corpse, go -2-skinning -3-Fishing -*/ - -void Player::SendLootRelease( uint64 guid ) -{ - WorldPacket data( SMSG_LOOT_RELEASE_RESPONSE, (8+1) ); - data << uint64(guid) << uint8(1); - SendDirectMessage( &data ); -} - -void Player::SendLoot(uint64 guid, LootType loot_type) -{ - Loot *loot = 0; - PermissionTypes permission = ALL_PERMISSION; - - sLog.outDebug("Player::SendLoot"); - if (IS_GAMEOBJECT_GUID(guid)) - { - sLog.outDebug(" IS_GAMEOBJECT_GUID(guid)"); - GameObject *go = - ObjectAccessor::GetGameObject(*this, guid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) - // And permit out of range GO with no owner in case fishing hole - if (!go || (loot_type != LOOT_FISHINGHOLE && (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this,INTERACTION_DISTANCE))) - { - SendLootRelease(guid); - return; - } - - loot = &go->loot; - - if(go->getLootState() == GO_READY) - { - uint32 lootid = go->GetLootId(); - - if(lootid) - { - sLog.outDebug(" if(lootid)"); - loot->clear(); - loot->FillLoot(lootid, LootTemplates_Gameobject, this); - } - - if(loot_type == LOOT_FISHING) - go->getFishLoot(loot); - - go->SetLootState(GO_ACTIVATED); - } - } - else if (IS_ITEM_GUID(guid)) - { - Item *item = GetItemByGuid( guid ); - - if (!item) - { - SendLootRelease(guid); - return; - } - - if(loot_type == LOOT_DISENCHANTING) - { - loot = &item->loot; - - if(!item->m_lootGenerated) - { - item->m_lootGenerated = true; - loot->clear(); - loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this); - } - } - else if(loot_type == LOOT_PROSPECTING) - { - loot = &item->loot; - - if(!item->m_lootGenerated) - { - item->m_lootGenerated = true; - loot->clear(); - loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this); - } - } - else - { - loot = &item->loot; - - if(!item->m_lootGenerated) - { - item->m_lootGenerated = true; - loot->clear(); - loot->FillLoot(item->GetEntry(), LootTemplates_Item, this); - - loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot); - } - } - } - else if (IS_CORPSE_GUID(guid)) // remove insignia - { - Corpse *bones = ObjectAccessor::GetCorpse(*this, guid); - - if (!bones || !((loot_type == LOOT_CORPSE) || (loot_type == LOOT_INSIGNIA)) || (bones->GetType() != CORPSE_BONES) ) - { - SendLootRelease(guid); - return; - } - - loot = &bones->loot; - - if (!bones->lootForBody) - { - bones->lootForBody = true; - uint32 pLevel = bones->loot.gold; - bones->loot.clear(); - // It may need a better formula - // Now it works like this: lvl10: ~6copper, lvl70: ~9silver - bones->loot.gold = (uint32)( urand(50, 150) * 0.016f * pow( ((float)pLevel)/5.76f, 2.5f) * sWorld.getRate(RATE_DROP_MONEY) ); - } - - if (bones->lootRecipient != this) - permission = NONE_PERMISSION; - } - else - { - Creature *creature = ObjectAccessor::GetCreature(*this, guid); - - // must be in range and creature must be alive for pickpocket and must be dead for another loot - if (!creature || creature->isAlive()!=(loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this,INTERACTION_DISTANCE)) - { - SendLootRelease(guid); - return; - } - - if(loot_type == LOOT_PICKPOCKETING && IsFriendlyTo(creature)) - { - SendLootRelease(guid); - return; - } - - loot = &creature->loot; - - if(loot_type == LOOT_PICKPOCKETING) - { - if ( !creature->lootForPickPocketed ) - { - creature->lootForPickPocketed = true; - loot->clear(); - - if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId) - loot->FillLoot(lootid, LootTemplates_Pickpocketing, this); - - // Generate extra money for pick pocket loot - const uint32 a = urand(0, creature->getLevel()/2); - const uint32 b = urand(0, getLevel()/2); - loot->gold = uint32(10 * (a + b) * sWorld.getRate(RATE_DROP_MONEY)); - } - } - else - { - // the player whose group may loot the corpse - Player *recipient = creature->GetLootRecipient(); - if (!recipient) - { - creature->SetLootRecipient(this); - recipient = this; - } - - if (creature->lootForPickPocketed) - { - creature->lootForPickPocketed = false; - loot->clear(); - } - - if(!creature->lootForBody) - { - creature->lootForBody = true; - loot->clear(); - - if (uint32 lootid = creature->GetCreatureInfo()->lootid) - loot->FillLoot(lootid, LootTemplates_Creature, recipient); - - loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold,creature->GetCreatureInfo()->maxgold); - - if(Group* group = recipient->GetGroup()) - { - group->UpdateLooterGuid(creature,true); - - switch (group->GetLootMethod()) - { - case GROUP_LOOT: - // GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with qualityGroupLoot(recipient->GetGUID(), loot, creature); - break; - case NEED_BEFORE_GREED: - group->NeedBeforeGreed(recipient->GetGUID(), loot, creature); - break; - case MASTER_LOOT: - group->MasterLoot(recipient->GetGUID(), loot, creature); - break; - default: - break; - } - } - } - - // possible only if creature->lootForBody && loot->empty() at spell cast check - if (loot_type == LOOT_SKINNING) - { - loot->clear(); - loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this); - } - // set group rights only for loot_type != LOOT_SKINNING - else - { - if(Group* group = GetGroup()) - { - if( group == recipient->GetGroup() ) - { - if(group->GetLootMethod() == FREE_FOR_ALL) - permission = ALL_PERMISSION; - else if(group->GetLooterGuid() == GetGUID()) - { - if(group->GetLootMethod() == MASTER_LOOT) - permission = MASTER_PERMISSION; - else - permission = ALL_PERMISSION; - } - else - permission = GROUP_PERMISSION; - } - else - permission = NONE_PERMISSION; - } - else if(recipient == this) - permission = ALL_PERMISSION; - else - permission = NONE_PERMISSION; - } - } - } - - SetLootGUID(guid); - - QuestItemList *q_list = 0; - if (permission != NONE_PERMISSION) - { - QuestItemMap const& lootPlayerQuestItems = loot->GetPlayerQuestItems(); - QuestItemMap::const_iterator itr = lootPlayerQuestItems.find(GetGUIDLow()); - if (itr == lootPlayerQuestItems.end()) - q_list = loot->FillQuestLoot(this); - else - q_list = itr->second; - } - - QuestItemList *ffa_list = 0; - if (permission != NONE_PERMISSION) - { - QuestItemMap const& lootPlayerFFAItems = loot->GetPlayerFFAItems(); - QuestItemMap::const_iterator itr = lootPlayerFFAItems.find(GetGUIDLow()); - if (itr == lootPlayerFFAItems.end()) - ffa_list = loot->FillFFALoot(this); - else - ffa_list = itr->second; - } - - QuestItemList *conditional_list = 0; - if (permission != NONE_PERMISSION) - { - QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = loot->GetPlayerNonQuestNonFFAConditionalItems(); - QuestItemMap::const_iterator itr = lootPlayerNonQuestNonFFAConditionalItems.find(GetGUIDLow()); - if (itr == lootPlayerNonQuestNonFFAConditionalItems.end()) - conditional_list = loot->FillNonQuestNonFFAConditionalLoot(this); - else - conditional_list = itr->second; - } - - // LOOT_PICKPOCKETING, LOOT_PROSPECTING, LOOT_DISENCHANTING and LOOT_INSIGNIA unsupported by client, sending LOOT_SKINNING instead - if(loot_type == LOOT_PICKPOCKETING || loot_type == LOOT_DISENCHANTING || loot_type == LOOT_PROSPECTING || loot_type == LOOT_INSIGNIA) - loot_type = LOOT_SKINNING; - - if(loot_type == LOOT_FISHINGHOLE) - loot_type = LOOT_FISHING; - - WorldPacket data(SMSG_LOOT_RESPONSE, (9+50)); // we guess size - - data << uint64(guid); - data << uint8(loot_type); - data << LootView(*loot, q_list, ffa_list, conditional_list, this, permission); - - SendDirectMessage(&data); - - // add 'this' player as one of the players that are looting 'loot' - if (permission != NONE_PERMISSION) - loot->AddLooter(GetGUID()); - - if ( loot_type == LOOT_CORPSE && !IS_ITEM_GUID(guid) ) - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); -} - -void Player::SendNotifyLootMoneyRemoved() -{ - WorldPacket data(SMSG_LOOT_CLEAR_MONEY, 0); - GetSession()->SendPacket( &data ); -} - -void Player::SendNotifyLootItemRemoved(uint8 lootSlot) -{ - WorldPacket data(SMSG_LOOT_REMOVED, 1); - data << uint8(lootSlot); - GetSession()->SendPacket( &data ); -} - -void Player::SendUpdateWorldState(uint32 Field, uint32 Value) -{ - WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); - data << Field; - data << Value; - GetSession()->SendPacket(&data); -} - -void Player::SendInitWorldStates() -{ - // data depends on zoneid/mapid... - BattleGround* bg = GetBattleGround(); - uint16 NumberOfFields = 0; - uint32 mapid = GetMapId(); - uint32 zoneid = GetZoneId(); - uint32 areaid = GetAreaId(); - sLog.outDebug("Sending SMSG_INIT_WORLD_STATES to Map:%u, Zone: %u", mapid, zoneid); - // may be exist better way to do this... - switch(zoneid) - { - case 0: - case 1: - case 4: - case 8: - case 10: - case 11: - case 12: - case 36: - case 38: - case 40: - case 41: - case 51: - case 267: - case 1519: - case 1537: - case 2257: - case 2918: - NumberOfFields = 6; - break; - case 2597: - NumberOfFields = 81; - break; - case 3277: - NumberOfFields = 14; - break; - case 3358: - case 3820: - NumberOfFields = 38; - break; - case 3483: - NumberOfFields = 22; - break; - case 3519: - NumberOfFields = 36; - break; - case 3521: - NumberOfFields = 35; - break; - case 3698: - case 3702: - case 3968: - NumberOfFields = 9; - break; - case 3703: - NumberOfFields = 9; - break; - default: - NumberOfFields = 10; - break; - } - - WorldPacket data(SMSG_INIT_WORLD_STATES, (4+4+4+2+(NumberOfFields*8))); - data << uint32(mapid); // mapid - data << uint32(zoneid); // zone id - data << uint32(areaid); // area id, new 2.1.0 - data << uint16(NumberOfFields); // count of uint64 blocks - data << uint32(0x8d8) << uint32(0x0); // 1 - data << uint32(0x8d7) << uint32(0x0); // 2 - data << uint32(0x8d6) << uint32(0x0); // 3 - data << uint32(0x8d5) << uint32(0x0); // 4 - data << uint32(0x8d4) << uint32(0x0); // 5 - data << uint32(0x8d3) << uint32(0x0); // 6 - if(mapid == 530) // Outland - { - data << uint32(0x9bf) << uint32(0x0); // 7 - data << uint32(0x9bd) << uint32(0xF); // 8 - data << uint32(0x9bb) << uint32(0xF); // 9 - } - switch(zoneid) - { - case 1: - case 11: - case 12: - case 38: - case 40: - case 51: - case 1519: - case 1537: - case 2257: - break; - case 2597: // AV - data << uint32(0x7ae) << uint32(0x1); // 7 - data << uint32(0x532) << uint32(0x1); // 8 - data << uint32(0x531) << uint32(0x0); // 9 - data << uint32(0x52e) << uint32(0x0); // 10 - data << uint32(0x571) << uint32(0x0); // 11 - data << uint32(0x570) << uint32(0x0); // 12 - data << uint32(0x567) << uint32(0x1); // 13 - data << uint32(0x566) << uint32(0x1); // 14 - data << uint32(0x550) << uint32(0x1); // 15 - data << uint32(0x544) << uint32(0x0); // 16 - data << uint32(0x536) << uint32(0x0); // 17 - data << uint32(0x535) << uint32(0x1); // 18 - data << uint32(0x518) << uint32(0x0); // 19 - data << uint32(0x517) << uint32(0x0); // 20 - data << uint32(0x574) << uint32(0x0); // 21 - data << uint32(0x573) << uint32(0x0); // 22 - data << uint32(0x572) << uint32(0x0); // 23 - data << uint32(0x56f) << uint32(0x0); // 24 - data << uint32(0x56e) << uint32(0x0); // 25 - data << uint32(0x56d) << uint32(0x0); // 26 - data << uint32(0x56c) << uint32(0x0); // 27 - data << uint32(0x56b) << uint32(0x0); // 28 - data << uint32(0x56a) << uint32(0x1); // 29 - data << uint32(0x569) << uint32(0x1); // 30 - data << uint32(0x568) << uint32(0x1); // 13 - data << uint32(0x565) << uint32(0x0); // 32 - data << uint32(0x564) << uint32(0x0); // 33 - data << uint32(0x563) << uint32(0x0); // 34 - data << uint32(0x562) << uint32(0x0); // 35 - data << uint32(0x561) << uint32(0x0); // 36 - data << uint32(0x560) << uint32(0x0); // 37 - data << uint32(0x55f) << uint32(0x0); // 38 - data << uint32(0x55e) << uint32(0x0); // 39 - data << uint32(0x55d) << uint32(0x0); // 40 - data << uint32(0x3c6) << uint32(0x4); // 41 - data << uint32(0x3c4) << uint32(0x6); // 42 - data << uint32(0x3c2) << uint32(0x4); // 43 - data << uint32(0x516) << uint32(0x1); // 44 - data << uint32(0x515) << uint32(0x0); // 45 - data << uint32(0x3b6) << uint32(0x6); // 46 - data << uint32(0x55c) << uint32(0x0); // 47 - data << uint32(0x55b) << uint32(0x0); // 48 - data << uint32(0x55a) << uint32(0x0); // 49 - data << uint32(0x559) << uint32(0x0); // 50 - data << uint32(0x558) << uint32(0x0); // 51 - data << uint32(0x557) << uint32(0x0); // 52 - data << uint32(0x556) << uint32(0x0); // 53 - data << uint32(0x555) << uint32(0x0); // 54 - data << uint32(0x554) << uint32(0x1); // 55 - data << uint32(0x553) << uint32(0x1); // 56 - data << uint32(0x552) << uint32(0x1); // 57 - data << uint32(0x551) << uint32(0x1); // 58 - data << uint32(0x54f) << uint32(0x0); // 59 - data << uint32(0x54e) << uint32(0x0); // 60 - data << uint32(0x54d) << uint32(0x1); // 61 - data << uint32(0x54c) << uint32(0x0); // 62 - data << uint32(0x54b) << uint32(0x0); // 63 - data << uint32(0x545) << uint32(0x0); // 64 - data << uint32(0x543) << uint32(0x1); // 65 - data << uint32(0x542) << uint32(0x0); // 66 - data << uint32(0x540) << uint32(0x0); // 67 - data << uint32(0x53f) << uint32(0x0); // 68 - data << uint32(0x53e) << uint32(0x0); // 69 - data << uint32(0x53d) << uint32(0x0); // 70 - data << uint32(0x53c) << uint32(0x0); // 71 - data << uint32(0x53b) << uint32(0x0); // 72 - data << uint32(0x53a) << uint32(0x1); // 73 - data << uint32(0x539) << uint32(0x0); // 74 - data << uint32(0x538) << uint32(0x0); // 75 - data << uint32(0x537) << uint32(0x0); // 76 - data << uint32(0x534) << uint32(0x0); // 77 - data << uint32(0x533) << uint32(0x0); // 78 - data << uint32(0x530) << uint32(0x0); // 79 - data << uint32(0x52f) << uint32(0x0); // 80 - data << uint32(0x52d) << uint32(0x1); // 81 - break; - case 3277: // WS - if (bg && bg->GetTypeID() == BATTLEGROUND_WS) - bg->FillInitialWorldStates(data); - else - { - data << uint32(0x62d) << uint32(0x0); // 7 1581 alliance flag captures - data << uint32(0x62e) << uint32(0x0); // 8 1582 horde flag captures - data << uint32(0x609) << uint32(0x0); // 9 1545 unk, set to 1 on alliance flag pickup... - data << uint32(0x60a) << uint32(0x0); // 10 1546 unk, set to 1 on horde flag pickup, after drop it's -1 - data << uint32(0x60b) << uint32(0x2); // 11 1547 unk - data << uint32(0x641) << uint32(0x3); // 12 1601 unk (max flag captures?) - data << uint32(0x922) << uint32(0x1); // 13 2338 horde (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing) - data << uint32(0x923) << uint32(0x1); // 14 2339 alliance (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing) - } - break; - case 3358: // AB - if (bg && bg->GetTypeID() == BATTLEGROUND_AB) - bg->FillInitialWorldStates(data); - else - { - data << uint32(0x6e7) << uint32(0x0); // 7 1767 stables alliance - data << uint32(0x6e8) << uint32(0x0); // 8 1768 stables horde - data << uint32(0x6e9) << uint32(0x0); // 9 1769 unk, ST? - data << uint32(0x6ea) << uint32(0x0); // 10 1770 stables (show/hide) - data << uint32(0x6ec) << uint32(0x0); // 11 1772 farm (0 - horde controlled, 1 - alliance controlled) - data << uint32(0x6ed) << uint32(0x0); // 12 1773 farm (show/hide) - data << uint32(0x6ee) << uint32(0x0); // 13 1774 farm color - data << uint32(0x6ef) << uint32(0x0); // 14 1775 gold mine color, may be FM? - data << uint32(0x6f0) << uint32(0x0); // 15 1776 alliance resources - data << uint32(0x6f1) << uint32(0x0); // 16 1777 horde resources - data << uint32(0x6f2) << uint32(0x0); // 17 1778 horde bases - data << uint32(0x6f3) << uint32(0x0); // 18 1779 alliance bases - data << uint32(0x6f4) << uint32(0x7d0); // 19 1780 max resources (2000) - data << uint32(0x6f6) << uint32(0x0); // 20 1782 blacksmith color - data << uint32(0x6f7) << uint32(0x0); // 21 1783 blacksmith (show/hide) - data << uint32(0x6f8) << uint32(0x0); // 22 1784 unk, bs? - data << uint32(0x6f9) << uint32(0x0); // 23 1785 unk, bs? - data << uint32(0x6fb) << uint32(0x0); // 24 1787 gold mine (0 - horde contr, 1 - alliance contr) - data << uint32(0x6fc) << uint32(0x0); // 25 1788 gold mine (0 - conflict, 1 - horde) - data << uint32(0x6fd) << uint32(0x0); // 26 1789 gold mine (1 - show/0 - hide) - data << uint32(0x6fe) << uint32(0x0); // 27 1790 gold mine color - data << uint32(0x700) << uint32(0x0); // 28 1792 gold mine color, wtf?, may be LM? - data << uint32(0x701) << uint32(0x0); // 29 1793 lumber mill color (0 - conflict, 1 - horde contr) - data << uint32(0x702) << uint32(0x0); // 30 1794 lumber mill (show/hide) - data << uint32(0x703) << uint32(0x0); // 31 1795 lumber mill color color - data << uint32(0x732) << uint32(0x1); // 32 1842 stables (1 - uncontrolled) - data << uint32(0x733) << uint32(0x1); // 33 1843 gold mine (1 - uncontrolled) - data << uint32(0x734) << uint32(0x1); // 34 1844 lumber mill (1 - uncontrolled) - data << uint32(0x735) << uint32(0x1); // 35 1845 farm (1 - uncontrolled) - data << uint32(0x736) << uint32(0x1); // 36 1846 blacksmith (1 - uncontrolled) - data << uint32(0x745) << uint32(0x2); // 37 1861 unk - data << uint32(0x7a3) << uint32(0x708); // 38 1955 warning limit (1800) - } - break; - case 3820: // EY - if (bg && bg->GetTypeID() == BATTLEGROUND_EY) - bg->FillInitialWorldStates(data); - else - { - data << uint32(0xac1) << uint32(0x0); // 7 2753 Horde Bases - data << uint32(0xac0) << uint32(0x0); // 8 2752 Alliance Bases - data << uint32(0xab6) << uint32(0x0); // 9 2742 Mage Tower - Horde conflict - data << uint32(0xab5) << uint32(0x0); // 10 2741 Mage Tower - Alliance conflict - data << uint32(0xab4) << uint32(0x0); // 11 2740 Fel Reaver - Horde conflict - data << uint32(0xab3) << uint32(0x0); // 12 2739 Fel Reaver - Alliance conflict - data << uint32(0xab2) << uint32(0x0); // 13 2738 Draenei - Alliance conflict - data << uint32(0xab1) << uint32(0x0); // 14 2737 Draenei - Horde conflict - data << uint32(0xab0) << uint32(0x0); // 15 2736 unk // 0 at start - data << uint32(0xaaf) << uint32(0x0); // 16 2735 unk // 0 at start - data << uint32(0xaad) << uint32(0x0); // 17 2733 Draenei - Horde control - data << uint32(0xaac) << uint32(0x0); // 18 2732 Draenei - Alliance control - data << uint32(0xaab) << uint32(0x1); // 19 2731 Draenei uncontrolled (1 - yes, 0 - no) - data << uint32(0xaaa) << uint32(0x0); // 20 2730 Mage Tower - Alliance control - data << uint32(0xaa9) << uint32(0x0); // 21 2729 Mage Tower - Horde control - data << uint32(0xaa8) << uint32(0x1); // 22 2728 Mage Tower uncontrolled (1 - yes, 0 - no) - data << uint32(0xaa7) << uint32(0x0); // 23 2727 Fel Reaver - Horde control - data << uint32(0xaa6) << uint32(0x0); // 24 2726 Fel Reaver - Alliance control - data << uint32(0xaa5) << uint32(0x1); // 25 2725 Fel Reaver uncontroled (1 - yes, 0 - no) - data << uint32(0xaa4) << uint32(0x0); // 26 2724 Boold Elf - Horde control - data << uint32(0xaa3) << uint32(0x0); // 27 2723 Boold Elf - Alliance control - data << uint32(0xaa2) << uint32(0x1); // 28 2722 Boold Elf uncontrolled (1 - yes, 0 - no) - data << uint32(0xac5) << uint32(0x1); // 29 2757 Flag (1 - show, 0 - hide) - doesn't work exactly this way! - data << uint32(0xad2) << uint32(0x1); // 30 2770 Horde top-stats (1 - show, 0 - hide) // 02 -> horde picked up the flag - data << uint32(0xad1) << uint32(0x1); // 31 2769 Alliance top-stats (1 - show, 0 - hide) // 02 -> alliance picked up the flag - data << uint32(0xabe) << uint32(0x0); // 32 2750 Horde resources - data << uint32(0xabd) << uint32(0x0); // 33 2749 Alliance resources - data << uint32(0xa05) << uint32(0x8e); // 34 2565 unk, constant? - data << uint32(0xaa0) << uint32(0x0); // 35 2720 Capturing progress-bar (100 -> empty (only grey), 0 -> blue|red (no grey), default 0) - data << uint32(0xa9f) << uint32(0x0); // 36 2719 Capturing progress-bar (0 - left, 100 - right) - data << uint32(0xa9e) << uint32(0x0); // 37 2718 Capturing progress-bar (1 - show, 0 - hide) - data << uint32(0xc0d) << uint32(0x17b); // 38 3085 unk - // and some more ... unknown - } - break; - case 3483: // Hellfire Peninsula - data << uint32(0x9ba) << uint32(0x1); // 10 - data << uint32(0x9b9) << uint32(0x1); // 11 - data << uint32(0x9b5) << uint32(0x0); // 12 - data << uint32(0x9b4) << uint32(0x1); // 13 - data << uint32(0x9b3) << uint32(0x0); // 14 - data << uint32(0x9b2) << uint32(0x0); // 15 - data << uint32(0x9b1) << uint32(0x1); // 16 - data << uint32(0x9b0) << uint32(0x0); // 17 - data << uint32(0x9ae) << uint32(0x0); // 18 horde pvp objectives captured - data << uint32(0x9ac) << uint32(0x0); // 19 - data << uint32(0x9a8) << uint32(0x0); // 20 - data << uint32(0x9a7) << uint32(0x0); // 21 - data << uint32(0x9a6) << uint32(0x1); // 22 - break; - case 3519: // Terokkar Forest - data << uint32(0xa41) << uint32(0x0); // 10 - data << uint32(0xa40) << uint32(0x14); // 11 - data << uint32(0xa3f) << uint32(0x0); // 12 - data << uint32(0xa3e) << uint32(0x0); // 13 - data << uint32(0xa3d) << uint32(0x5); // 14 - data << uint32(0xa3c) << uint32(0x0); // 15 - data << uint32(0xa87) << uint32(0x0); // 16 - data << uint32(0xa86) << uint32(0x0); // 17 - data << uint32(0xa85) << uint32(0x0); // 18 - data << uint32(0xa84) << uint32(0x0); // 19 - data << uint32(0xa83) << uint32(0x0); // 20 - data << uint32(0xa82) << uint32(0x0); // 21 - data << uint32(0xa81) << uint32(0x0); // 22 - data << uint32(0xa80) << uint32(0x0); // 23 - data << uint32(0xa7e) << uint32(0x0); // 24 - data << uint32(0xa7d) << uint32(0x0); // 25 - data << uint32(0xa7c) << uint32(0x0); // 26 - data << uint32(0xa7b) << uint32(0x0); // 27 - data << uint32(0xa7a) << uint32(0x0); // 28 - data << uint32(0xa79) << uint32(0x0); // 29 - data << uint32(0x9d0) << uint32(0x5); // 30 - data << uint32(0x9ce) << uint32(0x0); // 31 - data << uint32(0x9cd) << uint32(0x0); // 32 - data << uint32(0x9cc) << uint32(0x0); // 33 - data << uint32(0xa88) << uint32(0x0); // 34 - data << uint32(0xad0) << uint32(0x0); // 35 - data << uint32(0xacf) << uint32(0x1); // 36 - break; - case 3521: // Zangarmarsh - data << uint32(0x9e1) << uint32(0x0); // 10 - data << uint32(0x9e0) << uint32(0x0); // 11 - data << uint32(0x9df) << uint32(0x0); // 12 - data << uint32(0xa5d) << uint32(0x1); // 13 - data << uint32(0xa5c) << uint32(0x0); // 14 - data << uint32(0xa5b) << uint32(0x1); // 15 - data << uint32(0xa5a) << uint32(0x0); // 16 - data << uint32(0xa59) << uint32(0x1); // 17 - data << uint32(0xa58) << uint32(0x0); // 18 - data << uint32(0xa57) << uint32(0x0); // 19 - data << uint32(0xa56) << uint32(0x0); // 20 - data << uint32(0xa55) << uint32(0x1); // 21 - data << uint32(0xa54) << uint32(0x0); // 22 - data << uint32(0x9e7) << uint32(0x0); // 23 - data << uint32(0x9e6) << uint32(0x0); // 24 - data << uint32(0x9e5) << uint32(0x0); // 25 - data << uint32(0xa00) << uint32(0x0); // 26 - data << uint32(0x9ff) << uint32(0x1); // 27 - data << uint32(0x9fe) << uint32(0x0); // 28 - data << uint32(0x9fd) << uint32(0x0); // 29 - data << uint32(0x9fc) << uint32(0x1); // 30 - data << uint32(0x9fb) << uint32(0x0); // 31 - data << uint32(0xa62) << uint32(0x0); // 32 - data << uint32(0xa61) << uint32(0x1); // 33 - data << uint32(0xa60) << uint32(0x1); // 34 - data << uint32(0xa5f) << uint32(0x0); // 35 - break; - case 3698: // Nagrand Arena - data << uint32(0xa0f) << uint32(0x0); // 7 - data << uint32(0xa10) << uint32(0x0); // 8 - data << uint32(0xa11) << uint32(0x0); // 9 - break; - case 3702: // Blade's Edge Arena - data << uint32(0x9f0) << uint32(0x0); // 7 - data << uint32(0x9f1) << uint32(0x0); // 8 - data << uint32(0x9f3) << uint32(0x0); // 9 - break; - case 3968: // Ruins of Lordaeron - data << uint32(0xbb8) << uint32(0x0); // 7 - data << uint32(0xbb9) << uint32(0x0); // 8 - data << uint32(0xbba) << uint32(0x0); // 9 - break; - case 3703: // Shattrath City - break; - default: - data << uint32(0x914) << uint32(0x0); // 7 - data << uint32(0x913) << uint32(0x0); // 8 - data << uint32(0x912) << uint32(0x0); // 9 - data << uint32(0x915) << uint32(0x0); // 10 - break; - } - GetSession()->SendPacket(&data); -} - -uint32 Player::GetXPRestBonus(uint32 xp) -{ - uint32 rested_bonus = (uint32)GetRestBonus(); // xp for each rested bonus - - if(rested_bonus > xp) // max rested_bonus == xp or (r+x) = 200% xp - rested_bonus = xp; - - SetRestBonus( GetRestBonus() - rested_bonus); - - sLog.outDetail("Player gain %u xp (+ %u Rested Bonus). Rested points=%f",xp+rested_bonus,rested_bonus,GetRestBonus()); - return rested_bonus; -} - -void Player::SetBindPoint(uint64 guid) -{ - WorldPacket data(SMSG_BINDER_CONFIRM, 8); - data << uint64(guid); - GetSession()->SendPacket( &data ); -} - -void Player::SendTalentWipeConfirm(uint64 guid) -{ - WorldPacket data(MSG_TALENT_WIPE_CONFIRM, (8+4)); - data << uint64(guid); - data << uint32(resetTalentsCost()); - GetSession()->SendPacket( &data ); -} - -void Player::SendPetSkillWipeConfirm() -{ - Pet* pet = GetPet(); - if(!pet) - return; - WorldPacket data(SMSG_PET_UNLEARN_CONFIRM, (8+4)); - data << pet->GetGUID(); - data << uint32(pet->resetTalentsCost()); - GetSession()->SendPacket( &data ); -} - -/*********************************************************/ -/*** STORAGE SYSTEM ***/ -/*********************************************************/ - -void Player::SetVirtualItemSlot( uint8 i, Item* item) -{ - assert(i < 3); - if(i < 2 && item) - { - if(!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) - return; - uint32 charges = item->GetEnchantmentCharges(TEMP_ENCHANTMENT_SLOT); - if(charges == 0) - return; - if(charges > 1) - item->SetEnchantmentCharges(TEMP_ENCHANTMENT_SLOT,charges-1); - else if(charges <= 1) - { - ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false); - item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); - } - } -} - -void Player::SetSheath( uint32 sheathed ) -{ - switch (sheathed) - { - case SHEATH_STATE_UNARMED: // no prepared weapon - SetVirtualItemSlot(0,NULL); - SetVirtualItemSlot(1,NULL); - SetVirtualItemSlot(2,NULL); - break; - case SHEATH_STATE_MELEE: // prepared melee weapon - { - SetVirtualItemSlot(0,GetWeaponForAttack(BASE_ATTACK,true)); - SetVirtualItemSlot(1,GetWeaponForAttack(OFF_ATTACK,true)); - SetVirtualItemSlot(2,NULL); - }; break; - case SHEATH_STATE_RANGED: // prepared ranged weapon - SetVirtualItemSlot(0,NULL); - SetVirtualItemSlot(1,NULL); - SetVirtualItemSlot(2,GetWeaponForAttack(RANGED_ATTACK,true)); - break; - default: - SetVirtualItemSlot(0,NULL); - SetVirtualItemSlot(1,NULL); - SetVirtualItemSlot(2,NULL); - break; - } - SetByteValue(UNIT_FIELD_BYTES_2, 0, sheathed); // this must visualize Sheath changing for other players... -} - -uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const -{ - uint8 pClass = getClass(); - - uint8 slots[4]; - slots[0] = NULL_SLOT; - slots[1] = NULL_SLOT; - slots[2] = NULL_SLOT; - slots[3] = NULL_SLOT; - switch( proto->InventoryType ) - { - case INVTYPE_HEAD: - slots[0] = EQUIPMENT_SLOT_HEAD; - break; - case INVTYPE_NECK: - slots[0] = EQUIPMENT_SLOT_NECK; - break; - case INVTYPE_SHOULDERS: - slots[0] = EQUIPMENT_SLOT_SHOULDERS; - break; - case INVTYPE_BODY: - slots[0] = EQUIPMENT_SLOT_BODY; - break; - case INVTYPE_CHEST: - slots[0] = EQUIPMENT_SLOT_CHEST; - break; - case INVTYPE_ROBE: - slots[0] = EQUIPMENT_SLOT_CHEST; - break; - case INVTYPE_WAIST: - slots[0] = EQUIPMENT_SLOT_WAIST; - break; - case INVTYPE_LEGS: - slots[0] = EQUIPMENT_SLOT_LEGS; - break; - case INVTYPE_FEET: - slots[0] = EQUIPMENT_SLOT_FEET; - break; - case INVTYPE_WRISTS: - slots[0] = EQUIPMENT_SLOT_WRISTS; - break; - case INVTYPE_HANDS: - slots[0] = EQUIPMENT_SLOT_HANDS; - break; - case INVTYPE_FINGER: - slots[0] = EQUIPMENT_SLOT_FINGER1; - slots[1] = EQUIPMENT_SLOT_FINGER2; - break; - case INVTYPE_TRINKET: - slots[0] = EQUIPMENT_SLOT_TRINKET1; - slots[1] = EQUIPMENT_SLOT_TRINKET2; - break; - case INVTYPE_CLOAK: - slots[0] = EQUIPMENT_SLOT_BACK; - break; - case INVTYPE_WEAPON: - { - slots[0] = EQUIPMENT_SLOT_MAINHAND; - - // suggest offhand slot only if know dual wielding - // (this will be replace mainhand weapon at auto equip instead unwonted "you don't known dual wielding" ... - if(CanDualWield()) - slots[1] = EQUIPMENT_SLOT_OFFHAND; - };break; - case INVTYPE_SHIELD: - slots[0] = EQUIPMENT_SLOT_OFFHAND; - break; - case INVTYPE_RANGED: - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case INVTYPE_2HWEAPON: - slots[0] = EQUIPMENT_SLOT_MAINHAND; - break; - case INVTYPE_TABARD: - slots[0] = EQUIPMENT_SLOT_TABARD; - break; - case INVTYPE_WEAPONMAINHAND: - slots[0] = EQUIPMENT_SLOT_MAINHAND; - break; - case INVTYPE_WEAPONOFFHAND: - slots[0] = EQUIPMENT_SLOT_OFFHAND; - break; - case INVTYPE_HOLDABLE: - slots[0] = EQUIPMENT_SLOT_OFFHAND; - break; - case INVTYPE_THROWN: - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case INVTYPE_RANGEDRIGHT: - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case INVTYPE_BAG: - slots[0] = INVENTORY_SLOT_BAG_1; - slots[1] = INVENTORY_SLOT_BAG_2; - slots[2] = INVENTORY_SLOT_BAG_3; - slots[3] = INVENTORY_SLOT_BAG_4; - break; - case INVTYPE_RELIC: - { - switch(proto->SubClass) - { - case ITEM_SUBCLASS_ARMOR_LIBRAM: - if (pClass == CLASS_PALADIN) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case ITEM_SUBCLASS_ARMOR_IDOL: - if (pClass == CLASS_DRUID) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case ITEM_SUBCLASS_ARMOR_TOTEM: - if (pClass == CLASS_SHAMAN) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case ITEM_SUBCLASS_ARMOR_MISC: - if (pClass == CLASS_WARLOCK) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - } - break; - } - default : - return NULL_SLOT; - } - - if( slot != NULL_SLOT ) - { - if( swap || !GetItemByPos( INVENTORY_SLOT_BAG_0, slot ) ) - { - for (int i = 0; i < 4; i++) - { - if ( slots[i] == slot ) - return slot; - } - } - } - else - { - // search free slot at first - for (int i = 0; i < 4; i++) - { - if ( slots[i] != NULL_SLOT && !GetItemByPos( INVENTORY_SLOT_BAG_0, slots[i] ) ) - { - // in case 2hand equipped weapon offhand slot empty but not free - if(slots[i]==EQUIPMENT_SLOT_OFFHAND) - { - Item* mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ); - if(!mainItem || mainItem->GetProto()->InventoryType != INVTYPE_2HWEAPON) - return slots[i]; - } - else - return slots[i]; - } - } - - // if not found free and can swap return first appropriate from used - for (int i = 0; i < 4; i++) - { - if ( slots[i] != NULL_SLOT && swap ) - return slots[i]; - } - } - - // no free position - return NULL_SLOT; -} - -uint8 Player::CanUnequipItems( uint32 item, uint32 count ) const -{ - Item *pItem; - uint32 tempcount = 0; - - uint8 res = EQUIP_ERR_OK; - - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - uint8 ires = CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false); - if(ires==EQUIP_ERR_OK) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return EQUIP_ERR_OK; - } - else - res = ires; - } - } - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return EQUIP_ERR_OK; - } - } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return EQUIP_ERR_OK; - } - } - Bag *pBag; - ItemPrototype const *pBagProto; - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - pItem = GetItemByPos( i, j ); - if( pItem && pItem->GetEntry() == item ) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return EQUIP_ERR_OK; - } - } - } - } - } - - // not found req. item count and have unequippable items - return res; -} - -uint32 Player::GetItemCount( uint32 item, bool inBankAlso, Item* skipItem ) const -{ - uint32 count = 0; - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem != skipItem && pItem->GetEntry() == item ) - count += pItem->GetCount(); - } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem != skipItem && pItem->GetEntry() == item ) - count += pItem->GetCount(); - } - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - count += pBag->GetItemCount(item,skipItem); - } - - if(skipItem && skipItem->GetProto()->GemProperties) - { - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem != skipItem && pItem->GetProto()->Socket[0].Color ) - count += pItem->GetGemCountWithID(item); - } - } - - if(inBankAlso) - { - for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem != skipItem && pItem->GetEntry() == item ) - count += pItem->GetCount(); - } - for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - count += pBag->GetItemCount(item,skipItem); - } - - if(skipItem && skipItem->GetProto()->GemProperties) - { - for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem != skipItem && pItem->GetProto()->Socket[0].Color ) - count += pItem->GetGemCountWithID(item); - } - } - } - - return count; -} - -Item* Player::GetItemByGuid( uint64 guid ) const -{ - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetGUID() == guid ) - return pItem; - } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetGUID() == guid ) - return pItem; - } - - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - ItemPrototype const *pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - Item* pItem = pBag->GetItemByPos( j ); - if( pItem && pItem->GetGUID() == guid ) - return pItem; - } - } - } - } - for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - ItemPrototype const *pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - Item* pItem = pBag->GetItemByPos( j ); - if( pItem && pItem->GetGUID() == guid ) - return pItem; - } - } - } - } - - return NULL; -} - -Item* Player::GetItemByPos( uint16 pos ) const -{ - uint8 bag = pos >> 8; - uint8 slot = pos & 255; - return GetItemByPos( bag, slot ); -} - -Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const -{ - if( bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END || slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END ) ) - return m_items[slot]; - else if(bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END - || bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) - { - Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); - if ( pBag ) - return pBag->GetItemByPos(slot); - } - return NULL; -} - -Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable) const -{ - uint16 slot; - switch (attackType) - { - case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break; - case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break; - case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break; - default: return NULL; - } - - Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot); - if (!item || item->GetProto()->Class != ITEM_CLASS_WEAPON) - return NULL; - - if(!useable) - return item; - - if( item->IsBroken() || !IsUseEquipedWeapon(attackType==BASE_ATTACK) ) - return NULL; - - return item; -} - -Item* Player::GetShield(bool useable) const -{ - Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - if (!item || item->GetProto()->Class != ITEM_CLASS_ARMOR) - return NULL; - - if(!useable) - return item; - - if( item->IsBroken()) - return NULL; - - return item; -} - -uint32 Player::GetAttackBySlot( uint8 slot ) -{ - switch(slot) - { - case EQUIPMENT_SLOT_MAINHAND: return BASE_ATTACK; - case EQUIPMENT_SLOT_OFFHAND: return OFF_ATTACK; - case EQUIPMENT_SLOT_RANGED: return RANGED_ATTACK; - default: return MAX_ATTACK; - } -} - -bool Player::HasBankBagSlot( uint8 slot ) const -{ - uint32 maxslot = GetByteValue(PLAYER_BYTES_2, 2) + BANK_SLOT_BAG_START; - if( slot < maxslot ) - return true; - return false; -} - -bool Player::IsInventoryPos( uint8 bag, uint8 slot ) -{ - if( bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT ) - return true; - if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END ) ) - return true; - if( bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END ) - return true; - if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END ) ) - return true; - return false; -} - -bool Player::IsEquipmentPos( uint8 bag, uint8 slot ) -{ - if( bag == INVENTORY_SLOT_BAG_0 && ( slot < EQUIPMENT_SLOT_END ) ) - return true; - if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) ) - return true; - return false; -} - -bool Player::IsBankPos( uint8 bag, uint8 slot ) -{ - if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END ) ) - return true; - if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) ) - return true; - if( bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) - return true; - return false; -} - -bool Player::IsBagPos( uint16 pos ) -{ - uint8 bag = pos >> 8; - uint8 slot = pos & 255; - if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) ) - return true; - if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) ) - return true; - return false; -} - -bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const -{ - uint32 tempcount = 0; - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return true; - } - } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return true; - } - } - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - { - if(ItemPrototype const *pBagProto = pBag->GetProto()) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - Item* pItem = GetItemByPos( i, j ); - if( pItem && pItem->GetEntry() == item ) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return true; - } - } - } - } - } - - if(inBankAlso) - { - for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return true; - } - } - for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - { - if(ItemPrototype const *pBagProto = pBag->GetProto()) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - Item* pItem = GetItemByPos( i, j ); - if( pItem && pItem->GetEntry() == item ) - { - tempcount += pItem->GetCount(); - if( tempcount >= count ) - return true; - } - } - } - } - } - } - - return false; -} - -Item* Player::GetItemOrItemWithGemEquipped( uint32 item ) const -{ - Item *pItem; - for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - return pItem; - } - - ItemPrototype const *pProto = objmgr.GetItemPrototype(item); - if (pProto && pProto->GemProperties) - { - for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetProto()->Socket[0].Color ) - { - if (pItem->GetGemCountWithID(item) > 0 ) - return pItem; - } - } - } - - return NULL; -} - -uint8 Player::_CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count ) const -{ - ItemPrototype const *pProto = objmgr.GetItemPrototype(entry); - if( !pProto ) - { - if(no_space_count) - *no_space_count = count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - - // no maximum - if(pProto->MaxCount == 0) - return EQUIP_ERR_OK; - - uint32 curcount = GetItemCount(pProto->ItemId,true,pItem); - - if( curcount + count > pProto->MaxCount ) - { - if(no_space_count) - *no_space_count = count +curcount - pProto->MaxCount; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - - return EQUIP_ERR_OK; -} - -bool Player::HasItemTotemCategory( uint32 TotemCategory ) const -{ - Item *pItem; - for(uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory )) - return true; - } - for(uint8 i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory )) - return true; - } - Bag *pBag; - ItemPrototype const *pBagProto; - for(uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) - { - pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; ++j) - { - pItem = GetItemByPos( i, j ); - if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory )) - return true; - } - } - } - } - return false; -} - -uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool swap, Item* pSrcItem ) const -{ - Item* pItem2 = GetItemByPos( bag, slot ); - - // ignore move item (this slot will be empty at move) - if(pItem2==pSrcItem) - pItem2 = NULL; - - uint32 need_space; - - // empty specific slot - check item fit to slot - if( !pItem2 || swap ) - { - if( bag == INVENTORY_SLOT_BAG_0 ) - { - // keyring case - if(slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - // prevent cheating - if(slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - } - else - { - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); - if( !pBag ) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - ItemPrototype const* pBagProto = pBag->GetProto(); - if( !pBagProto ) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - if( !ItemCanGoIntoBag(pProto,pBagProto) ) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - } - - // non empty stack with space - need_space = pProto->Stackable; - } - // non empty slot, check item type - else - { - // check item type - if(pItem2->GetEntry() != pProto->ItemId) - return EQUIP_ERR_ITEM_CANT_STACK; - - // check free space - if(pItem2->GetCount() >= pProto->Stackable) - return EQUIP_ERR_ITEM_CANT_STACK; - - need_space = pProto->Stackable - pItem2->GetCount(); - } - - if(need_space > count) - need_space = count; - - ItemPosCount newPosition = ItemPosCount((bag << 8) | slot, need_space); - if(!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; - } - return EQUIP_ERR_OK; -} - -uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot ) const -{ - // skip specific bag already processed in first called _CanStoreItem_InBag - if(bag==skip_bag) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); - if( !pBag ) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - ItemPrototype const* pBagProto = pBag->GetProto(); - if( !pBagProto ) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - // specialized bag mode or non-specilized - if( non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER) ) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - if( !ItemCanGoIntoBag(pProto,pBagProto) ) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot - if(j==skip_slot) - continue; - - Item* pItem2 = GetItemByPos( bag, j ); - - // ignore move item (this slot will be empty at move) - if(pItem2==pSrcItem) - pItem2 = NULL; - - // if merge skip empty, if !merge skip non-empty - if((pItem2!=NULL)!=merge) - continue; - - if( pItem2 ) - { - if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->Stackable ) - { - uint32 need_space = pProto->Stackable - pItem2->GetCount(); - if(need_space > count) - need_space = count; - - ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); - if(!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; - - if(count==0) - return EQUIP_ERR_OK; - } - } - } - else - { - uint32 need_space = pProto->Stackable; - if(need_space > count) - need_space = count; - - ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); - if(!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; - - if(count==0) - return EQUIP_ERR_OK; - } - } - } - return EQUIP_ERR_OK; -} - -uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool merge, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot ) const -{ - for(uint32 j = slot_begin; j < slot_end; j++) - { - // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot - if(INVENTORY_SLOT_BAG_0==skip_bag && j==skip_slot) - continue; - - Item* pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, j ); - - // ignore move item (this slot will be empty at move) - if(pItem2==pSrcItem) - pItem2 = NULL; - - // if merge skip empty, if !merge skip non-empty - if((pItem2!=NULL)!=merge) - continue; - - if( pItem2 ) - { - if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->Stackable ) - { - uint32 need_space = pProto->Stackable - pItem2->GetCount(); - if(need_space > count) - need_space = count; - ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); - if(!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; - - if(count==0) - return EQUIP_ERR_OK; - } - } - } - else - { - uint32 need_space = pProto->Stackable; - if(need_space > count) - need_space = count; - - ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); - if(!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; - - if(count==0) - return EQUIP_ERR_OK; - } - } - } - return EQUIP_ERR_OK; -} - -uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 entry, uint32 count, Item *pItem, bool swap, uint32* no_space_count ) const -{ - sLog.outDebug( "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, entry, count); - - ItemPrototype const *pProto = objmgr.GetItemPrototype(entry); - if( !pProto ) - { - if(no_space_count) - *no_space_count = count; - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND; - } - - if(pItem && pItem->IsBindedNotWith(GetGUID())) - { - if(no_space_count) - *no_space_count = count; - return EQUIP_ERR_DONT_OWN_THAT_ITEM; - } - - // check count of items (skip for auto move for same player from bank) - uint32 no_similar_count = 0; // can't store this amount similar items - uint8 res = _CanTakeMoreSimilarItems(entry,count,pItem,&no_similar_count); - if(res!=EQUIP_ERR_OK) - { - if(count==no_similar_count) - { - if(no_space_count) - *no_space_count = no_similar_count; - return res; - } - count -= no_similar_count; - } - - // in specific slot - if( bag != NULL_BAG && slot != NULL_SLOT ) - { - res = _CanStoreItem_InSpecificSlot(bag,slot,dest,pProto,count,swap,pItem); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - - // not specific slot or have spece for partly store only in specific slot - - // in specific bag - if( bag != NULL_BAG ) - { - // search stack in bag for merge to - if( pProto->Stackable > 1 ) - { - if( bag == INVENTORY_SLOT_BAG_0 ) // inventory - { - res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - - res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - else // equipped bag - { - // we need check 2 time (specilized/non_specialized), use NULL_BAG to prevent skipping bag - res = _CanStoreItem_InBag(bag,dest,pProto,count,true,false,pItem,NULL_BAG,slot); - if(res!=EQUIP_ERR_OK) - res = _CanStoreItem_InBag(bag,dest,pProto,count,true,true,pItem,NULL_BAG,slot); - - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - } - - // search free slot in bag for place to - if( bag == INVENTORY_SLOT_BAG_0 ) // inventory - { - // search free slot - keyring case - if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS) - { - uint32 keyringSize = GetMaxKeyringSize(); - res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - - res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - else // equipped bag - { - res = _CanStoreItem_InBag(bag,dest,pProto,count,false,false,pItem,NULL_BAG,slot); - if(res!=EQUIP_ERR_OK) - res = _CanStoreItem_InBag(bag,dest,pProto,count,false,true,pItem,NULL_BAG,slot); - - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - } - - // not specific bag or have space for partly store only in specific bag - - // search stack for merge to - if( pProto->Stackable > 1 ) - { - res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - - res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - - if( pProto->BagFamily ) - { - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - res = _CanStoreItem_InBag(i,dest,pProto,count,true,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - continue; - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - } - - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - res = _CanStoreItem_InBag(i,dest,pProto,count,true,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - continue; - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - } - - // search free slot - special bag case - if( pProto->BagFamily ) - { - if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS) - { - uint32 keyringSize = GetMaxKeyringSize(); - res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - res = _CanStoreItem_InBag(i,dest,pProto,count,false,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - continue; - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - } - - // search free slot - res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - res = _CanStoreItem_InBag(i,dest,pProto,count,false,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - continue; - - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; - - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - - if(no_space_count) - *no_space_count = count + no_similar_count; - - return EQUIP_ERR_INVENTORY_FULL; -} - -////////////////////////////////////////////////////////////////////////// -uint8 Player::CanStoreItems( Item **pItems,int count) const -{ - Item *pItem2; - - // fill space table - int inv_slot_items[INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START]; - int inv_bags[INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE]; - int inv_keys[KEYRING_SLOT_END-KEYRING_SLOT_START]; - - memset(inv_slot_items,0,sizeof(int)*(INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START)); - memset(inv_bags,0,sizeof(int)*(INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START)*MAX_BAG_SIZE); - memset(inv_keys,0,sizeof(int)*(KEYRING_SLOT_END-KEYRING_SLOT_START)); - - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - - if (pItem2 && !pItem2->IsInTrade()) - { - inv_slot_items[i-INVENTORY_SLOT_ITEM_START] = pItem2->GetCount(); - } - } - - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - - if (pItem2 && !pItem2->IsInTrade()) - { - inv_keys[i-KEYRING_SLOT_START] = pItem2->GetCount(); - } - } - - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Bag *pBag; - ItemPrototype const *pBagProto; - - pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - pBagProto = pBag->GetProto(); - - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - pItem2 = GetItemByPos( i, j ); - if (pItem2 && !pItem2->IsInTrade()) - { - inv_bags[i-INVENTORY_SLOT_BAG_START][j] = pItem2->GetCount(); - } - } - } - } - } - - // check free space for all items - for (int k=0;kGetEntry(), pItem->GetCount()); - ItemPrototype const *pProto = pItem->GetProto(); - - // strange item - if( !pProto ) - return EQUIP_ERR_ITEM_NOT_FOUND; - - // item it 'bind' - if(pItem->IsBindedNotWith(GetGUID())) - return EQUIP_ERR_DONT_OWN_THAT_ITEM; - - Bag *pBag; - ItemPrototype const *pBagProto; - - // item is 'one item only' - uint8 res = CanTakeMoreSimilarItems(pItem); - if(res != EQUIP_ERR_OK) - return res; - - // search stack for merge to - if( pProto->Stackable > 1 ) - { - bool b_found = false; - - for(int t = KEYRING_SLOT_START; t < KEYRING_SLOT_END; t++) - { - pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); - if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_keys[t-KEYRING_SLOT_START] + pItem->GetCount() <= pProto->Stackable ) - { - inv_keys[t-KEYRING_SLOT_START] += pItem->GetCount(); - b_found = true; - break; - } - } - if (b_found) continue; - - for(int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; t++) - { - pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); - if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_slot_items[t-INVENTORY_SLOT_ITEM_START] + pItem->GetCount() <= pProto->Stackable ) - { - inv_slot_items[t-INVENTORY_SLOT_ITEM_START] += pItem->GetCount(); - b_found = true; - break; - } - } - if (b_found) continue; - - for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++) - { - pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t ); - if( pBag ) - { - pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - pItem2 = GetItemByPos( t, j ); - if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_bags[t-INVENTORY_SLOT_BAG_START][j] + pItem->GetCount() <= pProto->Stackable ) - { - inv_bags[t-INVENTORY_SLOT_BAG_START][j] += pItem->GetCount(); - b_found = true; - break; - } - } - } - } - } - if (b_found) continue; - } - - // special bag case - if( pProto->BagFamily ) - { - bool b_found = false; - if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS) - { - uint32 keyringSize = GetMaxKeyringSize(); - for(uint32 t = KEYRING_SLOT_START; t < KEYRING_SLOT_START+keyringSize; ++t) - { - if( inv_keys[t-KEYRING_SLOT_START] == 0 ) - { - inv_keys[t-KEYRING_SLOT_START] = 1; - b_found = true; - break; - } - } - } - - if (b_found) continue; - - for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++) - { - pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t ); - if( pBag ) - { - pBagProto = pBag->GetProto(); - - // not plain container check - if( pBagProto && (pBagProto->Class != ITEM_CLASS_CONTAINER || pBagProto->SubClass != ITEM_SUBCLASS_CONTAINER) && - ItemCanGoIntoBag(pProto,pBagProto) ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - if( inv_bags[t-INVENTORY_SLOT_BAG_START][j] == 0 ) - { - inv_bags[t-INVENTORY_SLOT_BAG_START][j] = 1; - b_found = true; - break; - } - } - } - } - } - if (b_found) continue; - } - - // search free slot - bool b_found = false; - for(int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; t++) - { - if( inv_slot_items[t-INVENTORY_SLOT_ITEM_START] == 0 ) - { - inv_slot_items[t-INVENTORY_SLOT_ITEM_START] = 1; - b_found = true; - break; - } - } - if (b_found) continue; - - // search free slot in bags - for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++) - { - pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t ); - if( pBag ) - { - pBagProto = pBag->GetProto(); - if( pBagProto && ItemCanGoIntoBag(pProto,pBagProto)) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - if( inv_bags[t-INVENTORY_SLOT_BAG_START][j] == 0 ) - { - inv_bags[t-INVENTORY_SLOT_BAG_START][j] = 1; - b_found = true; - break; - } - } - } - } - } - - // no free slot found? - if (!b_found) - return EQUIP_ERR_INVENTORY_FULL; - } - - return EQUIP_ERR_OK; -} - -////////////////////////////////////////////////////////////////////////// -uint8 Player::CanEquipNewItem( uint8 slot, uint16 &dest, uint32 item, uint32 count, bool swap ) const -{ - dest = 0; - Item *pItem = Item::CreateItem( item, count, this ); - if( pItem ) - { - uint8 result = CanEquipItem(slot, dest, pItem, swap ); - delete pItem; - return result; - } - - return EQUIP_ERR_ITEM_NOT_FOUND; -} - -uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading ) const -{ - dest = 0; - if( pItem ) - { - sLog.outDebug( "STORAGE: CanEquipItem slot = %u, item = %u, count = %u", slot, pItem->GetEntry(), pItem->GetCount()); - ItemPrototype const *pProto = pItem->GetProto(); - if( pProto ) - { - if(pItem->IsBindedNotWith(GetGUID())) - return EQUIP_ERR_DONT_OWN_THAT_ITEM; - - // check count of items (skip for auto move for same player from bank) - uint8 res = CanTakeMoreSimilarItems(pItem); - if(res != EQUIP_ERR_OK) - return res; - - // do not allow equipping gear except weapons, offhands, projectiles, relics in - // - combat - // - in-progress arenas - if( !pProto->CanChangeEquipStateInCombat() ) - { - if( isInCombat() ) - return EQUIP_ERR_NOT_IN_COMBAT; - - if(BattleGround* bg = GetBattleGround()) - if( bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS ) - return EQUIP_ERR_NOT_DURING_ARENA_MATCH; - } - - if(isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer != 0) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err - - uint8 eslot = FindEquipSlot( pProto, slot, swap ); - if( eslot == NULL_SLOT ) - return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; - - uint8 msg = CanUseItem( pItem , not_loading ); - if( msg != EQUIP_ERR_OK ) - return msg; - if( !swap && GetItemByPos( INVENTORY_SLOT_BAG_0, eslot ) ) - return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE; - - // check unique-equipped on item - if (pProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED) - { - // there is an equip limit on this item - Item* tItem = GetItemOrItemWithGemEquipped(pProto->ItemId); - if (tItem && (!swap || tItem->GetSlot() != eslot ) ) - return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE; - } - - // check unique-equipped on gems - for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) - { - uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot)); - if(!enchant_id) - continue; - SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!enchantEntry) - continue; - - ItemPrototype const* pGem = objmgr.GetItemPrototype(enchantEntry->GemID); - if(pGem && (pGem->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)) - { - Item* tItem = GetItemOrItemWithGemEquipped(enchantEntry->GemID); - if(tItem && (!swap || tItem->GetSlot() != eslot )) - return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE; - } - } - - // check unique-equipped special item classes - if (pProto->Class == ITEM_CLASS_QUIVER) - { - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) - { - if( Item* pBag = GetItemByPos( INVENTORY_SLOT_BAG_0, i ) ) - { - if( ItemPrototype const* pBagProto = pBag->GetProto() ) - { - if( pBagProto->Class==pProto->Class && pBagProto->SubClass==pProto->SubClass && - (!swap || pBag->GetSlot() != eslot ) ) - { - if(pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH) - return EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH; - else - return EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER; - } - } - } - } - } - - uint32 type = pProto->InventoryType; - - if(eslot == EQUIPMENT_SLOT_OFFHAND) - { - if( type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND ) - { - if(!CanDualWield()) - return EQUIP_ERR_CANT_DUAL_WIELD; - } - - Item *mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ); - if(mainItem) - { - if(mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON) - return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED; - } - } - - // equip two-hand weapon case (with possible unequip 2 items) - if( type == INVTYPE_2HWEAPON ) - { - if(eslot != EQUIPMENT_SLOT_MAINHAND) - return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; - - // offhand item must can be stored in inventitory for offhand item and it also must be unequipped - Item *offItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND ); - ItemPosCountVec off_dest; - if( offItem && (!not_loading || - CanUnequipItem(uint16(INVENTORY_SLOT_BAG_0) << 8 | EQUIPMENT_SLOT_OFFHAND,false) != EQUIP_ERR_OK || - CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ) != EQUIP_ERR_OK ) ) - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_INVENTORY_FULL; - } - dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot); - return EQUIP_ERR_OK; - } - } - if( !swap ) - return EQUIP_ERR_ITEM_NOT_FOUND; - else - return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED; -} - -uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const -{ - // Applied only to equipped items and bank bags - if(!IsEquipmentPos(pos) && !IsBagPos(pos)) - return EQUIP_ERR_OK; - - Item* pItem = GetItemByPos(pos); - - // Applied only to existed equipped item - if( !pItem ) - return EQUIP_ERR_OK; - - sLog.outDebug( "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount()); - - ItemPrototype const *pProto = pItem->GetProto(); - if( !pProto ) - return EQUIP_ERR_ITEM_NOT_FOUND; - - // do not allow unequipping gear except weapons, offhands, projectiles, relics in - // - combat - // - in-progress arenas - if( !pProto->CanChangeEquipStateInCombat() ) - { - if( isInCombat() ) - return EQUIP_ERR_NOT_IN_COMBAT; - - if(BattleGround* bg = GetBattleGround()) - if( bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS ) - return EQUIP_ERR_NOT_DURING_ARENA_MATCH; - } - - if(!swap && pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) - return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS; - - return EQUIP_ERR_OK; -} - -uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap, bool not_loading ) const -{ - if( !pItem ) - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; - - uint32 count = pItem->GetCount(); - - sLog.outDebug( "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount()); - ItemPrototype const *pProto = pItem->GetProto(); - if( !pProto ) - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; - - if( pItem->IsBindedNotWith(GetGUID()) ) - return EQUIP_ERR_DONT_OWN_THAT_ITEM; - - // check count of items (skip for auto move for same player from bank) - uint8 res = CanTakeMoreSimilarItems(pItem); - if(res != EQUIP_ERR_OK) - return res; - - // in specific slot - if( bag != NULL_BAG && slot != NULL_SLOT ) - { - if( pProto->InventoryType == INVTYPE_BAG ) - { - Bag *pBag = (Bag*)pItem; - if( pBag ) - { - if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) - { - if( !HasBankBagSlot( slot ) ) - return EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT; - if( uint8 cantuse = CanUseItem( pItem, not_loading ) != EQUIP_ERR_OK ) - return cantuse; - } - else - { - if( !pBag->IsEmpty() ) - return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG; - } - } - } - else - { - if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) - return EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT; - } - - res = _CanStoreItem_InSpecificSlot(bag,slot,dest,pProto,count,swap,pItem); - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - } - - // not specific slot or have spece for partly store only in specific slot - - // in specific bag - if( bag != NULL_BAG ) - { - if( pProto->InventoryType == INVTYPE_BAG ) - { - Bag *pBag = (Bag*)pItem; - if( pBag && !pBag->IsEmpty() ) - return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG; - } - - // search stack in bag for merge to - if( pProto->Stackable > 1 ) - { - if( bag == INVENTORY_SLOT_BAG_0 ) - { - res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - } - else - { - res = _CanStoreItem_InBag(bag,dest,pProto,count,true,false,pItem,NULL_BAG,slot); - if(res!=EQUIP_ERR_OK) - res = _CanStoreItem_InBag(bag,dest,pProto,count,true,true,pItem,NULL_BAG,slot); - - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - } - } - - // search free slot in bag - if( bag == INVENTORY_SLOT_BAG_0 ) - { - res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - } - else - { - res = _CanStoreItem_InBag(bag,dest,pProto,count,false,false,pItem,NULL_BAG,slot); - if(res!=EQUIP_ERR_OK) - res = _CanStoreItem_InBag(bag,dest,pProto,count,false,true,pItem,NULL_BAG,slot); - - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - } - } - - // not specific bag or have spece for partly store only in specific bag - - // search stack for merge to - if( pProto->Stackable > 1 ) - { - // in slots - res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - - // in special bags - if( pProto->BagFamily ) - { - for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - res = _CanStoreItem_InBag(i,dest,pProto,count,true,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - continue; - - if(count==0) - return EQUIP_ERR_OK; - } - } - - for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - res = _CanStoreItem_InBag(i,dest,pProto,count,true,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - continue; - - if(count==0) - return EQUIP_ERR_OK; - } - } - - // search free place in special bag - if( pProto->BagFamily ) - { - for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - res = _CanStoreItem_InBag(i,dest,pProto,count,false,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - continue; - - if(count==0) - return EQUIP_ERR_OK; - } - } - - // search free space - res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - return res; - - if(count==0) - return EQUIP_ERR_OK; - - for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - res = _CanStoreItem_InBag(i,dest,pProto,count,false,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - continue; - - if(count==0) - return EQUIP_ERR_OK; - } - return EQUIP_ERR_BANK_FULL; -} - -uint8 Player::CanUseItem( Item *pItem, bool not_loading ) const -{ - if( pItem ) - { - sLog.outDebug( "STORAGE: CanUseItem item = %u", pItem->GetEntry()); - if( !isAlive() && not_loading ) - return EQUIP_ERR_YOU_ARE_DEAD; - //if( isStunned() ) - // return EQUIP_ERR_YOU_ARE_STUNNED; - ItemPrototype const *pProto = pItem->GetProto(); - if( pProto ) - { - if( pItem->IsBindedNotWith(GetGUID()) ) - return EQUIP_ERR_DONT_OWN_THAT_ITEM; - if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 ) - return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; - if( pItem->GetSkill() != 0 ) - { - if( GetSkillValue( pItem->GetSkill() ) == 0 ) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; - } - if( pProto->RequiredSkill != 0 ) - { - if( GetSkillValue( pProto->RequiredSkill ) == 0 ) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; - else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank ) - return EQUIP_ERR_ERR_CANT_EQUIP_SKILL; - } - if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) ) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; - if( pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank ) - return EQUIP_ERR_CANT_EQUIP_REPUTATION; - if( getLevel() < pProto->RequiredLevel ) - return EQUIP_ERR_CANT_EQUIP_LEVEL_I; - return EQUIP_ERR_OK; - } - } - return EQUIP_ERR_ITEM_NOT_FOUND; -} - -bool Player::CanUseItem( ItemPrototype const *pProto ) -{ - // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player - - if( pProto ) - { - if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 ) - return false; - if( pProto->RequiredSkill != 0 ) - { - if( GetSkillValue( pProto->RequiredSkill ) == 0 ) - return false; - else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank ) - return false; - } - if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) ) - return false; - if( getLevel() < pProto->RequiredLevel ) - return false; - return true; - } - return false; -} - -uint8 Player::CanUseAmmo( uint32 item ) const -{ - sLog.outDebug( "STORAGE: CanUseAmmo item = %u", item); - if( !isAlive() ) - return EQUIP_ERR_YOU_ARE_DEAD; - //if( isStunned() ) - // return EQUIP_ERR_YOU_ARE_STUNNED; - ItemPrototype const *pProto = objmgr.GetItemPrototype( item ); - if( pProto ) - { - if( pProto->InventoryType!= INVTYPE_AMMO ) - return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE; - if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 ) - return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; - if( pProto->RequiredSkill != 0 ) - { - if( GetSkillValue( pProto->RequiredSkill ) == 0 ) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; - else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank ) - return EQUIP_ERR_ERR_CANT_EQUIP_SKILL; - } - if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) ) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; - /*if( GetReputation() < pProto->RequiredReputation ) - return EQUIP_ERR_CANT_EQUIP_REPUTATION; - */ - if( getLevel() < pProto->RequiredLevel ) - return EQUIP_ERR_CANT_EQUIP_LEVEL_I; - - // Requires No Ammo - if(GetDummyAura(46699)) - return EQUIP_ERR_BAG_FULL6; - - return EQUIP_ERR_OK; - } - return EQUIP_ERR_ITEM_NOT_FOUND; -} - -void Player::SetAmmo( uint32 item ) -{ - if(!item) - return; - - // already set - if( GetUInt32Value(PLAYER_AMMO_ID) == item ) - return; - - // check ammo - if(item) - { - uint8 msg = CanUseAmmo( item ); - if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, NULL, NULL ); - return; - } - } - - SetUInt32Value(PLAYER_AMMO_ID, item); - - _ApplyAmmoBonuses(); -} - -void Player::RemoveAmmo() -{ - SetUInt32Value(PLAYER_AMMO_ID, 0); - - m_ammoDPS = 0.0f; - - if(CanModifyStats()) - UpdateDamagePhysical(RANGED_ATTACK); -} - -// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. -Item* Player::StoreNewItem( ItemPosCountVec const& dest, uint32 item, bool update,int32 randomPropertyId ) -{ - uint32 count = 0; - for(ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr) - count += itr->count; - - Item *pItem = Item::CreateItem( item, count, this ); - if( pItem ) - { - ItemAddedQuestCheck( item, count ); - if(randomPropertyId) - pItem->SetItemRandomProperties(randomPropertyId); - pItem = StoreItem( dest, pItem, update ); - } - return pItem; -} - -Item* Player::StoreItem( ItemPosCountVec const& dest, Item* pItem, bool update ) -{ - if( !pItem ) - return NULL; - - Item* lastItem = pItem; - - for(ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ) - { - uint16 pos = itr->pos; - uint32 count = itr->count; - - ++itr; - - if(itr == dest.end()) - { - lastItem = _StoreItem(pos,pItem,count,false,update); - break; - } - - lastItem = _StoreItem(pos,pItem,count,true,update); - } - - return lastItem; -} - -// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. -Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update ) -{ - if( !pItem ) - return NULL; - - uint8 bag = pos >> 8; - uint8 slot = pos & 255; - - sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), count); - - Item *pItem2 = GetItemByPos( bag, slot ); - - if( !pItem2 ) - { - if(clone) - pItem = pItem->CloneItem(count,this); - else - pItem->SetCount(count); - - if(!pItem) - return NULL; - - if( pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || - pItem->GetProto()->Bonding == BIND_QUEST_ITEM || - pItem->GetProto()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos) ) - pItem->SetBinding( true ); - - if( bag == INVENTORY_SLOT_BAG_0 ) - { - m_items[slot] = pItem; - SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() ); - pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, GetGUID() ); - pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetGUID() ); - - pItem->SetSlot( slot ); - pItem->SetContainer( NULL ); - - if( IsInWorld() && update ) - { - pItem->AddToWorld(); - pItem->SendUpdateToPlayer( this ); - } - - pItem->SetState(ITEM_CHANGED, this); - } - else - { - Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); - if( pBag ) - { - pBag->StoreItem( slot, pItem, update ); - if( IsInWorld() && update ) - { - pItem->AddToWorld(); - pItem->SendUpdateToPlayer( this ); - } - pItem->SetState(ITEM_CHANGED, this); - pBag->SetState(ITEM_CHANGED, this); - } - } - - AddEnchantmentDurations(pItem); - AddItemDurations(pItem); - - return pItem; - } - else - { - if( pItem2->GetProto()->Bonding == BIND_WHEN_PICKED_UP || - pItem2->GetProto()->Bonding == BIND_QUEST_ITEM || - pItem2->GetProto()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos) ) - pItem2->SetBinding( true ); - - pItem2->SetCount( pItem2->GetCount() + count ); - if( IsInWorld() && update ) - pItem2->SendUpdateToPlayer( this ); - - if(!clone) - { - // delete item (it not in any slot currently) - if( IsInWorld() && update ) - { - pItem->RemoveFromWorld(); - pItem->DestroyForPlayer( this ); - } - - RemoveEnchantmentDurations(pItem); - RemoveItemDurations(pItem); - - pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor - pItem->SetState(ITEM_REMOVED, this); - } - // AddItemDurations(pItem2); - pItem2 already have duration listed for player - AddEnchantmentDurations(pItem2); - - pItem2->SetState(ITEM_CHANGED, this); - - return pItem2; - } -} - -Item* Player::EquipNewItem( uint16 pos, uint32 item, uint32 count, bool update ) -{ - Item *pItem = Item::CreateItem( item, count, this ); - if( pItem ) - { - ItemAddedQuestCheck( item, count ); - Item * retItem = EquipItem( pos, pItem, update ); - - return retItem; - } - return NULL; -} - -Item* Player::EquipItem( uint16 pos, Item *pItem, bool update ) -{ - if( pItem ) - { - AddEnchantmentDurations(pItem); - AddItemDurations(pItem); - - uint8 bag = pos >> 8; - uint8 slot = pos & 255; - - Item *pItem2 = GetItemByPos( bag, slot ); - - if( !pItem2 ) - { - VisualizeItem( slot, pItem); - - if(isAlive()) - { - ItemPrototype const *pProto = pItem->GetProto(); - - // item set bonuses applied only at equip and removed at unequip, and still active for broken items - if(pProto && pProto->ItemSet) - AddItemsSetItem(this,pItem); - - _ApplyItemMods(pItem, slot, true); - - if(pProto && isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer == 0) - { - m_weaponChangeTimer = DEFAULT_SWITCH_WEAPON; - if (getClass() == CLASS_ROGUE) - m_weaponChangeTimer = ROGUE_SWITCH_WEAPON; - } - } - - if( IsInWorld() && update ) - { - pItem->AddToWorld(); - pItem->SendUpdateToPlayer( this ); - } - - ApplyEquipCooldown(pItem); - - if( slot == EQUIPMENT_SLOT_MAINHAND ) - UpdateExpertise(BASE_ATTACK); - else if( slot == EQUIPMENT_SLOT_OFFHAND ) - UpdateExpertise(OFF_ATTACK); - } - else - { - pItem2->SetCount( pItem2->GetCount() + pItem->GetCount() ); - if( IsInWorld() && update ) - pItem2->SendUpdateToPlayer( this ); - - // delete item (it not in any slot currently) - //pItem->DeleteFromDB(); - if( IsInWorld() && update ) - { - pItem->RemoveFromWorld(); - pItem->DestroyForPlayer( this ); - } - - RemoveEnchantmentDurations(pItem); - RemoveItemDurations(pItem); - - pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor - pItem->SetState(ITEM_REMOVED, this); - pItem2->SetState(ITEM_CHANGED, this); - - ApplyEquipCooldown(pItem2); - - return pItem2; - } - } - - return pItem; -} - -void Player::QuickEquipItem( uint16 pos, Item *pItem) -{ - if( pItem ) - { - AddEnchantmentDurations(pItem); - AddItemDurations(pItem); - - uint8 slot = pos & 255; - VisualizeItem( slot, pItem); - - if( IsInWorld() ) - { - pItem->AddToWorld(); - pItem->SendUpdateToPlayer( this ); - } - } -} - -void Player::SetVisibleItemSlot(uint8 slot, Item *pItem) -{ - // PLAYER_VISIBLE_ITEM_i_CREATOR // Size: 2 - // PLAYER_VISIBLE_ITEM_i_0 // Size: 12 - // entry // Size: 1 - // inspected enchantments // Size: 6 - // ? // Size: 5 - // PLAYER_VISIBLE_ITEM_i_PROPERTIES // Size: 1 (property,suffix factor) - // PLAYER_VISIBLE_ITEM_i_PAD // Size: 1 - // // = 16 - - if(pItem) - { - SetUInt64Value(PLAYER_VISIBLE_ITEM_1_CREATOR + (slot * MAX_VISIBLE_ITEM_OFFSET), pItem->GetUInt64Value(ITEM_FIELD_CREATOR)); - - int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * MAX_VISIBLE_ITEM_OFFSET); - SetUInt32Value(VisibleBase + 0, pItem->GetEntry()); - - for(int i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i) - SetUInt32Value(VisibleBase + 1 + i, pItem->GetEnchantmentId(EnchantmentSlot(i))); - - // Use SetInt16Value to prevent set high part to FFFF for negative value - SetInt16Value( PLAYER_VISIBLE_ITEM_1_PROPERTIES + (slot * MAX_VISIBLE_ITEM_OFFSET), 0, pItem->GetItemRandomPropertyId()); - SetUInt32Value(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 1 + (slot * MAX_VISIBLE_ITEM_OFFSET), pItem->GetItemSuffixFactor()); - } - else - { - SetUInt64Value(PLAYER_VISIBLE_ITEM_1_CREATOR + (slot * MAX_VISIBLE_ITEM_OFFSET), 0); - - int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * MAX_VISIBLE_ITEM_OFFSET); - SetUInt32Value(VisibleBase + 0, 0); - - for(int i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i) - SetUInt32Value(VisibleBase + 1 + i, 0); - - SetUInt32Value(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 0 + (slot * MAX_VISIBLE_ITEM_OFFSET), 0); - SetUInt32Value(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 1 + (slot * MAX_VISIBLE_ITEM_OFFSET), 0); - } -} - -void Player::VisualizeItem( uint8 slot, Item *pItem) -{ - if(!pItem) - return; - - // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) - if( pItem->GetProto()->Bonding == BIND_WHEN_EQUIPED || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM ) - pItem->SetBinding( true ); - - sLog.outDebug( "STORAGE: EquipItem slot = %u, item = %u", slot, pItem->GetEntry()); - - m_items[slot] = pItem; - SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() ); - pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, GetGUID() ); - pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetGUID() ); - pItem->SetSlot( slot ); - pItem->SetContainer( NULL ); - - if( slot < EQUIPMENT_SLOT_END ) - SetVisibleItemSlot(slot,pItem); - - pItem->SetState(ITEM_CHANGED, this); -} - -void Player::RemoveItem( uint8 bag, uint8 slot, bool update ) -{ - // note: removeitem does not actually change the item - // it only takes the item out of storage temporarily - // note2: if removeitem is to be used for delinking - // the item must be removed from the player's updatequeue - - Item *pItem = GetItemByPos( bag, slot ); - if( pItem ) - { - sLog.outDebug( "STORAGE: RemoveItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry()); - - RemoveEnchantmentDurations(pItem); - RemoveItemDurations(pItem); - - if( bag == INVENTORY_SLOT_BAG_0 ) - { - if ( slot < INVENTORY_SLOT_BAG_END ) - { - ItemPrototype const *pProto = pItem->GetProto(); - // item set bonuses applied only at equip and removed at unequip, and still active for broken items - - if(pProto && pProto->ItemSet) - RemoveItemsSetItem(this,pProto); - - _ApplyItemMods(pItem, slot, false); - - // remove item dependent auras and casts (only weapon and armor slots) - if(slot < EQUIPMENT_SLOT_END) - RemoveItemDependentAurasAndCasts(pItem); - - // remove held enchantments - if ( slot == EQUIPMENT_SLOT_MAINHAND ) - { - if (pItem->GetItemSuffixFactor()) - { - pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_3); - pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_4); - } - else - { - pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_0); - pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_1); - } - } - } - - m_items[slot] = NULL; - SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0); - - if ( slot < EQUIPMENT_SLOT_END ) - SetVisibleItemSlot(slot,NULL); - } - else - { - Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); - if( pBag ) - pBag->RemoveItem(slot, update); - } - pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, 0 ); - // pItem->SetUInt64Value( ITEM_FIELD_OWNER, 0 ); not clear owner at remove (it will be set at store). This used in mail and auction code - pItem->SetSlot( NULL_SLOT ); - if( IsInWorld() && update ) - pItem->SendUpdateToPlayer( this ); - - if( slot == EQUIPMENT_SLOT_MAINHAND ) - UpdateExpertise(BASE_ATTACK); - else if( slot == EQUIPMENT_SLOT_OFFHAND ) - UpdateExpertise(OFF_ATTACK); - } -} - -// Common operation need to remove item from inventory without delete in trade, auction, guild bank, mail.... -void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update) -{ - if(Item* it = GetItemByPos(bag,slot)) - { - ItemRemovedQuestCheck(it->GetEntry(),it->GetCount()); - RemoveItem( bag,slot,update); - it->RemoveFromUpdateQueueOf(this); - if(it->IsInWorld()) - { - it->RemoveFromWorld(); - it->DestroyForPlayer( this ); - } - } -} - -// Common operation need to add item from inventory without delete in trade, guild bank, mail.... -void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB) -{ - // update quest counters - ItemAddedQuestCheck(pItem->GetEntry(),pItem->GetCount()); - - // store item - Item* pLastItem = StoreItem( dest, pItem, update); - - // only set if not merged to existed stack (pItem can be deleted already but we can compare pointers any way) - if(pLastItem==pItem) - { - // update owner for last item (this can be original item with wrong owner - if(pLastItem->GetOwnerGUID() != GetGUID()) - pLastItem->SetOwnerGUID(GetGUID()); - - // if this original item then it need create record in inventory - // in case trade we laready have item in other player inventory - pLastItem->SetState(in_characterInventoryDB ? ITEM_CHANGED : ITEM_NEW, this); - } -} - -void Player::DestroyItem( uint8 bag, uint8 slot, bool update ) -{ - Item *pItem = GetItemByPos( bag, slot ); - if( pItem ) - { - sLog.outDebug( "STORAGE: DestroyItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry()); - - // start from destroy contained items (only equipped bag can have its) - if (pItem->IsBag() && pItem->IsEquipped()) // this also prevent infinity loop if empty bag stored in bag==slot - { - for (int i = 0; i < MAX_BAG_SIZE; i++) - DestroyItem(slot,i,update); - } - - if(pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) - CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); - - ItemPrototype const *pProto = pItem->GetProto(); - - RemoveEnchantmentDurations(pItem); - RemoveItemDurations(pItem); - - ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount() ); - - if( bag == INVENTORY_SLOT_BAG_0 ) - { - - SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0); - - // equipment and equipped bags can have applied bonuses - if ( slot < INVENTORY_SLOT_BAG_END ) - { - ItemPrototype const *pProto = pItem->GetProto(); - - // item set bonuses applied only at equip and removed at unequip, and still active for broken items - if(pProto && pProto->ItemSet) - RemoveItemsSetItem(this,pProto); - - _ApplyItemMods(pItem, slot, false); - } - - if ( slot < EQUIPMENT_SLOT_END ) - { - // remove item dependent auras and casts (only weapon and armor slots) - RemoveItemDependentAurasAndCasts(pItem); - - // equipment visual show - SetVisibleItemSlot(slot,NULL); - } - - m_items[slot] = NULL; - } - else if(Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag )) - pBag->RemoveItem(slot, update); - - if( IsInWorld() && update ) - { - pItem->RemoveFromWorld(); - pItem->DestroyForPlayer(this); - } - - //pItem->SetOwnerGUID(0); - pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, 0 ); - pItem->SetSlot( NULL_SLOT ); - pItem->SetState(ITEM_REMOVED, this); - } -} - -void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check) -{ - sLog.outDebug( "STORAGE: DestroyItemCount item = %u, count = %u", item, count); - Item *pItem; - ItemPrototype const *pProto; - uint32 remcount = 0; - - // in inventory - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - if( pItem->GetCount() + remcount <= count ) - { - // all items in inventory can unequipped - remcount += pItem->GetCount(); - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - - if(remcount >=count) - return; - } - else - { - pProto = pItem->GetProto(); - ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); - pItem->SetCount( pItem->GetCount() - count + remcount ); - if( IsInWorld() & update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - return; - } - } - } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - if( pItem->GetCount() + remcount <= count ) - { - // all keys can be unequipped - remcount += pItem->GetCount(); - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - - if(remcount >=count) - return; - } - else - { - pProto = pItem->GetProto(); - ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); - pItem->SetCount( pItem->GetCount() - count + remcount ); - if( IsInWorld() & update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - return; - } - } - } - - // in inventory bags - Bag *pBag; - ItemPrototype const *pBagProto; - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - pItem = pBag->GetItemByPos(j); - if( pItem && pItem->GetEntry() == item ) - { - // all items in bags can be unequipped - if( pItem->GetCount() + remcount <= count ) - { - remcount += pItem->GetCount(); - DestroyItem( i, j, update ); - - if(remcount >=count) - return; - } - else - { - pProto = pItem->GetProto(); - ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); - pItem->SetCount( pItem->GetCount() - count + remcount ); - if( IsInWorld() && update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - return; - } - } - } - } - } - } - - // in equipment and bag list - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) - { - pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEntry() == item ) - { - if( pItem->GetCount() + remcount <= count ) - { - if(!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i,false) == EQUIP_ERR_OK ) - { - remcount += pItem->GetCount(); - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - - if(remcount >=count) - return; - } - } - else - { - pProto = pItem->GetProto(); - ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); - pItem->SetCount( pItem->GetCount() - count + remcount ); - if( IsInWorld() & update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - return; - } - } - } -} - -void Player::DestroyZoneLimitedItem( bool update, uint32 new_zone ) -{ - sLog.outDebug( "STORAGE: DestroyZoneLimitedItem in map %u and area %u", GetMapId(), new_zone ); - - // in inventory - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } - - // in inventory bags - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - ItemPrototype const *pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - Item* pItem = pBag->GetItemByPos(j); - if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) - DestroyItem( i, j, update); - } - } - } - } - - // in equipment and bag list - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } -} - -void Player::DestroyConjuredItems( bool update ) -{ - // used when entering arena - // distroys all conjured items - sLog.outDebug( "STORAGE: DestroyConjuredItems" ); - - // in inventory - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetProto() && - (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && - (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } - - // in inventory bags - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - ItemPrototype const *pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - Item* pItem = pBag->GetItemByPos(j); - if( pItem && pItem->GetProto() && - (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && - (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) - DestroyItem( i, j, update); - } - } - } - } - - // in equipment and bag list - for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetProto() && - (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && - (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) - DestroyItem( INVENTORY_SLOT_BAG_0, i, update); - } -} - -void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update ) -{ - if(!pItem) - return; - - sLog.outDebug( "STORAGE: DestroyItemCount item (GUID: %u, Entry: %u) count = %u", pItem->GetGUIDLow(),pItem->GetEntry(), count); - - if( pItem->GetCount() <= count ) - { - count-= pItem->GetCount(); - - DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), update); - } - else - { - ItemRemovedQuestCheck( pItem->GetEntry(), count); - pItem->SetCount( pItem->GetCount() - count ); - count = 0; - if( IsInWorld() & update ) - pItem->SendUpdateToPlayer( this ); - pItem->SetState(ITEM_CHANGED, this); - } -} - -void Player::SplitItem( uint16 src, uint16 dst, uint32 count ) -{ - uint8 srcbag = src >> 8; - uint8 srcslot = src & 255; - - uint8 dstbag = dst >> 8; - uint8 dstslot = dst & 255; - - Item *pSrcItem = GetItemByPos( srcbag, srcslot ); - if( !pSrcItem ) - { - SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL ); - return; - } - - // not let split all items (can be only at cheating) - if(pSrcItem->GetCount() == count) - { - SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL ); - return; - } - - // not let split more existed items (can be only at cheating) - if(pSrcItem->GetCount() < count) - { - SendEquipError( EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, NULL ); - return; - } - - if(pSrcItem->m_lootGenerated) // prevent split looting item (item - { - //best error message found for attempting to split while looting - SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL ); - return; - } - - sLog.outDebug( "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count); - Item *pNewItem = pSrcItem->CloneItem( count, this ); - if( !pNewItem ) - { - SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL ); - return; - } - - if( IsInventoryPos( dst ) ) - { - // change item amount before check (for unique max count check) - pSrcItem->SetCount( pSrcItem->GetCount() - count ); - - ItemPosCountVec dest; - uint8 msg = CanStoreItem( dstbag, dstslot, dest, pNewItem, false ); - if( msg != EQUIP_ERR_OK ) - { - delete pNewItem; - pSrcItem->SetCount( pSrcItem->GetCount() + count ); - SendEquipError( msg, pSrcItem, NULL ); - return; - } - - if( IsInWorld() ) - pSrcItem->SendUpdateToPlayer( this ); - pSrcItem->SetState(ITEM_CHANGED, this); - StoreItem( dest, pNewItem, true); - } - else if( IsBankPos ( dst ) ) - { - // change item amount before check (for unique max count check) - pSrcItem->SetCount( pSrcItem->GetCount() - count ); - - ItemPosCountVec dest; - uint8 msg = CanBankItem( dstbag, dstslot, dest, pNewItem, false ); - if( msg != EQUIP_ERR_OK ) - { - delete pNewItem; - pSrcItem->SetCount( pSrcItem->GetCount() + count ); - SendEquipError( msg, pSrcItem, NULL ); - return; - } - - if( IsInWorld() ) - pSrcItem->SendUpdateToPlayer( this ); - pSrcItem->SetState(ITEM_CHANGED, this); - BankItem( dest, pNewItem, true); - } - else if( IsEquipmentPos ( dst ) ) - { - // change item amount before check (for unique max count check), provide space for splitted items - pSrcItem->SetCount( pSrcItem->GetCount() - count ); - - uint16 dest; - uint8 msg = CanEquipItem( dstslot, dest, pNewItem, false ); - if( msg != EQUIP_ERR_OK ) - { - delete pNewItem; - pSrcItem->SetCount( pSrcItem->GetCount() + count ); - SendEquipError( msg, pSrcItem, NULL ); - return; - } - - if( IsInWorld() ) - pSrcItem->SendUpdateToPlayer( this ); - pSrcItem->SetState(ITEM_CHANGED, this); - EquipItem( dest, pNewItem, true); - AutoUnequipOffhandIfNeed(); - } -} - -void Player::SwapItem( uint16 src, uint16 dst ) -{ - uint8 srcbag = src >> 8; - uint8 srcslot = src & 255; - - uint8 dstbag = dst >> 8; - uint8 dstslot = dst & 255; - - Item *pSrcItem = GetItemByPos( srcbag, srcslot ); - Item *pDstItem = GetItemByPos( dstbag, dstslot ); - - if( !pSrcItem ) - return; - - sLog.outDebug( "STORAGE: SwapItem bag = %u, slot = %u, item = %u", dstbag, dstslot, pSrcItem->GetEntry()); - - if(!isAlive() ) - { - SendEquipError( EQUIP_ERR_YOU_ARE_DEAD, pSrcItem, pDstItem ); - return; - } - - if(pSrcItem->m_lootGenerated) // prevent swap looting item - { - //best error message found for attempting to swap while looting - SendEquipError( EQUIP_ERR_CANT_DO_RIGHT_NOW, pSrcItem, NULL ); - return; - } - - // check unequip potability for equipped items and bank bags - if(IsEquipmentPos ( src ) || IsBagPos ( src )) - { - // bags can be swapped with empty bag slots - uint8 msg = CanUnequipItem( src, !IsBagPos ( src ) || IsBagPos ( dst )); - if(msg != EQUIP_ERR_OK) - { - SendEquipError( msg, pSrcItem, pDstItem ); - return; - } - } - - // prevent put equipped/bank bag in self - if( IsBagPos ( src ) && srcslot == dstbag) - { - SendEquipError( EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem ); - return; - } - - if( !pDstItem ) - { - if( IsInventoryPos( dst ) ) - { - ItemPosCountVec dest; - uint8 msg = CanStoreItem( dstbag, dstslot, dest, pSrcItem, false ); - if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, pSrcItem, NULL ); - return; - } - - RemoveItem(srcbag, srcslot, true); - StoreItem( dest, pSrcItem, true); - } - else if( IsBankPos ( dst ) ) - { - ItemPosCountVec dest; - uint8 msg = CanBankItem( dstbag, dstslot, dest, pSrcItem, false); - if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, pSrcItem, NULL ); - return; - } - - RemoveItem(srcbag, srcslot, true); - BankItem( dest, pSrcItem, true); - } - else if( IsEquipmentPos ( dst ) ) - { - uint16 dest; - uint8 msg = CanEquipItem( dstslot, dest, pSrcItem, false ); - if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, pSrcItem, NULL ); - return; - } - - RemoveItem(srcbag, srcslot, true); - EquipItem( dest, pSrcItem, true); - AutoUnequipOffhandIfNeed(); - } - } - else // if (!pDstItem) - { - if(pDstItem->m_lootGenerated) // prevent swap looting item - { - //best error message found for attempting to swap while looting - SendEquipError( EQUIP_ERR_CANT_DO_RIGHT_NOW, pDstItem, NULL ); - return; - } - - // check unequip potability for equipped items and bank bags - if(IsEquipmentPos ( dst ) || IsBagPos ( dst )) - { - // bags can be swapped with empty bag slots - uint8 msg = CanUnequipItem( dst, !IsBagPos ( dst ) || IsBagPos ( src ) ); - if(msg != EQUIP_ERR_OK) - { - SendEquipError( msg, pSrcItem, pDstItem ); - return; - } - } - - // attempt merge to / fill target item - { - uint8 msg; - ItemPosCountVec sDest; - uint16 eDest; - if( IsInventoryPos( dst ) ) - msg = CanStoreItem( dstbag, dstslot, sDest, pSrcItem, false ); - else if( IsBankPos ( dst ) ) - msg = CanBankItem( dstbag, dstslot, sDest, pSrcItem, false ); - else if( IsEquipmentPos ( dst ) ) - msg = CanEquipItem( dstslot, eDest, pSrcItem, false ); - else - return; - - // can be merge/fill - if(msg == EQUIP_ERR_OK) - { - if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable ) - { - RemoveItem(srcbag, srcslot, true); - - if( IsInventoryPos( dst ) ) - StoreItem( sDest, pSrcItem, true); - else if( IsBankPos ( dst ) ) - BankItem( sDest, pSrcItem, true); - else if( IsEquipmentPos ( dst ) ) - { - EquipItem( eDest, pSrcItem, true); - AutoUnequipOffhandIfNeed(); - } - } - else - { - pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable ); - pDstItem->SetCount( pSrcItem->GetProto()->Stackable ); - pSrcItem->SetState(ITEM_CHANGED, this); - pDstItem->SetState(ITEM_CHANGED, this); - if( IsInWorld() ) - { - pSrcItem->SendUpdateToPlayer( this ); - pDstItem->SendUpdateToPlayer( this ); - } - } - return; - } - } - - // impossible merge/fill, do real swap - uint8 msg; - - // check src->dest move possibility - ItemPosCountVec sDest; - uint16 eDest; - if( IsInventoryPos( dst ) ) - msg = CanStoreItem( dstbag, dstslot, sDest, pSrcItem, true ); - else if( IsBankPos( dst ) ) - msg = CanBankItem( dstbag, dstslot, sDest, pSrcItem, true ); - else if( IsEquipmentPos( dst ) ) - { - msg = CanEquipItem( dstslot, eDest, pSrcItem, true ); - if( msg == EQUIP_ERR_OK ) - msg = CanUnequipItem( eDest, true ); - } - - if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, pSrcItem, pDstItem ); - return; - } - - // check dest->src move possibility - ItemPosCountVec sDest2; - uint16 eDest2; - if( IsInventoryPos( src ) ) - msg = CanStoreItem( srcbag, srcslot, sDest2, pDstItem, true ); - else if( IsBankPos( src ) ) - msg = CanBankItem( srcbag, srcslot, sDest2, pDstItem, true ); - else if( IsEquipmentPos( src ) ) - { - msg = CanEquipItem( srcslot, eDest2, pDstItem, true); - if( msg == EQUIP_ERR_OK ) - msg = CanUnequipItem( eDest2, true); - } - - if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, pDstItem, pSrcItem ); - return; - } - - // now do moves, remove... - RemoveItem(dstbag, dstslot, false); - RemoveItem(srcbag, srcslot, false); - - // add to dest - if( IsInventoryPos( dst ) ) - StoreItem(sDest, pSrcItem, true); - else if( IsBankPos( dst ) ) - BankItem(sDest, pSrcItem, true); - else if( IsEquipmentPos( dst ) ) - EquipItem(eDest, pSrcItem, true); - - // add to src - if( IsInventoryPos( src ) ) - StoreItem(sDest2, pDstItem, true); - else if( IsBankPos( src ) ) - BankItem(sDest2, pDstItem, true); - else if( IsEquipmentPos( src ) ) - EquipItem(eDest2, pDstItem, true); - - AutoUnequipOffhandIfNeed(); - } -} - -void Player::AddItemToBuyBackSlot( Item *pItem ) -{ - if( pItem ) - { - uint32 slot = m_currentBuybackSlot; - // if current back slot non-empty search oldest or free - if(m_items[slot]) - { - uint32 oldest_time = GetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 ); - uint32 oldest_slot = BUYBACK_SLOT_START; - - for(uint32 i = BUYBACK_SLOT_START+1; i < BUYBACK_SLOT_END; ++i ) - { - // found empty - if(!m_items[i]) - { - slot = i; - break; - } - - uint32 i_time = GetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + i - BUYBACK_SLOT_START); - - if(oldest_time > i_time) - { - oldest_time = i_time; - oldest_slot = i; - } - } - - // find oldest - slot = oldest_slot; - } - - RemoveItemFromBuyBackSlot( slot, true ); - sLog.outDebug( "STORAGE: AddItemToBuyBackSlot item = %u, slot = %u", pItem->GetEntry(), slot); - - m_items[slot] = pItem; - time_t base = time(NULL); - uint32 etime = uint32(base - m_logintime + (30 * 3600)); - uint32 eslot = slot - BUYBACK_SLOT_START; - - SetUInt64Value( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + eslot * 2, pItem->GetGUID() ); - ItemPrototype const *pProto = pItem->GetProto(); - if( pProto ) - SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, pProto->SellPrice * pItem->GetCount() ); - else - SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0 ); - SetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, (uint32)etime ); - - // move to next (for non filled list is move most optimized choice) - if(m_currentBuybackSlot < BUYBACK_SLOT_END-1) - ++m_currentBuybackSlot; - } -} - -Item* Player::GetItemFromBuyBackSlot( uint32 slot ) -{ - sLog.outDebug( "STORAGE: GetItemFromBuyBackSlot slot = %u", slot); - if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END ) - return m_items[slot]; - return NULL; -} - -void Player::RemoveItemFromBuyBackSlot( uint32 slot, bool del ) -{ - sLog.outDebug( "STORAGE: RemoveItemFromBuyBackSlot slot = %u", slot); - if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END ) - { - Item *pItem = m_items[slot]; - if( pItem ) - { - pItem->RemoveFromWorld(); - if(del) pItem->SetState(ITEM_REMOVED, this); - } - - m_items[slot] = NULL; - - uint32 eslot = slot - BUYBACK_SLOT_START; - SetUInt64Value( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + eslot * 2, 0 ); - SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0 ); - SetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0 ); - - // if current backslot is filled set to now free slot - if(m_items[m_currentBuybackSlot]) - m_currentBuybackSlot = slot; - } -} - -void Player::SendEquipError( uint8 msg, Item* pItem, Item *pItem2 ) -{ - sLog.outDebug( "WORLD: Sent SMSG_INVENTORY_CHANGE_FAILURE (%u)",msg); - WorldPacket data( SMSG_INVENTORY_CHANGE_FAILURE, (msg == EQUIP_ERR_CANT_EQUIP_LEVEL_I ? 22 : 18) ); - data << uint8(msg); - - if(msg) - { - data << uint64(pItem ? pItem->GetGUID() : 0); - data << uint64(pItem2 ? pItem2->GetGUID() : 0); - data << uint8(0); // not 0 there... - - if(msg == EQUIP_ERR_CANT_EQUIP_LEVEL_I) - { - uint32 level = 0; - - if(pItem) - if(ItemPrototype const* proto = pItem->GetProto()) - level = proto->RequiredLevel; - - data << uint32(level); // new 2.4.0 - } - } - GetSession()->SendPacket(&data); -} - -void Player::SendBuyError( uint8 msg, Creature* pCreature, uint32 item, uint32 param ) -{ - sLog.outDebug( "WORLD: Sent SMSG_BUY_FAILED" ); - WorldPacket data( SMSG_BUY_FAILED, (8+4+4+1) ); - data << uint64(pCreature ? pCreature->GetGUID() : 0); - data << uint32(item); - if( param > 0 ) - data << uint32(param); - data << uint8(msg); - GetSession()->SendPacket(&data); -} - -void Player::SendSellError( uint8 msg, Creature* pCreature, uint64 guid, uint32 param ) -{ - sLog.outDebug( "WORLD: Sent SMSG_SELL_ITEM" ); - WorldPacket data( SMSG_SELL_ITEM,(8+8+(param?4:0)+1)); // last check 2.0.10 - data << uint64(pCreature ? pCreature->GetGUID() : 0); - data << uint64(guid); - if( param > 0 ) - data << uint32(param); - data << uint8(msg); - GetSession()->SendPacket(&data); -} - -void Player::ClearTrade() -{ - tradeGold = 0; - acceptTrade = false; - for(int i = 0; i < TRADE_SLOT_COUNT; i++) - tradeItems[i] = NULL_SLOT; -} - -void Player::TradeCancel(bool sendback) -{ - if(pTrader) - { - // send yellow "Trade cancelled" message to both traders - WorldSession* ws; - ws = GetSession(); - if(sendback) - ws->SendCancelTrade(); - ws = pTrader->GetSession(); - if(!ws->PlayerLogout()) - ws->SendCancelTrade(); - - // cleanup - ClearTrade(); - pTrader->ClearTrade(); - // prevent loss of reference - pTrader->pTrader = NULL; - pTrader = NULL; - } -} - -void Player::UpdateItemDuration(uint32 time, bool realtimeonly) -{ - if(m_itemDuration.empty()) - return; - - sLog.outDebug("Player::UpdateItemDuration(%u,%u)", time,realtimeonly); - - for(ItemDurationList::iterator itr = m_itemDuration.begin();itr != m_itemDuration.end(); ) - { - Item* item = *itr; - ++itr; // current element can be erased in UpdateDuration - - if (realtimeonly && item->GetProto()->Duration < 0 || !realtimeonly) - item->UpdateDuration(this,time); - } -} - -void Player::UpdateEnchantTime(uint32 time) -{ - for(EnchantDurationList::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next) - { - assert(itr->item); - next=itr; - if(!itr->item->GetEnchantmentId(itr->slot)) - { - next = m_enchantDuration.erase(itr); - } - else if(itr->leftduration <= time) - { - ApplyEnchantment(itr->item,itr->slot,false,false); - itr->item->ClearEnchantment(itr->slot); - next = m_enchantDuration.erase(itr); - } - else if(itr->leftduration > time) - { - itr->leftduration -= time; - ++next; - } - } -} - -void Player::AddEnchantmentDurations(Item *item) -{ - for(int x=0;xGetEnchantmentId(EnchantmentSlot(x))) - continue; - - uint32 duration = item->GetEnchantmentDuration(EnchantmentSlot(x)); - if( duration > 0 ) - AddEnchantmentDuration(item,EnchantmentSlot(x),duration); - } -} - -void Player::RemoveEnchantmentDurations(Item *item) -{ - for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();) - { - if(itr->item == item) - { - // save duration in item - item->SetEnchantmentDuration(EnchantmentSlot(itr->slot),itr->leftduration); - itr = m_enchantDuration.erase(itr); - } - else - ++itr; - } -} - - -void Player::RemoveAllEnchantments(EnchantmentSlot slot) -{ - // remove enchantments from equipped items first to clean up the m_enchantDuration list - for(EnchantDurationList::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next) - { - next = itr; - if(itr->slot==slot) - { - if(itr->item && itr->item->GetEnchantmentId(slot)) - { - // remove from stats - ApplyEnchantment(itr->item,slot,false,false); - // remove visual - itr->item->ClearEnchantment(slot); - } - // remove from update list - next = m_enchantDuration.erase(itr); - } - else - ++next; - } - - // remove enchants from inventory items - // NOTE: no need to remove these from stats, since these aren't equipped - // in inventory - for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) - { - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetEnchantmentId(slot) ) - pItem->ClearEnchantment(slot); - } - - // in inventory bags - for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { - ItemPrototype const *pBagProto = pBag->GetProto(); - if( pBagProto ) - { - for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) - { - Item* pItem = pBag->GetItemByPos(j); - if( pItem && pItem->GetEnchantmentId(slot) ) - pItem->ClearEnchantment(slot); - } - } - } - } -} - -// duration == 0 will remove item enchant -void Player::AddEnchantmentDuration(Item *item,EnchantmentSlot slot,uint32 duration) -{ - if(!item) - return; - - if(slot >= MAX_ENCHANTMENT_SLOT) - return; - - for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();++itr) - { - if(itr->item == item && itr->slot == slot) - { - itr->item->SetEnchantmentDuration(itr->slot,itr->leftduration); - m_enchantDuration.erase(itr); - break; - } - } - if(item && duration > 0 ) - { - GetSession()->SendItemEnchantTimeUpdate(GetGUID(), item->GetGUID(),slot,uint32(duration/1000)); - m_enchantDuration.push_back(EnchantDuration(item,slot,duration)); - } -} - -void Player::ApplyEnchantment(Item *item,bool apply) -{ - for(uint32 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) - ApplyEnchantment(item, EnchantmentSlot(slot), apply); -} - -void Player::ApplyEnchantment(Item *item,EnchantmentSlot slot,bool apply, bool apply_dur, bool ignore_condition) -{ - if(!item) - return; - - if(!item->IsEquipped()) - return; - - if(slot >= MAX_ENCHANTMENT_SLOT) - return; - - uint32 enchant_id = item->GetEnchantmentId(slot); - if(!enchant_id) - return; - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) - return; - - if(!ignore_condition && pEnchant->EnchantmentCondition && !((Player*)this)->EnchantmentFitsRequirements(pEnchant->EnchantmentCondition, -1)) - return; - - for (int s=0; s<3; s++) - { - uint32 enchant_display_type = pEnchant->type[s]; - uint32 enchant_amount = pEnchant->amount[s]; - uint32 enchant_spell_id = pEnchant->spellid[s]; - - switch(enchant_display_type) - { - case ITEM_ENCHANTMENT_TYPE_NONE: - break; - case ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL: - // processed in Player::CastItemCombatSpell - break; - case ITEM_ENCHANTMENT_TYPE_DAMAGE: - if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) - HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(enchant_amount), apply); - else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND) - HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(enchant_amount), apply); - else if (item->GetSlot() == EQUIPMENT_SLOT_RANGED) - HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(enchant_amount), apply); - break; - case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL: - if(enchant_spell_id) - { - if(apply) - { - int32 basepoints = int32(enchant_amount); - // Random Property Exist - try found basepoints for spell (basepoints depencs from item suffix factor) - if (item->GetItemRandomPropertyId() !=0 && !enchant_amount) - { - ItemRandomSuffixEntry const *item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); - if (item_rand) - { - // Search enchant_amount - for (int k=0; k<3; k++) - { - if(item_rand->enchant_id[k] == enchant_id) - { - basepoints = int32((item_rand->prefix[k]*item->GetItemSuffixFactor()) / 10000 ); - break; - } - } - } - } - // Cast custom spell vs all equal basepoints getted from enchant_amount - if (basepoints) - CastCustomSpell(this,enchant_spell_id,&basepoints,&basepoints,&basepoints,true,item); - else - CastSpell(this,enchant_spell_id,true,item); - } - else - RemoveAurasDueToItemSpell(item,enchant_spell_id); - } - break; - case ITEM_ENCHANTMENT_TYPE_RESISTANCE: - if (!enchant_amount) - { - ItemRandomSuffixEntry const *item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); - if(item_rand) - { - for (int k=0; k<3; k++) - { - if(item_rand->enchant_id[k] == enchant_id) - { - enchant_amount = uint32((item_rand->prefix[k]*item->GetItemSuffixFactor()) / 10000 ); - break; - } - } - } - } - - HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply); - break; - case ITEM_ENCHANTMENT_TYPE_STAT: - { - if (!enchant_amount) - { - ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); - if(item_rand_suffix) - { - for (int k=0; k<3; k++) - { - if(item_rand_suffix->enchant_id[k] == enchant_id) - { - enchant_amount = uint32((item_rand_suffix->prefix[k]*item->GetItemSuffixFactor()) / 10000 ); - break; - } - } - } - } - - sLog.outDebug("Adding %u to stat nb %u",enchant_amount,enchant_spell_id); - switch (enchant_spell_id) - { - case ITEM_MOD_AGILITY: - sLog.outDebug("+ %u AGILITY",enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_AGILITY, enchant_amount, apply); - break; - case ITEM_MOD_STRENGTH: - sLog.outDebug("+ %u STRENGTH",enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_STRENGTH, enchant_amount, apply); - break; - case ITEM_MOD_INTELLECT: - sLog.outDebug("+ %u INTELLECT",enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_INTELLECT, enchant_amount, apply); - break; - case ITEM_MOD_SPIRIT: - sLog.outDebug("+ %u SPIRIT",enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_SPIRIT, enchant_amount, apply); - break; - case ITEM_MOD_STAMINA: - sLog.outDebug("+ %u STAMINA",enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_STAMINA, enchant_amount, apply); - break; - case ITEM_MOD_DEFENSE_SKILL_RATING: - ((Player*)this)->ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply); - sLog.outDebug("+ %u DEFENCE", enchant_amount); - break; - case ITEM_MOD_DODGE_RATING: - ((Player*)this)->ApplyRatingMod(CR_DODGE, enchant_amount, apply); - sLog.outDebug("+ %u DODGE", enchant_amount); - break; - case ITEM_MOD_PARRY_RATING: - ((Player*)this)->ApplyRatingMod(CR_PARRY, enchant_amount, apply); - sLog.outDebug("+ %u PARRY", enchant_amount); - break; - case ITEM_MOD_BLOCK_RATING: - ((Player*)this)->ApplyRatingMod(CR_BLOCK, enchant_amount, apply); - sLog.outDebug("+ %u SHIELD_BLOCK", enchant_amount); - break; - case ITEM_MOD_HIT_MELEE_RATING: - ((Player*)this)->ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply); - sLog.outDebug("+ %u MELEE_HIT", enchant_amount); - break; - case ITEM_MOD_HIT_RANGED_RATING: - ((Player*)this)->ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply); - sLog.outDebug("+ %u RANGED_HIT", enchant_amount); - break; - case ITEM_MOD_HIT_SPELL_RATING: - ((Player*)this)->ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply); - sLog.outDebug("+ %u SPELL_HIT", enchant_amount); - break; - case ITEM_MOD_CRIT_MELEE_RATING: - ((Player*)this)->ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply); - sLog.outDebug("+ %u MELEE_CRIT", enchant_amount); - break; - case ITEM_MOD_CRIT_RANGED_RATING: - ((Player*)this)->ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply); - sLog.outDebug("+ %u RANGED_CRIT", enchant_amount); - break; - case ITEM_MOD_CRIT_SPELL_RATING: - ((Player*)this)->ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply); - sLog.outDebug("+ %u SPELL_CRIT", enchant_amount); - break; -// Values from ITEM_STAT_MELEE_HA_RATING to ITEM_MOD_HASTE_RANGED_RATING are never used -// in Enchantments -// case ITEM_MOD_HIT_TAKEN_MELEE_RATING: -// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply); -// break; -// case ITEM_MOD_HIT_TAKEN_RANGED_RATING: -// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply); -// break; -// case ITEM_MOD_HIT_TAKEN_SPELL_RATING: -// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply); -// break; -// case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: -// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); -// break; -// case ITEM_MOD_CRIT_TAKEN_RANGED_RATING: -// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); -// break; -// case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: -// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); -// break; -// case ITEM_MOD_HASTE_MELEE_RATING: -// ((Player*)this)->ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply); -// break; -// case ITEM_MOD_HASTE_RANGED_RATING: -// ((Player*)this)->ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply); -// break; - case ITEM_MOD_HASTE_SPELL_RATING: - ((Player*)this)->ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply); - break; - case ITEM_MOD_HIT_RATING: - ((Player*)this)->ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply); - ((Player*)this)->ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply); - ((Player*)this)->ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply); - sLog.outDebug("+ %u HIT", enchant_amount); - break; - case ITEM_MOD_CRIT_RATING: - ((Player*)this)->ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply); - ((Player*)this)->ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply); - ((Player*)this)->ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply); - sLog.outDebug("+ %u CRITICAL", enchant_amount); - break; -// Values ITEM_MOD_HIT_TAKEN_RATING and ITEM_MOD_CRIT_TAKEN_RATING are never used in Enchantment -// case ITEM_MOD_HIT_TAKEN_RATING: -// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply); -// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply); -// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply); -// break; -// case ITEM_MOD_CRIT_TAKEN_RATING: -// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); -// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); -// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); -// break; - case ITEM_MOD_RESILIENCE_RATING: - ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); - ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); - ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); - sLog.outDebug("+ %u RESILIENCE", enchant_amount); - break; - case ITEM_MOD_HASTE_RATING: - ((Player*)this)->ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply); - ((Player*)this)->ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply); - ((Player*)this)->ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply); - sLog.outDebug("+ %u HASTE", enchant_amount); - break; - case ITEM_MOD_EXPERTISE_RATING: - ((Player*)this)->ApplyRatingMod(CR_EXPERTISE, enchant_amount, apply); - sLog.outDebug("+ %u EXPERTISE", enchant_amount); - break; - default: - break; - } - break; - } - case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon - { - if(getClass() == CLASS_SHAMAN) - { - float addValue = 0.0f; - if(item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) - { - addValue = float(enchant_amount * item->GetProto()->Delay/1000.0f); - HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply); - } - else if(item->GetSlot() == EQUIPMENT_SLOT_OFFHAND ) - { - addValue = float(enchant_amount * item->GetProto()->Delay/1000.0f); - HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, addValue, apply); - } - } - break; - } - default: - sLog.outError("Unknown item enchantment display type: %d",enchant_display_type); - break; - } /*switch(enchant_display_type)*/ - } /*for*/ - - // visualize enchantment at player and equipped items - if(slot < MAX_INSPECTED_ENCHANTMENT_SLOT) - { - int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (item->GetSlot() * MAX_VISIBLE_ITEM_OFFSET); - SetUInt32Value(VisibleBase + 1 + slot, apply? item->GetEnchantmentId(slot) : 0); - } - - if(apply_dur) - { - if(apply) - { - // set duration - uint32 duration = item->GetEnchantmentDuration(slot); - if(duration > 0) - AddEnchantmentDuration(item,slot,duration); - } - else - { - // duration == 0 will remove EnchantDuration - AddEnchantmentDuration(item,slot,0); - } - } -} - -void Player::SendEnchantmentDurations() -{ - for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();++itr) - { - GetSession()->SendItemEnchantTimeUpdate(GetGUID(), itr->item->GetGUID(),itr->slot,uint32(itr->leftduration)/1000); - } -} - -void Player::SendItemDurations() -{ - for(ItemDurationList::iterator itr = m_itemDuration.begin();itr != m_itemDuration.end();++itr) - { - (*itr)->SendTimeUpdate(this); - } -} - -void Player::SendNewItem(Item *item, uint32 count, bool received, bool created, bool broadcast) -{ - if(!item) // prevent crash - return; - - // last check 2.0.10 - WorldPacket data( SMSG_ITEM_PUSH_RESULT, (8+4+4+4+1+4+4+4+4+4) ); - data << GetGUID(); // player GUID - data << uint32(received); // 0=looted, 1=from npc - data << uint32(created); // 0=received, 1=created - data << uint32(1); // always 0x01 (probably meant to be count of listed items) - data << (uint8)item->GetBagSlot(); // bagslot - // item slot, but when added to stack: 0xFFFFFFFF - data << (uint32) ((item->GetCount()==count) ? item->GetSlot() : -1); - data << uint32(item->GetEntry()); // item id - data << uint32(item->GetItemSuffixFactor()); // SuffixFactor - data << uint32(item->GetItemRandomPropertyId()); // random item property id - data << uint32(count); // count of items - data << GetItemCount(item->GetEntry()); // count of items in inventory - - if (broadcast && GetGroup()) - GetGroup()->BroadcastPacket(&data); - else - GetSession()->SendPacket(&data); -} - -/*********************************************************/ -/*** QUEST SYSTEM ***/ -/*********************************************************/ - -void Player::PrepareQuestMenu( uint64 guid ) -{ - Object *pObject; - QuestRelations* pObjectQR; - QuestRelations* pObjectQIR; - Creature *pCreature = ObjectAccessor::GetCreature(*this, guid); - if( pCreature ) - { - pObject = (Object*)pCreature; - pObjectQR = &objmgr.mCreatureQuestRelations; - pObjectQIR = &objmgr.mCreatureQuestInvolvedRelations; - } - else - { - GameObject *pGameObject = ObjectAccessor::GetGameObject(*this, guid); - if( pGameObject ) - { - pObject = (Object*)pGameObject; - pObjectQR = &objmgr.mGOQuestRelations; - pObjectQIR = &objmgr.mGOQuestInvolvedRelations; - } - else - return; - } - - QuestMenu *qm = PlayerTalkClass->GetQuestMenu(); - qm->ClearMenu(); - - for(QuestRelations::const_iterator i = pObjectQIR->lower_bound(pObject->GetEntry()); i != pObjectQIR->upper_bound(pObject->GetEntry()); ++i) - { - uint32 quest_id = i->second; - QuestStatus status = GetQuestStatus( quest_id ); - if ( status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus( quest_id ) ) - qm->AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP); - else if ( status == QUEST_STATUS_INCOMPLETE ) - qm->AddMenuItem(quest_id, DIALOG_STATUS_INCOMPLETE); - else if (status == QUEST_STATUS_AVAILABLE ) - qm->AddMenuItem(quest_id, DIALOG_STATUS_CHAT); - } - - for(QuestRelations::const_iterator i = pObjectQR->lower_bound(pObject->GetEntry()); i != pObjectQR->upper_bound(pObject->GetEntry()); ++i) - { - uint32 quest_id = i->second; - Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); - if(!pQuest) continue; - - QuestStatus status = GetQuestStatus( quest_id ); - - if (pQuest->IsAutoComplete() && CanTakeQuest(pQuest, false)) - qm->AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP); - else if ( status == QUEST_STATUS_NONE && CanTakeQuest( pQuest, false ) ) - qm->AddMenuItem(quest_id, DIALOG_STATUS_AVAILABLE); - } -} - -void Player::SendPreparedQuest( uint64 guid ) -{ - QuestMenu* pQuestMenu = PlayerTalkClass->GetQuestMenu(); - if( !pQuestMenu || pQuestMenu->MenuItemCount() < 1 ) - return; - - uint32 status = pQuestMenu->GetItem(0).m_qIcon; - if ( pQuestMenu->MenuItemCount() == 1 ) - { - // Auto open -- maybe also should verify there is no greeting - uint32 quest_id = pQuestMenu->GetItem(0).m_qId; - Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); - if ( pQuest ) - { - if( status == DIALOG_STATUS_REWARD_REP && !GetQuestRewardStatus( quest_id ) ) - PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanRewardQuest(pQuest,false), true ); - else if( status == DIALOG_STATUS_INCOMPLETE ) - PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, false, true ); - // Send completable on repeatable quest if player don't have quest - else if( pQuest->IsRepeatable() ) - PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanCompleteRepeatableQuest(pQuest), true ); - else - PlayerTalkClass->SendQuestGiverQuestDetails( pQuest, guid, true ); - } - } - else - { - QEmote qe; - qe._Delay = 0; - qe._Emote = 0; - std::string title = ""; - Creature *pCreature = ObjectAccessor::GetCreature(*this, guid); - if( pCreature ) - { - uint32 textid = pCreature->GetNpcTextId(); - GossipText * gossiptext = objmgr.GetGossipText(textid); - if( !gossiptext ) - { - qe._Delay = 0; //TEXTEMOTE_MESSAGE; //zyg: player emote - qe._Emote = 0; //TEXTEMOTE_HELLO; //zyg: NPC emote - title = ""; - } - else - { - qe = gossiptext->Options[0].Emotes[0]; - - if(!gossiptext->Options[0].Text_0.empty()) - { - title = gossiptext->Options[0].Text_0; - - int loc_idx = GetSession()->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textid); - if (nl) - { - if (nl->Text_0[0].size() > loc_idx && !nl->Text_0[0][loc_idx].empty()) - title = nl->Text_0[0][loc_idx]; - } - } - } - else - { - title = gossiptext->Options[0].Text_1; - - int loc_idx = GetSession()->GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textid); - if (nl) - { - if (nl->Text_1[0].size() > loc_idx && !nl->Text_1[0][loc_idx].empty()) - title = nl->Text_1[0][loc_idx]; - } - } - } - } - } - PlayerTalkClass->SendQuestGiverQuestList( qe, title, guid ); - } -} - -bool Player::IsActiveQuest( uint32 quest_id ) const -{ - QuestStatusMap::const_iterator itr = mQuestStatus.find(quest_id); - - return itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE; -} - -Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest ) -{ - Object *pObject; - QuestRelations* pObjectQR; - QuestRelations* pObjectQIR; - - Creature *pCreature = ObjectAccessor::GetCreature(*this, guid); - if( pCreature ) - { - pObject = (Object*)pCreature; - pObjectQR = &objmgr.mCreatureQuestRelations; - pObjectQIR = &objmgr.mCreatureQuestInvolvedRelations; - } - else - { - GameObject *pGameObject = ObjectAccessor::GetGameObject(*this, guid); - if( pGameObject ) - { - pObject = (Object*)pGameObject; - pObjectQR = &objmgr.mGOQuestRelations; - pObjectQIR = &objmgr.mGOQuestInvolvedRelations; - } - else - return NULL; - } - - uint32 nextQuestID = pQuest->GetNextQuestInChain(); - for(QuestRelations::const_iterator itr = pObjectQR->lower_bound(pObject->GetEntry()); itr != pObjectQR->upper_bound(pObject->GetEntry()); ++itr) - { - if (itr->second == nextQuestID) - return objmgr.GetQuestTemplate(nextQuestID); - } - - return NULL; -} - -bool Player::CanSeeStartQuest( Quest const *pQuest ) -{ - if( SatisfyQuestRace( pQuest, false ) && SatisfyQuestSkillOrClass( pQuest, false ) && - SatisfyQuestExclusiveGroup( pQuest, false ) && SatisfyQuestReputation( pQuest, false ) && - SatisfyQuestPreviousQuest( pQuest, false ) && SatisfyQuestNextChain( pQuest, false ) && - SatisfyQuestPrevChain( pQuest, false ) && SatisfyQuestDay( pQuest, false ) ) - { - return getLevel() + sWorld.getConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF) >= pQuest->GetMinLevel(); - } - - return false; -} - -bool Player::CanTakeQuest( Quest const *pQuest, bool msg ) -{ - return SatisfyQuestStatus( pQuest, msg ) && SatisfyQuestExclusiveGroup( pQuest, msg ) - && SatisfyQuestRace( pQuest, msg ) && SatisfyQuestLevel( pQuest, msg ) - && SatisfyQuestSkillOrClass( pQuest, msg ) && SatisfyQuestReputation( pQuest, msg ) - && SatisfyQuestPreviousQuest( pQuest, msg ) && SatisfyQuestTimed( pQuest, msg ) - && SatisfyQuestNextChain( pQuest, msg ) && SatisfyQuestPrevChain( pQuest, msg ) - && SatisfyQuestDay( pQuest, msg ); -} - -bool Player::CanAddQuest( Quest const *pQuest, bool msg ) -{ - if( !SatisfyQuestLog( msg ) ) - return false; - - uint32 srcitem = pQuest->GetSrcItemId(); - if( srcitem > 0 ) - { - uint32 count = pQuest->GetSrcItemCount(); - ItemPosCountVec dest; - uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count ); - - // player already have max number (in most case 1) source item, no additional item needed and quest can be added. - if( msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS ) - return true; - else if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, NULL, NULL ); - return false; - } - } - return true; -} - -bool Player::CanCompleteQuest( uint32 quest_id ) -{ - if( quest_id ) - { - QuestStatusData& q_status = mQuestStatus[quest_id]; - if( q_status.m_status == QUEST_STATUS_COMPLETE ) - return false; // not allow re-complete quest - - Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); - - if(!qInfo) - return false; - - // auto complete quest - if (qInfo->IsAutoComplete() && CanTakeQuest(qInfo, false)) - return true; - - if ( q_status.m_status == QUEST_STATUS_INCOMPLETE ) - { - - if ( qInfo->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) - { - for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - { - if( qInfo->ReqItemCount[i]!= 0 && q_status.m_itemcount[i] < qInfo->ReqItemCount[i] ) - return false; - } - } - - if ( qInfo->HasFlag(QUEST_MANGOS_FLAGS_KILL_OR_CAST | QUEST_MANGOS_FLAGS_SPEAKTO) ) - { - for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - { - if( qInfo->ReqCreatureOrGOId[i] == 0 ) - continue; - - if( qInfo->ReqCreatureOrGOCount[i] != 0 && q_status.m_creatureOrGOcount[i] < qInfo->ReqCreatureOrGOCount[i] ) - return false; - } - } - - if ( qInfo->HasFlag( QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT ) && !q_status.m_explored ) - return false; - - if ( qInfo->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) && q_status.m_timer == 0 ) - return false; - - if ( qInfo->GetRewOrReqMoney() < 0 ) - { - if ( GetMoney() < uint32(-qInfo->GetRewOrReqMoney()) ) - return false; - } - - uint32 repFacId = qInfo->GetRepObjectiveFaction(); - if ( repFacId && GetReputation(repFacId) < qInfo->GetRepObjectiveValue() ) - return false; - - return true; - } - } - return false; -} - -bool Player::CanCompleteRepeatableQuest( Quest const *pQuest ) -{ - // Solve problem that player don't have the quest and try complete it. - // if repeatable she must be able to complete event if player don't have it. - // Seem that all repeatable quest are DELIVER Flag so, no need to add more. - if( !CanTakeQuest(pQuest, false) ) - return false; - - if (pQuest->HasFlag( QUEST_MANGOS_FLAGS_DELIVER) ) - for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - if( pQuest->ReqItemId[i] && pQuest->ReqItemCount[i] && !HasItemCount(pQuest->ReqItemId[i],pQuest->ReqItemCount[i]) ) - return false; - - if( !CanRewardQuest(pQuest, false) ) - return false; - - return true; -} - -bool Player::CanRewardQuest( Quest const *pQuest, bool msg ) -{ - // not auto complete quest and not completed quest (only cheating case, then ignore without message) - if(!pQuest->IsAutoComplete() && GetQuestStatus(pQuest->GetQuestId()) != QUEST_STATUS_COMPLETE) - return false; - - // daily quest can't be rewarded (10 daily quest already completed) - if(!SatisfyQuestDay(pQuest,true)) - return false; - - // rewarded and not repeatable quest (only cheating case, then ignore without message) - if(GetQuestRewardStatus(pQuest->GetQuestId())) - return false; - - // prevent receive reward with quest items in bank - if ( pQuest->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) - { - for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - { - if( pQuest->ReqItemCount[i]!= 0 && - GetItemCount(pQuest->ReqItemId[i]) < pQuest->ReqItemCount[i] ) - { - if(msg) - SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); - return false; - } - } - } - - // prevent receive reward with low money and GetRewOrReqMoney() < 0 - if(pQuest->GetRewOrReqMoney() < 0 && GetMoney() < uint32(-pQuest->GetRewOrReqMoney()) ) - return false; - - return true; -} - -bool Player::CanRewardQuest( Quest const *pQuest, uint32 reward, bool msg ) -{ - // prevent receive reward with quest items in bank or for not completed quest - if(!CanRewardQuest(pQuest,msg)) - return false; - - if ( pQuest->GetRewChoiceItemsCount() > 0 ) - { - if( pQuest->RewChoiceItemId[reward] ) - { - ItemPosCountVec dest; - uint8 res = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ); - if( res != EQUIP_ERR_OK ) - { - SendEquipError( res, NULL, NULL ); - return false; - } - } - } - - if ( pQuest->GetRewItemsCount() > 0 ) - { - for (uint32 i = 0; i < pQuest->GetRewItemsCount(); ++i) - { - if( pQuest->RewItemId[i] ) - { - ItemPosCountVec dest; - uint8 res = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ); - if( res != EQUIP_ERR_OK ) - { - SendEquipError( res, NULL, NULL ); - return false; - } - } - } - } - - return true; -} - -void Player::AddQuest( Quest const *pQuest, Object *questGiver ) -{ - uint16 log_slot = FindQuestSlot( 0 ); - assert(log_slot < MAX_QUEST_LOG_SIZE); - - uint32 quest_id = pQuest->GetQuestId(); - - // if not exist then created with set uState==NEW and rewarded=false - QuestStatusData& questStatusData = mQuestStatus[quest_id]; - if (questStatusData.uState != QUEST_NEW) - questStatusData.uState = QUEST_CHANGED; - - // check for repeatable quests status reset - questStatusData.m_status = QUEST_STATUS_INCOMPLETE; - questStatusData.m_explored = false; - - if ( pQuest->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) - { - for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - questStatusData.m_itemcount[i] = 0; - } - - if ( pQuest->HasFlag(QUEST_MANGOS_FLAGS_KILL_OR_CAST | QUEST_MANGOS_FLAGS_SPEAKTO) ) - { - for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - questStatusData.m_creatureOrGOcount[i] = 0; - } - - GiveQuestSourceItem( pQuest ); - AdjustQuestReqItemCount( pQuest ); - - if( pQuest->GetRepObjectiveFaction() ) - SetFactionVisibleForFactionId(pQuest->GetRepObjectiveFaction()); - - uint32 qtime = 0; - if( pQuest->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) ) - { - uint32 limittime = pQuest->GetLimitTime(); - - // shared timed quest - if(questGiver && questGiver->GetTypeId()==TYPEID_PLAYER) - limittime = ((Player*)questGiver)->getQuestStatusMap()[quest_id].m_timer / 1000; - - AddTimedQuest( quest_id ); - questStatusData.m_timer = limittime * 1000; - qtime = static_cast(time(NULL)) + limittime; - } - else - questStatusData.m_timer = 0; - - SetQuestSlot(log_slot, quest_id, qtime); - - //starting initial quest script - if(questGiver && pQuest->GetQuestStartScript()!=0) - sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this); - - UpdateForQuestsGO(); -} - -void Player::CompleteQuest( uint32 quest_id ) -{ - if( quest_id ) - { - SetQuestStatus( quest_id, QUEST_STATUS_COMPLETE ); - - uint16 log_slot = FindQuestSlot( quest_id ); - if( log_slot < MAX_QUEST_LOG_SIZE) - SetQuestSlotState(log_slot,QUEST_STATE_COMPLETE); - - if(Quest const* qInfo = objmgr.GetQuestTemplate(quest_id)) - { - if( qInfo->HasFlag(QUEST_FLAGS_AUTO_REWARDED) ) - RewardQuest(qInfo,0,this,false); - else - SendQuestComplete( quest_id ); - } - } -} - -void Player::IncompleteQuest( uint32 quest_id ) -{ - if( quest_id ) - { - SetQuestStatus( quest_id, QUEST_STATUS_INCOMPLETE ); - - uint16 log_slot = FindQuestSlot( quest_id ); - if( log_slot < MAX_QUEST_LOG_SIZE) - RemoveQuestSlotState(log_slot,QUEST_STATE_COMPLETE); - } -} - -void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce ) -{ - uint32 quest_id = pQuest->GetQuestId(); - - for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++ ) - { - if ( pQuest->ReqItemId[i] ) - DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true); - } - - //if( qInfo->HasSpecialFlag( QUEST_FLAGS_TIMED ) ) - // SetTimedQuest( 0 ); - m_timedquests.erase(pQuest->GetQuestId()); - - if ( pQuest->GetRewChoiceItemsCount() > 0 ) - { - if( pQuest->RewChoiceItemId[reward] ) - { - ItemPosCountVec dest; - if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK ) - { - Item* item = StoreNewItem( dest, pQuest->RewChoiceItemId[reward], true); - SendNewItem(item, pQuest->RewChoiceItemCount[reward], true, false); - } - } - } - - if ( pQuest->GetRewItemsCount() > 0 ) - { - for (uint32 i=0; i < pQuest->GetRewItemsCount(); ++i) - { - if( pQuest->RewItemId[i] ) - { - ItemPosCountVec dest; - if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ) == EQUIP_ERR_OK ) - { - Item* item = StoreNewItem( dest, pQuest->RewItemId[i], true); - SendNewItem(item, pQuest->RewItemCount[i], true, false); - } - } - } - } - - RewardReputation( pQuest ); - - if( pQuest->GetRewSpellCast() > 0 ) - CastSpell( this, pQuest->GetRewSpellCast(), true); - else if( pQuest->GetRewSpell() > 0) - CastSpell( this, pQuest->GetRewSpell(), true); - - uint16 log_slot = FindQuestSlot( quest_id ); - if( log_slot < MAX_QUEST_LOG_SIZE) - SetQuestSlot(log_slot,0); - - QuestStatusData& q_status = mQuestStatus[quest_id]; - - // Not give XP in case already completed once repeatable quest - uint32 XP = q_status.m_rewarded ? 0 : uint32(pQuest->XPValue( this )*sWorld.getRate(RATE_XP_QUEST)); - - if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) - GiveXP( XP , NULL ); - else - ModifyMoney( int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)) ); - - // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative - ModifyMoney( pQuest->GetRewOrReqMoney() ); - - // title reward - if(pQuest->GetCharTitleId()) - { - if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId())) - SetFlag64(PLAYER__FIELD_KNOWN_TITLES, (uint64(1) << titleEntry->bit_index)); - } - - // Send reward mail - if(pQuest->GetRewMailTemplateId()) - { - MailMessageType mailType; - uint32 senderGuidOrEntry; - switch(questGiver->GetTypeId()) - { - case TYPEID_UNIT: - mailType = MAIL_CREATURE; - senderGuidOrEntry = questGiver->GetEntry(); - break; - case TYPEID_GAMEOBJECT: - mailType = MAIL_GAMEOBJECT; - senderGuidOrEntry = questGiver->GetEntry(); - break; - case TYPEID_ITEM: - mailType = MAIL_ITEM; - senderGuidOrEntry = questGiver->GetEntry(); - break; - case TYPEID_PLAYER: - mailType = MAIL_NORMAL; - senderGuidOrEntry = questGiver->GetGUIDLow(); - break; - default: - mailType = MAIL_NORMAL; - senderGuidOrEntry = GetGUIDLow(); - break; - } - - Loot questMailLoot; - - questMailLoot.FillLoot(pQuest->GetQuestId(), LootTemplates_QuestMail, this); - - // fill mail - MailItemsInfo mi; // item list preparing - - for(size_t i = 0; mi.size() < MAX_MAIL_ITEMS && i < questMailLoot.items.size(); ++i) - { - if(LootItem* lootitem = questMailLoot.LootItemInSlot(i,this)) - { - if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this)) - { - item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted - mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); - } - } - } - - for(size_t i = 0; mi.size() < MAX_MAIL_ITEMS && i < questMailLoot.quest_items.size(); ++i) - { - if(LootItem* lootitem = questMailLoot.LootItemInSlot(i+questMailLoot.items.size(),this)) - { - if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this)) - { - item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted - mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); - } - } - } - - WorldSession::SendMailTo(this, mailType, MAIL_STATIONERY_NORMAL, senderGuidOrEntry, GetGUIDLow(), "", 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE,pQuest->GetRewMailDelaySecs(),pQuest->GetRewMailTemplateId()); - } - - if(pQuest->IsDaily()) - SetDailyQuestStatus(quest_id); - - if ( !pQuest->IsRepeatable() ) - SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE); - else - SetQuestStatus(quest_id, QUEST_STATUS_NONE); - - q_status.m_rewarded = true; - - if(announce) - SendQuestReward( pQuest, XP, questGiver ); - - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; -} - -void Player::FailQuest( uint32 quest_id ) -{ - if( quest_id ) - { - IncompleteQuest( quest_id ); - - uint16 log_slot = FindQuestSlot( quest_id ); - if( log_slot < MAX_QUEST_LOG_SIZE) - { - SetQuestSlotTimer(log_slot, 1 ); - SetQuestSlotState(log_slot,QUEST_STATE_FAIL); - } - SendQuestFailed( quest_id ); - } -} - -void Player::FailTimedQuest( uint32 quest_id ) -{ - if( quest_id ) - { - QuestStatusData& q_status = mQuestStatus[quest_id]; - - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - q_status.m_timer = 0; - - IncompleteQuest( quest_id ); - - uint16 log_slot = FindQuestSlot( quest_id ); - if( log_slot < MAX_QUEST_LOG_SIZE) - { - SetQuestSlotTimer(log_slot, 1 ); - SetQuestSlotState(log_slot,QUEST_STATE_FAIL); - } - SendQuestTimerFailed( quest_id ); - } -} - -bool Player::SatisfyQuestSkillOrClass( Quest const* qInfo, bool msg ) -{ - int32 zoneOrSort = qInfo->GetZoneOrSort(); - int32 skillOrClass = qInfo->GetSkillOrClass(); - - // skip zone zoneOrSort and 0 case skillOrClass - if( zoneOrSort >= 0 && skillOrClass == 0 ) - return true; - - int32 questSort = -zoneOrSort; - uint8 reqSortClass = ClassByQuestSort(questSort); - - // check class sort cases in zoneOrSort - if( reqSortClass != 0 && getClass() != reqSortClass) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - - // check class - if( skillOrClass < 0 ) - { - uint8 reqClass = -int32(skillOrClass); - if(getClass() != reqClass) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - } - // check skill - else if( skillOrClass > 0 ) - { - uint32 reqSkill = skillOrClass; - if( GetSkillValue( reqSkill ) < qInfo->GetRequiredSkillValue() ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - } - - return true; -} - -bool Player::SatisfyQuestLevel( Quest const* qInfo, bool msg ) -{ - if( getLevel() < qInfo->GetMinLevel() ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - return true; -} - -bool Player::SatisfyQuestLog( bool msg ) -{ - // exist free slot - if( FindQuestSlot(0) < MAX_QUEST_LOG_SIZE ) - return true; - - if( msg ) - { - WorldPacket data( SMSG_QUESTLOG_FULL, 0 ); - GetSession()->SendPacket( &data ); - sLog.outDebug( "WORLD: Sent QUEST_LOG_FULL_MESSAGE" ); - } - return false; -} - -bool Player::SatisfyQuestPreviousQuest( Quest const* qInfo, bool msg ) -{ - // No previous quest (might be first quest in a series) - if( qInfo->prevQuests.empty()) - return true; - - for(Quest::PrevQuests::const_iterator iter = qInfo->prevQuests.begin(); iter != qInfo->prevQuests.end(); ++iter ) - { - uint32 prevId = abs(*iter); - - QuestStatusMap::iterator i_prevstatus = mQuestStatus.find( prevId ); - Quest const* qPrevInfo = objmgr.GetQuestTemplate(prevId); - - if( qPrevInfo && i_prevstatus != mQuestStatus.end() ) - { - // If any of the positive previous quests completed, return true - if( *iter > 0 && i_prevstatus->second.m_rewarded ) - { - // skip one-from-all exclusive group - if(qPrevInfo->GetExclusiveGroup() >= 0) - return true; - - // each-from-all exclusive group ( < 0) - // can be start if only all quests in prev quest exclusive group complited and rewarded - ObjectMgr::ExclusiveQuestGroups::iterator iter = objmgr.mExclusiveQuestGroups.lower_bound(qPrevInfo->GetExclusiveGroup()); - ObjectMgr::ExclusiveQuestGroups::iterator end = objmgr.mExclusiveQuestGroups.upper_bound(qPrevInfo->GetExclusiveGroup()); - - assert(iter!=end); // always must be found if qPrevInfo->ExclusiveGroup != 0 - - for(; iter != end; ++iter) - { - uint32 exclude_Id = iter->second; - - // skip checked quest id, only state of other quests in group is interesting - if(exclude_Id == prevId) - continue; - - QuestStatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id ); - - // alternative quest from group also must be completed and rewarded(reported) - if( i_exstatus == mQuestStatus.end() || !i_exstatus->second.m_rewarded ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - } - return true; - } - // If any of the negative previous quests active, return true - if( *iter < 0 && (i_prevstatus->second.m_status == QUEST_STATUS_INCOMPLETE - || (i_prevstatus->second.m_status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(prevId)))) - { - // skip one-from-all exclusive group - if(qPrevInfo->GetExclusiveGroup() >= 0) - return true; - - // each-from-all exclusive group ( < 0) - // can be start if only all quests in prev quest exclusive group active - ObjectMgr::ExclusiveQuestGroups::iterator iter = objmgr.mExclusiveQuestGroups.lower_bound(qPrevInfo->GetExclusiveGroup()); - ObjectMgr::ExclusiveQuestGroups::iterator end = objmgr.mExclusiveQuestGroups.upper_bound(qPrevInfo->GetExclusiveGroup()); - - assert(iter!=end); // always must be found if qPrevInfo->ExclusiveGroup != 0 - - for(; iter != end; ++iter) - { - uint32 exclude_Id = iter->second; - - // skip checked quest id, only state of other quests in group is interesting - if(exclude_Id == prevId) - continue; - - QuestStatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id ); - - // alternative quest from group also must be active - if( i_exstatus == mQuestStatus.end() || - i_exstatus->second.m_status != QUEST_STATUS_INCOMPLETE && - (i_prevstatus->second.m_status != QUEST_STATUS_COMPLETE || GetQuestRewardStatus(prevId)) ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - } - return true; - } - } - } - - // Has only positive prev. quests in non-rewarded state - // and negative prev. quests in non-active state - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - - return false; -} - -bool Player::SatisfyQuestRace( Quest const* qInfo, bool msg ) -{ - uint32 reqraces = qInfo->GetRequiredRaces(); - if ( reqraces == 0 ) - return true; - if( (reqraces & getRaceMask()) == 0 ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_QUEST_FAILED_WRONG_RACE ); - return false; - } - return true; -} - -bool Player::SatisfyQuestReputation( Quest const* qInfo, bool msg ) -{ - uint32 fIdMin = qInfo->GetRequiredMinRepFaction(); //Min required rep - if(fIdMin && GetReputation(fIdMin) < qInfo->GetRequiredMinRepValue()) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - - uint32 fIdMax = qInfo->GetRequiredMaxRepFaction(); //Max required rep - if(fIdMax && GetReputation(fIdMax) >= qInfo->GetRequiredMaxRepValue()) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - - return true; -} - -bool Player::SatisfyQuestStatus( Quest const* qInfo, bool msg ) -{ - QuestStatusMap::iterator itr = mQuestStatus.find( qInfo->GetQuestId() ); - if ( itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_QUEST_ALREADY_ON ); - return false; - } - return true; -} - -bool Player::SatisfyQuestTimed( Quest const* qInfo, bool msg ) -{ - if ( (find(m_timedquests.begin(), m_timedquests.end(), qInfo->GetQuestId()) != m_timedquests.end()) && qInfo->HasFlag(QUEST_MANGOS_FLAGS_TIMED) ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_QUEST_ONLY_ONE_TIMED ); - return false; - } - return true; -} - -bool Player::SatisfyQuestExclusiveGroup( Quest const* qInfo, bool msg ) -{ - // non positive exclusive group, if > 0 then can be start if any other quest in exclusive group already started/completed - if(qInfo->GetExclusiveGroup() <= 0) - return true; - - ObjectMgr::ExclusiveQuestGroups::iterator iter = objmgr.mExclusiveQuestGroups.lower_bound(qInfo->GetExclusiveGroup()); - ObjectMgr::ExclusiveQuestGroups::iterator end = objmgr.mExclusiveQuestGroups.upper_bound(qInfo->GetExclusiveGroup()); - - assert(iter!=end); // always must be found if qInfo->ExclusiveGroup != 0 - - for(; iter != end; ++iter) - { - uint32 exclude_Id = iter->second; - - // skip checked quest id, only state of other quests in group is interesting - if(exclude_Id == qInfo->GetQuestId()) - continue; - - QuestStatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id ); - - // alternative quest already started or completed - if( i_exstatus != mQuestStatus.end() - && (i_exstatus->second.m_status == QUEST_STATUS_COMPLETE || i_exstatus->second.m_status == QUEST_STATUS_INCOMPLETE) ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - } - return true; -} - -bool Player::SatisfyQuestNextChain( Quest const* qInfo, bool msg ) -{ - if(!qInfo->GetNextQuestInChain()) - return true; - - // next quest in chain already started or completed - QuestStatusMap::iterator itr = mQuestStatus.find( qInfo->GetNextQuestInChain() ); - if( itr != mQuestStatus.end() - && (itr->second.m_status == QUEST_STATUS_COMPLETE || itr->second.m_status == QUEST_STATUS_INCOMPLETE) ) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - - // check for all quests further up the chain - // only necessary if there are quest chains with more than one quest that can be skipped - //return SatisfyQuestNextChain( qInfo->GetNextQuestInChain(), msg ); - return true; -} - -bool Player::SatisfyQuestPrevChain( Quest const* qInfo, bool msg ) -{ - // No previous quest in chain - if( qInfo->prevChainQuests.empty()) - return true; - - for(Quest::PrevChainQuests::const_iterator iter = qInfo->prevChainQuests.begin(); iter != qInfo->prevChainQuests.end(); ++iter ) - { - uint32 prevId = *iter; - - QuestStatusMap::iterator i_prevstatus = mQuestStatus.find( prevId ); - - if( i_prevstatus != mQuestStatus.end() ) - { - // If any of the previous quests in chain active, return false - if( i_prevstatus->second.m_status == QUEST_STATUS_INCOMPLETE - || (i_prevstatus->second.m_status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(prevId))) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); - return false; - } - } - - // check for all quests further down the chain - // only necessary if there are quest chains with more than one quest that can be skipped - //if( !SatisfyQuestPrevChain( prevId, msg ) ) - // return false; - } - - // No previous quest in chain active - return true; -} - -bool Player::SatisfyQuestDay( Quest const* qInfo, bool msg ) -{ - if(!qInfo->IsDaily()) - return true; - - bool have_slot = false; - for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) - { - uint32 id = GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx); - if(qInfo->GetQuestId()==id) - return false; - - if(!id) - have_slot = true; - } - - if(!have_slot) - { - if( msg ) - SendCanTakeQuestResponse( INVALIDREASON_DAILY_QUESTS_REMAINING ); - return false; - } - - return true; -} - -bool Player::GiveQuestSourceItem( Quest const *pQuest ) -{ - uint32 srcitem = pQuest->GetSrcItemId(); - if( srcitem > 0 ) - { - uint32 count = pQuest->GetSrcItemCount(); - if( count <= 0 ) - count = 1; - - ItemPosCountVec dest; - uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count ); - if( msg == EQUIP_ERR_OK ) - { - Item * item = StoreNewItem(dest, srcitem, true); - SendNewItem(item, count, true, false); - return true; - } - // player already have max amount required item, just report success - else if( msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS ) - return true; - else - SendEquipError( msg, NULL, NULL ); - return false; - } - - return true; -} - -bool Player::TakeQuestSourceItem( uint32 quest_id, bool msg ) -{ - Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); - if( qInfo ) - { - uint32 srcitem = qInfo->GetSrcItemId(); - if( srcitem > 0 ) - { - uint32 count = qInfo->GetSrcItemCount(); - if( count <= 0 ) - count = 1; - - // exist one case when destroy source quest item not possible: - // non un-equippable item (equipped non-empty bag, for example) - uint8 res = CanUnequipItems(srcitem,count); - if(res != EQUIP_ERR_OK) - { - if(msg) - SendEquipError( res, NULL, NULL ); - return false; - } - - DestroyItemCount(srcitem, count, true, true); - } - } - return true; -} - -bool Player::GetQuestRewardStatus( uint32 quest_id ) const -{ - Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); - if( qInfo ) - { - // for repeatable quests: rewarded field is set after first reward only to prevent getting XP more than once - QuestStatusMap::const_iterator itr = mQuestStatus.find( quest_id ); - if( itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE - && !qInfo->IsRepeatable() ) - return itr->second.m_rewarded; - - return false; - } - return false; -} - -QuestStatus Player::GetQuestStatus( uint32 quest_id ) const -{ - if( quest_id ) - { - QuestStatusMap::const_iterator itr = mQuestStatus.find( quest_id ); - if( itr != mQuestStatus.end() ) - return itr->second.m_status; - } - return QUEST_STATUS_NONE; -} - -bool Player::CanShareQuest(uint32 quest_id) const -{ - Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); - if( qInfo && qInfo->HasFlag(QUEST_FLAGS_SHARABLE) ) - { - QuestStatusMap::const_iterator itr = mQuestStatus.find( quest_id ); - if( itr != mQuestStatus.end() ) - return itr->second.m_status == QUEST_STATUS_NONE || itr->second.m_status == QUEST_STATUS_INCOMPLETE; - } - return false; -} - -void Player::SetQuestStatus( uint32 quest_id, QuestStatus status ) -{ - Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); - if( qInfo ) - { - if( status == QUEST_STATUS_NONE || status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE ) - { - if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) ) - m_timedquests.erase(qInfo->GetQuestId()); - } - - QuestStatusData& q_status = mQuestStatus[quest_id]; - - q_status.m_status = status; - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - } - - UpdateForQuestsGO(); -} - -// not used in MaNGOS, but used in scripting code -uint32 Player::GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry) -{ - Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); - if( !qInfo ) - return 0; - - for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) - if ( qInfo->ReqCreatureOrGOId[j] == entry ) - return mQuestStatus[quest_id].m_creatureOrGOcount[j]; - - return 0; -} - -void Player::AdjustQuestReqItemCount( Quest const* pQuest ) -{ - if ( pQuest->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) - { - for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) - { - uint32 reqitemcount = pQuest->ReqItemCount[i]; - if( reqitemcount != 0 ) - { - uint32 quest_id = pQuest->GetQuestId(); - uint32 curitemcount = GetItemCount(pQuest->ReqItemId[i],true); - - QuestStatusData& q_status = mQuestStatus[quest_id]; - q_status.m_itemcount[i] = std::min(curitemcount, reqitemcount); - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - } - } - } -} - -uint16 Player::FindQuestSlot( uint32 quest_id ) const -{ - for ( uint16 i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) - if ( GetQuestSlotQuestId(i) == quest_id ) - return i; - - return MAX_QUEST_LOG_SIZE; -} - -void Player::AreaExploredOrEventHappens( uint32 questId ) -{ - if( questId ) - { - uint16 log_slot = FindQuestSlot( questId ); - if( log_slot < MAX_QUEST_LOG_SIZE) - { - QuestStatusData& q_status = mQuestStatus[questId]; - - if(!q_status.m_explored) - { - q_status.m_explored = true; - if (q_status.uState != QUEST_NEW) - q_status.uState = QUEST_CHANGED; - } - } - if( CanCompleteQuest( questId ) ) - CompleteQuest( questId ); - } -} - -//not used in mangosd, function for external script library -void Player::GroupEventHappens( uint32 questId, WorldObject const* pEventObject ) -{ - if( Group *pGroup = GetGroup() ) - { - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *pGroupGuy = itr->getSource(); - - // for any leave or dead (with not released body) group member at appropriate distance - if( pGroupGuy && pGroupGuy->IsAtGroupRewardDistance(pEventObject) && !pGroupGuy->GetCorpse() ) - pGroupGuy->AreaExploredOrEventHappens(questId); - } - } - else - AreaExploredOrEventHappens(questId); -} - -void Player::ItemAddedQuestCheck( uint32 entry, uint32 count ) -{ - for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) - { - uint32 questid = GetQuestSlotQuestId(i); - if ( questid == 0 ) - continue; - - QuestStatusData& q_status = mQuestStatus[questid]; - - if ( q_status.m_status != QUEST_STATUS_INCOMPLETE ) - continue; - - Quest const* qInfo = objmgr.GetQuestTemplate(questid); - if( !qInfo || !qInfo->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) - continue; - - for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) - { - uint32 reqitem = qInfo->ReqItemId[j]; - if ( reqitem == entry ) - { - uint32 reqitemcount = qInfo->ReqItemCount[j]; - uint32 curitemcount = q_status.m_itemcount[j]; - if ( curitemcount < reqitemcount ) - { - uint32 additemcount = ( curitemcount + count <= reqitemcount ? count : reqitemcount - curitemcount); - q_status.m_itemcount[j] += additemcount; - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - - SendQuestUpdateAddItem( qInfo, j, additemcount ); - } - if ( CanCompleteQuest( questid ) ) - CompleteQuest( questid ); - return; - } - } - } - UpdateForQuestsGO(); -} - -void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count ) -{ - for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) - { - uint32 questid = GetQuestSlotQuestId(i); - if(!questid) - continue; - Quest const* qInfo = objmgr.GetQuestTemplate(questid); - if ( !qInfo ) - continue; - if( !qInfo->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) - continue; - - for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) - { - uint32 reqitem = qInfo->ReqItemId[j]; - if ( reqitem == entry ) - { - QuestStatusData& q_status = mQuestStatus[questid]; - - uint32 reqitemcount = qInfo->ReqItemCount[j]; - uint32 curitemcount; - if( q_status.m_status != QUEST_STATUS_COMPLETE ) - curitemcount = q_status.m_itemcount[j]; - else - curitemcount = GetItemCount(entry,true); - if ( curitemcount < reqitemcount + count ) - { - uint32 remitemcount = ( curitemcount <= reqitemcount ? count : count + reqitemcount - curitemcount); - q_status.m_itemcount[j] = curitemcount - remitemcount; - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - - IncompleteQuest( questid ); - } - return; - } - } - } - UpdateForQuestsGO(); -} - -void Player::KilledMonster( uint32 entry, uint64 guid ) -{ - uint32 addkillcount = 1; - for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) - { - uint32 questid = GetQuestSlotQuestId(i); - if(!questid) - continue; - - Quest const* qInfo = objmgr.GetQuestTemplate(questid); - if( !qInfo ) - continue; - // just if !ingroup || !noraidgroup || raidgroup - QuestStatusData& q_status = mQuestStatus[questid]; - if( q_status.m_status == QUEST_STATUS_INCOMPLETE && (!GetGroup() || !GetGroup()->isRaidGroup() || qInfo->GetType() == QUEST_TYPE_RAID)) - { - if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_KILL_OR_CAST) ) - { - for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) - { - // skip GO activate objective or none - if(qInfo->ReqCreatureOrGOId[j] <=0) - continue; - - // skip Cast at creature objective - if(qInfo->ReqSpell[j] !=0 ) - continue; - - uint32 reqkill = qInfo->ReqCreatureOrGOId[j]; - - if ( reqkill == entry ) - { - uint32 reqkillcount = qInfo->ReqCreatureOrGOCount[j]; - uint32 curkillcount = q_status.m_creatureOrGOcount[j]; - if ( curkillcount < reqkillcount ) - { - q_status.m_creatureOrGOcount[j] = curkillcount + addkillcount; - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - - SendQuestUpdateAddCreatureOrGo( qInfo, guid, j, curkillcount, addkillcount); - } - if ( CanCompleteQuest( questid ) ) - CompleteQuest( questid ); - - // same objective target can be in many active quests, but not in 2 objectives for single quest (code optimization). - continue; - } - } - } - } - } -} - -void Player::CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id ) -{ - bool isCreature = IS_CREATURE_GUID(guid); - - uint32 addCastCount = 1; - for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) - { - uint32 questid = GetQuestSlotQuestId(i); - if(!questid) - continue; - - Quest const* qInfo = objmgr.GetQuestTemplate(questid); - if ( !qInfo ) - continue; - - QuestStatusData& q_status = mQuestStatus[questid]; - - if ( q_status.m_status == QUEST_STATUS_INCOMPLETE ) - { - if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_KILL_OR_CAST ) ) - { - for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) - { - // skip kill creature objective (0) or wrong spell casts - if(qInfo->ReqSpell[j] != spell_id ) - continue; - - uint32 reqTarget = 0; - - if(isCreature) - { - // creature activate objectives - if(qInfo->ReqCreatureOrGOId[j] > 0) - // checked at quest_template loading - reqTarget = qInfo->ReqCreatureOrGOId[j]; - } - else - { - // GO activate objective - if(qInfo->ReqCreatureOrGOId[j] < 0) - // checked at quest_template loading - reqTarget = - qInfo->ReqCreatureOrGOId[j]; - } - - // other not this creature/GO related objectives - if( reqTarget != entry ) - continue; - - uint32 reqCastCount = qInfo->ReqCreatureOrGOCount[j]; - uint32 curCastCount = q_status.m_creatureOrGOcount[j]; - if ( curCastCount < reqCastCount ) - { - q_status.m_creatureOrGOcount[j] = curCastCount + addCastCount; - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - - SendQuestUpdateAddCreatureOrGo( qInfo, guid, j, curCastCount, addCastCount); - } - - if ( CanCompleteQuest( questid ) ) - CompleteQuest( questid ); - - // same objective target can be in many active quests, but not in 2 objectives for single quest (code optimization). - break; - } - } - } - } -} - -void Player::TalkedToCreature( uint32 entry, uint64 guid ) -{ - uint32 addTalkCount = 1; - for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) - { - uint32 questid = GetQuestSlotQuestId(i); - if(!questid) - continue; - - Quest const* qInfo = objmgr.GetQuestTemplate(questid); - if ( !qInfo ) - continue; - - QuestStatusData& q_status = mQuestStatus[questid]; - - if ( q_status.m_status == QUEST_STATUS_INCOMPLETE ) - { - if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_KILL_OR_CAST | QUEST_MANGOS_FLAGS_SPEAKTO ) ) - { - for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) - { - // skip spell casts and Gameobject objectives - if(qInfo->ReqSpell[j] > 0 || qInfo->ReqCreatureOrGOId[j] < 0) - continue; - - uint32 reqTarget = 0; - - if(qInfo->ReqCreatureOrGOId[j] > 0) // creature activate objectives - // checked at quest_template loading - reqTarget = qInfo->ReqCreatureOrGOId[j]; - else - continue; - - if ( reqTarget == entry ) - { - uint32 reqTalkCount = qInfo->ReqCreatureOrGOCount[j]; - uint32 curTalkCount = q_status.m_creatureOrGOcount[j]; - if ( curTalkCount < reqTalkCount ) - { - q_status.m_creatureOrGOcount[j] = curTalkCount + addTalkCount; - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; - - SendQuestUpdateAddCreatureOrGo( qInfo, guid, j, curTalkCount, addTalkCount); - } - if ( CanCompleteQuest( questid ) ) - CompleteQuest( questid ); - - // same objective target can be in many active quests, but not in 2 objectives for single quest (code optimization). - continue; - } - } - } - } - } -} - -void Player::MoneyChanged( uint32 count ) -{ - for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) - { - uint32 questid = GetQuestSlotQuestId(i); - if (!questid) - continue; - - Quest const* qInfo = objmgr.GetQuestTemplate(questid); - if( qInfo && qInfo->GetRewOrReqMoney() < 0 ) - { - QuestStatusData& q_status = mQuestStatus[questid]; - - if( q_status.m_status == QUEST_STATUS_INCOMPLETE ) - { - if(int32(count) >= -qInfo->GetRewOrReqMoney()) - { - if ( CanCompleteQuest( questid ) ) - CompleteQuest( questid ); - } - } - else if( q_status.m_status == QUEST_STATUS_COMPLETE ) - { - if(int32(count) < -qInfo->GetRewOrReqMoney()) - IncompleteQuest( questid ); - } - } - } -} - -bool Player::HasQuestForItem( uint32 itemid ) const -{ - for( QuestStatusMap::const_iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i ) - { - QuestStatusData const& q_status = i->second; - - if (q_status.m_status == QUEST_STATUS_INCOMPLETE) - { - Quest const* qinfo = objmgr.GetQuestTemplate(i->first); - if(!qinfo) - continue; - - // hide quest if player is in raid-group and quest is no raid quest - if(GetGroup() && GetGroup()->isRaidGroup() && qinfo->GetType() != QUEST_TYPE_RAID) - continue; - - // There should be no mixed ReqItem/ReqSource drop - // This part for ReqItem drop - for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) - { - if(itemid == qinfo->ReqItemId[j] && q_status.m_itemcount[j] < qinfo->ReqItemCount[j] ) - return true; - } - // This part - for ReqSource - for (int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; j++) - { - // examined item is a source item - if (qinfo->ReqSourceId[j] == itemid && qinfo->ReqSourceRef[j] > 0 && qinfo->ReqSourceRef[j] <= QUEST_OBJECTIVES_COUNT) - { - uint32 idx = qinfo->ReqSourceRef[j]-1; - - // total count of created ReqItems and SourceItems is less than ReqItemCount - if(qinfo->ReqItemId[idx] != 0 && - q_status.m_itemcount[idx] * qinfo->ReqSourceCount[j] + GetItemCount(itemid,true) < qinfo->ReqItemCount[idx] * qinfo->ReqSourceCount[j]) - return true; - - // total count of casted ReqCreatureOrGOs and SourceItems is less than ReqCreatureOrGOCount - if (qinfo->ReqCreatureOrGOId[idx] != 0) - { - if(q_status.m_creatureOrGOcount[idx] * qinfo->ReqSourceCount[j] + GetItemCount(itemid,true) < qinfo->ReqCreatureOrGOCount[idx] * qinfo->ReqSourceCount[j]) - return true; - } - // spell with SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT (with script) case - else if(qinfo->ReqSpell[idx] != 0) - { - // not casted and need more reagents/item for use. - if(!q_status.m_explored && GetItemCount(itemid,true) < qinfo->ReqSourceCount[j]) - return true; - } - } - } - } - } - return false; -} - -void Player::SendQuestComplete( uint32 quest_id ) -{ - if( quest_id ) - { - WorldPacket data( SMSG_QUESTUPDATE_COMPLETE, 4 ); - data << quest_id; - GetSession()->SendPacket( &data ); - sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_COMPLETE quest = %u", quest_id ); - } -} - -void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGiver ) -{ - uint32 questid = pQuest->GetQuestId(); - sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid ); - WorldPacket data( SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4+4+pQuest->GetRewItemsCount()*8) ); - data << questid; - data << uint32(0x03); - - if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) - { - data << XP; - data << uint32(pQuest->GetRewOrReqMoney()); - } - else - { - data << uint32(0); - data << uint32(pQuest->GetRewOrReqMoney() + int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY))); - } - data << uint32(0); // new 2.3.0, HonorPoints? - data << uint32( pQuest->GetRewItemsCount() ); // max is 5 - - for (uint32 i = 0; i < pQuest->GetRewItemsCount(); ++i) - { - if ( pQuest->RewItemId[i] > 0 ) - data << pQuest->RewItemId[i] << pQuest->RewItemCount[i]; - else - data << uint32(0) << uint32(0); - } - GetSession()->SendPacket( &data ); - - if (pQuest->GetQuestCompleteScript() != 0) - sWorld.ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this); -} - -void Player::SendQuestFailed( uint32 quest_id ) -{ - if( quest_id ) - { - WorldPacket data( SMSG_QUESTGIVER_QUEST_FAILED, 4 ); - data << quest_id; - GetSession()->SendPacket( &data ); - sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED"); - } -} - -void Player::SendQuestTimerFailed( uint32 quest_id ) -{ - if( quest_id ) - { - WorldPacket data( SMSG_QUESTUPDATE_FAILEDTIMER, 4 ); - data << quest_id; - GetSession()->SendPacket( &data ); - sLog.outDebug("WORLD: Sent SMSG_QUESTUPDATE_FAILEDTIMER"); - } -} - -void Player::SendCanTakeQuestResponse( uint32 msg ) -{ - WorldPacket data( SMSG_QUESTGIVER_QUEST_INVALID, 4 ); - data << uint32(msg); - GetSession()->SendPacket( &data ); - sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_INVALID"); -} - -void Player::SendPushToPartyResponse( Player *pPlayer, uint32 msg ) -{ - if( pPlayer ) - { - WorldPacket data( MSG_QUEST_PUSH_RESULT, (8+1) ); - data << uint64(pPlayer->GetGUID()); - data << uint8(msg); // valid values: 0-8 - GetSession()->SendPacket( &data ); - sLog.outDebug("WORLD: Sent MSG_QUEST_PUSH_RESULT"); - } -} - -void Player::SendQuestUpdateAddItem( Quest const* pQuest, uint32 item_idx, uint32 count ) -{ - WorldPacket data( SMSG_QUESTUPDATE_ADD_ITEM, (4+4) ); - sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_ITEM" ); - data << pQuest->ReqItemId[item_idx]; - data << count; - GetSession()->SendPacket( &data ); -} - -void Player::SendQuestUpdateAddCreatureOrGo( Quest const* pQuest, uint64 guid, uint32 creatureOrGO_idx, uint32 old_count, uint32 add_count ) -{ - assert(old_count + add_count < 256 && "mob/GO count store in 8 bits 2^8 = 256 (0..256)"); - - int32 entry = pQuest->ReqCreatureOrGOId[ creatureOrGO_idx ]; - if (entry < 0) - // client expected gameobject template id in form (id|0x80000000) - entry = (-entry) | 0x80000000; - - WorldPacket data( SMSG_QUESTUPDATE_ADD_KILL, (4*4+8) ); - sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_KILL" ); - data << uint32(pQuest->GetQuestId()); - data << uint32(entry); - data << uint32(old_count + add_count); - data << uint32(pQuest->ReqCreatureOrGOCount[ creatureOrGO_idx ]); - data << uint64(guid); - GetSession()->SendPacket(&data); - - uint16 log_slot = FindQuestSlot( pQuest->GetQuestId() ); - if( log_slot < MAX_QUEST_LOG_SIZE) - SetQuestSlotCounter(log_slot,creatureOrGO_idx,GetQuestSlotCounter(log_slot,creatureOrGO_idx)+add_count); -} - -/*********************************************************/ -/*** LOAD SYSTEM ***/ -/*********************************************************/ - -bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid ) -{ - bool delete_result = true; - if(!result) - { - // 0 1 2 3 4 5 6 7 8 - result = CharacterDatabase.PQuery("SELECT data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login FROM characters WHERE guid = '%u'",guid); - if(!result) return false; - } - else delete_result = false; - - Field *fields = result->Fetch(); - - if(!LoadValues( fields[0].GetString())) - { - sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid)); - if(delete_result) delete result; - return false; - } - - // overwrite possible wrong/corrupted guid - SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); - - m_name = fields[1].GetCppString(); - - Relocate(fields[2].GetFloat(),fields[3].GetFloat(),fields[4].GetFloat()); - SetMapId(fields[5].GetUInt32()); - // the instance id is not needed at character enum - - m_Played_time[0] = fields[6].GetUInt32(); - m_Played_time[1] = fields[7].GetUInt32(); - - m_atLoginFlags = fields[8].GetUInt32(); - - // I don't see these used anywhere .. - /*_LoadGroup(); - - _LoadBoundInstances();*/ - - if (delete_result) delete result; - - for (int i = 0; i < PLAYER_SLOTS_COUNT; i++) - m_items[i] = NULL; - - if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST) ) - m_deathState = DEAD; - - return true; -} - -void Player::_LoadDeclinedNames(QueryResult* result) -{ - if(!result) - return; - - if(m_declinedname) - delete m_declinedname; - - m_declinedname = new DeclinedName; - Field *fields = result->Fetch(); - for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - m_declinedname->name[i] = fields[i].GetCppString(); - - delete result; -} - -bool Player::LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid) -{ - QueryResult *result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,taxi_path FROM characters WHERE guid = '%u'",GUID_LOPART(guid)); - if(!result) - return false; - - Field *fields = result->Fetch(); - - x = fields[0].GetFloat(); - y = fields[1].GetFloat(); - z = fields[2].GetFloat(); - o = fields[3].GetFloat(); - mapid = fields[4].GetUInt32(); - in_flight = !fields[5].GetCppString().empty(); - - delete result; - return true; -} - -bool Player::LoadValuesArrayFromDB(Tokens& data, uint64 guid) -{ - QueryResult *result = CharacterDatabase.PQuery("SELECT data FROM characters WHERE guid='%u'",GUID_LOPART(guid)); - if( !result ) - return false; - - Field *fields = result->Fetch(); - - data = StrSplit(fields[0].GetCppString(), " "); - - delete result; - - return true; -} - -uint32 Player::GetUInt32ValueFromArray(Tokens const& data, uint16 index) -{ - if(index >= data.size()) - return 0; - - return (uint32)atoi(data[index].c_str()); -} - -float Player::GetFloatValueFromArray(Tokens const& data, uint16 index) -{ - float result; - uint32 temp = Player::GetUInt32ValueFromArray(data,index); - memcpy(&result, &temp, sizeof(result)); - - return result; -} - -uint32 Player::GetUInt32ValueFromDB(uint16 index, uint64 guid) -{ - Tokens data; - if(!LoadValuesArrayFromDB(data,guid)) - return 0; - - return GetUInt32ValueFromArray(data,index); -} - -float Player::GetFloatValueFromDB(uint16 index, uint64 guid) -{ - float result; - uint32 temp = Player::GetUInt32ValueFromDB(index, guid); - memcpy(&result, &temp, sizeof(result)); - - return result; -} - -bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) -{ - //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [28] [29] 30 31 32 - //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, gmstate, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty FROM characters WHERE guid = '%u'", guid); - QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM); - - if(!result) - { - sLog.outError("ERROR: Player (GUID: %u) not found in table `characters`, can't load. ",guid); - return false; - } - - Field *fields = result->Fetch(); - - uint32 dbAccountId = fields[1].GetUInt32(); - - // check if the character's account in the db and the logged in account match. - // player should be able to load/delete character only with correct account! - if( dbAccountId != GetSession()->GetAccountId() ) - { - sLog.outError("ERROR: Player (GUID: %u) loading from wrong account (is: %u, should be: %u)",guid,GetSession()->GetAccountId(),dbAccountId); - delete result; - return false; - } - - Object::_Create( guid, 0, HIGHGUID_PLAYER ); - - m_name = fields[3].GetCppString(); - - // check name limitations - if(!ObjectMgr::IsValidName(m_name) || GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name)) - { - delete result; - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid); - return false; - } - - if(!LoadValues( fields[2].GetString())) - { - sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid)); - delete result; - return false; - } - - // overwrite possible wrong/corrupted guid - SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); - - // cleanup inventory related item value fields (its will be filled correctly in _LoadInventory) - for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) - { - SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), 0 ); - SetVisibleItemSlot(slot,NULL); - - if (m_items[slot]) - { - delete m_items[slot]; - m_items[slot] = NULL; - } - } - - // update money limits - if(GetMoney() > MAX_MONEY_AMOUNT) - SetMoney(MAX_MONEY_AMOUNT); - - sLog.outDebug("Load Basic value of player %s is: ", m_name.c_str()); - outDebugValues(); - - m_race = fields[4].GetUInt8(); - //Need to call it to initialize m_team (m_team can be calculated from m_race) - //Other way is to saves m_team into characters table. - setFactionForRace(m_race); - SetCharm(0); - - m_class = fields[5].GetUInt8(); - - PlayerInfo const *info = objmgr.GetPlayerInfo(m_race, m_class); - if(!info) - { - sLog.outError("Player have incorrect race/class pair. Can't be loaded."); - delete result; - return false; - } - - InitPrimaryProffesions(); // to max set before any spell loaded - - uint32 transGUID = fields[24].GetUInt32(); - Relocate(fields[6].GetFloat(),fields[7].GetFloat(),fields[8].GetFloat(),fields[10].GetFloat()); - SetMapId(fields[9].GetUInt32()); - SetDifficulty(fields[32].GetUInt32()); // may be changed in _LoadGroup - - _LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP)); - - // check arena teams integrity - for(uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) - { - uint32 arena_team_id = GetArenaTeamId(arena_slot); - if(!arena_team_id) - continue; - - if(ArenaTeam * at = objmgr.GetArenaTeamById(arena_team_id)) - if(at->HaveMember(GetGUID())) - continue; - - // arena team not exist or not member, cleanup fields - for(int j =0; j < 6; ++j) - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arena_slot * 6 + j, 0); - } - - _LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES)); - - if(!IsPositionValid()) - { - sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); - - SetMapId(info->mapId); - Relocate(info->positionX,info->positionY,info->positionZ,0.0f); - - transGUID = 0; - - m_movementInfo.t_x = 0.0f; - m_movementInfo.t_y = 0.0f; - m_movementInfo.t_z = 0.0f; - m_movementInfo.t_o = 0.0f; - } - - // load the player's map here if it's not already loaded - Map *map = GetMap(); - // since the player may not be bound to the map yet, make sure subsequent - // getmap calls won't create new maps - SetInstanceId(map->GetInstanceId()); - - SaveRecallPosition(); - - if (transGUID != 0) - { - m_movementInfo.t_x = fields[20].GetFloat(); - m_movementInfo.t_y = fields[21].GetFloat(); - m_movementInfo.t_z = fields[22].GetFloat(); - m_movementInfo.t_o = fields[23].GetFloat(); - - if( !MaNGOS::IsValidMapCoord( - GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y, - GetPositionZ()+m_movementInfo.t_z,GetOrientation()+m_movementInfo.t_o) || - // transport size limited - m_movementInfo.t_x > 50 || m_movementInfo.t_y > 50 || m_movementInfo.t_z > 50 ) - { - sLog.outError("ERROR: Player (guidlow %d) have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.", - guid,GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y, - GetPositionZ()+m_movementInfo.t_z,GetOrientation()+m_movementInfo.t_o); - - SetMapId(info->mapId); - Relocate(info->positionX,info->positionY,info->positionZ,0.0f); - - m_movementInfo.t_x = 0.0f; - m_movementInfo.t_y = 0.0f; - m_movementInfo.t_z = 0.0f; - m_movementInfo.t_o = 0.0f; - - transGUID = 0; - } - } - - if (transGUID != 0) - { - for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) - { - if( (*iter)->GetGUIDLow() == transGUID) - { - m_transport = *iter; - m_transport->AddPassenger(this); - SetMapId(m_transport->GetMapId()); - break; - } - } - - if(!m_transport) - { - sLog.outError("ERROR: Player (guidlow %d) have invalid transport guid (%u). Teleport to default race/class locations.", - guid,transGUID); - - SetMapId(info->mapId); - Relocate(info->positionX,info->positionY,info->positionZ,0.0f); - - m_movementInfo.t_x = 0.0f; - m_movementInfo.t_y = 0.0f; - m_movementInfo.t_z = 0.0f; - m_movementInfo.t_o = 0.0f; - - transGUID = 0; - } - } - - time_t now = time(NULL); - time_t logoutTime = time_t(fields[16].GetUInt64()); - - // since last logout (in seconds) - uint64 time_diff = uint64(now - logoutTime); - - // set value, including drunk invisibility detection - // calculate sobering. after 15 minutes logged out, the player will be sober again - float soberFactor; - if(time_diff > 15*MINUTE) - soberFactor = 0; - else - soberFactor = 1-time_diff/(15.0f*MINUTE); - uint16 newDrunkenValue = uint16(soberFactor*(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE)); - SetDrunkValue(newDrunkenValue); - - m_rest_bonus = fields[15].GetFloat(); - //speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour) - float bubble0 = 0.031; - //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour) - float bubble1 = 0.125; - - if((int32)fields[16].GetUInt32() > 0) - { - float bubble = fields[17].GetUInt32() > 0 - ? bubble1*sWorld.getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY) - : bubble0*sWorld.getRate(RATE_REST_OFFLINE_IN_WILDERNESS); - - SetRestBonus(GetRestBonus()+ time_diff*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble); - } - - m_cinematic = fields[12].GetUInt32(); - m_Played_time[0]= fields[13].GetUInt32(); - m_Played_time[1]= fields[14].GetUInt32(); - - m_resetTalentsCost = fields[18].GetUInt32(); - m_resetTalentsTime = time_t(fields[19].GetUInt64()); - - // reserve some flags - uint32 old_safe_flags = GetUInt32Value(PLAYER_FLAGS) & ( PLAYER_FLAGS_HIDE_CLOAK | PLAYER_FLAGS_HIDE_HELM ); - - if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM) ) - SetUInt32Value(PLAYER_FLAGS, 0 | old_safe_flags); - - m_taxi.LoadTaxiMask( fields[11].GetString() ); // must be before InitTaxiNodesForLevel - - uint32 gmstate = fields[25].GetUInt32(); - - m_stableSlots = fields[26].GetUInt32(); - if(m_stableSlots > 2) - { - sLog.outError("Player can have not more 2 stable slots, but have in DB %u",uint32(m_stableSlots)); - m_stableSlots = 2; - } - - m_atLoginFlags = fields[27].GetUInt32(); - - // Honor system - // Update Honor kills data - m_lastHonorUpdateTime = logoutTime; - UpdateHonorFields(); - - m_deathExpireTime = (time_t)fields[30].GetUInt64(); - if(m_deathExpireTime > now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP) - m_deathExpireTime = now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP-1; - - std::string taxi_nodes = fields[31].GetCppString(); - - delete result; - - // clear channel spell data (if saved at channel spell casting) - SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0); - SetUInt32Value(UNIT_CHANNEL_SPELL,0); - - // clear charm/summon related fields - SetUInt64Value(UNIT_FIELD_CHARM,0); - SetUInt64Value(UNIT_FIELD_SUMMON,0); - SetUInt64Value(UNIT_FIELD_CHARMEDBY,0); - SetUInt64Value(UNIT_FIELD_SUMMONEDBY,0); - SetUInt64Value(UNIT_FIELD_CREATEDBY,0); - - // reset some aura modifiers before aura apply - SetUInt64Value(PLAYER_FARSIGHT, 0); - SetUInt32Value(PLAYER_TRACK_CREATURES, 0 ); - SetUInt32Value(PLAYER_TRACK_RESOURCES, 0 ); - - // reset skill modifiers and set correct unlearn flags - for (uint32 i = 0; i < PLAYER_MAX_SKILLS; i++) - { - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); - - // set correct unlearn bit - uint32 id = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; - if(!id) continue; - - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); - if(!pSkill) continue; - - // enable unlearn button for primary professions only - if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); - else - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); - } - - // make sure the unit is considered out of combat for proper loading - ClearInCombat(); - - // make sure the unit is considered not in duel for proper loading - SetUInt64Value(PLAYER_DUEL_ARBITER, 0); - SetUInt32Value(PLAYER_DUEL_TEAM, 0); - - // remember loaded power/health values to restore after stats initialization and modifier applying - uint32 savedHealth = GetHealth(); - uint32 savedPower[MAX_POWERS]; - for(uint32 i = 0; i < MAX_POWERS; ++i) - savedPower[i] = GetPower(Powers(i)); - - // reset stats before loading any modifiers - InitStatsForLevel(); - InitTaxiNodesForLevel(); - - // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods() - - //mails are loaded only when needed ;-) - when player in game click on mailbox. - //_LoadMail(); - - _LoadAuras(holder->GetResult(PLAYER_LOGIN_QUERY_LOADAURAS), time_diff); - - // add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura) - if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST) ) - m_deathState = DEAD; - - _LoadSpells(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSPELLS)); - - // after spell load - InitTalentForLevel(); - learnSkillRewardedSpells(); - - // after spell load, learn rewarded spell if need also - _LoadQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS)); - _LoadDailyQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS)); - - _LoadTutorials(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTUTORIALS)); - - // must be before inventory (some items required reputation check) - _LoadReputation(holder->GetResult(PLAYER_LOGIN_QUERY_LOADREPUTATION)); - - _LoadInventory(holder->GetResult(PLAYER_LOGIN_QUERY_LOADINVENTORY), time_diff); - - // update items with duration and realtime - UpdateItemDuration(time_diff, true); - - _LoadActions(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACTIONS)); - - // unread mails and next delivery time, actual mails not loaded - _LoadMailInit(holder->GetResult(PLAYER_LOGIN_QUERY_LOADMAILCOUNT), holder->GetResult(PLAYER_LOGIN_QUERY_LOADMAILDATE)); - - m_social = sSocialMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSOCIALLIST), GetGUIDLow()); - - if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND))) - return false; - - // check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES - // note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded - if(uint32 curTitle = GetUInt32Value(PLAYER_CHOSEN_TITLE)) - { - if(!HasFlag64(PLAYER__FIELD_KNOWN_TITLES,uint64(1) << curTitle)) - SetUInt32Value(PLAYER_CHOSEN_TITLE,0); - } - - // Not finish taxi flight path - if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes)) - { - // problems with taxi path loading - TaxiNodesEntry const* nodeEntry = NULL; - if(uint32 node_id = m_taxi.GetTaxiSource()) - nodeEntry = sTaxiNodesStore.LookupEntry(node_id); - - if(!nodeEntry) // don't know taxi start node, to homebind - { - sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow()); - SetMapId(m_homebindMapId); - Relocate( m_homebindX, m_homebindY, m_homebindZ,0.0f); - SaveRecallPosition(); // save as recall also to prevent recall and fall from sky - } - else // have start node, to it - { - sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow()); - SetMapId(nodeEntry->map_id); - Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f); - SaveRecallPosition(); // save as recall also to prevent recall and fall from sky - } - m_taxi.ClearTaxiDestinations(); - } - else if(uint32 node_id = m_taxi.GetTaxiSource()) - { - // save source node as recall coord to prevent recall and fall from sky - TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id); - assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString - m_recallMap = nodeEntry->map_id; - m_recallX = nodeEntry->x; - m_recallY = nodeEntry->y; - m_recallZ = nodeEntry->z; - - // flight will started later - } - - _LoadSpellCooldowns(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS)); - - // Spell code allow apply any auras to dead character in load time in aura/spell/item loading - // Do now before stats re-calculation cleanup for ghost state unexpected auras - if(!isAlive()) - RemoveAllAurasOnDeath(); - - //apply all stat bonuses from items and auras - SetCanModifyStats(true); - UpdateAllStats(); - - // restore remembered power/health values (but not more max values) - SetHealth(savedHealth > GetMaxHealth() ? GetMaxHealth() : savedHealth); - for(uint32 i = 0; i < MAX_POWERS; ++i) - SetPower(Powers(i),savedPower[i] > GetMaxPower(Powers(i)) ? GetMaxPower(Powers(i)) : savedPower[i]); - - sLog.outDebug("The value of player %s after load item and aura is: ", m_name.c_str()); - outDebugValues(); - - // GM state - if(GetSession()->GetSecurity() > SEC_PLAYER) - { - switch(sWorld.getConfig(CONFIG_GM_LOGIN_STATE)) - { - case 0: // disable - break; - case 1: // enable - SetGameMaster(true); - break; - case 2: // save state - if(gmstate) - SetGameMaster(true); - break; - default: - break; - } - } - - //Unmount Player from previous mount, so speed bug with mount is no more... - if(IsMounted()) - { - Unmount(); - RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); - } - - _LoadDeclinedNames(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES)); - - return true; -} - -bool Player::isAllowedToLoot(Creature* creature) -{ - if(Player* recipient = creature->GetLootRecipient()) - { - if (recipient == this) - return true; - if( Group* otherGroup = recipient->GetGroup()) - { - Group* thisGroup = GetGroup(); - if(!thisGroup) - return false; - return thisGroup == otherGroup; - } - return false; - } - else - // prevent other players from looting if the recipient got disconnected - return !creature->hasLootRecipient(); -} - -void Player::_LoadActions(QueryResult *result) -{ - m_actionButtons.clear(); - - //QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button",GetGUIDLow()); - - if(result) - { - do - { - Field *fields = result->Fetch(); - - uint8 button = fields[0].GetUInt8(); - - addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8()); - - m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED; - } - while( result->NextRow() ); - - delete result; - } -} - -void Player::_LoadAuras(QueryResult *result, uint32 timediff) -{ - m_Auras.clear(); - for (int i = 0; i < TOTAL_AURAS; i++) - m_modAuras[i].clear(); - - // all aura related fields - for(int i = UNIT_FIELD_AURA; i <= UNIT_FIELD_AURASTATE; ++i) - SetUInt32Value(i, 0); - - //QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'",GetGUIDLow()); - - if(result) - { - do - { - Field *fields = result->Fetch(); - uint64 caster_guid = fields[0].GetUInt64(); - uint32 spellid = fields[1].GetUInt32(); - uint32 effindex = fields[2].GetUInt32(); - int32 damage = (int32)fields[3].GetUInt32(); - int32 maxduration = (int32)fields[4].GetUInt32(); - int32 remaintime = (int32)fields[5].GetUInt32(); - int32 remaincharges = (int32)fields[6].GetUInt32(); - - SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid); - if(!spellproto) - { - sLog.outError("Unknown aura (spellid %u, effindex %u), ignore.",spellid,effindex); - continue; - } - - if(effindex >= 3) - { - sLog.outError("Invalid effect index (spellid %u, effindex %u), ignore.",spellid,effindex); - continue; - } - - // negative effects should continue counting down after logout - if (remaintime != -1 && !IsPositiveEffect(spellid, effindex)) - { - if(remaintime <= int32(timediff)) - continue; - - remaintime -= timediff; - } - - // prevent wrong values of remaincharges - if(spellproto->procCharges) - { - if(remaincharges <= 0 || remaincharges > spellproto->procCharges) - remaincharges = spellproto->procCharges; - } - else - remaincharges = -1; - - //do not load single target auras (unless they were cast by the player) - if (caster_guid != GetGUID() && IsSingleTargetSpell(spellproto)) - continue; - - Aura* aura = CreateAura(spellproto, effindex, NULL, this, NULL); - if(!damage) - damage = aura->GetModifier()->m_amount; - aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges); - AddAura(aura); - } - while( result->NextRow() ); - - delete result; - } - - if(m_class == CLASS_WARRIOR) - CastSpell(this,SPELL_ID_PASSIVE_BATTLE_STANCE,true); -} - -void Player::LoadCorpse() -{ - if( isAlive() ) - { - ObjectAccessor::Instance().ConvertCorpseForPlayer(GetGUID()); - } - else - { - if(Corpse *corpse = GetCorpse()) - { - ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, corpse && !sMapStore.LookupEntry(corpse->GetMapId())->Instanceable() ); - } - else - { - //Prevent Dead Player login without corpse - ResurrectPlayer(0.5f); - } - } -} - -void Player::_LoadInventory(QueryResult *result, uint32 timediff) -{ - //QueryResult *result = CharacterDatabase.PQuery("SELECT data,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GetGUIDLow()); - std::map bagMap; // fast guid lookup for bags - //NOTE: the "order by `bag`" is important because it makes sure - //the bagMap is filled before items in the bags are loaded - //NOTE2: the "order by `slot`" is needed becaue mainhand weapons are (wrongly?) - //expected to be equipped before offhand items (TODO: fixme) - - uint32 zone = GetZoneId(); - - if (result) - { - std::list problematicItems; - - // prevent items from being added to the queue when stored - m_itemUpdateQueueBlocked = true; - do - { - Field *fields = result->Fetch(); - uint32 bag_guid = fields[1].GetUInt32(); - uint8 slot = fields[2].GetUInt8(); - uint32 item_guid = fields[3].GetUInt32(); - uint32 item_id = fields[4].GetUInt32(); - - ItemPrototype const * proto = objmgr.GetItemPrototype(item_id); - - if(!proto) - { - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid); - sLog.outError( "Player::_LoadInventory: Player %s has an unknown item (id: #%u) in inventory, deleted.", GetName(),item_id ); - continue; - } - - Item *item = NewItemOrBag(proto); - - if(!item->LoadFromDB(item_guid, GetGUID(), result)) - { - sLog.outError( "Player::_LoadInventory: Player %s has broken item (id: #%u) in inventory, deleted.", GetName(),item_id ); - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); - item->FSetState(ITEM_REMOVED); - item->SaveToDB(); // it also deletes item object ! - continue; - } - - // not allow have in alive state item limited to another map/zone - if(isAlive() && item->IsLimitedToAnotherMapOrZone(GetMapId(),zone) ) - { - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); - item->FSetState(ITEM_REMOVED); - item->SaveToDB(); // it also deletes item object ! - continue; - } - - // "Conjured items disappear if you are logged out for more than 15 minutes" - if ((timediff > 15*60) && (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED))) - { - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); - item->FSetState(ITEM_REMOVED); - item->SaveToDB(); // it also deletes item object ! - continue; - } - - bool success = true; - - if (!bag_guid) - { - // the item is not in a bag - item->SetContainer( NULL ); - item->SetSlot(slot); - - if( IsInventoryPos( INVENTORY_SLOT_BAG_0, slot ) ) - { - ItemPosCountVec dest; - if( CanStoreItem( INVENTORY_SLOT_BAG_0, slot, dest, item, false ) == EQUIP_ERR_OK ) - item = StoreItem(dest, item, true); - else - success = false; - } - else if( IsEquipmentPos( INVENTORY_SLOT_BAG_0, slot ) ) - { - uint16 dest; - if( CanEquipItem( slot, dest, item, false, false ) == EQUIP_ERR_OK ) - QuickEquipItem(dest, item); - else - success = false; - } - else if( IsBankPos( INVENTORY_SLOT_BAG_0, slot ) ) - { - ItemPosCountVec dest; - if( CanBankItem( INVENTORY_SLOT_BAG_0, slot, dest, item, false, false ) == EQUIP_ERR_OK ) - item = BankItem(dest, item, true); - else - success = false; - } - - if(success) - { - // store bags that may contain items in them - if(item->IsBag() && IsBagPos(item->GetPos())) - bagMap[item_guid] = (Bag*)item; - } - } - else - { - item->SetSlot(NULL_SLOT); - // the item is in a bag, find the bag - std::map::iterator itr = bagMap.find(bag_guid); - if(itr != bagMap.end()) - itr->second->StoreItem(slot, item, true ); - else - success = false; - } - - // item's state may have changed after stored - if (success) - item->SetState(ITEM_UNCHANGED, this); - else - { - sLog.outError("Player::_LoadInventory: Player %s has item (GUID: %u Entry: %u) can't be loaded to inventory (Bag GUID: %u Slot: %u) by some reason, will send by mail.", GetName(),item_guid, item_id, bag_guid, slot); - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); - problematicItems.push_back(item); - } - } while (result->NextRow()); - - delete result; - m_itemUpdateQueueBlocked = false; - - // send by mail problematic items - while(!problematicItems.empty()) - { - // fill mail - MailItemsInfo mi; // item list prepering - - for(int i = 0; !problematicItems.empty() && i < MAX_MAIL_ITEMS; ++i) - { - Item* item = problematicItems.front(); - problematicItems.pop_front(); - - mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); - } - - std::string subject = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM); - - WorldSession::SendMailTo(this, MAIL_NORMAL, MAIL_STATIONERY_GM, GetGUIDLow(), GetGUIDLow(), subject, 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE); - } - } - //if(isAlive()) - _ApplyAllItemMods(); -} - -// load mailed item which should receive current player -void Player::_LoadMailedItems(Mail *mail) -{ - QueryResult* result = CharacterDatabase.PQuery("SELECT item_guid, item_template FROM mail_items WHERE mail_id='%u'", mail->messageID); - if(!result) - return; - - do - { - Field *fields = result->Fetch(); - uint32 item_guid_low = fields[0].GetUInt32(); - uint32 item_template = fields[1].GetUInt32(); - - mail->AddItem(item_guid_low, item_template); - - ItemPrototype const *proto = objmgr.GetItemPrototype(item_template); - - if(!proto) - { - sLog.outError( "Player %u have unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID); - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low); - continue; - } - - Item *item = NewItemOrBag(proto); - - if(!item->LoadFromDB(item_guid_low, 0)) - { - sLog.outError( "Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, item_guid_low); - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); - item->FSetState(ITEM_REMOVED); - item->SaveToDB(); // it also deletes item object ! - continue; - } - - AddMItem(item); - } while (result->NextRow()); - - delete result; -} - -void Player::_LoadMailInit(QueryResult *resultUnread, QueryResult *resultDelivery) -{ - //set a count of unread mails - //QueryResult *resultMails = CharacterDatabase.PQuery("SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" I64FMTD "'", GUID_LOPART(playerGuid),(uint64)cTime); - if (resultUnread) - { - Field *fieldMail = resultUnread->Fetch(); - unReadMails = fieldMail[0].GetUInt8(); - delete resultUnread; - } - - // store nearest delivery time (it > 0 and if it < current then at next player update SendNewMaill will be called) - //resultMails = CharacterDatabase.PQuery("SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(playerGuid)); - if (resultDelivery) - { - Field *fieldMail = resultDelivery->Fetch(); - m_nextMailDelivereTime = (time_t)fieldMail[0].GetUInt64(); - delete resultDelivery; - } -} - -void Player::_LoadMail() -{ - m_mail.clear(); - //mails are in right order 0 1 2 3 4 5 6 7 8 9 10 11 12 13 - QueryResult *result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,subject,itemTextId,has_items,expire_time,deliver_time,money,cod,checked,stationery,mailTemplateId FROM mail WHERE receiver = '%u' ORDER BY id DESC",GetGUIDLow()); - if(result) - { - do - { - Field *fields = result->Fetch(); - Mail *m = new Mail; - m->messageID = fields[0].GetUInt32(); - m->messageType = fields[1].GetUInt8(); - m->sender = fields[2].GetUInt32(); - m->receiver = fields[3].GetUInt32(); - m->subject = fields[4].GetCppString(); - m->itemTextId = fields[5].GetUInt32(); - bool has_items = fields[6].GetBool(); - m->expire_time = (time_t)fields[7].GetUInt64(); - m->deliver_time = (time_t)fields[8].GetUInt64(); - m->money = fields[9].GetUInt32(); - m->COD = fields[10].GetUInt32(); - m->checked = fields[11].GetUInt32(); - m->stationery = fields[12].GetUInt8(); - m->mailTemplateId = fields[13].GetInt16(); - - if(m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId)) - { - sLog.outError( "Player::_LoadMail - Mail (%u) have not existed MailTemplateId (%u), remove at load", m->messageID, m->mailTemplateId); - m->mailTemplateId = 0; - } - - m->state = MAIL_STATE_UNCHANGED; - - if (has_items) - _LoadMailedItems(m); - - m_mail.push_back(m); - } while( result->NextRow() ); - delete result; - } - m_mailsLoaded = true; -} - -void Player::LoadPet() -{ - //fixme: the pet should still be loaded if the player is not in world - // just not added to the map - if(IsInWorld()) - { - Pet *pet = new Pet; - if(!pet->LoadPetFromDB(this,0,0,true)) - delete pet; - } -} - -void Player::_LoadQuestStatus(QueryResult *result) -{ - mQuestStatus.clear(); - - uint32 slot = 0; - - //// 0 1 2 3 4 5 6 7 8 9 10 11 12 - //QueryResult *result = CharacterDatabase.PQuery("SELECT quest, status, rewarded, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, itemcount1, itemcount2, itemcount3, itemcount4 FROM character_queststatus WHERE guid = '%u'", GetGUIDLow()); - - if(result) - { - do - { - Field *fields = result->Fetch(); - - uint32 quest_id = fields[0].GetUInt32(); - // used to be new, no delete? - Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); - if( pQuest ) - { - // find or create - QuestStatusData& questStatusData = mQuestStatus[quest_id]; - - uint32 qstatus = fields[1].GetUInt32(); - if(qstatus < MAX_QUEST_STATUS) - questStatusData.m_status = QuestStatus(qstatus); - else - { - questStatusData.m_status = QUEST_STATUS_NONE; - sLog.outError("Player %s have invalid quest %d status (%d), replaced by QUEST_STATUS_NONE(0).",GetName(),quest_id,qstatus); - } - - questStatusData.m_rewarded = ( fields[2].GetUInt8() > 0 ); - questStatusData.m_explored = ( fields[3].GetUInt8() > 0 ); - - time_t quest_time = time_t(fields[4].GetUInt64()); - - if( pQuest->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) && !GetQuestRewardStatus(quest_id) && questStatusData.m_status != QUEST_STATUS_NONE ) - { - AddTimedQuest( quest_id ); - - if (quest_time <= sWorld.GetGameTime()) - questStatusData.m_timer = 1; - else - questStatusData.m_timer = (quest_time - sWorld.GetGameTime()) * 1000; - } - else - quest_time = 0; - - questStatusData.m_creatureOrGOcount[0] = fields[5].GetUInt32(); - questStatusData.m_creatureOrGOcount[1] = fields[6].GetUInt32(); - questStatusData.m_creatureOrGOcount[2] = fields[7].GetUInt32(); - questStatusData.m_creatureOrGOcount[3] = fields[8].GetUInt32(); - questStatusData.m_itemcount[0] = fields[9].GetUInt32(); - questStatusData.m_itemcount[1] = fields[10].GetUInt32(); - questStatusData.m_itemcount[2] = fields[11].GetUInt32(); - questStatusData.m_itemcount[3] = fields[12].GetUInt32(); - - questStatusData.uState = QUEST_UNCHANGED; - - // add to quest log - if( slot < MAX_QUEST_LOG_SIZE && - ( questStatusData.m_status==QUEST_STATUS_INCOMPLETE || - questStatusData.m_status==QUEST_STATUS_COMPLETE && !questStatusData.m_rewarded ) ) - { - SetQuestSlot(slot,quest_id,quest_time); - - if(questStatusData.m_status == QUEST_STATUS_COMPLETE) - SetQuestSlotState(slot,QUEST_STATE_COMPLETE); - - for(uint8 idx = 0; idx < QUEST_OBJECTIVES_COUNT; ++idx) - if(questStatusData.m_creatureOrGOcount[idx]) - SetQuestSlotCounter(slot,idx,questStatusData.m_creatureOrGOcount[idx]); - - ++slot; - } - - if(questStatusData.m_rewarded) - { - // learn rewarded spell if unknown - learnQuestRewardedSpells(pQuest); - - // set rewarded title if any - if(pQuest->GetCharTitleId()) - { - if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId())) - SetFlag64(PLAYER__FIELD_KNOWN_TITLES, (uint64(1) << titleEntry->bit_index)); - } - } - - sLog.outDebug("Quest status is {%u} for quest {%u} for player (GUID: %u)", questStatusData.m_status, quest_id, GetGUIDLow()); - } - } - while( result->NextRow() ); - - delete result; - } - - // clear quest log tail - for ( uint16 i = slot; i < MAX_QUEST_LOG_SIZE; ++i ) - SetQuestSlot(i,0); -} - -void Player::_LoadDailyQuestStatus(QueryResult *result) -{ - for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) - SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,0); - - //QueryResult *result = CharacterDatabase.PQuery("SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GetGUIDLow()); - - if(result) - { - uint32 quest_daily_idx = 0; - - do - { - if(quest_daily_idx >= PLAYER_MAX_DAILY_QUESTS) // max amount with exist data in query - { - sLog.outError("Player (GUID: %u) have more 25 daily quest records in `charcter_queststatus_daily`",GetGUIDLow()); - break; - } - - Field *fields = result->Fetch(); - - uint32 quest_id = fields[0].GetUInt32(); - - // save _any_ from daily quest times (it must be after last reset anyway) - m_lastDailyQuestTime = (time_t)fields[1].GetUInt64(); - - Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); - if( !pQuest ) - continue; - - SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,quest_id); - ++quest_daily_idx; - - sLog.outDebug("Daily quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUIDLow()); - } - while( result->NextRow() ); - - delete result; - } - - m_DailyQuestChanged = false; -} - -void Player::_LoadReputation(QueryResult *result) -{ - m_factions.clear(); - - // Set initial reputations (so everything is nifty before DB data load) - SetInitialFactions(); - - //QueryResult *result = CharacterDatabase.PQuery("SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'",GetGUIDLow()); - - if(result) - { - do - { - Field *fields = result->Fetch(); - - FactionEntry const *factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt32()); - if( factionEntry && (factionEntry->reputationListID >= 0)) - { - FactionState* faction = &m_factions[factionEntry->reputationListID]; - - // update standing to current - faction->Standing = int32(fields[1].GetUInt32()); - - uint32 dbFactionFlags = fields[2].GetUInt32(); - - if( dbFactionFlags & FACTION_FLAG_VISIBLE ) - SetFactionVisible(faction); // have internal checks for forced invisibility - - if( dbFactionFlags & FACTION_FLAG_INACTIVE) - SetFactionInactive(faction,true); // have internal checks for visibility requirement - - if( dbFactionFlags & FACTION_FLAG_AT_WAR ) // DB at war - SetFactionAtWar(faction,true); // have internal checks for FACTION_FLAG_PEACE_FORCED - else // DB not at war - { - // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN) - if( faction->Flags & FACTION_FLAG_VISIBLE ) - SetFactionAtWar(faction,false); // have internal checks for FACTION_FLAG_PEACE_FORCED - } - - // set atWar for hostile - if(GetReputationRank(factionEntry) <= REP_HOSTILE) - SetFactionAtWar(faction,true); - - // reset changed flag if values similar to saved in DB - if(faction->Flags==dbFactionFlags) - faction->Changed = false; - } - } - while( result->NextRow() ); - - delete result; - } -} - -void Player::_LoadSpells(QueryResult *result) -{ - for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - delete itr->second; - m_spells.clear(); - - //QueryResult *result = CharacterDatabase.PQuery("SELECT spell,slot,active FROM character_spell WHERE guid = '%u'",GetGUIDLow()); - - if(result) - { - do - { - Field *fields = result->Fetch(); - - addSpell(fields[0].GetUInt16(), fields[2].GetBool(), false, true, fields[1].GetUInt16(), fields[3].GetBool()); - } - while( result->NextRow() ); - - delete result; - } -} - -void Player::_LoadTutorials(QueryResult *result) -{ - //QueryResult *result = CharacterDatabase.PQuery("SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetAccountId(), realmid); - - if(result) - { - do - { - Field *fields = result->Fetch(); - - for (int iI=0; iI<8; iI++) - m_Tutorials[iI] = fields[iI].GetUInt32(); - } - while( result->NextRow() ); - - delete result; - } - - m_TutorialsChanged = false; -} - -void Player::_LoadGroup(QueryResult *result) -{ - //QueryResult *result = CharacterDatabase.PQuery("SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", GetGUIDLow()); - if(result) - { - uint64 leaderGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); - delete result; - Group* group = objmgr.GetGroupByLeader(leaderGuid); - if(group) - { - uint8 subgroup = group->GetMemberGroup(GetGUID()); - SetGroup(group, subgroup); - if(getLevel() >= LEVELREQUIREMENT_HEROIC) - { - // the group leader may change the instance difficulty while the player is offline - SetDifficulty(group->GetDifficulty()); - } - } - } -} - -void Player::_LoadBoundInstances(QueryResult *result) -{ - for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) - m_boundInstances[i].clear(); - - Group *group = GetGroup(); - - //QueryResult *result = CharacterDatabase.PQuery("SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid)); - if(result) - { - do - { - Field *fields = result->Fetch(); - bool perm = fields[1].GetBool(); - uint32 mapId = fields[2].GetUInt32(); - uint32 instanceId = fields[0].GetUInt32(); - uint8 difficulty = fields[3].GetUInt8(); - time_t resetTime = (time_t)fields[4].GetUInt64(); - // the resettime for normal instances is only saved when the InstanceSave is unloaded - // so the value read from the DB may be wrong here but only if the InstanceSave is loaded - // and in that case it is not used - - if(!perm && group) - { - sLog.outError("_LoadBoundInstances: player %s(%d) is in group %d but has a non-permanent character bind to map %d,%d,%d", GetName(), GetGUIDLow(), GUID_LOPART(group->GetLeaderGUID()), mapId, instanceId, difficulty); - CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId); - continue; - } - - // since non permanent binds are always solo bind, they can always be reset - InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapId, instanceId, difficulty, resetTime, !perm, true); - if(save) BindToInstance(save, perm, true); - } while(result->NextRow()); - delete result; - } -} - -InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) -{ - // some instances only have one difficulty - const MapEntry* entry = sMapStore.LookupEntry(mapid); - if(!entry || !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; - - BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); - if(itr != m_boundInstances[difficulty].end()) - return &itr->second; - else - return NULL; -} - -void Player::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload) -{ - BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); - UnbindInstance(itr, difficulty, unload); -} - -void Player::UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload) -{ - if(itr != m_boundInstances[difficulty].end()) - { - if(!unload) CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u' AND instance = '%u'", GetGUIDLow(), itr->second.save->GetInstanceId()); - itr->second.save->RemovePlayer(this); // save can become invalid - m_boundInstances[difficulty].erase(itr++); - } -} - -InstancePlayerBind* Player::BindToInstance(InstanceSave *save, bool permanent, bool load) -{ - if(save) - { - InstancePlayerBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()]; - if(bind.save) - { - // update the save when the group kills a boss - if(permanent != bind.perm || save != bind.save) - if(!load) CharacterDatabase.PExecute("UPDATE character_instance SET instance = '%u', permanent = '%u' WHERE guid = '%u' AND instance = '%u'", save->GetInstanceId(), permanent, GetGUIDLow(), bind.save->GetInstanceId()); - } - else - if(!load) CharacterDatabase.PExecute("INSERT INTO character_instance (guid, instance, permanent) VALUES ('%u', '%u', '%u')", GetGUIDLow(), save->GetInstanceId(), permanent); - - if(bind.save != save) - { - if(bind.save) bind.save->RemovePlayer(this); - save->AddPlayer(this); - } - - if(permanent) save->SetCanReset(false); - - bind.save = save; - bind.perm = permanent; - if(!load) sLog.outDebug("Player::BindToInstance: %s(%d) is now bound to map %d, instance %d, difficulty %d", GetName(), GetGUIDLow(), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty()); - return &bind; - } - else - return NULL; -} - -void Player::SendRaidInfo() -{ - WorldPacket data(SMSG_RAID_INSTANCE_INFO, 4); - - uint32 counter = 0, i; - for(i = 0; i < TOTAL_DIFFICULTIES; i++) - for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); itr++) - if(itr->second.perm) counter++; - - data << counter; - for(i = 0; i < TOTAL_DIFFICULTIES; i++) - { - for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); itr++) - { - if(itr->second.perm) - { - InstanceSave *save = itr->second.save; - data << (save->GetMapId()); - data << (uint32)(save->GetResetTime() - time(NULL)); - data << save->GetInstanceId(); - data << uint32(counter); - counter--; - } - } - } - GetSession()->SendPacket(&data); -} - -/* -- called on every successful teleportation to a map -*/ -void Player::SendSavedInstances() -{ - bool hasBeenSaved = false; - WorldPacket data; - - for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) - { - for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) - { - if(itr->second.perm) // only permanent binds are sent - { - hasBeenSaved = true; - break; - } - } - } - - //Send opcode 811. true or flase means, whether you have current raid/heroic instances - data.Initialize(SMSG_UPDATE_INSTANCE_OWNERSHIP); - data << uint32(hasBeenSaved); - GetSession()->SendPacket(&data); - - if(!hasBeenSaved) - return; - - for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) - { - for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) - { - if(itr->second.perm) - { - data.Initialize(SMSG_UPDATE_LAST_INSTANCE); - data << uint32(itr->second.save->GetMapId()); - GetSession()->SendPacket(&data); - } - } - } -} - -/// convert the player's binds to the group -void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player_guid) -{ - bool has_binds = false; - bool has_solo = false; - - if(player) { player_guid = player->GetGUID(); if(!group) group = player->GetGroup(); } - assert(player_guid); - - // copy all binds to the group, when changing leader it's assumed the character - // will not have any solo binds - - if(player) - { - for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) - { - for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) - { - has_binds = true; - if(group) group->BindToInstance(itr->second.save, itr->second.perm, true); - // permanent binds are not removed - if(!itr->second.perm) - { - player->UnbindInstance(itr, i, true); // increments itr - has_solo = true; - } - else - ++itr; - } - } - } - - // if the player's not online we don't know what binds it has - if(!player || !group || has_binds) CharacterDatabase.PExecute("INSERT INTO group_instance SELECT guid, instance, permanent FROM character_instance WHERE guid = '%u'", GUID_LOPART(player_guid)); - // the following should not get executed when changing leaders - if(!player || has_solo) CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND permanent = 0", GUID_LOPART(player_guid)); -} - -bool Player::_LoadHomeBind(QueryResult *result) -{ - bool ok = false; - //QueryResult *result = CharacterDatabase.PQuery("SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(playerGuid)); - if (result) - { - Field *fields = result->Fetch(); - m_homebindMapId = fields[0].GetUInt32(); - m_homebindZoneId = fields[1].GetUInt16(); - m_homebindX = fields[2].GetFloat(); - m_homebindY = fields[3].GetFloat(); - m_homebindZ = fields[4].GetFloat(); - delete result; - - // accept saved data only for valid position (and non instanceable) - if( MapManager::IsValidMapCoord(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ) && - !sMapStore.LookupEntry(m_homebindMapId)->Instanceable() ) - { - ok = true; - } - else - CharacterDatabase.PExecute("DELETE FROM character_homebind WHERE guid = '%u'", GetGUIDLow()); - } - - if(!ok) - { - PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass()); - if(!info) return false; - - m_homebindMapId = info->mapId; - m_homebindZoneId = info->zoneId; - m_homebindX = info->positionX; - m_homebindY = info->positionY; - m_homebindZ = info->positionZ; - - CharacterDatabase.PExecute("INSERT INTO character_homebind (guid,map,zone,position_x,position_y,position_z) VALUES ('%u', '%u', '%u', '%f', '%f', '%f')", GetGUIDLow(), m_homebindMapId, (uint32)m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ); - } - - DEBUG_LOG("Setting player home position: mapid is: %u, zoneid is %u, X is %f, Y is %f, Z is %f\n", - m_homebindMapId, m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ); - - return true; -} - -/*********************************************************/ -/*** SAVE SYSTEM ***/ -/*********************************************************/ - -void Player::SaveToDB() -{ - // delay auto save at any saves (manual, in code, or autosave) - m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE); - - // first save/honor gain after midnight will also update the player's honor fields - UpdateHonorFields(); - - // Must saved before enter into BattleGround - if(InBattleGround()) - return; - - int is_save_resting = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0; - //save, far from tavern/city - //save, but in tavern/city - sLog.outDebug("The value of player %s at save: ", m_name.c_str()); - outDebugValues(); - - // save state (after auras removing), if aura remove some flags then it must set it back by self) - uint32 tmp_bytes = GetUInt32Value(UNIT_FIELD_BYTES_1); - uint32 tmp_bytes2 = GetUInt32Value(UNIT_FIELD_BYTES_2); - uint32 tmp_flags = GetUInt32Value(UNIT_FIELD_FLAGS); - uint32 tmp_pflags = GetUInt32Value(PLAYER_FLAGS); - uint32 tmp_displayid = GetDisplayId(); - - // Set player sit state to standing on save, also stealth and shifted form - SetByteValue(UNIT_FIELD_BYTES_1, 0, 0); // stand state - SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift - SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); // stand flags? - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE); - SetDisplayId(GetNativeDisplayId()); - - bool inworld = IsInWorld(); - - CharacterDatabase.BeginTransaction(); - - CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",GetGUIDLow()); - - std::string sql_name = m_name; - CharacterDatabase.escape_string(sql_name); - - std::ostringstream ss; - ss << "INSERT INTO characters (guid,account,name,race,class," - "map, dungeon_difficulty, position_x, position_y, position_z, orientation, data, " - "taximask, online, cinematic, " - "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, " - "trans_x, trans_y, trans_z, trans_o, transguid, gmstate, stable_slots, at_login, zone, " - "death_expire_time, taxi_path) VALUES (" - << GetGUIDLow() << ", " - << GetSession()->GetAccountId() << ", '" - << sql_name << "', " - << m_race << ", " - << m_class << ", "; - - bool save_to_dest = false; - if(IsBeingTeleported()) - { - // don't save to battlegrounds or arenas - const MapEntry *entry = sMapStore.LookupEntry(GetTeleportDest().mapid); - if(entry && entry->map_type != MAP_BATTLEGROUND && entry->map_type != MAP_ARENA) - save_to_dest = true; - } - - if(!save_to_dest) - { - ss << GetMapId() << ", " - << (uint32)GetDifficulty() << ", " - << finiteAlways(GetPositionX()) << ", " - << finiteAlways(GetPositionY()) << ", " - << finiteAlways(GetPositionZ()) << ", " - << finiteAlways(GetOrientation()) << ", '"; - } - else - { - ss << GetTeleportDest().mapid << ", " - << (uint32)GetDifficulty() << ", " - << finiteAlways(GetTeleportDest().x) << ", " - << finiteAlways(GetTeleportDest().y) << ", " - << finiteAlways(GetTeleportDest().z) << ", " - << finiteAlways(GetTeleportDest().o) << ", '"; - } - - uint16 i; - for( i = 0; i < m_valuesCount; i++ ) - { - ss << GetUInt32Value(i) << " "; - } - - ss << "', '"; - - for( i = 0; i < 8; i++ ) - ss << m_taxi.GetTaximask(i) << " "; - - ss << "', "; - ss << (inworld ? 1 : 0); - - ss << ", "; - ss << m_cinematic; - - ss << ", "; - ss << m_Played_time[0]; - ss << ", "; - ss << m_Played_time[1]; - - ss << ", "; - ss << finiteAlways(m_rest_bonus); - ss << ", "; - ss << (uint64)time(NULL); - ss << ", "; - ss << is_save_resting; - ss << ", "; - ss << m_resetTalentsCost; - ss << ", "; - ss << (uint64)m_resetTalentsTime; - - ss << ", "; - ss << finiteAlways(m_movementInfo.t_x); - ss << ", "; - ss << finiteAlways(m_movementInfo.t_y); - ss << ", "; - ss << finiteAlways(m_movementInfo.t_z); - ss << ", "; - ss << finiteAlways(m_movementInfo.t_o); - ss << ", "; - if (m_transport) - ss << m_transport->GetGUIDLow(); - else - ss << "0"; - - ss << ", "; - ss << (isGameMaster()? 1 : 0); - - ss << ", "; - ss << uint32(m_stableSlots); // to prevent save uint8 as char - - ss << ", "; - ss << uint32(m_atLoginFlags); - - ss << ", "; - ss << GetZoneId(); - - ss << ", "; - ss << (uint64)m_deathExpireTime; - - ss << ", '"; - ss << m_taxi.SaveTaxiDestinationsToString(); - ss << "' )"; - - CharacterDatabase.Execute( ss.str().c_str() ); - - if(m_mailsUpdated) //save mails only when needed - _SaveMail(); - - _SaveInventory(); - _SaveQuestStatus(); - _SaveDailyQuestStatus(); - _SaveTutorials(); - _SaveSpells(); - _SaveSpellCooldowns(); - _SaveActions(); - _SaveAuras(); - _SaveReputation(); - - CharacterDatabase.CommitTransaction(); - - // restore state (before aura apply, if aura remove flag then aura must set it ack by self) - SetDisplayId(tmp_displayid); - SetUInt32Value(UNIT_FIELD_BYTES_1, tmp_bytes); - SetUInt32Value(UNIT_FIELD_BYTES_2, tmp_bytes2); - SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags); - SetUInt32Value(PLAYER_FLAGS, tmp_pflags); - - // save pet (hunter pet level and experience and all type pets health/mana). - if(Pet* pet = GetPet()) - pet->SavePetToDB(PET_SAVE_AS_CURRENT); -} - -// fast save function for item/money cheating preventing - save only inventory and money state -void Player::SaveInventoryAndGoldToDB() -{ - _SaveInventory(); - SetUInt32ValueInDB(PLAYER_FIELD_COINAGE,GetMoney(),GetGUID()); -} - -void Player::_SaveActions() -{ - for(ActionButtonList::iterator itr = m_actionButtons.begin(); itr != m_actionButtons.end(); ) - { - switch (itr->second.uState) - { - case ACTIONBUTTON_NEW: - CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type,misc) VALUES ('%u', '%u', '%u', '%u', '%u')", - GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc ); - itr->second.uState = ACTIONBUTTON_UNCHANGED; - ++itr; - break; - case ACTIONBUTTON_CHANGED: - CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u', misc= '%u' WHERE guid= '%u' AND button= '%u' ", - (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc, GetGUIDLow(), (uint32)itr->first ); - itr->second.uState = ACTIONBUTTON_UNCHANGED; - ++itr; - break; - case ACTIONBUTTON_DELETED: - CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u' and button = '%u'", GetGUIDLow(), (uint32)itr->first ); - m_actionButtons.erase(itr++); - break; - default: - ++itr; - break; - }; - } -} - -void Player::_SaveAuras() -{ - CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",GetGUIDLow()); - - AuraMap const& auras = GetAuras(); - for(AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - SpellEntry const *spellInfo = itr->second->GetSpellProto(); - - //skip all auras from spells that are passive or need a shapeshift - if (itr->second->IsPassive() || itr->second->IsRemovedOnShapeLost()) - continue; - - //do not save single target auras (unless they were cast by the player) - if (itr->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(spellInfo)) - continue; - - uint8 i; - // or apply at cast SPELL_AURA_MOD_SHAPESHIFT or SPELL_AURA_MOD_STEALTH auras - for (i = 0; i < 3; i++) - if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT || - spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH) - break; - - if (i == 3) - { - CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u' and spell = '%u' and effect_index= '%u'",GetGUIDLow(),(uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex()); - CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges) " - "VALUES ('%u', '" I64FMTD "' ,'%u', '%u', '%d', '%d', '%d', '%d')", - GetGUIDLow(), itr->second->GetCasterGUID(), (uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(), (*itr).second->GetModifier()->m_amount,int((*itr).second->GetAuraMaxDuration()),int((*itr).second->GetAuraDuration()),int((*itr).second->m_procCharges)); - } - } -} - -void Player::_SaveInventory() -{ - // force items in buyback slots to new state - // and remove those that aren't already - for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; i++) - { - Item *item = m_items[i]; - if (!item || item->GetState() == ITEM_NEW) continue; - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow()); - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item->GetGUIDLow()); - m_items[i]->FSetState(ITEM_NEW); - } - - // update enchantment durations - for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();++itr) - { - itr->item->SetEnchantmentDuration(itr->slot,itr->leftduration); - } - - // if no changes - if (m_itemUpdateQueue.empty()) return; - - // do not save if the update queue is corrupt - bool error = false; - for(size_t i = 0; i < m_itemUpdateQueue.size(); i++) - { - Item *item = m_itemUpdateQueue[i]; - if(!item || item->GetState() == ITEM_REMOVED) continue; - Item *test = GetItemByPos( item->GetBagSlot(), item->GetSlot()); - - if (test == NULL) - { - sLog.outError("Player(GUID: %u Name: %s)::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", GetGUIDLow(), GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); - error = true; - } - else if (test != item) - { - sLog.outError("Player(GUID: %u Name: %s)::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", GetGUIDLow(), GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); - error = true; - } - } - - if (error) - { - sLog.outError("Player::_SaveInventory - one or more errors occurred save aborted!"); - ChatHandler(this).SendSysMessage(LANG_ITEM_SAVE_FAILED); - return; - } - - for(size_t i = 0; i < m_itemUpdateQueue.size(); i++) - { - Item *item = m_itemUpdateQueue[i]; - if(!item) continue; - - Bag *container = item->GetContainer(); - uint32 bag_guid = container ? container->GetGUIDLow() : 0; - - switch(item->GetState()) - { - case ITEM_NEW: - CharacterDatabase.PExecute("INSERT INTO character_inventory (guid,bag,slot,item,item_template) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetGUIDLow(), item->GetEntry()); - break; - case ITEM_CHANGED: - CharacterDatabase.PExecute("UPDATE character_inventory SET guid='%u', bag='%u', slot='%u', item_template='%u' WHERE item='%u'", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetEntry(), item->GetGUIDLow()); - break; - case ITEM_REMOVED: - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow()); - break; - case ITEM_UNCHANGED: - break; - } - - item->SaveToDB(); // item have unchanged inventory record and can be save standalone - } - m_itemUpdateQueue.clear(); -} - -void Player::_SaveMail() -{ - if (!m_mailsLoaded) - return; - - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); itr++) - { - Mail *m = (*itr); - if (m->state == MAIL_STATE_CHANGED) - { - CharacterDatabase.PExecute("UPDATE mail SET itemTextId = '%u',has_items = '%u',expire_time = '" I64FMTD "', deliver_time = '" I64FMTD "',money = '%u',cod = '%u',checked = '%u' WHERE id = '%u'", - m->itemTextId, m->HasItems() ? 1 : 0, (uint64)m->expire_time, (uint64)m->deliver_time, m->money, m->COD, m->checked, m->messageID); - if(m->removedItems.size()) - { - for(std::vector::iterator itr2 = m->removedItems.begin(); itr2 != m->removedItems.end(); ++itr2) - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", *itr2); - m->removedItems.clear(); - } - m->state = MAIL_STATE_UNCHANGED; - } - else if (m->state == MAIL_STATE_DELETED) - { - if (m->HasItems()) - for(std::vector::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid); - if (m->itemTextId) - CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId); - CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID); - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", m->messageID); - } - } - - //deallocate deleted mails... - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ) - { - if ((*itr)->state == MAIL_STATE_DELETED) - { - Mail* m = *itr; - m_mail.erase(itr); - delete m; - itr = m_mail.begin(); - } - else - ++itr; - } - - m_mailsUpdated = false; -} - -void Player::_SaveQuestStatus() -{ - // we don't need transactions here. - for( QuestStatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i ) - { - switch (i->second.uState) - { - case QUEST_NEW : - CharacterDatabase.PExecute("INSERT INTO character_queststatus (guid,quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4) " - "VALUES ('%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", - GetGUIDLow(), i->first, i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3]); - break; - case QUEST_CHANGED : - CharacterDatabase.PExecute("UPDATE character_queststatus SET status = '%u',rewarded = '%u',explored = '%u',timer = '" I64FMTD "',mobcount1 = '%u',mobcount2 = '%u',mobcount3 = '%u',mobcount4 = '%u',itemcount1 = '%u',itemcount2 = '%u',itemcount3 = '%u',itemcount4 = '%u' WHERE guid = '%u' AND quest = '%u' ", - i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3], GetGUIDLow(), i->first ); - break; - case QUEST_UNCHANGED: - break; - }; - i->second.uState = QUEST_UNCHANGED; - } -} - -void Player::_SaveDailyQuestStatus() -{ - if(!m_DailyQuestChanged) - return; - - m_DailyQuestChanged = false; - - // save last daily quest time for all quests: we need only mostly reset time for reset check anyway - - // we don't need transactions here. - CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",GetGUIDLow()); - for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) - if(GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)) - CharacterDatabase.PExecute("INSERT INTO character_queststatus_daily (guid,quest,time) VALUES ('%u', '%u','" I64FMTD "')", - GetGUIDLow(), GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx),uint64(m_lastDailyQuestTime)); -} - -void Player::_SaveReputation() -{ - for(FactionStateList::iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) - { - if (itr->second.Changed) - { - CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u' AND faction='%u'", GetGUIDLow(), itr->second.ID); - CharacterDatabase.PExecute("INSERT INTO character_reputation (guid,faction,standing,flags) VALUES ('%u', '%u', '%i', '%u')", GetGUIDLow(), itr->second.ID, itr->second.Standing, itr->second.Flags); - itr->second.Changed = false; - } - } -} - -void Player::_SaveSpells() -{ - for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next) - { - ++next; - if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED) - CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first); - if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED) - CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,slot,active,disabled) VALUES ('%u', '%u', '%u','%u','%u')", GetGUIDLow(), itr->first, itr->second->slotId,itr->second->active ? 1 : 0,itr->second->disabled ? 1 : 0); - - if (itr->second->state == PLAYERSPELL_REMOVED) - _removeSpell(itr->first); - else - itr->second->state = PLAYERSPELL_UNCHANGED; - } -} - -void Player::_SaveTutorials() -{ - if(!m_TutorialsChanged) - return; - - uint32 Rows=0; - // it's better than rebuilding indexes multiple times - QueryResult *result = CharacterDatabase.PQuery("SELECT count(*) AS r FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetSession()->GetAccountId(), realmID ); - if(result) - { - Rows = result->Fetch()[0].GetUInt32(); - delete result; - } - - if (Rows) - { - CharacterDatabase.PExecute("UPDATE character_tutorial SET tut0='%u', tut1='%u', tut2='%u', tut3='%u', tut4='%u', tut5='%u', tut6='%u', tut7='%u' WHERE account = '%u' AND realmid = '%u'", - m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7], GetSession()->GetAccountId(), realmID ); - } - else - { - CharacterDatabase.PExecute("INSERT INTO character_tutorial (account,realmid,tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", GetSession()->GetAccountId(), realmID, m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7]); - }; - - m_TutorialsChanged = false; -} - -void Player::outDebugValues() const -{ - if(!sLog.IsOutDebug()) // optimize disabled debug output - return; - - sLog.outDebug("HP is: \t\t\t%u\t\tMP is: \t\t\t%u",GetMaxHealth(), GetMaxPower(POWER_MANA)); - sLog.outDebug("AGILITY is: \t\t%f\t\tSTRENGTH is: \t\t%f",GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH)); - sLog.outDebug("INTELLECT is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_INTELLECT), GetStat(STAT_SPIRIT)); - sLog.outDebug("STAMINA is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_STAMINA), GetStat(STAT_SPIRIT)); - sLog.outDebug("Armor is: \t\t%u\t\tBlock is: \t\t%f",GetArmor(), GetFloatValue(PLAYER_BLOCK_PERCENTAGE)); - sLog.outDebug("HolyRes is: \t\t%u\t\tFireRes is: \t\t%u",GetResistance(SPELL_SCHOOL_HOLY), GetResistance(SPELL_SCHOOL_FIRE)); - sLog.outDebug("NatureRes is: \t\t%u\t\tFrostRes is: \t\t%u",GetResistance(SPELL_SCHOOL_NATURE), GetResistance(SPELL_SCHOOL_FROST)); - sLog.outDebug("ShadowRes is: \t\t%u\t\tArcaneRes is: \t\t%u",GetResistance(SPELL_SCHOOL_SHADOW), GetResistance(SPELL_SCHOOL_ARCANE)); - sLog.outDebug("MIN_DAMAGE is: \t\t%f\tMAX_DAMAGE is: \t\t%f",GetFloatValue(UNIT_FIELD_MINDAMAGE), GetFloatValue(UNIT_FIELD_MAXDAMAGE)); - sLog.outDebug("MIN_OFFHAND_DAMAGE is: \t%f\tMAX_OFFHAND_DAMAGE is: \t%f",GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE), GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)); - sLog.outDebug("MIN_RANGED_DAMAGE is: \t%f\tMAX_RANGED_DAMAGE is: \t%f",GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE), GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE)); - sLog.outDebug("ATTACK_TIME is: \t%u\t\tRANGE_ATTACK_TIME is: \t%u",GetAttackTime(BASE_ATTACK), GetAttackTime(RANGED_ATTACK)); -} - -/*********************************************************/ -/*** FLOOD FILTER SYSTEM ***/ -/*********************************************************/ - -void Player::UpdateSpeakTime() -{ - // ignore chat spam protection for GMs in any mode - if(GetSession()->GetSecurity() > SEC_PLAYER) - return; - - time_t current = time (NULL); - if(m_speakTime > current) - { - uint32 max_count = sWorld.getConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT); - if(!max_count) - return; - - ++m_speakCount; - if(m_speakCount >= max_count) - { - // prevent overwrite mute time, if message send just before mutes set, for example. - time_t new_mute = current + sWorld.getConfig(CONFIG_CHATFLOOD_MUTE_TIME); - if(GetSession()->m_muteTime < new_mute) - GetSession()->m_muteTime = new_mute; - - m_speakCount = 0; - } - } - else - m_speakCount = 0; - - m_speakTime = current + sWorld.getConfig(CONFIG_CHATFLOOD_MESSAGE_DELAY); -} - -bool Player::CanSpeak() const -{ - return GetSession()->m_muteTime <= time (NULL); -} - -/*********************************************************/ -/*** LOW LEVEL FUNCTIONS:Notifiers ***/ -/*********************************************************/ - -void Player::SendAttackSwingNotInRange() -{ - WorldPacket data(SMSG_ATTACKSWING_NOTINRANGE, 0); - GetSession()->SendPacket( &data ); -} - -void Player::SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint32 zone,uint64 guid) -{ - std::ostringstream ss; - ss << "UPDATE characters SET position_x='"<= tokens.size()) - return; - - tokens[index] = buf; -} - -void Player::SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid) -{ - Tokens tokens; - if(!LoadValuesArrayFromDB(tokens,guid)) - return; - - if(index >= tokens.size()) - return; - - char buf[11]; - snprintf(buf,11,"%u",value); - tokens[index] = buf; - - SaveValuesArrayInDB(tokens,guid); -} - -void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid) -{ - uint32 temp; - memcpy(&temp, &value, sizeof(value)); - Player::SetUInt32ValueInDB(index, temp, guid); -} - -void Player::SendAttackSwingNotStanding() -{ - WorldPacket data(SMSG_ATTACKSWING_NOTSTANDING, 0); - GetSession()->SendPacket( &data ); -} - -void Player::SendAttackSwingDeadTarget() -{ - WorldPacket data(SMSG_ATTACKSWING_DEADTARGET, 0); - GetSession()->SendPacket( &data ); -} - -void Player::SendAttackSwingCantAttack() -{ - WorldPacket data(SMSG_ATTACKSWING_CANT_ATTACK, 0); - GetSession()->SendPacket( &data ); -} - -void Player::SendAttackSwingCancelAttack() -{ - WorldPacket data(SMSG_CANCEL_COMBAT, 0); - GetSession()->SendPacket( &data ); -} - -void Player::SendAttackSwingBadFacingAttack() -{ - WorldPacket data(SMSG_ATTACKSWING_BADFACING, 0); - GetSession()->SendPacket( &data ); -} - -void Player::SendAutoRepeatCancel() -{ - WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, 0); - GetSession()->SendPacket( &data ); -} - -void Player::PlaySound(uint32 Sound, bool OnlySelf) -{ - WorldPacket data(SMSG_PLAY_SOUND, 4); - data << Sound; - if (OnlySelf) - GetSession()->SendPacket( &data ); - else - SendMessageToSet( &data, true ); -} - -void Player::SendExplorationExperience(uint32 Area, uint32 Experience) -{ - WorldPacket data( SMSG_EXPLORATION_EXPERIENCE, 8 ); - data << Area; - data << Experience; - GetSession()->SendPacket(&data); -} - -void Player::SendDungeonDifficulty(bool IsInGroup) -{ - uint8 val = 0x00000001; - WorldPacket data(MSG_SET_DUNGEON_DIFFICULTY, 12); - data << (uint32)GetDifficulty(); - data << uint32(val); - data << uint32(IsInGroup); - GetSession()->SendPacket(&data); -} - -void Player::SendResetFailedNotify(uint32 mapid) -{ - WorldPacket data(SMSG_RESET_FAILED_NOTIFY, 4); - data << uint32(mapid); - GetSession()->SendPacket(&data); -} - -/// Reset all solo instances and optionally send a message on success for each -void Player::ResetInstances(uint8 method) -{ - // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_JOIN - - // we assume that when the difficulty changes, all instances that can be reset will be - uint8 dif = GetDifficulty(); - - for (BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();) - { - InstanceSave *p = itr->second.save; - const MapEntry *entry = sMapStore.LookupEntry(itr->first); - if(!entry || !p->CanReset()) - { - ++itr; - continue; - } - - if(method == INSTANCE_RESET_ALL) - { - // the "reset all instances" method can only reset normal maps - if(dif == DIFFICULTY_HEROIC || entry->map_type == MAP_RAID) - { - ++itr; - continue; - } - } - - // if the map is loaded, reset it - Map *map = MapManager::Instance().FindMap(p->GetMapId(), p->GetInstanceId()); - if(map && map->IsDungeon()) - ((InstanceMap*)map)->Reset(method); - - // since this is a solo instance there should not be any players inside - if(method == INSTANCE_RESET_ALL || method == INSTANCE_RESET_CHANGE_DIFFICULTY) - SendResetInstanceSuccess(p->GetMapId()); - - p->DeleteFromDB(); - m_boundInstances[dif].erase(itr++); - - // the following should remove the instance save from the manager and delete it as well - p->RemovePlayer(this); - } -} - -void Player::SendResetInstanceSuccess(uint32 MapId) -{ - WorldPacket data(SMSG_INSTANCE_RESET, 4); - data << MapId; - GetSession()->SendPacket(&data); -} - -void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) -{ - // TODO: find what other fail reasons there are besides players in the instance - WorldPacket data(SMSG_INSTANCE_RESET_FAILED, 4); - data << reason; - data << MapId; - GetSession()->SendPacket(&data); -} - -/*********************************************************/ -/*** Update timers ***/ -/*********************************************************/ - -///checks the 15 afk reports per 5 minutes limit -void Player::UpdateAfkReport(time_t currTime) -{ - if(m_bgAfkReportedTimer <= currTime) - { - m_bgAfkReportedCount = 0; - m_bgAfkReportedTimer = currTime+5*MINUTE; - } -} - -void Player::UpdateContestedPvP(uint32 diff) -{ - if(!m_contestedPvPTimer||isInCombat()) - return; - if(m_contestedPvPTimer <= diff) - { - ResetContestedPvP(); - } - else - m_contestedPvPTimer -= diff; -} - -void Player::UpdatePvPFlag(time_t currTime) -{ - if(!IsPvP()) - return; - if(pvpInfo.endTimer == 0 || currTime < (pvpInfo.endTimer + 300)) - return; - - UpdatePvP(false); -} - -void Player::UpdateDuelFlag(time_t currTime) -{ - if(!duel || duel->startTimer == 0 ||currTime < duel->startTimer + 3) - return; - - SetUInt32Value(PLAYER_DUEL_TEAM, 1); - duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 2); - - duel->startTimer = 0; - duel->startTime = currTime; - duel->opponent->duel->startTimer = 0; - duel->opponent->duel->startTime = currTime; -} - -void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) -{ - if(!pet) - pet = GetPet(); - - if(returnreagent && (pet || m_temporaryUnsummonedPetNumber)) - { - //returning of reagents only for players, so best done here - uint32 spellId = pet ? pet->GetUInt32Value(UNIT_CREATED_BY_SPELL) : m_oldpetspell; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - - if(spellInfo) - { - for(uint32 i = 0; i < 7; ++i) - { - if(spellInfo->Reagent[i] > 0) - { - ItemPosCountVec dest; //for succubus, voidwalker, felhunter and felguard credit soulshard when despawn reason other than death (out of range, logout) - uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, spellInfo->Reagent[i], spellInfo->ReagentCount[i] ); - if( msg == EQUIP_ERR_OK ) - { - Item* item = StoreNewItem( dest, spellInfo->Reagent[i], true); - if(IsInWorld()) - SendNewItem(item,spellInfo->ReagentCount[i],true,false); - } - } - } - } - m_temporaryUnsummonedPetNumber = 0; - } - - if(!pet || pet->GetOwnerGUID()!=GetGUID()) - return; - - // only if current pet in slot - switch(pet->getPetType()) - { - case MINI_PET: - m_miniPet = 0; - break; - case GUARDIAN_PET: - m_guardianPets.erase(pet->GetGUID()); - break; - default: - if(GetPetGUID()==pet->GetGUID()) - SetPet(0); - break; - } - - pet->CombatStop(); - - if(returnreagent) - { - switch(pet->GetEntry()) - { - //warlock pets except imp are removed(?) when logging out - case 1860: - case 1863: - case 417: - case 17252: - mode = PET_SAVE_NOT_IN_SLOT; - break; - } - } - - pet->SavePetToDB(mode); - - pet->CleanupsBeforeDelete(); - pet->AddObjectToRemoveList(); - pet->m_removed = true; - - if(pet->isControlled()) - { - WorldPacket data(SMSG_PET_SPELLS, 8); - data << uint64(0); - GetSession()->SendPacket(&data); - - if(GetGroup()) - SetGroupUpdateFlag(GROUP_UPDATE_PET); - } -} - - -void Player::RemoveMiniPet() -{ - if(Pet* pet = GetMiniPet()) - { - pet->Remove(PET_SAVE_AS_DELETED); - m_miniPet = 0; - } -} - -Pet* Player::GetMiniPet() -{ - if(!m_miniPet) - return NULL; - return ObjectAccessor::GetPet(m_miniPet); -} - -void Player::RemoveGuardians() -{ - while(!m_guardianPets.empty()) - { - uint64 guid = *m_guardianPets.begin(); - if(Pet* pet = ObjectAccessor::GetPet(guid)) - pet->Remove(PET_SAVE_AS_DELETED); - - m_guardianPets.erase(guid); - } -} - -bool Player::HasGuardianWithEntry(uint32 entry) -{ - // pet guid middle part is entry (and creature also) - // and in guardian list must be guardians with same entry _always_ - for(GuardianPetList::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) - if(GUID_ENPART(*itr)==entry) - return true; - - return false; -} - -void Player::Uncharm() -{ - Unit* charm = GetCharm(); - if(!charm) - return; - - charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM); - charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS); -} - -void Player::BuildPlayerChat(WorldPacket *data, uint8 msgtype, std::string text, uint32 language) const -{ - bool pre = (msgtype==CHAT_MSG_EMOTE); - - *data << (uint8)msgtype; - *data << (uint32)language; - *data << (uint64)GetGUID(); - *data << (uint32)language; //language 2.1.0 ? - *data << (uint64)GetGUID(); - *data << (uint32)(text.length()+1+(pre?3:0)); - if(pre) - data->append("%s ",3); - *data << text; - *data << (uint8)chatTag(); -} - -void Player::Say(const std::string text, const uint32 language) -{ - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_SAY, text, language); - SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),true); -} - -void Player::Yell(const std::string text, const uint32 language) -{ - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_YELL, text, language); - SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),true); -} - -void Player::TextEmote(const std::string text) -{ - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL); - SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true, !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) ); -} - -void Player::Whisper(std::string text, uint32 language,uint64 receiver) -{ - if (language != LANG_ADDON) // if not addon data - language = LANG_UNIVERSAL; // whispers should always be readable - - Player *rPlayer = objmgr.GetPlayer(receiver); - - // when player you are whispering to is dnd, he cannot receive your message, unless you are in gm mode - if(!rPlayer->isDND() || isGameMaster()) - { - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_WHISPER, text, language); - rPlayer->GetSession()->SendPacket(&data); - - data.Initialize(SMSG_MESSAGECHAT, 200); - rPlayer->BuildPlayerChat(&data, CHAT_MSG_REPLY, text, language); - GetSession()->SendPacket(&data); - } - else - { - // announce to player that player he is whispering to is dnd and cannot receive his message - ChatHandler(this).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName(), rPlayer->dndMsg.c_str()); - } - - if(!isAcceptWhispers()) - { - SetAcceptWhispers(true); - ChatHandler(this).SendSysMessage(LANG_COMMAND_WHISPERON); - } - - // announce to player that player he is whispering to is afk - if(rPlayer->isAFK()) - ChatHandler(this).PSendSysMessage(LANG_PLAYER_AFK, rPlayer->GetName(), rPlayer->afkMsg.c_str()); - - // if player whisper someone, auto turn of dnd to be able to receive an answer - if(isDND() && !rPlayer->isGameMaster()) - ToggleDND(); -} - -void Player::PetSpellInitialize() -{ - Pet* pet = GetPet(); - - if(pet) - { - uint8 addlist = 0; - - sLog.outDebug("Pet Spells Groups"); - - CreatureInfo const *cinfo = pet->GetCreatureInfo(); - - if(pet->isControlled() && (pet->getPetType() == HUNTER_PET || cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)) - { - for(PetSpellMap::iterator itr = pet->m_spells.begin();itr != pet->m_spells.end();itr++) - { - if(itr->second->state == PETSPELL_REMOVED) - continue; - ++addlist; - } - } - - // first line + actionbar + spellcount + spells + last adds - WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25); - - CharmInfo *charmInfo = pet->GetCharmInfo(); - - //16 - data << (uint64)pet->GetGUID() << uint32(0x00000000) << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); - - for(uint32 i = 0; i < 10; i++) //40 - { - data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); - } - - data << uint8(addlist); //1 - - if(addlist && pet->isControlled()) - { - for (PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr) - { - if(itr->second->state == PETSPELL_REMOVED) - continue; - - data << uint16(itr->first); - data << uint16(itr->second->active); // pet spell active state isn't boolean - } - } - - //data << uint8(0x01) << uint32(0x6010) << uint32(0x01) << uint32(0x05) << uint16(0x00); //15 - uint8 count = 3; //1+8+8+8=25 - - // if count = 0, then end of packet... - data << count; - // uint32 value is spell id... - // uint64 value is constant 0, unknown... - data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3 - //data << uint32(0x5fd1) << uint64(0); // if count = 2 - data << uint32(0x8e8c) << uint64(0); // if count = 3 - data << uint32(0x8e8b) << uint64(0); // if count = 3 - - GetSession()->SendPacket(&data); - } -} - -void Player::PossessSpellInitialize() -{ - Unit* charm = GetCharm(); - - if(!charm) - return; - - CharmInfo *charmInfo = charm->GetCharmInfo(); - - if(!charmInfo) - { - sLog.outError("Player::PossessSpellInitialize(): charm ("I64FMTD") has no charminfo!", charm->GetGUID()); - return; - } - - uint8 addlist = 0; - WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds - - //16 - data << (uint64)charm->GetGUID() << uint32(0x00000000) << uint8(0) << uint8(0) << uint16(0); - - for(uint32 i = 0; i < 10; i++) //40 - { - data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); - } - - data << uint8(addlist); //1 - - uint8 count = 3; - data << count; - data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3 - data << uint32(0x8e8c) << uint64(0); // if count = 3 - data << uint32(0x8e8b) << uint64(0); // if count = 3 - - GetSession()->SendPacket(&data); -} - -void Player::CharmSpellInitialize() -{ - Unit* charm = GetCharm(); - - if(!charm) - return; - - CharmInfo *charmInfo = charm->GetCharmInfo(); - if(!charmInfo) - { - sLog.outError("Player::CharmSpellInitialize(): the player's charm ("I64FMTD") has no charminfo!", charm->GetGUID()); - return; - } - - uint8 addlist = 0; - - if(charm->GetTypeId() != TYPEID_PLAYER) - { - CreatureInfo const *cinfo = ((Creature*)charm)->GetCreatureInfo(); - - if(cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK) - { - for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) - { - if(charmInfo->GetCharmSpell(i)->spellId) - ++addlist; - } - } - } - - WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds - - data << (uint64)charm->GetGUID() << uint32(0x00000000); - - if(charm->GetTypeId() != TYPEID_PLAYER) - data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()); - else - data << uint8(0) << uint8(0); - - data << uint16(0); - - for(uint32 i = 0; i < 10; i++) //40 - { - data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); - } - - data << uint8(addlist); //1 - - if(addlist) - { - for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) - { - CharmSpellEntry *cspell = charmInfo->GetCharmSpell(i); - if(cspell->spellId) - { - data << uint16(cspell->spellId); - data << uint16(cspell->active); - } - } - } - - uint8 count = 3; - data << count; - data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3 - data << uint32(0x8e8c) << uint64(0); // if count = 3 - data << uint32(0x8e8b) << uint64(0); // if count = 3 - - GetSession()->SendPacket(&data); -} - -int32 Player::GetTotalFlatMods(uint32 spellId, SpellModOp op) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) return 0; - int32 total = 0; - for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr) - { - SpellModifier *mod = *itr; - - if(!IsAffectedBySpellmod(spellInfo,mod)) - continue; - - if (mod->type == SPELLMOD_FLAT) - total += mod->value; - } - return total; -} - -int32 Player::GetTotalPctMods(uint32 spellId, SpellModOp op) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) return 0; - int32 total = 0; - for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr) - { - SpellModifier *mod = *itr; - - if(!IsAffectedBySpellmod(spellInfo,mod)) - continue; - - if (mod->type == SPELLMOD_PCT) - total += mod->value; - } - return total; -} - -bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell) -{ - if (!mod || !spellInfo) - return false; - - if(mod->charges == -1 && mod->lastAffected ) // marked as expired but locked until spell casting finish - { - // prevent apply to any spell except spell that trigger expire - if(spell) - { - if(mod->lastAffected != spell) - return false; - } - else if(mod->lastAffected != FindCurrentSpellBySpellId(spellInfo->Id)) - return false; - } - - return spellmgr.IsAffectedBySpell(spellInfo,mod->spellId,mod->effectId,mod->mask); -} - -void Player::AddSpellMod(SpellModifier* mod, bool apply) -{ - uint16 Opcode= (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; - - for(int eff=0;eff<64;++eff) - { - uint64 _mask = uint64(1) << eff; - if ( mod->mask & _mask) - { - int32 val = 0; - for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr) - { - if ((*itr)->type == mod->type && (*itr)->mask & _mask) - val += (*itr)->value; - } - val += apply ? mod->value : -(mod->value); - WorldPacket data(Opcode, (1+1+4)); - data << uint8(eff); - data << uint8(mod->op); - data << int32(val); - SendDirectMessage(&data); - } - } - - if (apply) - m_spellMods[mod->op].push_back(mod); - else - { - if (mod->charges == -1) - --m_SpellModRemoveCount; - m_spellMods[mod->op].remove(mod); - delete mod; - } -} - -void Player::RemoveSpellMods(Spell const* spell) -{ - if(!spell || (m_SpellModRemoveCount == 0)) - return; - - for(int i=0;icharges == -1 && (mod->lastAffected == spell || mod->lastAffected==NULL)) - { - RemoveAurasDueToSpell(mod->spellId); - if (m_spellMods[i].empty()) - break; - else - itr = m_spellMods[i].begin(); - } - } - } -} - -// send Proficiency -void Player::SendProficiency(uint8 pr1, uint32 pr2) -{ - WorldPacket data(SMSG_SET_PROFICIENCY, 8); - data << pr1 << pr2; - GetSession()->SendPacket (&data); -} - -void Player::RemovePetitionsAndSigns(uint64 guid, uint32 type) -{ - QueryResult *result = NULL; - if(type==10) - result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid)); - else - result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); - if(result) - { - do // this part effectively does nothing, since the deletion / modification only takes place _after_ the PetitionQuery. Though I don't know if the result remains intact if I execute the delete query beforehand. - { // and SendPetitionQueryOpcode reads data from the DB - Field *fields = result->Fetch(); - uint64 ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - uint64 petitionguid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_ITEM); - - // send update if charter owner in game - Player* owner = objmgr.GetPlayer(ownerguid); - if(owner) - owner->GetSession()->SendPetitionQueryOpcode(petitionguid); - - } while ( result->NextRow() ); - - delete result; - - if(type==10) - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid)); - else - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); - } - - CharacterDatabase.BeginTransaction(); - if(type == 10) - { - CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u'", GUID_LOPART(guid)); - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u'", GUID_LOPART(guid)); - } - else - { - CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); - } - CharacterDatabase.CommitTransaction(); -} - -void Player::SetRestBonus (float rest_bonus_new) -{ - // Prevent resting on max level - if(getLevel() >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - rest_bonus_new = 0; - - if(rest_bonus_new < 0) - rest_bonus_new = 0; - - float rest_bonus_max = (float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)*1.5/2; - - if(rest_bonus_new > rest_bonus_max) - m_rest_bonus = rest_bonus_max; - else - m_rest_bonus = rest_bonus_new; - - // update data for client - if(m_rest_bonus>10) - SetByteValue(PLAYER_BYTES_2, 3, 0x01); // Set Reststate = Rested - else if(m_rest_bonus<=1) - SetByteValue(PLAYER_BYTES_2, 3, 0x02); // Set Reststate = Normal - - //RestTickUpdate - SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus)); -} - -void Player::HandleStealthedUnitsDetection() -{ - std::list stealthedUnits; - - CellPair p(MaNGOS::ComputeCellPair(GetPositionX(),GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::AnyStealthedCheck u_check; - MaNGOS::UnitListSearcher searcher(stealthedUnits, u_check); - - TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); - TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); - cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); - - for (std::list::iterator i = stealthedUnits.begin(); i != stealthedUnits.end();) - { - if((*i)==this) - { - i = stealthedUnits.erase(i); - continue; - } - - if ((*i)->isVisibleForOrDetect(this,true)) - { - - (*i)->SendUpdateToPlayer(this); - m_clientGUIDs.insert((*i)->GetGUID()); - - #ifdef MANGOS_DEBUG - if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) - sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i)); - #endif - - // target aura duration for caster show only if target exist at caster client - // send data at target visibility change (adding to client) - if((*i)!=this && (*i)->isType(TYPEMASK_UNIT)) - SendAuraDurationsForTarget(*i); - - i = stealthedUnits.erase(i); - continue; - } - - ++i; - } -} - -bool Player::ActivateTaxiPathTo(std::vector const& nodes, uint32 mount_id, Creature* npc) -{ - if(nodes.size() < 2) - return false; - - // not let cheating with start flight mounted - if(IsMounted()) - { - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIPLAYERALREADYMOUNTED); - GetSession()->SendPacket(&data); - return false; - } - - if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW ) - { - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIPLAYERSHAPESHIFTED); - GetSession()->SendPacket(&data); - return false; - } - - // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi - if(GetSession()->isLogingOut() || - (!m_currentSpells[CURRENT_GENERIC_SPELL] || - m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Effect[0] != SPELL_EFFECT_SEND_TAXI)&& - IsNonMeleeSpellCasted(false) || - isInCombat()) - { - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIPLAYERBUSY); - GetSession()->SendPacket(&data); - return false; - } - - if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) - return false; - - uint32 sourcenode = nodes[0]; - - // starting node too far away (cheat?) - TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(sourcenode); - if( !node || node->map_id != GetMapId() || - (node->x - GetPositionX())*(node->x - GetPositionX())+ - (node->y - GetPositionY())*(node->y - GetPositionY())+ - (node->z - GetPositionZ())*(node->z - GetPositionZ()) > - (2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE) ) - { - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR); - GetSession()->SendPacket(&data); - return false; - } - - // Prepare to flight start now - - // stop combat at start taxi flight if any - CombatStop(); - - // stop trade (client cancel trade at taxi map open but cheating tools can be used for reopen it) - TradeCancel(true); - - // clean not finished taxi path if any - m_taxi.ClearTaxiDestinations(); - - // 0 element current node - m_taxi.AddTaxiDestination(sourcenode); - - // fill destinations path tail - uint32 sourcepath = 0; - uint32 totalcost = 0; - - uint32 prevnode = sourcenode; - uint32 lastnode = 0; - - for(uint32 i = 1; i < nodes.size(); ++i) - { - uint32 path, cost; - - lastnode = nodes[i]; - objmgr.GetTaxiPath(prevnode, lastnode, path, cost); - - if(!path) - { - m_taxi.ClearTaxiDestinations(); - return false; - } - - totalcost += cost; - - if(prevnode == sourcenode) - sourcepath = path; - - m_taxi.AddTaxiDestination(lastnode); - - prevnode = lastnode; - } - - if(!mount_id) // if not provide then attempt use default. - mount_id = objmgr.GetTaxiMount(sourcenode, GetTeam()); - - if (mount_id == 0 || sourcepath == 0) - { - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR); - GetSession()->SendPacket(&data); - m_taxi.ClearTaxiDestinations(); - return false; - } - - uint32 money = GetMoney(); - - if(npc) - { - totalcost = (uint32)ceil(totalcost*GetReputationPriceDiscount(npc)); - } - - if(money < totalcost) - { - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXINOTENOUGHMONEY); - GetSession()->SendPacket(&data); - m_taxi.ClearTaxiDestinations(); - return false; - } - - //Checks and preparations done, DO FLIGHT - ModifyMoney(-(int32)totalcost); - - // prevent stealth flight - RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIOK); - GetSession()->SendPacket(&data); - - sLog.outDebug("WORLD: Sent SMSG_ACTIVATETAXIREPLY"); - - GetSession()->SendDoFlight(mount_id, sourcepath); - - return true; -} - -void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ) -{ - // last check 2.0.10 - WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+m_spells.size()*8); - data << GetGUID(); - data << uint8(0x0); - time_t curTime = time(NULL); - for(PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED) - continue; - uint32 unSpellId = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(unSpellId); - if (!spellInfo) - { - ASSERT(spellInfo); - continue; - } - - // Not send cooldown for this spells - if (spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) - continue; - - if((idSchoolMask & GetSpellSchoolMask(spellInfo)) && GetSpellCooldownDelay(unSpellId) < unTimeMs ) - { - data << unSpellId; - data << unTimeMs; // in m.secs - AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/1000); - } - } - GetSession()->SendPacket(&data); -} - -void Player::InitDataForForm(bool reapplyMods) -{ - SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(m_form); - if(ssEntry && ssEntry->attackSpeed) - { - SetAttackTime(BASE_ATTACK,ssEntry->attackSpeed); - SetAttackTime(OFF_ATTACK,ssEntry->attackSpeed); - SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME); - } - else - SetRegularAttackTime(); - - switch(m_form) - { - case FORM_CAT: - { - if(getPowerType()!=POWER_ENERGY) - setPowerType(POWER_ENERGY); - break; - } - case FORM_BEAR: - case FORM_DIREBEAR: - { - if(getPowerType()!=POWER_RAGE) - setPowerType(POWER_RAGE); - break; - } - default: // 0, for example - { - ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(getClass()); - if(cEntry && cEntry->powerType < MAX_POWERS && uint32(getPowerType()) != cEntry->powerType) - setPowerType(Powers(cEntry->powerType)); - break; - } - } - - // update auras at form change, ignore this at mods reapply (.reset stats/etc) when form not change. - if (!reapplyMods) - UpdateEquipSpellsAtFormChange(); - - UpdateAttackPowerAndDamage(); - UpdateAttackPowerAndDamage(true); -} - -// Return true is the bought item has a max count to force refresh of window by caller -bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot) -{ - // cheating attempt - if(count < 1) count = 1; - - if(!isAlive()) - return false; - - ItemPrototype const *pProto = objmgr.GetItemPrototype( item ); - if( !pProto ) - { - SendBuyError( BUY_ERR_CANT_FIND_ITEM, NULL, item, 0); - return false; - } - - Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*this, vendorguid,UNIT_NPC_FLAG_VENDOR); - if (!pCreature) - { - sLog.outDebug( "WORLD: BuyItemFromVendor - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) ); - SendBuyError( BUY_ERR_DISTANCE_TOO_FAR, NULL, item, 0); - return false; - } - - // load vendor items if not yet - pCreature->LoadGoods(); - - CreatureItem* crItem = pCreature->FindItem(item); - if(!crItem) - { - SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0); - return false; - } - - if( crItem->maxcount != 0 && crItem->count < count ) - { - SendBuyError( BUY_ERR_ITEM_ALREADY_SOLD, pCreature, item, 0); - return false; - } - - if( uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank) - { - SendBuyError( BUY_ERR_REPUTATION_REQUIRE, pCreature, item, 0); - return false; - } - - if(crItem->ExtendedCost) - { - ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); - if(!iece) - { - sLog.outError("Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); - return false; - } - - // honor points price - if(GetHonorPoints() < (iece->reqhonorpoints * count)) - { - SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL); - return false; - } - - // arena points price - if(GetArenaPoints() < (iece->reqarenapoints * count)) - { - SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL); - return false; - } - - // item base price - for (uint8 i = 0; i < 5; ++i) - { - if(iece->reqitem[i] && !HasItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count))) - { - SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); - return false; - } - } - - // check for personal arena rating requirement - if( GetMaxPersonalArenaRatingRequirement() < iece->reqpersonalarenarating ) - { - // probably not the proper equip err - SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK,NULL,NULL); - return false; - } - } - - uint32 price = pProto->BuyPrice * count; - - // reputation discount - price = uint32(floor(price * GetReputationPriceDiscount(pCreature))); - - if( GetMoney() < price ) - { - SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, item, 0); - return false; - } - - uint8 bag = 0; // init for case invalid bagGUID - - if (bagguid != NULL_BAG && slot != NULL_SLOT) - { - Bag *pBag; - if( bagguid == GetGUID() ) - { - bag = INVENTORY_SLOT_BAG_0; - } - else - { - for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;i++) - { - pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0,i); - if( pBag ) - { - if( bagguid == pBag->GetGUID() ) - { - bag = i; - break; - } - } - } - } - } - - if( IsInventoryPos( bag, slot ) || (bagguid == NULL_BAG && slot == NULL_SLOT) ) - { - ItemPosCountVec dest; - uint8 msg = CanStoreNewItem( bag, slot, dest, item, pProto->BuyCount * count ); - if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, NULL, NULL ); - return false; - } - - ModifyMoney( -(int32)price ); - if(crItem->ExtendedCost) // case for new honor system - { - ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); - if(iece->reqhonorpoints) - ModifyHonorPoints( - int32(iece->reqhonorpoints * count)); - if(iece->reqarenapoints) - ModifyArenaPoints( - int32(iece->reqarenapoints * count)); - for (uint8 i = 0; i < 5; ++i) - { - if(iece->reqitem[i]) - DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true); - } - } - - if(Item *it = StoreNewItem( dest, item, true )) - { - if( crItem->maxcount != 0 ) - crItem->count -= pProto->BuyCount * count; - - WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); - data << pCreature->GetGUID(); - data << (uint32)crItem->id; // entry - data << (uint32)crItem->count; - data << (uint32)count; - GetSession()->SendPacket(&data); - - SendNewItem(it, count, true, false, false); - } - } - else if( IsEquipmentPos( bag, slot ) ) - { - uint16 dest; - uint8 msg = CanEquipNewItem( slot, dest, item, pProto->BuyCount * count, false ); - if( msg != EQUIP_ERR_OK ) - { - SendEquipError( msg, NULL, NULL ); - return false; - } - - ModifyMoney( -(int32)price ); - if(crItem->ExtendedCost) // case for new honor system - { - ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); - if(iece->reqhonorpoints) - ModifyHonorPoints( - int32(iece->reqhonorpoints)); - if(iece->reqarenapoints) - ModifyArenaPoints( - int32(iece->reqarenapoints)); - for (uint8 i = 0; i < 5; ++i) - { - if(iece->reqitem[i]) - DestroyItemCount(iece->reqitem[i], iece->reqitemcount[i], true); - } - } - - if(Item *it = EquipNewItem( dest, item, pProto->BuyCount * count, true )) - { - if( crItem->maxcount != 0 ) - crItem->count -= pProto->BuyCount * count; - - WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); - data << pCreature->GetGUID(); - data << (uint32)crItem->id; // entry - data << (uint32)crItem->count; - data << (uint32)count; - GetSession()->SendPacket(&data); - - SendNewItem(it, count, true, false, false); - - AutoUnequipOffhandIfNeed(); - } - } - else - { - SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL ); - return false; - } - - return crItem->maxcount!=0?true:false; -} - -uint32 Player::GetMaxPersonalArenaRatingRequirement() -{ - // returns the maximal personal arena rating that can be used to purchase items requiring this condition - // the personal rating of the arena team must match the required limit as well - // so return max[in arenateams](min(personalrating[teamtype], teamrating[teamtype])) - uint32 max_personal_rating = 0; - for(int i = 0; i < MAX_ARENA_SLOT; ++i) - { - if(ArenaTeam * at = objmgr.GetArenaTeamById(GetArenaTeamId(i))) - { - uint32 p_rating = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (i * 6) + 5); - uint32 t_rating = at->GetRating(); - p_rating = p_ratingSendPacket(&data); - } - // instance is valid, reset homebind timer - m_HomebindTimer = 0; - } - else if (m_HomebindTimer > 0) - { - if (time >= m_HomebindTimer) - { - // teleport to homebind location - TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); - } - else - m_HomebindTimer -= time; - } - else - { - // instance is invalid, start homebind timer - m_HomebindTimer = 60000; - // send message to player - WorldPacket data(SMSG_RAID_GROUP_ONLY, 4+4); - data << m_HomebindTimer; - data << uint32(1); - GetSession()->SendPacket(&data); - sLog.outDebug("PLAYER: Player '%s' (GUID: %u) will be teleported to homebind in 60 seconds", GetName(),GetGUIDLow()); - } -} - -void Player::UpdatePvP(bool state, bool ovrride) -{ - if(!state || ovrride) - { - SetPvP(state); - if(Pet* pet = GetPet()) - pet->SetPvP(state); - if(Unit* charmed = GetCharm()) - charmed->SetPvP(state); - - pvpInfo.endTimer = 0; - } - else - { - if(pvpInfo.endTimer != 0) - pvpInfo.endTimer = time(NULL); - else - { - SetPvP(state); - - if(Pet* pet = GetPet()) - pet->SetPvP(state); - if(Unit* charmed = GetCharm()) - charmed->SetPvP(state); - } - } -} - -void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time) -{ - SpellCooldown sc; - sc.end = end_time; - sc.itemid = itemid; - m_spellCooldowns[spellid] = sc; -} - -void Player::SendCooldownEvent(SpellEntry const *spellInfo) -{ - if ( !(spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) ) - return; - - // Get spell cooldwn - int32 cooldown = GetSpellRecoveryTime(spellInfo); - // Apply spellmods - ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown); - if (cooldown < 0) - cooldown = 0; - // Add cooldown - AddSpellCooldown(spellInfo->Id, 0, time(NULL) + cooldown / 1000); - // Send activate - WorldPacket data(SMSG_COOLDOWN_EVENT, (4+8)); - data << spellInfo->Id; - data << GetGUID(); - SendDirectMessage(&data); -} - //slot to be excluded while counting -bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) -{ - if(!enchantmentcondition) - return true; - - SpellItemEnchantmentConditionEntry const *Condition = sSpellItemEnchantmentConditionStore.LookupEntry(enchantmentcondition); - - if(!Condition) - return true; - - uint8 curcount[4] = {0, 0, 0, 0}; - - //counting current equipped gem colors - for(uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) - { - if(i == slot) - continue; - Item *pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if(pItem2 && pItem2->GetProto()->Socket[0].Color) - { - for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) - { - uint32 enchant_id = pItem2->GetEnchantmentId(EnchantmentSlot(enchant_slot)); - if(!enchant_id) - continue; - - SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!enchantEntry) - continue; - - uint32 gemid = enchantEntry->GemID; - if(!gemid) - continue; - - ItemPrototype const* gemProto = sItemStorage.LookupEntry(gemid); - if(!gemProto) - continue; - - GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GemProperties); - if(!gemProperty) - continue; - - uint8 GemColor = gemProperty->color; - - for(uint8 b = 0, tmpcolormask = 1; b < 4; b++, tmpcolormask <<= 1) - { - if(tmpcolormask & GemColor) - ++curcount[b]; - } - } - } - } - - bool activate = true; - - for(int i = 0; i < 5; i++) - { - if(!Condition->Color[i]) - continue; - - uint32 _cur_gem = curcount[Condition->Color[i] - 1]; - - // if have use them as count, else use from Condition - uint32 _cmp_gem = Condition->CompareColor[i] ? curcount[Condition->CompareColor[i] - 1]: Condition->Value[i]; - - switch(Condition->Comparator[i]) - { - case 2: // requires less than ( || ) gems - activate &= (_cur_gem < _cmp_gem) ? true : false; - break; - case 3: // requires more than ( || ) gems - activate &= (_cur_gem > _cmp_gem) ? true : false; - break; - case 5: // requires at least than ( || ) gems - activate &= (_cur_gem >= _cmp_gem) ? true : false; - break; - } - } - - sLog.outDebug("Checking Condition %u, there are %u Meta Gems, %u Red Gems, %u Yellow Gems and %u Blue Gems, Activate:%s", enchantmentcondition, curcount[0], curcount[1], curcount[2], curcount[3], activate ? "yes" : "no"); - - return activate; -} - -void Player::CorrectMetaGemEnchants(uint8 exceptslot, bool apply) -{ - //cycle all equipped items - for(uint32 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) - { - //enchants for the slot being socketed are handled by Player::ApplyItemMods - if(slot == exceptslot) - continue; - - Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, slot ); - - if(!pItem || !pItem->GetProto()->Socket[0].Color) - continue; - - for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) - { - uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot)); - if(!enchant_id) - continue; - - SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!enchantEntry) - continue; - - uint32 condition = enchantEntry->EnchantmentCondition; - if(condition) - { - //was enchant active with/without item? - bool wasactive = EnchantmentFitsRequirements(condition, apply ? exceptslot : -1); - //should it now be? - if(wasactive ^ EnchantmentFitsRequirements(condition, apply ? -1 : exceptslot)) - { - // ignore item gem conditions - //if state changed, (dis)apply enchant - ApplyEnchantment(pItem,EnchantmentSlot(enchant_slot),!wasactive,true,true); - } - } - } - } -} - - //if false -> then toggled off if was on| if true -> toggled on if was off AND meets requirements -void Player::ToggleMetaGemsActive(uint8 exceptslot, bool apply) -{ - //cycle all equipped items - for(int slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) - { - //enchants for the slot being socketed are handled by WorldSession::HandleSocketOpcode(WorldPacket& recv_data) - if(slot == exceptslot) - continue; - - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, slot ); - - if(!pItem || !pItem->GetProto()->Socket[0].Color) //if item has no sockets or no item is equipped go to next item - continue; - - //cycle all (gem)enchants - for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) - { - uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot)); - if(!enchant_id) //if no enchant go to next enchant(slot) - continue; - - SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!enchantEntry) - continue; - - //only metagems to be (de)activated, so only enchants with condition - uint32 condition = enchantEntry->EnchantmentCondition; - if(condition) - ApplyEnchantment(pItem,EnchantmentSlot(enchant_slot), apply); - } - } -} - -void Player::LeaveBattleground(bool teleportToEntryPoint) -{ - if(BattleGround *bg = GetBattleGround()) - { - bool need_debuf = bg->isBattleGround() && (bg->GetStatus() == STATUS_IN_PROGRESS) && sWorld.getConfig(CONFIG_BATTLEGROUND_CAST_DESERTER); - - bg->RemovePlayerAtLeave(GetGUID(), teleportToEntryPoint, true); - - // call after remove to be sure that player resurrected for correct cast - if(need_debuf) - CastSpell(this, 26013, true); // Deserter - } -} - -bool Player::CanJoinToBattleground() const -{ - // check Deserter debuff - if(GetDummyAura(26013)) - return false; - - return true; -} - -bool Player::CanReportAfkDueToLimit() -{ - // a player can complain about 15 people per 5 minutes - if(m_bgAfkReportedCount >= 15) - return false; - ++m_bgAfkReportedCount; - return true; -} - -///This player has been blamed to be inactive in a battleground -void Player::ReportedAfkBy(Player* reporter) -{ - BattleGround *bg = GetBattleGround(); - if(!bg || bg != reporter->GetBattleGround() || GetTeam() != reporter->GetTeam()) - return; - - // check if player has 'Idle' or 'Inactive' debuff - if(m_bgAfkReporter.find(reporter->GetGUIDLow())==m_bgAfkReporter.end() && !HasAura(43680,0) && !HasAura(43681,0) && reporter->CanReportAfkDueToLimit()) - { - m_bgAfkReporter.insert(reporter->GetGUIDLow()); - // 3 players have to complain to apply debuff - if(m_bgAfkReporter.size() >= 3) - { - // cast 'Idle' spell - CastSpell(this, 43680, true); - m_bgAfkReporter.clear(); - } - } -} - -bool Player::IsVisibleInGridForPlayer( Player* pl ) const -{ - // gamemaster in GM mode see all, including ghosts - if(pl->isGameMaster() && GetSession()->GetSecurity() <= pl->GetSession()->GetSecurity()) - return true; - - // It seems in battleground everyone sees everyone, except the enemy-faction ghosts - if (InBattleGround()) - { - if (!(isAlive() || m_deathTimer > 0) && !IsFriendlyTo(pl) ) - return false; - return true; - } - - // Live player see live player or dead player with not realized corpse - if(pl->isAlive() || pl->m_deathTimer > 0) - { - return isAlive() || m_deathTimer > 0; - } - - // Ghost see other friendly ghosts, that's for sure - if(!(isAlive() || m_deathTimer > 0) && IsFriendlyTo(pl)) - return true; - - // Dead player see live players near own corpse - if(isAlive()) - { - Corpse *corpse = pl->GetCorpse(); - if(corpse) - { - // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level - if(corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO))) - return true; - } - } - - // and not see any other - return false; -} - -bool Player::IsVisibleGloballyFor( Player* u ) const -{ - if(!u) - return false; - - // Always can see self - if (u==this) - return true; - - // Visible units, always are visible for all players - if (GetVisibility() == VISIBILITY_ON) - return true; - - // GMs are visible for higher gms (or players are visible for gms) - if (u->GetSession()->GetSecurity() > SEC_PLAYER) - return GetSession()->GetSecurity() <= u->GetSession()->GetSecurity(); - - // non faction visibility non-breakable for non-GMs - if (GetVisibility() == VISIBILITY_OFF) - return false; - - // non-gm stealth/invisibility not hide from global player lists - return true; -} - -void Player::UpdateVisibilityOf(WorldObject* target) -{ - if(HaveAtClient(target)) - { - if(!target->isVisibleForInState(this,true)) - { - target->DestroyForPlayer(this); - m_clientGUIDs.erase(target->GetGUID()); - - #ifdef MANGOS_DEBUG - if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) - sLog.outDebug("Object %u (Type: %u) out of range for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),GetGUIDLow(),GetDistance(target)); - #endif - } - } - else - { - if(target->isVisibleForInState(this,false)) - { - target->SendUpdateToPlayer(this); - if(target->GetTypeId()!=TYPEID_GAMEOBJECT||!((GameObject*)target)->IsTransport()) - m_clientGUIDs.insert(target->GetGUID()); - - #ifdef MANGOS_DEBUG - if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) - sLog.outDebug("Object %u (Type: %u) is visible now for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),GetGUIDLow(),GetDistance(target)); - #endif - - // target aura duration for caster show only if target exist at caster client - // send data at target visibility change (adding to client) - if(target!=this && target->isType(TYPEMASK_UNIT)) - SendAuraDurationsForTarget((Unit*)target); - - if(target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isAlive()) - ((Creature*)target)->SendMonsterMoveWithSpeedToCurrentDestination(this); - } - } -} - -template -inline void UpdateVisibilityOf_helper(std::set& s64, T* target) -{ - s64.insert(target->GetGUID()); -} - -template<> -inline void UpdateVisibilityOf_helper(std::set& s64, GameObject* target) -{ - if(!target->IsTransport()) - s64.insert(target->GetGUID()); -} - -template -void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow) -{ - if(HaveAtClient(target)) - { - if(!target->isVisibleForInState(this,true)) - { - target->BuildOutOfRangeUpdateBlock(&data); - m_clientGUIDs.erase(target->GetGUID()); - - #ifdef MANGOS_DEBUG - if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) - sLog.outDebug("Object %u (Type: %u, Entry: %u) is out of range for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),target->GetEntry(),GetGUIDLow(),GetDistance(target)); - #endif - } - } - else - { - if(target->isVisibleForInState(this,false)) - { - visibleNow.insert(target); - target->BuildUpdate(data_updates); - target->BuildCreateUpdateBlockForPlayer(&data, this); - UpdateVisibilityOf_helper(m_clientGUIDs,target); - - #ifdef MANGOS_DEBUG - if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) - sLog.outDebug("Object %u (Type: %u, Entry: %u) is visible now for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),target->GetEntry(),GetGUIDLow(),GetDistance(target)); - #endif - } - } -} - -template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); - -void Player::InitPrimaryProffesions() -{ - SetFreePrimaryProffesions(sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)); -} - -void Player::SendComboPoints() -{ - Unit *combotarget = ObjectAccessor::GetUnit(*this, m_comboTarget); - if (combotarget) - { - WorldPacket data(SMSG_UPDATE_COMBO_POINTS, combotarget->GetPackGUID().size()+1); - data.append(combotarget->GetPackGUID()); - data << uint8(m_comboPoints); - GetSession()->SendPacket(&data); - } -} - -void Player::AddComboPoints(Unit* target, int8 count) -{ - if(!count) - return; - - // without combo points lost (duration checked in aura) - RemoveSpellsCausingAura(SPELL_AURA_RETAIN_COMBO_POINTS); - - if(target->GetGUID() == m_comboTarget) - { - m_comboPoints += count; - } - else - { - if(m_comboTarget) - if(Unit* target = ObjectAccessor::GetUnit(*this,m_comboTarget)) - target->RemoveComboPointHolder(GetGUIDLow()); - - m_comboTarget = target->GetGUID(); - m_comboPoints = count; - - target->AddComboPointHolder(GetGUIDLow()); - } - - if (m_comboPoints > 5) m_comboPoints = 5; - if (m_comboPoints < 0) m_comboPoints = 0; - - SendComboPoints(); -} - -void Player::ClearComboPoints() -{ - if(!m_comboTarget) - return; - - // without combopoints lost (duration checked in aura) - RemoveSpellsCausingAura(SPELL_AURA_RETAIN_COMBO_POINTS); - - m_comboPoints = 0; - - SendComboPoints(); - - if(Unit* target = ObjectAccessor::GetUnit(*this,m_comboTarget)) - target->RemoveComboPointHolder(GetGUIDLow()); - - m_comboTarget = 0; -} - -void Player::SetGroup(Group *group, int8 subgroup) -{ - if(group == NULL) m_group.unlink(); - else - { - // never use SetGroup without a subgroup unless you specify NULL for group - assert(subgroup >= 0); - m_group.link(group, this); - m_group.setSubGroup((uint8)subgroup); - } -} - -void Player::SendInitialPacketsBeforeAddToMap() -{ - WorldPacket data(SMSG_SET_REST_START, 4); - data << uint32(0); // unknown, may be rest state time or expirience - GetSession()->SendPacket(&data); - - // Homebind - data.Initialize(SMSG_BINDPOINTUPDATE, 5*4); - data << m_homebindX << m_homebindY << m_homebindZ; - data << (uint32) m_homebindMapId; - data << (uint32) m_homebindZoneId; - GetSession()->SendPacket(&data); - - // SMSG_SET_PROFICIENCY - // SMSG_UPDATE_AURA_DURATION - - // tutorial stuff - data.Initialize(SMSG_TUTORIAL_FLAGS, 8*4); - for (int i = 0; i < 8; ++i) - data << uint32( GetTutorialInt(i) ); - GetSession()->SendPacket(&data); - - SendInitialSpells(); - - data.Initialize(SMSG_SEND_UNLEARN_SPELLS, 4); - data << uint32(0); // count, for(count) uint32; - GetSession()->SendPacket(&data); - - SendInitialActionButtons(); - SendInitialReputations(); - UpdateZone(GetZoneId()); - SendInitWorldStates(); - - // SMSG_SET_AURA_SINGLE - - data.Initialize(SMSG_LOGIN_SETTIMESPEED, 8); - data << uint32(secsToTimeBitFields(sWorld.GetGameTime())); - data << (float)0.01666667f; // game speed - GetSession()->SendPacket( &data ); -} - -void Player::SendInitialPacketsAfterAddToMap() -{ - CastSpell(this, 836, true); // LOGINEFFECT - - // set some aura effects that send packet to player client after add player to map - // SendMessageToSet not send it to player not it map, only for aura that not changed anything at re-apply - // same auras state lost at far teleport, send it one more time in this case also - static const AuraType auratypes[] = - { - SPELL_AURA_MOD_FEAR, SPELL_AURA_TRANSFORM, SPELL_AURA_WATER_WALK, - SPELL_AURA_FEATHER_FALL, SPELL_AURA_HOVER, SPELL_AURA_SAFE_FALL, - SPELL_AURA_FLY, SPELL_AURA_NONE - }; - for(AuraType const* itr = &auratypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr) - { - Unit::AuraList const& auraList = GetAurasByType(*itr); - if(!auraList.empty()) - auraList.front()->ApplyModifier(true,true); - } - - if(HasAuraType(SPELL_AURA_MOD_STUN)) - SetMovement(MOVE_ROOT); - - // manual send package (have code in ApplyModifier(true,true); that don't must be re-applied. - if(HasAuraType(SPELL_AURA_MOD_ROOT)) - { - WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10); - data.append(GetPackGUID()); - data << (uint32)2; - SendMessageToSet(&data,true); - } - - SendEnchantmentDurations(); // must be after add to map - SendItemDurations(); // must be after add to map -} - -void Player::SendUpdateToOutOfRangeGroupMembers() -{ - if (m_groupUpdateMask == GROUP_UPDATE_FLAG_NONE) - return; - if(Group* group = GetGroup()) - group->UpdatePlayerOutOfRange(this); - - m_groupUpdateMask = GROUP_UPDATE_FLAG_NONE; - m_auraUpdateMask = 0; - if(Pet *pet = GetPet()) - pet->ResetAuraUpdateMask(); -} - -void Player::SendTransferAborted(uint32 mapid, uint16 reason) -{ - WorldPacket data(SMSG_TRANSFER_ABORTED, 4+2); - data << uint32(mapid); - data << uint16(reason); // transfer abort reason - GetSession()->SendPacket(&data); -} - -void Player::SendInstanceResetWarning(uint32 mapid, uint32 time) -{ - // type of warning, based on the time remaining until reset - uint32 type; - if(time > 3600) - type = RAID_INSTANCE_WELCOME; - else if(time > 900 && time <= 3600) - type = RAID_INSTANCE_WARNING_HOURS; - else if(time > 300 && time <= 900) - type = RAID_INSTANCE_WARNING_MIN; - else - type = RAID_INSTANCE_WARNING_MIN_SOON; - WorldPacket data(SMSG_RAID_INSTANCE_MESSAGE, 4+4+4); - data << uint32(type); - data << uint32(mapid); - data << uint32(time); - GetSession()->SendPacket(&data); -} - -void Player::ApplyEquipCooldown( Item * pItem ) -{ - for(int i = 0; i <5; ++i) - { - _Spell const& spellData = pItem->GetProto()->Spells[i]; - - // no spell - if( !spellData.SpellId ) - continue; - - // wrong triggering type (note: ITEM_SPELLTRIGGER_ON_NO_DELAY_USE not have cooldown) - if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE ) - continue; - - AddSpellCooldown(spellData.SpellId, pItem->GetEntry(), time(NULL) + 30); - - WorldPacket data(SMSG_ITEM_COOLDOWN, 12); - data << pItem->GetGUID(); - data << uint32(spellData.SpellId); - GetSession()->SendPacket(&data); - } -} - -void Player::resetSpells() -{ - // not need after this call - if(HasAtLoginFlag(AT_LOGIN_RESET_SPELLS)) - { - m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_SPELLS; - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_SPELLS), GetGUIDLow()); - } - - // make full copy of map (spells removed and marked as deleted at another spell remove - // and we can't use original map for safe iterative with visit each spell at loop end - PlayerSpellMap smap = GetSpellMap(); - - for(PlayerSpellMap::const_iterator iter = smap.begin();iter != smap.end(); ++iter) - removeSpell(iter->first); // only iter->first can be accessed, object by iter->second can be deleted already - - learnDefaultSpells(); - learnQuestRewardedSpells(); -} - -void Player::learnDefaultSpells(bool loading) -{ - // learn default race/class spells - PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(),getClass()); - std::list::const_iterator spell_itr; - for (spell_itr = info->spell.begin(); spell_itr!=info->spell.end(); ++spell_itr) - { - uint16 tspell = spell_itr->first; - if (tspell) - { - sLog.outDebug("PLAYER: Adding initial spell, id = %u",tspell); - if(loading || !spell_itr->second) // not care about passive spells or loading case - addSpell(tspell,spell_itr->second); - else // but send in normal spell in game learn case - learnSpell(tspell); - } - } -} - -void Player::learnQuestRewardedSpells(Quest const* quest) -{ - uint32 spell_id = quest->GetRewSpellCast(); - - // skip quests without rewarded spell - if( !spell_id ) - return; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); - if(!spellInfo) - return; - - // check learned spells state - bool found = false; - for(int i=0; i < 3; ++i) - { - if(spellInfo->Effect[i] == SPELL_EFFECT_LEARN_SPELL && !HasSpell(spellInfo->EffectTriggerSpell[i])) - { - found = true; - break; - } - } - - // skip quests with not teaching spell or already known spell - if(!found) - return; - - // prevent learn non first rank unknown profession and second specialization for same profession) - uint32 learned_0 = spellInfo->EffectTriggerSpell[0]; - if( spellmgr.GetSpellRank(learned_0) > 1 && !HasSpell(learned_0) ) - { - // not have first rank learned (unlearned prof?) - uint32 first_spell = spellmgr.GetFirstSpellInChain(learned_0); - if( !HasSpell(first_spell) ) - return; - - SpellEntry const *learnedInfo = sSpellStore.LookupEntry(learned_0); - if(!learnedInfo) - return; - - // specialization - if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0) - { - // search other specialization for same prof - for(PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if(itr->second->state == PLAYERSPELL_REMOVED || itr->first==learned_0) - continue; - - SpellEntry const *itrInfo = sSpellStore.LookupEntry(itr->first); - if(!itrInfo) - return; - - // compare only specializations - if(itrInfo->Effect[0]!=SPELL_EFFECT_TRADE_SKILL || itrInfo->Effect[1]!=0) - continue; - - // compare same chain spells - if(spellmgr.GetFirstSpellInChain(itr->first) != first_spell) - continue; - - // now we have 2 specialization, learn possible only if found is lesser specialization rank - if(!spellmgr.IsHighRankOfSpell(learned_0,itr->first)) - return; - } - } - } - - CastSpell( this, spell_id, true); -} - -void Player::learnQuestRewardedSpells() -{ - // learn spells received from quest completing - for(QuestStatusMap::const_iterator itr = mQuestStatus.begin(); itr != mQuestStatus.end(); ++itr) - { - // skip no rewarded quests - if(!itr->second.m_rewarded) - continue; - - Quest const* quest = objmgr.GetQuestTemplate(itr->first); - if( !quest ) - continue; - - learnQuestRewardedSpells(quest); - } -} - -void Player::learnSkillRewardedSpells(uint32 skill_id ) -{ - uint32 raceMask = getRaceMask(); - uint32 classMask = getClassMask(); - for (uint32 j=0; jskillId!=skill_id || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL) - continue; - // Check race if set - if (pAbility->racemask && !(pAbility->racemask & raceMask)) - continue; - // Check class if set - if (pAbility->classmask && !(pAbility->classmask & classMask)) - continue; - - if (SpellEntry const* spellentry = sSpellStore.LookupEntry(pAbility->spellId)) - { - // Ok need learn spell - learnSpell(pAbility->spellId); - } - } -} - -void Player::learnSkillRewardedSpells() -{ - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - { - if(!GetUInt32Value(PLAYER_SKILL_INDEX(i))) - continue; - - uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; - - learnSkillRewardedSpells(pskill); - } -} - -void Player::SendAuraDurationsForTarget(Unit* target) -{ - for(Unit::AuraMap::const_iterator itr = target->GetAuras().begin(); itr != target->GetAuras().end(); ++itr) - { - Aura* aura = itr->second; - if(aura->GetAuraSlot() >= MAX_AURAS || aura->IsPassive() || aura->GetCasterGUID()!=GetGUID()) - continue; - - aura->SendAuraDurationForCaster(this); - } -} - -void Player::SetDailyQuestStatus( uint32 quest_id ) -{ - for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) - { - if(!GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)) - { - SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,quest_id); - m_lastDailyQuestTime = time(NULL); // last daily quest time - m_DailyQuestChanged = true; - break; - } - } -} - -void Player::ResetDailyQuestStatus() -{ - for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) - SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,0); - - // DB data deleted in caller - m_DailyQuestChanged = false; - m_lastDailyQuestTime = 0; -} - -BattleGround* Player::GetBattleGround() const -{ - if(GetBattleGroundId()==0) - return NULL; - - return sBattleGroundMgr.GetBattleGround(GetBattleGroundId()); -} - -bool Player::InArena() const -{ - BattleGround *bg = GetBattleGround(); - if(!bg || !bg->isArena()) - return false; - - return true; -} - -bool Player::GetBGAccessByLevel(uint32 bgTypeId) const -{ - BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId); - if(!bg) - return false; - - if(getLevel() < bg->GetMinLevel() || getLevel() > bg->GetMaxLevel()) - return false; - - return true; -} - -uint32 Player::GetMinLevelForBattleGroundQueueId(uint32 queue_id) -{ - if(queue_id < 1) - return 0; - - if(queue_id >=6) - queue_id = 6; - - return 10*(queue_id+1); -} - -uint32 Player::GetMaxLevelForBattleGroundQueueId(uint32 queue_id) -{ - if(queue_id >=6) - return 255; // hardcoded max level - - return 10*(queue_id+2)-1; -} - -uint32 Player::GetBattleGroundQueueIdFromLevel() const -{ - uint32 level = getLevel(); - if(level <= 19) - return 0; - else if (level > 69) - return 6; - else - return level/10 - 1; // 20..29 -> 1, 30-39 -> 2, ... -} - -float Player::GetReputationPriceDiscount( Creature const* pCreature ) const -{ - FactionTemplateEntry const* vendor_faction = pCreature->getFactionTemplateEntry(); - if(!vendor_faction) - return 1.0f; - - ReputationRank rank = GetReputationRank(vendor_faction->faction); - if(rank <= REP_NEUTRAL) - return 1.0f; - - return 1.0f - 0.05f* (rank - REP_NEUTRAL); -} - -bool Player::IsSpellFitByClassAndRace( uint32 spell_id ) const -{ - uint32 racemask = getRaceMask(); - uint32 classmask = getClassMask(); - - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id); - - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - // skip wrong race skills - if( _spell_idx->second->racemask && (_spell_idx->second->racemask & racemask) == 0) - return false; - - // skip wrong class skills - if( _spell_idx->second->classmask && (_spell_idx->second->classmask & classmask) == 0) - return false; - } - return true; -} - -bool Player::HasQuestForGO(int32 GOId) -{ - for( QuestStatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i ) - { - QuestStatusData qs=i->second; - if (qs.m_status == QUEST_STATUS_INCOMPLETE) - { - Quest const* qinfo = objmgr.GetQuestTemplate(i->first); - if(!qinfo) - continue; - - if(GetGroup() && GetGroup()->isRaidGroup() && qinfo->GetType() != QUEST_TYPE_RAID) - continue; - - for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) - { - if (qinfo->ReqCreatureOrGOId[j]>=0) //skip non GO case - continue; - - if((-1)*GOId == qinfo->ReqCreatureOrGOId[j] && qs.m_creatureOrGOcount[j] < qinfo->ReqCreatureOrGOCount[j]) - return true; - } - } - } - return false; -} - -void Player::UpdateForQuestsGO() -{ - if(m_clientGUIDs.empty()) - return; - - UpdateData udata; - WorldPacket packet; - for(ClientGUIDs::iterator itr=m_clientGUIDs.begin(); itr!=m_clientGUIDs.end(); ++itr) - { - if(IS_GAMEOBJECT_GUID(*itr)) - { - GameObject *obj = HashMapHolder::Find(*itr); - if(obj) - obj->BuildValuesUpdateBlockForPlayer(&udata,this); - } - } - udata.BuildPacket(&packet); - GetSession()->SendPacket(&packet); -} - -void Player::SummonIfPossible(bool agree) -{ - if(!agree) - { - m_summon_expire = 0; - return; - } - - // expire and auto declined - if(m_summon_expire < time(NULL)) - return; - - // stop taxi flight at summon - if(isInFlight()) - { - GetMotionMaster()->MovementExpired(); - m_taxi.ClearTaxiDestinations(); - } - - // drop flag at summon - if(BattleGround *bg = GetBattleGround()) - bg->EventPlayerDroppedFlag(this); - - m_summon_expire = 0; - - TeleportTo(m_summon_mapid, m_summon_x, m_summon_y, m_summon_z,GetOrientation()); -} - -void Player::RemoveItemDurations( Item *item ) -{ - for(ItemDurationList::iterator itr = m_itemDuration.begin();itr != m_itemDuration.end(); ++itr) - { - if(*itr==item) - { - m_itemDuration.erase(itr); - break; - } - } -} - -void Player::AddItemDurations( Item *item ) -{ - if(item->GetUInt32Value(ITEM_FIELD_DURATION)) - { - m_itemDuration.push_back(item); - item->SendTimeUpdate(this); - } -} - -void Player::AutoUnequipOffhandIfNeed() -{ - Item *offItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND ); - if(!offItem) - return; - - Item *mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ); - - if(!mainItem || mainItem->GetProto()->InventoryType != INVTYPE_2HWEAPON) - return; - - ItemPosCountVec off_dest; - uint8 off_msg = CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ); - if( off_msg == EQUIP_ERR_OK ) - { - RemoveItem(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND, true); - StoreItem( off_dest, offItem, true ); - } - else - { - sLog.outError("Player::EquipItem: Can's store offhand item at 2hand item equip for player (GUID: %u).",GetGUIDLow()); - } -} - -bool Player::HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item const* ignoreItem) -{ - if(spellInfo->EquippedItemClass < 0) - return true; - - // scan other equipped items for same requirements (mostly 2 daggers/etc) - // for optimize check 2 used cases only - switch(spellInfo->EquippedItemClass) - { - case ITEM_CLASS_WEAPON: - { - for(int i= EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_TABARD; ++i) - if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo)) - return true; - break; - } - case ITEM_CLASS_ARMOR: - { - // tabard not have dependent spells - for(int i= EQUIPMENT_SLOT_START; i< EQUIPMENT_SLOT_MAINHAND; ++i) - if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) - if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo)) - return true; - - // shields can be equipped to offhand slot - if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) - if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo)) - return true; - - // ranged slot can have some armor subclasses - if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED)) - if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo)) - return true; - - break; - } - default: - sLog.outError("HasItemFitToSpellReqirements: Not handeled spell reqirement for item class %u",spellInfo->EquippedItemClass); - break; - } - - return false; -} - -void Player::RemoveItemDependentAurasAndCasts( Item * pItem ) -{ - AuraMap& auras = GetAuras(); - for(AuraMap::iterator itr = auras.begin(); itr != auras.end(); ) - { - Aura* aura = itr->second; - - // skip passive (passive item dependent spells work in another way) and not self applied auras - SpellEntry const* spellInfo = aura->GetSpellProto(); - if(aura->IsPassive() || aura->GetCasterGUID()!=GetGUID()) - { - ++itr; - continue; - } - - // skip if not item dependent or have alternative item - if(HasItemFitToSpellReqirements(spellInfo,pItem)) - { - ++itr; - continue; - } - - // no alt item, remove aura, restart check - RemoveAurasDueToSpell(aura->GetId()); - itr = auras.begin(); - } - - // currently casted spells can be dependent from item - for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) - { - if( m_currentSpells[i] && m_currentSpells[i]->getState()!=SPELL_STATE_DELAYED && - !HasItemFitToSpellReqirements(m_currentSpells[i]->m_spellInfo,pItem) ) - InterruptSpell(i); - } -} - -uint32 Player::GetResurrectionSpellId() -{ - // search priceless resurrection possabilities - uint32 prio = 0; - uint32 spell_id = 0; - AuraList const& dummyAuras = GetAurasByType(SPELL_AURA_DUMMY); - for(AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr) - { - // Soulstone Resurrection // prio: 3 (max, non death persistent) - if( prio < 2 && (*itr)->GetSpellProto()->SpellVisual == 99 && (*itr)->GetSpellProto()->SpellIconID == 92 ) - { - switch((*itr)->GetId()) - { - case 20707: spell_id = 3026; break; // rank 1 - case 20762: spell_id = 20758; break; // rank 2 - case 20763: spell_id = 20759; break; // rank 3 - case 20764: spell_id = 20760; break; // rank 4 - case 20765: spell_id = 20761; break; // rank 5 - case 27239: spell_id = 27240; break; // rank 6 - default: - sLog.outError("Unhandled spell %%u: S.Resurrection",(*itr)->GetId()); - continue; - } - - prio = 3; - } - // Twisting Nether // prio: 2 (max) - else if((*itr)->GetId()==23701 && roll_chance_i(10)) - { - prio = 2; - spell_id = 23700; - } - } - - // Reincarnation (passive spell) // prio: 1 - if(prio < 1 && HasSpell(20608) && !HasSpellCooldown(21169) && HasItemCount(17030,1)) - spell_id = 21169; - - return spell_id; -} - -bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim) -{ - bool PvP = pVictim->isCharmedOwnedByPlayerOrPlayer(); - - // prepare data for near group iteration (PvP and !PvP cases) - uint32 xp = 0; - bool honored_kill = false; - - if(Group *pGroup = GetGroup()) - { - uint32 count = 0; - uint32 sum_level = 0; - Player* member_with_max_level = NULL; - - pGroup->GetDataForXPAtKill(pVictim,count,sum_level,member_with_max_level); - - if(member_with_max_level) - { - xp = PvP ? 0 : MaNGOS::XP::Gain(member_with_max_level, pVictim); - - // skip in check PvP case (for speed, not used) - bool is_raid = PvP ? false : sMapStore.LookupEntry(GetMapId())->IsRaid() && pGroup->isRaidGroup(); - bool is_dungeon = PvP ? false : sMapStore.LookupEntry(GetMapId())->IsDungeon(); - float group_rate = MaNGOS::XP::xp_in_group_rate(count,is_raid); - - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* pGroupGuy = itr->getSource(); - if(!pGroupGuy) - continue; - - if(!pGroupGuy->IsAtGroupRewardDistance(pVictim)) - continue; // member (alive or dead) or his corpse at req. distance - - // honor can be in PvP and !PvP (racial leader) cases (for alive) - if(pGroupGuy->isAlive() && pGroupGuy->RewardHonor(pVictim,count) && pGroupGuy==this) - honored_kill = true; - - // xp and reputation only in !PvP case - if(!PvP) - { - float rate = group_rate * float(pGroupGuy->getLevel()) / sum_level; - - // if is in dungeon then all receive full reputation at kill - // rewarded any alive/dead/near_corpse group member - pGroupGuy->RewardReputation(pVictim,is_dungeon ? 1.0f : rate); - - // XP updated only for alive group member - if(pGroupGuy->isAlive()) - { - uint32 itr_xp = uint32(xp*rate); - - pGroupGuy->GiveXP(itr_xp, pVictim); - if(Pet* pet = pGroupGuy->GetPet()) - pet->GivePetXP(itr_xp/2); - } - - // quest objectives updated only for alive group member or dead but with not released body - if(pGroupGuy->isAlive()|| !pGroupGuy->GetCorpse()) - { - // normal creature (not pet/etc) can be only in !PvP case - if(pVictim->GetTypeId()==TYPEID_UNIT) - pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID()); - } - } - } - } - } - else // if (!pGroup) - { - xp = PvP ? 0 : MaNGOS::XP::Gain(this, pVictim); - - // honor can be in PvP and !PvP (racial leader) cases - if(RewardHonor(pVictim,1)) - honored_kill = true; - - // xp and reputation only in !PvP case - if(!PvP) - { - RewardReputation(pVictim,1); - GiveXP(xp, pVictim); - - if(Pet* pet = GetPet()) - pet->GivePetXP(xp); - - // normal creature (not pet/etc) can be only in !PvP case - if(pVictim->GetTypeId()==TYPEID_UNIT) - KilledMonster(pVictim->GetEntry(),pVictim->GetGUID()); - } - } - return xp || honored_kill; -} - -bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const -{ - if(pRewardSource->GetDistance(this) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) - return true; - - if(isAlive()) - return false; - - Corpse* corpse = GetCorpse(); - if(!corpse) - return false; - - return pRewardSource->GetDistance(corpse) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE); -} - -uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const -{ - Item* item = GetWeaponForAttack(attType,true); - - // unarmmed only with base attack - if(attType != BASE_ATTACK && !item) - return 0; - - // weapon skill or (unarmed for base attack) - uint32 skill = item ? item->GetSkill() : SKILL_UNARMED; - return GetBaseSkillValue(skill); -} - -void Player::ResurectUsingRequestData() -{ - ResurrectPlayer(0.0f,false); - - if(GetMaxHealth() > m_resurrectHealth) - SetHealth( m_resurrectHealth ); - else - SetHealth( GetMaxHealth() ); - - if(GetMaxPower(POWER_MANA) > m_resurrectMana) - SetPower(POWER_MANA, m_resurrectMana ); - else - SetPower(POWER_MANA, GetMaxPower(POWER_MANA) ); - - SetPower(POWER_RAGE, 0 ); - - SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY) ); - - SpawnCorpseBones(); - - TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation()); -} - -void Player::SetClientControl(Unit* target, uint8 allowMove) -{ - WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, target->GetPackGUID().size()+1); - data.append(target->GetPackGUID()); - data << uint8(allowMove); - GetSession()->SendPacket(&data); -} - -void Player::UpdateZoneDependentAuras( uint32 newZone ) -{ - // remove new continent flight forms - if( !isGameMaster() && - GetVirtualMapForMapAndZone(GetMapId(),newZone) != 530) - { - RemoveSpellsCausingAura(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED); - RemoveSpellsCausingAura(SPELL_AURA_FLY); - } - - // Some spells applied at enter into zone (with subzones) - // Human Illusion - // NOTE: these are removed by RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP); - if ( newZone == 2367 ) // Old Hillsbrad Foothills - { - uint32 spellid = 0; - // all horde races - if( GetTeam() == HORDE ) - spellid = getGender() == GENDER_FEMALE ? 35481 : 35480; - // and some alliance races - else if( getRace() == RACE_NIGHTELF || getRace() == RACE_DRAENEI ) - spellid = getGender() == GENDER_FEMALE ? 35483 : 35482; - - if(spellid && !HasAura(spellid,0) ) - CastSpell(this,spellid,true); - } -} - -void Player::UpdateAreaDependentAuras( uint32 newArea ) -{ - // remove auras from spells with area limitations - for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) - { - // use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date - if(!IsSpellAllowedInLocation(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea)) - RemoveAura(iter); - else - ++iter; - } - - // unmount if enter in this subzone - if( newArea == 35) - RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); - // Dragonmaw Illusion - else if( newArea == 3759 || newArea == 3966 || newArea == 3939 ) - { - if( GetDummyAura(40214) ) - { - if( !HasAura(40216,0) ) - CastSpell(this,40216,true); - if( !HasAura(42016,0) ) - CastSpell(this,42016,true); - } - } -} - -uint32 Player::GetCorpseReclaimDelay(bool pvp) const -{ - if( pvp && !sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP) || - !pvp && !sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE) ) - { - return copseReclaimDelay[0]; - } - - time_t now = time(NULL); - // 0..2 full period - uint32 count = (now < m_deathExpireTime) ? (m_deathExpireTime - now)/DEATH_EXPIRE_STEP : 0; - return copseReclaimDelay[count]; -} - -void Player::UpdateCorpseReclaimDelay() -{ - bool pvp = m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH; - - if( pvp && !sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP) || - !pvp && !sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE) ) - return; - - time_t now = time(NULL); - if(now < m_deathExpireTime) - { - // full and partly periods 1..3 - uint32 count = (m_deathExpireTime - now)/DEATH_EXPIRE_STEP +1; - if(count < MAX_DEATH_COUNT) - m_deathExpireTime = now+(count+1)*DEATH_EXPIRE_STEP; - else - m_deathExpireTime = now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP; - } - else - m_deathExpireTime = now+DEATH_EXPIRE_STEP; -} - -void Player::SendCorpseReclaimDelay(bool load) -{ - Corpse* corpse = GetCorpse(); - if(!corpse) - return; - - uint32 delay; - if(load) - { - if(corpse->GetGhostTime() > m_deathExpireTime) - return; - - bool pvp = corpse->GetType()==CORPSE_RESURRECTABLE_PVP; - - uint32 count; - if( pvp && sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP) || - !pvp && sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE) ) - { - count = (m_deathExpireTime-corpse->GetGhostTime())/DEATH_EXPIRE_STEP; - if(count>=MAX_DEATH_COUNT) - count = MAX_DEATH_COUNT-1; - } - else - count=0; - - time_t expected_time = corpse->GetGhostTime()+copseReclaimDelay[count]; - - time_t now = time(NULL); - if(now >= expected_time) - return; - - delay = expected_time-now; - } - else - delay = GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP); - - //! corpse reclaim delay 30 * 1000ms or longer at often deaths - WorldPacket data(SMSG_CORPSE_RECLAIM_DELAY, 4); - data << uint32(delay*1000); - GetSession()->SendPacket( &data ); -} - -Player* Player::GetNextRandomRaidMember(float radius) -{ - Group *pGroup = GetGroup(); - if(!pGroup) - return NULL; - - std::vector nearMembers; - nearMembers.reserve(pGroup->GetMembersCount()); - - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* Target = itr->getSource(); - - // IsHostileTo check duel and controlled by enemy - if( Target && Target != this && IsWithinDistInMap(Target, radius) && - !Target->HasInvisibilityAura() && !IsHostileTo(Target) ) - nearMembers.push_back(Target); - } - - if (nearMembers.empty()) - return NULL; - - uint32 randTarget = urand(0,nearMembers.size()-1); - return nearMembers[randTarget]; -} - -void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) -{ - float water_z = m->GetWaterLevel(x,y); - float height_z = m->GetHeight(x,y,z, false); // use .map base surface height - uint8 flag1 = m->GetTerrainType(x,y); - - //!Underwater check, not in water if underground or above water level - if (height_z <= INVALID_HEIGHT || z < (height_z-2) || z > (water_z - 2) ) - m_isunderwater &= 0x7A; - else if ((z < (water_z - 2)) && (flag1 & 0x01)) - m_isunderwater |= 0x01; - - //!in lava check, anywhere under lava level - if ((height_z <= INVALID_HEIGHT || z < (height_z - 0)) && (flag1 == 0x00) && IsInWater()) - m_isunderwater |= 0x80; -} - -bool ItemPosCount::isContainedIn(ItemPosCountVec &vec) -{ - for(ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr) - { - if(itr->pos == this->pos/* && itr->count == this.count*/) - { - return true; - } - } - return false; -} - +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Language.h" +#include "Database/DatabaseEnv.h" +#include "Log.h" +#include "Opcodes.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "UpdateMask.h" +#include "Player.h" +#include "SkillDiscovery.h" +#include "QuestDef.h" +#include "GossipDef.h" +#include "UpdateData.h" +#include "Channel.h" +#include "ChannelMgr.h" +#include "MapManager.h" +#include "MapInstanced.h" +#include "InstanceSaveMgr.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "ObjectMgr.h" +#include "ObjectAccessor.h" +#include "CreatureAI.h" +#include "Formulas.h" +#include "Group.h" +#include "Guild.h" +#include "Pet.h" +#include "SpellAuras.h" +#include "Util.h" +#include "Transports.h" +#include "Weather.h" +#include "BattleGround.h" +#include "BattleGroundMgr.h" +#include "ArenaTeam.h" +#include "Chat.h" +#include "Database/DatabaseImpl.h" +#include "Spell.h" +#include "SocialMgr.h" + +#include + +#define ZONE_UPDATE_INTERVAL 1000 + +#define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3)) +#define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1) +#define PLAYER_SKILL_BONUS_INDEX(x) (PLAYER_SKILL_INDEX(x)+2) + +#define SKILL_VALUE(x) PAIR32_LOPART(x) +#define SKILL_MAX(x) PAIR32_HIPART(x) +#define MAKE_SKILL_VALUE(v, m) MAKE_PAIR32(v,m) + +#define SKILL_TEMP_BONUS(x) int16(PAIR32_LOPART(x)) +#define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x)) +#define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t,p) + +enum CharacterFlags +{ + CHARACTER_FLAG_NONE = 0x00000000, + CHARACTER_FLAG_UNK1 = 0x00000001, + CHARACTER_FLAG_UNK2 = 0x00000002, + CHARACTER_LOCKED_FOR_TRANSFER = 0x00000004, + CHARACTER_FLAG_UNK4 = 0x00000008, + CHARACTER_FLAG_UNK5 = 0x00000010, + CHARACTER_FLAG_UNK6 = 0x00000020, + CHARACTER_FLAG_UNK7 = 0x00000040, + CHARACTER_FLAG_UNK8 = 0x00000080, + CHARACTER_FLAG_UNK9 = 0x00000100, + CHARACTER_FLAG_UNK10 = 0x00000200, + CHARACTER_FLAG_HIDE_HELM = 0x00000400, + CHARACTER_FLAG_HIDE_CLOAK = 0x00000800, + CHARACTER_FLAG_UNK13 = 0x00001000, + CHARACTER_FLAG_GHOST = 0x00002000, + CHARACTER_FLAG_RENAME = 0x00004000, + CHARACTER_FLAG_UNK16 = 0x00008000, + CHARACTER_FLAG_UNK17 = 0x00010000, + CHARACTER_FLAG_UNK18 = 0x00020000, + CHARACTER_FLAG_UNK19 = 0x00040000, + CHARACTER_FLAG_UNK20 = 0x00080000, + CHARACTER_FLAG_UNK21 = 0x00100000, + CHARACTER_FLAG_UNK22 = 0x00200000, + CHARACTER_FLAG_UNK23 = 0x00400000, + CHARACTER_FLAG_UNK24 = 0x00800000, + CHARACTER_FLAG_LOCKED_BY_BILLING = 0x01000000, + CHARACTER_FLAG_DECLINED = 0x02000000, + CHARACTER_FLAG_UNK27 = 0x04000000, + CHARACTER_FLAG_UNK28 = 0x08000000, + CHARACTER_FLAG_UNK29 = 0x10000000, + CHARACTER_FLAG_UNK30 = 0x20000000, + CHARACTER_FLAG_UNK31 = 0x40000000, + CHARACTER_FLAG_UNK32 = 0x80000000 +}; + +// corpse reclaim times +#define DEATH_EXPIRE_STEP (5*MINUTE) +#define MAX_DEATH_COUNT 3 + +static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 }; + +//== PlayerTaxi ================================================ + +PlayerTaxi::PlayerTaxi() +{ + // Taxi nodes + memset(m_taximask, 0, sizeof(m_taximask)); +} + +void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 level) +{ + // capital and taxi hub masks + switch(race) + { + case RACE_HUMAN: SetTaximaskNode(2); break; // Human + case RACE_ORC: SetTaximaskNode(23); break; // Orc + case RACE_DWARF: SetTaximaskNode(6); break; // Dwarf + case RACE_NIGHTELF: SetTaximaskNode(26); + SetTaximaskNode(27); break; // Night Elf + case RACE_UNDEAD_PLAYER: SetTaximaskNode(11); break;// Undead + case RACE_TAUREN: SetTaximaskNode(22); break; // Tauren + case RACE_GNOME: SetTaximaskNode(6); break; // Gnome + case RACE_TROLL: SetTaximaskNode(23); break; // Troll + case RACE_BLOODELF: SetTaximaskNode(82); break; // Blood Elf + case RACE_DRAENEI: SetTaximaskNode(94); break; // Draenei + } + // new continent starting masks (It will be accessible only at new map) + switch(Player::TeamForRace(race)) + { + case ALLIANCE: SetTaximaskNode(100); break; + case HORDE: SetTaximaskNode(99); break; + } + // level dependent taxi hubs + if(level>=68) + SetTaximaskNode(213); //Shattered Sun Staging Area +} + +void PlayerTaxi::LoadTaxiMask(const char* data) +{ + Tokens tokens = StrSplit(data, " "); + + int index; + Tokens::iterator iter; + for (iter = tokens.begin(), index = 0; + (index < TaxiMaskSize) && (iter != tokens.end()); ++iter, ++index) + { + // load and set bits only for existed taxi nodes + m_taximask[index] = sTaxiNodesMask[index] & uint32(atol((*iter).c_str())); + } +} + +void PlayerTaxi::AppendTaximaskTo( ByteBuffer& data, bool all ) +{ + if(all) + { + for (uint8 i=0; ic_str())); + AddTaxiDestination(node); + } + + if(m_TaxiDestinations.empty()) + return true; + + // Check integrity + if(m_TaxiDestinations.size() < 2) + return false; + + for(size_t i = 1; i < m_TaxiDestinations.size(); ++i) + { + uint32 cost; + uint32 path; + objmgr.GetTaxiPath(m_TaxiDestinations[i-1],m_TaxiDestinations[i],path,cost); + if(!path) + return false; + } + + return true; +} + +std::string PlayerTaxi::SaveTaxiDestinationsToString() +{ + if(m_TaxiDestinations.empty()) + return ""; + + std::ostringstream ss; + + for(size_t i=0; i < m_TaxiDestinations.size(); ++i) + ss << m_TaxiDestinations[i] << " "; + + return ss.str(); +} + +uint32 PlayerTaxi::GetCurrentTaxiPath() const +{ + if(m_TaxiDestinations.size() < 2) + return 0; + + uint32 path; + uint32 cost; + + objmgr.GetTaxiPath(m_TaxiDestinations[0],m_TaxiDestinations[1],path,cost); + + return path; +} + +//== Player ==================================================== + +const int32 Player::ReputationRank_Length[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000}; + +UpdateMask Player::updateVisualBits; + +Player::Player (WorldSession *session): Unit() +{ + m_transport = 0; + + m_speakTime = 0; + m_speakCount = 0; + + m_objectType |= TYPEMASK_PLAYER; + m_objectTypeId = TYPEID_PLAYER; + + m_valuesCount = PLAYER_END; + + m_session = session; + + m_divider = 0; + + m_ExtraFlags = 0; + if(GetSession()->GetSecurity() >= SEC_GAMEMASTER) + SetAcceptTicket(true); + + // players always and GM if set in config accept whispers by default + if(GetSession()->GetSecurity() == SEC_PLAYER || sWorld.getConfig(CONFIG_GM_WISPERING_TO)) + SetAcceptWhispers(true); + + m_curSelection = 0; + m_lootGuid = 0; + + m_comboTarget = 0; + m_comboPoints = 0; + + m_usedTalentCount = 0; + + m_regenTimer = 0; + m_weaponChangeTimer = 0; + + m_zoneUpdateId = 0; + m_zoneUpdateTimer = 0; + + m_areaUpdateId = 0; + + m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE); + + // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE] + // this must help in case next save after mass player load after server startup + m_nextSave = urand(m_nextSave/2,m_nextSave*3/2); + + clearResurrectRequestData(); + + m_SpellModRemoveCount = 0; + + memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT); + + m_social = NULL; + + // group is initialized in the reference constructor + SetGroupInvite(NULL); + m_groupUpdateMask = 0; + m_auraUpdateMask = 0; + + duel = NULL; + + m_GuildIdInvited = 0; + m_ArenaTeamIdInvited = 0; + + m_atLoginFlags = AT_LOGIN_NONE; + + m_dontMove = false; + + pTrader = 0; + ClearTrade(); + + m_cinematic = 0; + + PlayerTalkClass = new PlayerMenu( GetSession() ); + m_currentBuybackSlot = BUYBACK_SLOT_START; + + for ( int aX = 0 ; aX < 8 ; aX++ ) + m_Tutorials[ aX ] = 0x00; + m_TutorialsChanged = false; + + m_DailyQuestChanged = false; + m_lastDailyQuestTime = 0; + + m_regenTimer = 0; + m_weaponChangeTimer = 0; + m_breathTimer = 0; + m_isunderwater = 0; + m_isInWater = false; + m_drunkTimer = 0; + m_drunk = 0; + m_restTime = 0; + m_deathTimer = 0; + m_deathExpireTime = 0; + + m_swingErrorMsg = 0; + + m_DetectInvTimer = 1000; + + m_bgBattleGroundID = 0; + for (int j=0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; j++) + { + m_bgBattleGroundQueueID[j].bgType = 0; + m_bgBattleGroundQueueID[j].invited = false; + } + m_bgTeam = 0; + + m_logintime = time(NULL); + m_Last_tick = m_logintime; + m_WeaponProficiency = 0; + m_ArmorProficiency = 0; + m_canParry = false; + m_canBlock = false; + m_canDualWield = false; + m_ammoDPS = 0.0f; + + m_temporaryUnsummonedPetNumber = 0; + //cache for UNIT_CREATED_BY_SPELL to allow + //returning reagests for temporarily removed pets + //when dying/logging out + m_oldpetspell = 0; + + ////////////////////Rest System///////////////////// + time_inn_enter=0; + inn_pos_mapid=0; + inn_pos_x=0; + inn_pos_y=0; + inn_pos_z=0; + m_rest_bonus=0; + rest_type=REST_TYPE_NO; + ////////////////////Rest System///////////////////// + + m_mailsLoaded = false; + m_mailsUpdated = false; + unReadMails = 0; + m_nextMailDelivereTime = 0; + + m_resetTalentsCost = 0; + m_resetTalentsTime = 0; + m_itemUpdateQueueBlocked = false; + + for (int i = 0; i < MAX_MOVE_TYPE; ++i) + m_forced_speed_changes[i] = 0; + + m_stableSlots = 0; + + /////////////////// Instance System ///////////////////// + + m_HomebindTimer = 0; + m_InstanceValid = true; + m_dungeonDifficulty = DIFFICULTY_NORMAL; + + for (int i = 0; i < BASEMOD_END; i++) + { + m_auraBaseMod[i][FLAT_MOD] = 0.0f; + m_auraBaseMod[i][PCT_MOD] = 1.0f; + } + + // Honor System + m_lastHonorUpdateTime = time(NULL); + + // Player summoning + m_summon_expire = 0; + m_summon_mapid = 0; + m_summon_x = 0.0f; + m_summon_y = 0.0f; + m_summon_z = 0.0f; + + //Default movement to run mode + m_unit_movement_flags = 0; + + m_miniPet = 0; + m_bgAfkReportedTimer = 0; + m_contestedPvPTimer = 0; + + m_declinedname = NULL; +} + +Player::~Player () +{ + CleanupsBeforeDelete(); + + if(m_uint32Values) // only for fully created Object + { + sSocialMgr.RemovePlayerSocial(GetGUIDLow()); + } + + // Note: buy back item already deleted from DB when player was saved + for(int i = 0; i < PLAYER_SLOTS_COUNT; ++i) + { + if(m_items[i]) + delete m_items[i]; + } + CleanupChannels(); + + for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) + delete itr->second; + + //all mailed items should be deleted, also all mail should be deallocated + for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end();++itr) + delete *itr; + + for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter) + delete iter->second; //if item is duplicated... then server may crash ... but that item should be deallocated + + delete PlayerTalkClass; + + if (m_transport) + { + m_transport->RemovePassenger(this); + } + + for(size_t x = 0; x < ItemSetEff.size(); x++) + if(ItemSetEff[x]) + delete ItemSetEff[x]; + + // clean up player-instance binds, may unload some instance saves + for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) + for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) + itr->second.save->RemovePlayer(this); + + delete m_declinedname; +} + +void Player::CleanupsBeforeDelete() +{ + if(m_uint32Values) // only for fully created Object + { + TradeCancel(false); + DuelComplete(DUEL_INTERUPTED); + } + Unit::CleanupsBeforeDelete(); +} + +bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair, uint8 outfitId ) +{ + Object::_Create(guidlow, 0, HIGHGUID_PLAYER); + + m_name = name; + + PlayerInfo const* info = objmgr.GetPlayerInfo(race, class_); + if(!info) + { + sLog.outError("Player have incorrect race/class pair. Can't be loaded."); + return false; + } + + for (int i = 0; i < PLAYER_SLOTS_COUNT; i++) + m_items[i] = NULL; + + //for(int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; j++) + //{ + // SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1+j*2,0); + // SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1+j,0); + // SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1+j,0); + //} + + m_race = race; + m_class = class_; + + SetMapId(info->mapId); + Relocate(info->positionX,info->positionY,info->positionZ); + + ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(class_); + if(!cEntry) + { + sLog.outError("Class %u not found in DBC (Wrong DBC files?)",class_); + return false; + } + + uint8 powertype = cEntry->powerType; + + uint32 unitfield; + + switch(powertype) + { + case POWER_ENERGY: + case POWER_MANA: + unitfield = 0x00000000; + break; + case POWER_RAGE: + unitfield = 0x00110000; + break; + default: + sLog.outError("Invalid default powertype %u for player (class %u)",powertype,class_); + return false; + } + + SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE ); + SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f ); + + switch(gender) + { + case GENDER_FEMALE: + SetDisplayId(info->displayId_f ); + SetNativeDisplayId(info->displayId_f ); + break; + case GENDER_MALE: + SetDisplayId(info->displayId_m ); + SetNativeDisplayId(info->displayId_m ); + break; + default: + sLog.outError("Invalid gender %u for player",gender); + return false; + break; + } + + setFactionForRace(m_race); + + SetUInt32Value(UNIT_FIELD_BYTES_0, ( ( race ) | ( class_ << 8 ) | ( gender << 16 ) | ( powertype << 24 ) ) ); + SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield); + SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK3 | UNIT_BYTE2_FLAG_UNK5 ); + SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE ); + SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); // fix cast time showed in spell tooltip on client + + //-1 is default value + SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); + + SetUInt32Value(PLAYER_BYTES, (skin | (face << 8) | (hairStyle << 16) | (hairColor << 24))); + SetUInt32Value(PLAYER_BYTES_2, (facialHair | (0x00 << 8) | (0x00 << 16) | (0x02 << 24))); + SetByteValue(PLAYER_BYTES_3, 0, gender); + + SetUInt32Value( PLAYER_GUILDID, 0 ); + SetUInt32Value( PLAYER_GUILDRANK, 0 ); + SetUInt32Value( PLAYER_GUILD_TIMESTAMP, 0 ); + + SetUInt64Value( PLAYER__FIELD_KNOWN_TITLES, 0 ); // 0=disabled + SetUInt32Value( PLAYER_CHOSEN_TITLE, 0 ); + SetUInt32Value( PLAYER_FIELD_KILLS, 0 ); + SetUInt32Value( PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 0 ); + SetUInt32Value( PLAYER_FIELD_TODAY_CONTRIBUTION, 0 ); + SetUInt32Value( PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0 ); + + // set starting level + SetUInt32Value( UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) ); + + // Played time + m_Last_tick = time(NULL); + m_Played_time[0] = 0; + m_Played_time[1] = 0; + + // base stats and related field values + InitStatsForLevel(); + InitTaxiNodesForLevel(); + InitTalentForLevel(); + InitPrimaryProffesions(); // to max set before any spell added + + // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods() + UpdateMaxHealth(); // Update max Health (for add bonus from stamina) + SetHealth(GetMaxHealth()); + if (getPowerType()==POWER_MANA) + { + UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intelect) + SetPower(POWER_MANA,GetMaxPower(POWER_MANA)); + } + + learnDefaultSpells(true); + + std::list::const_iterator action_itr[4]; + for(int i=0; i<4; i++) + action_itr[i] = info->action[i].begin(); + + for (; action_itr[0]!=info->action[0].end() && action_itr[1]!=info->action[1].end();) + { + uint16 taction[4]; + for(int i=0; i<4 ;i++) + taction[i] = (*action_itr[i]); + + addActionButton((uint8)taction[0], taction[1], (uint8)taction[2], (uint8)taction[3]); + + for(int i=0; i<4 ;i++) + ++action_itr[i]; + } + + for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr!=info->item.end(); ++item_id_itr++) + { + uint32 titem_id = item_id_itr->item_id; + uint32 titem_amount = item_id_itr->item_amount; + + sLog.outDebug("STORAGE: Creating initial item, itemId = %u, count = %u",titem_id, titem_amount); + + // attempt equip + uint16 eDest; + uint8 msg = CanEquipNewItem( NULL_SLOT, eDest, titem_id, titem_amount, false ); + if( msg == EQUIP_ERR_OK ) + { + EquipNewItem( eDest, titem_id, titem_amount, true); + AutoUnequipOffhandIfNeed(); + continue; // equipped, to next + } + + // attempt store + ItemPosCountVec sDest; + // store in main bag to simplify second pass (special bags can be not equipped yet at this moment) + msg = CanStoreNewItem( INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount ); + if( msg == EQUIP_ERR_OK ) + { + StoreNewItem( sDest, titem_id, true, Item::GenerateItemRandomPropertyId(titem_id) ); + continue; // stored, to next + } + + // item can't be added + sLog.outError("STORAGE: Can't equip or store initial item %u for race %u class %u , error msg = %u",titem_id,race,class_,msg); + } + + // bags and main-hand weapon must equipped at this moment + // now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon) + // or ammo not equipped in special bag + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + if(Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + { + uint16 eDest; + // equip offhand weapon/shield if it attempt equipped before main-hand weapon + uint8 msg = CanEquipItem( NULL_SLOT, eDest, pItem, false ); + if( msg == EQUIP_ERR_OK ) + { + RemoveItem(INVENTORY_SLOT_BAG_0, i,true); + EquipItem( eDest, pItem, true); + } + // move other items to more appropriate slots (ammo not equipped in special bag) + else + { + ItemPosCountVec sDest; + msg = CanStoreItem( NULL_BAG, NULL_SLOT, sDest, pItem, false ); + if( msg == EQUIP_ERR_OK ) + { + RemoveItem(INVENTORY_SLOT_BAG_0, i,true); + pItem = StoreItem( sDest, pItem, true); + } + + // if this is ammo then use it + uint8 msg = CanUseAmmo( pItem->GetProto()->ItemId ); + if( msg == EQUIP_ERR_OK ) + SetAmmo( pItem->GetProto()->ItemId ); + } + } + } + // all item positions resolved + + return true; +} + +void Player::StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue) +{ + uint32 BreathRegen = (uint32)-1; + + WorldPacket data(SMSG_START_MIRROR_TIMER, (21)); + data << (uint32)Type; + data << MaxValue; + data << MaxValue; + data << BreathRegen; + data << (uint8)0; + data << (uint32)0; // spell id + GetSession()->SendPacket(&data); +} + +void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen) +{ + if(Type==BREATH_TIMER) + m_breathTimer = ((MaxValue + 1000) - CurrentValue) / Regen; + + WorldPacket data(SMSG_START_MIRROR_TIMER, (21)); + data << (uint32)Type; + data << CurrentValue; + data << MaxValue; + data << Regen; + data << (uint8)0; + data << (uint32)0; // spell id + GetSession()->SendPacket( &data ); +} + +void Player::StopMirrorTimer(MirrorTimerType Type) +{ + if(Type==BREATH_TIMER) + m_breathTimer = 0; + + WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4); + data << (uint32)Type; + GetSession()->SendPacket( &data ); +} + +void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 damage) +{ + WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21)); + data << (uint64)guid; + data << (uint8)(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL); + data << (uint32)damage; + data << (uint32)0; + data << (uint32)0; + //m_session->SendPacket(&data); + //Let other players see that you get damage + SendMessageToSet(&data, true); + DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + if(type==DAMAGE_FALL && !isAlive()) // DealDamage not apply item durability loss at self damage + { + DEBUG_LOG("We are fall to death, loosing 10 percents durability"); + DurabilityLossAll(0.10f,false); + // durability lost message + WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); + GetSession()->SendPacket(&data); + } +} + +void Player::HandleDrowning() +{ + if(!m_isunderwater) + return; + + //if have water breath , then remove bar + if(waterbreath || isGameMaster() || !isAlive()) + { + StopMirrorTimer(BREATH_TIMER); + m_isunderwater = 0; + return; + } + + uint32 UnderWaterTime = 1*MINUTE*1000; // default leangthL 1 min + + AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING); + for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i) + UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f); + + if ((m_isunderwater & 0x01) && !(m_isunderwater & 0x80) && isAlive()) + { + //single trigger timer + if (!(m_isunderwater & 0x02)) + { + m_isunderwater|= 0x02; + m_breathTimer = UnderWaterTime + 1000; + } + //single trigger "Breathbar" + if ( m_breathTimer <= UnderWaterTime && !(m_isunderwater & 0x04)) + { + m_isunderwater|= 0x04; + StartMirrorTimer(BREATH_TIMER, UnderWaterTime); + } + //continius trigger drowning "Damage" + if ((m_breathTimer == 0) && (m_isunderwater & 0x01)) + { + //TODO: Check this formula + uint64 guid = GetGUID(); + uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); + + EnvironmentalDamage(guid, DAMAGE_DROWNING,damage); + m_breathTimer = 2000; + } + } + //single trigger retract bar + else if (!(m_isunderwater & 0x01) && !(m_isunderwater & 0x08) && (m_isunderwater & 0x02) && (m_breathTimer > 0) && isAlive()) + { + m_isunderwater = 0x08; + + uint32 BreathRegen = 10; + ModifyMirrorTimer(BREATH_TIMER, UnderWaterTime, m_breathTimer,BreathRegen); + m_isunderwater = 0x10; + } + //remove bar + else if ((m_breathTimer < 50) && !(m_isunderwater & 0x01) && (m_isunderwater == 0x10)) + { + StopMirrorTimer(BREATH_TIMER); + m_isunderwater = 0; + } +} + +void Player::HandleLava() +{ + bool ValidArea = false; + + if ((m_isunderwater & 0x80) && isAlive()) + { + //Single trigger Set BreathTimer + if (!(m_isunderwater & 0x80)) + { + m_isunderwater|= 0x04; + m_breathTimer = 1000; + } + //Reset BreathTimer and still in the lava + if (!m_breathTimer) + { + uint64 guid = GetGUID(); + uint32 damage = urand(600, 700); // TODO: Get more detailed information about lava damage + uint32 dmgZone = GetZoneId(); // TODO: Find correct "lava dealing zone" flag in Area Table + + // Deal lava damage only in lava zones. + switch(dmgZone) + { + case 0x8D: + ValidArea = false; + break; + case 0x94: + ValidArea = false; + break; + case 0x2CE: + ValidArea = false; + break; + case 0x2CF: + ValidArea = false; + break; + default: + if (dmgZone / 5 & 0x408) + ValidArea = true; + } + + // if is valid area and is not gamemaster then deal damage + if ( ValidArea && !isGameMaster() ) + EnvironmentalDamage(guid, DAMAGE_LAVA, damage); + + m_breathTimer = 1000; + } + + } + //Death timer disabled and WaterFlags reset + else if (m_deathState == DEAD) + { + m_breathTimer = 0; + m_isunderwater = 0; + } +} + +///The player sobers by 256 every 10 seconds +void Player::HandleSobering() +{ + m_drunkTimer = 0; + + uint32 drunk = (m_drunk <= 256) ? 0 : (m_drunk - 256); + SetDrunkValue(drunk); +} + +DrunkenState Player::GetDrunkenstateByValue(uint16 value) +{ + if(value >= 23000) + return DRUNKEN_SMASHED; + if(value >= 12800) + return DRUNKEN_DRUNK; + if(value & 0xFFFE) + return DRUNKEN_TIPSY; + return DRUNKEN_SOBER; +} + +void Player::SetDrunkValue(uint16 newDrunkenValue, uint32 itemId) +{ + uint32 oldDrunkenState = Player::GetDrunkenstateByValue(m_drunk); + + m_drunk = newDrunkenValue; + SetUInt32Value(PLAYER_BYTES_3,(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | (m_drunk & 0xFFFE)); + + uint32 newDrunkenState = Player::GetDrunkenstateByValue(m_drunk); + + // special drunk invisibility detection + if(newDrunkenState >= DRUNKEN_DRUNK) + m_detectInvisibilityMask |= (1<<6); + else + m_detectInvisibilityMask &= ~(1<<6); + + if(newDrunkenState == oldDrunkenState) + return; + + WorldPacket data(SMSG_CROSSED_INEBRIATION_THRESHOLD, (8+4+4)); + data << GetGUID(); + data << uint32(newDrunkenState); + data << uint32(itemId); + + SendMessageToSet(&data, true); +} + +void Player::Update( uint32 p_time ) +{ + if(!IsInWorld()) + return; + + // undelivered mail + if(m_nextMailDelivereTime && m_nextMailDelivereTime <= time(NULL)) + { + SendNewMail(); + ++unReadMails; + + // It will be recalculate at mailbox open (for unReadMails important non-0 until mailbox open, it also will be recalculated) + m_nextMailDelivereTime = 0; + } + + Unit::Update( p_time ); + + // update player only attacks + if(uint32 ranged_att = getAttackTimer(RANGED_ATTACK)) + { + setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time) ); + } + + if(uint32 off_att = getAttackTimer(OFF_ATTACK)) + { + setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time) ); + } + + time_t now = time (NULL); + + UpdatePvPFlag(now); + + UpdateContestedPvP(p_time); + + UpdateDuelFlag(now); + + CheckDuelDistance(now); + + UpdateAfkReport(now); + + CheckExploreSystem(); + + // Update items that have just a limited lifetime + if (now>m_Last_tick) + UpdateItemDuration(uint32(now- m_Last_tick)); + + if (!m_timedquests.empty()) + { + std::set::iterator iter = m_timedquests.begin(); + while (iter != m_timedquests.end()) + { + QuestStatusData& q_status = mQuestStatus[*iter]; + if( q_status.m_timer <= p_time ) + { + uint32 quest_id = *iter; + ++iter; // current iter will be removed in FailTimedQuest + FailTimedQuest( quest_id ); + } + else + { + q_status.m_timer -= p_time; + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + ++iter; + } + } + } + + if (hasUnitState(UNIT_STAT_MELEE_ATTACKING)) + { + Unit *pVictim = getVictim(); + if( !IsNonMeleeSpellCasted(false) && pVictim) + { + // default combat reach 10 + // TODO add weapon,skill check + + float pldistance = ATTACK_DISTANCE; + + if (isAttackReady(BASE_ATTACK)) + { + if(!IsWithinDistInMap(pVictim, pldistance)) + { + setAttackTimer(BASE_ATTACK,100); + if(m_swingErrorMsg != 1) // send single time (client auto repeat) + { + SendAttackSwingNotInRange(); + m_swingErrorMsg = 1; + } + } + //120 degrees of radiant range + else if( !HasInArc( 2*M_PI/3, pVictim )) + { + setAttackTimer(BASE_ATTACK,100); + if(m_swingErrorMsg != 2) // send single time (client auto repeat) + { + SendAttackSwingBadFacingAttack(); + m_swingErrorMsg = 2; + } + } + else + { + m_swingErrorMsg = 0; // reset swing error state + + // prevent base and off attack in same time, delay attack at 0.2 sec + if(haveOffhandWeapon()) + { + uint32 off_att = getAttackTimer(OFF_ATTACK); + if(off_att < ATTACK_DISPLAY_DELAY) + setAttackTimer(OFF_ATTACK,ATTACK_DISPLAY_DELAY); + } + AttackerStateUpdate(pVictim, BASE_ATTACK); + resetAttackTimer(BASE_ATTACK); + } + } + + if ( haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) + { + if(!IsWithinDistInMap(pVictim, pldistance)) + { + setAttackTimer(OFF_ATTACK,100); + } + else if( !HasInArc( 2*M_PI/3, pVictim )) + { + setAttackTimer(OFF_ATTACK,100); + } + else + { + // prevent base and off attack in same time, delay attack at 0.2 sec + uint32 base_att = getAttackTimer(BASE_ATTACK); + if(base_att < ATTACK_DISPLAY_DELAY) + setAttackTimer(BASE_ATTACK,ATTACK_DISPLAY_DELAY); + // do attack + AttackerStateUpdate(pVictim, OFF_ATTACK); + resetAttackTimer(OFF_ATTACK); + } + } + + Unit *owner = pVictim->GetOwner(); + Unit *u = owner ? owner : pVictim; + if(u->IsPvP() && (!duel || duel->opponent != u)) + { + UpdatePvP(true); + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + } + } + } + + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) + { + if(roll_chance_i(3) && GetTimeInnEnter() > 0) //freeze update + { + int time_inn = time(NULL)-GetTimeInnEnter(); + if (time_inn >= 10) //freeze update + { + float bubble = 0.125*sWorld.getRate(RATE_REST_INGAME); + //speed collect rest bonus (section/in hour) + SetRestBonus( GetRestBonus()+ time_inn*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble ); + UpdateInnerTime(time(NULL)); + } + } + } + + if(m_regenTimer > 0) + { + if(p_time >= m_regenTimer) + m_regenTimer = 0; + else + m_regenTimer -= p_time; + } + + if (m_weaponChangeTimer > 0) + { + if(p_time >= m_weaponChangeTimer) + m_weaponChangeTimer = 0; + else + m_weaponChangeTimer -= p_time; + } + + if (m_zoneUpdateTimer > 0) + { + if(p_time >= m_zoneUpdateTimer) + { + uint32 newzone = GetZoneId(); + if( m_zoneUpdateId != newzone ) + UpdateZone(newzone); // also update area + else + { + // use area updates as well + // needed for free far all arenas for example + uint32 newarea = GetAreaId(); + if( m_areaUpdateId != newarea ) + UpdateArea(newarea); + + m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; + } + } + else + m_zoneUpdateTimer -= p_time; + } + + if (isAlive()) + { + RegenerateAll(); + } + + if (m_deathState == JUST_DIED) + { + KillPlayer(); + } + + if(m_nextSave > 0) + { + if(p_time >= m_nextSave) + { + // m_nextSave reseted in SaveToDB call + SaveToDB(); + sLog.outDetail("Player '%s' (GUID: %u) saved", GetName(), GetGUIDLow()); + } + else + { + m_nextSave -= p_time; + } + } + + //Breathtimer + if(m_breathTimer > 0) + { + if(p_time >= m_breathTimer) + m_breathTimer = 0; + else + m_breathTimer -= p_time; + + } + + //Handle Water/drowning + HandleDrowning(); + + //Handle lava + HandleLava(); + + //Handle detect stealth players + if (m_DetectInvTimer > 0) + { + if (p_time >= m_DetectInvTimer) + { + m_DetectInvTimer = 3000; + HandleStealthedUnitsDetection(); + } + else + m_DetectInvTimer -= p_time; + } + + // Played time + if (now > m_Last_tick) + { + uint32 elapsed = uint32(now - m_Last_tick); + m_Played_time[0] += elapsed; // Total played time + m_Played_time[1] += elapsed; // Level played time + m_Last_tick = now; + } + + if (m_drunk) + { + m_drunkTimer += p_time; + + if (m_drunkTimer > 10000) + HandleSobering(); + } + + // not auto-free ghost from body in instances + if(m_deathTimer > 0 && !GetBaseMap()->Instanceable()) + { + if(p_time >= m_deathTimer) + { + m_deathTimer = 0; + BuildPlayerRepop(); + RepopAtGraveyard(); + } + else + m_deathTimer -= p_time; + } + + UpdateEnchantTime(p_time); + UpdateHomebindTime(p_time); + + // group update + SendUpdateToOutOfRangeGroupMembers(); + + Pet* pet = GetPet(); + if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE)) + { + RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true); + return; + } +} + +void Player::setDeathState(DeathState s) +{ + uint32 ressSpellId = 0; + + bool cur = isAlive(); + + if(s == JUST_DIED && cur) + { + // drunken state is cleared on death + SetDrunkValue(0); + // lost combo points at any target (targeted combo points clear in Unit::setDeathState) + ClearComboPoints(); + + clearResurrectRequestData(); + + // remove form before other mods to prevent incorrect stats calculation + RemoveAurasDueToSpell(m_ShapeShiftFormSpellId); + + //FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequestOpcode and define pet unsummon here with (s == DEAD) + RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); + + // remove uncontrolled pets + RemoveMiniPet(); + RemoveGuardians(); + + // save value before aura remove in Unit::setDeathState + ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL); + + // passive spell + if(!ressSpellId) + ressSpellId = GetResurrectionSpellId(); + } + Unit::setDeathState(s); + + // restore resurrection spell id for player after aura remove + if(s == JUST_DIED && cur && ressSpellId) + SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); + + if(isAlive() && !cur) + { + //clear aura case after resurrection by another way (spells will be applied before next death) + SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); + + // restore default warrior stance + if(getClass()== CLASS_WARRIOR) + CastSpell(this,SPELL_ID_PASSIVE_BATTLE_STANCE,true); + } +} + +void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) +{ + *p_data << GetGUID(); + *p_data << m_name; + + *p_data << getRace(); + uint8 pClass = getClass(); + *p_data << pClass; + *p_data << getGender(); + + uint32 bytes = GetUInt32Value(PLAYER_BYTES); + *p_data << uint8(bytes); + *p_data << uint8(bytes >> 8); + *p_data << uint8(bytes >> 16); + *p_data << uint8(bytes >> 24); + + bytes = GetUInt32Value(PLAYER_BYTES_2); + *p_data << uint8(bytes); + + *p_data << uint8(getLevel()); // player level + // do not use GetMap! it will spawn a new instance since the bound instances are not loaded + uint32 zoneId = MapManager::Instance().GetZoneId(GetMapId(), GetPositionX(),GetPositionY()); + + *p_data << zoneId; + *p_data << GetMapId(); + + *p_data << GetPositionX(); + *p_data << GetPositionY(); + *p_data << GetPositionZ(); + + *p_data << GetUInt32Value(PLAYER_GUILDID); // guild id + + uint32 char_flags = 0; + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) + char_flags |= CHARACTER_FLAG_HIDE_HELM; + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) + char_flags |= CHARACTER_FLAG_HIDE_CLOAK; + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + char_flags |= CHARACTER_FLAG_GHOST; + if(HasAtLoginFlag(AT_LOGIN_RENAME)) + char_flags |= CHARACTER_FLAG_RENAME; + // always send the flag if declined names aren't used + // to let the client select a default method of declining the name + if(!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) || (result && result->Fetch()[12].GetCppString() != "")) + char_flags |= CHARACTER_FLAG_DECLINED; + + *p_data << (uint32)char_flags; // character flags + + *p_data << (uint8)1; // unknown + + // Pets info + { + uint32 petDisplayId = 0; + uint32 petLevel = 0; + uint32 petFamily = 0; + + // show pet at selection character in character list only for non-ghost character + if(result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER)) + { + Field* fields = result->Fetch(); + + uint32 entry = fields[9].GetUInt32(); + CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(entry); + if(cInfo) + { + petDisplayId = fields[10].GetUInt32(); + petLevel = fields[11].GetUInt32(); + petFamily = cInfo->family; + } + } + + *p_data << (uint32)petDisplayId; + *p_data << (uint32)petLevel; + *p_data << (uint32)petFamily; + } + + /*ItemPrototype const *items[EQUIPMENT_SLOT_END]; + for (int i = 0; i < EQUIPMENT_SLOT_END; i++) + items[i] = NULL; + + QueryResult *result = CharacterDatabase.PQuery("SELECT slot,item_template FROM character_inventory WHERE guid = '%u' AND bag = 0",GetGUIDLow()); + if (result) + { + do + { + Field *fields = result->Fetch(); + uint8 slot = fields[0].GetUInt8() & 255; + uint32 item_id = fields[1].GetUInt32(); + if( slot >= EQUIPMENT_SLOT_END ) + continue; + + items[slot] = objmgr.GetItemPrototype(item_id); + if(!items[slot]) + { + sLog.outError( "Player::BuildEnumData: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id ); + continue; + } + } while (result->NextRow()); + delete result; + }*/ + + for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++) + { + uint32 visualbase = PLAYER_VISIBLE_ITEM_1_0 + (slot * MAX_VISIBLE_ITEM_OFFSET); + uint32 item_id = GetUInt32Value(visualbase); + const ItemPrototype * proto = objmgr.GetItemPrototype(item_id); + SpellItemEnchantmentEntry const *enchant = NULL; + + for(uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot<=TEMP_ENCHANTMENT_SLOT; enchantSlot++) + { + uint32 enchantId = GetUInt32Value(visualbase+1+enchantSlot); + if(enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId)) + break; + } + + if (proto != NULL) + { + *p_data << (uint32)proto->DisplayInfoID; + *p_data << (uint8)proto->InventoryType; + *p_data << (uint32)(enchant?enchant->aura_id:0); + } + else + { + *p_data << (uint32)0; + *p_data << (uint8)0; + *p_data << (uint32)0; // enchant? + } + } + *p_data << (uint32)0; // first bag display id + *p_data << (uint8)0; // first bag inventory type + *p_data << (uint32)0; // enchant? +} + +bool Player::ToggleAFK() +{ + ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); + + bool state = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); + + // afk player not allowed in battleground + if(state && InBattleGround()) + LeaveBattleground(); + + return state; +} + +bool Player::ToggleDND() +{ + ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); + + return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); +} + +uint8 Player::chatTag() const +{ + // it's bitmask + // 0x8 - ?? + // 0x4 - gm + // 0x2 - dnd + // 0x1 - afk + if(isGameMaster()) + return 4; + else if(isDND()) + return 3; + if(isAFK()) + return 1; + else + return 0; +} + +bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options) +{ + if(!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) + { + sLog.outError("TeleportTo: invalid map %d or absent instance template.", mapid); + return false; + } + + // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later) + Pet* pet = GetPet(); + + MapEntry const* mEntry = sMapStore.LookupEntry(mapid); + + // don't let enter battlegrounds without assigned battleground id (for example through areatrigger)... + if(!InBattleGround() && mEntry->IsBattleGround() && !GetSession()->GetSecurity()) + return false; + + bool tbc = GetSession()->IsTBC() && sWorld.getConfig(CONFIG_EXPANSION) > 0; + + // normal client and TBC map + if(!tbc && mEntry->IsExpansionMap()) + { + sLog.outDebug("Player %s using Normal client and tried teleport to non existing map %u", GetName(), mapid); + + if(GetTransport()) + RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) + + SendTransferAborted(mapid, TRANSFER_ABORT_INSUF_EXPAN_LVL1); + + return false; // normal client can't teleport to this map... + } + else if(tbc) // can teleport to any existing map + { + sLog.outDebug("Player %s have TBC client and will teleported to map %u", GetName(), mapid); + } + else + { + sLog.outDebug("Player %s have normal client and will teleported to standard map %u", GetName(), mapid); + } + /* + only TBC (no 0x80000 and 0x10 flags...) + 3604590=0x37006E=0x200000 + 0x100000 + 0x40000 + 0x20000 + 0x10000 + 0x40 + 0x20 + 0x8 + 0x4 + 0x2 + + Kharazan (normal/TBC??), but not have 0x10 flag (accessible by normal client?) + 4128878=0x3F006E=0x200000 + 0x100000 + 0x80000 + 0x40000 + 0x20000 + 0x10000 + 0x40 + 0x20 + 0x8 + 0x4 + 0x2 + + normal+TBC maps + 4128894=0x3F007E=0x200000 + 0x100000 + 0x80000 + 0x40000 + 0x20000 + 0x10000 + 0x40 + 0x20 + 0x10 + 0x8 + 0x4 + 0x2 + + normal+TBC maps + 8323198=0x7F007E=0x400000 + 0x200000 + 0x100000 + 0x80000 + 0x40000 + 0x20000 + 0x10000 + 0x40 + 0x20 + 0x10 + 0x8 + 0x4 + 0x2 + */ + + // if we were on a transport, leave + if (!(options & TELE_TO_NOT_LEAVE_TRANSPORT) && m_transport) + { + m_transport->RemovePassenger(this); + m_transport = NULL; + m_movementInfo.t_x = 0.0f; + m_movementInfo.t_y = 0.0f; + m_movementInfo.t_z = 0.0f; + m_movementInfo.t_o = 0.0f; + m_movementInfo.t_time = 0; + } + + SetSemaphoreTeleport(true); + + // The player was ported to another map and looses the duel immediatly. + // We have to perform this check before the teleport, otherwise the + // ObjectAccessor won't find the flag. + if (duel && this->GetMapId()!=mapid) + { + GameObject* obj = ObjectAccessor::GetGameObject(*this, GetUInt64Value(PLAYER_DUEL_ARBITER)); + if (obj) + DuelComplete(DUEL_FLED); + } + + // reset movement flags at teleport, because player will continue move with these flags after teleport + SetUnitMovementFlags(0); + + if ((this->GetMapId() == mapid) && (!m_transport)) + { + // prepare zone change detect + uint32 old_zone = GetZoneId(); + + // near teleport + if(!GetSession()->PlayerLogout()) + { + WorldPacket data; + BuildTeleportAckMsg(&data, x, y, z, orientation); + GetSession()->SendPacket(&data); + SetPosition( x, y, z, orientation, true); + } + else + // this will be used instead of the current location in SaveToDB + m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); + + //BuildHeartBeatMsg(&data); + //SendMessageToSet(&data, true); + if (!(options & TELE_TO_NOT_UNSUMMON_PET)) + { + //same map, only remove pet if out of range + if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE)) + { + if(pet->isControlled() && !pet->isTemporarySummoned() ) + m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); + else + m_temporaryUnsummonedPetNumber = 0; + + RemovePet(pet, PET_SAVE_NOT_IN_SLOT); + } + } + + if(!(options & TELE_TO_NOT_LEAVE_COMBAT)) + CombatStop(); + + if (!(options & TELE_TO_NOT_UNSUMMON_PET)) + { + // resummon pet + if(pet && m_temporaryUnsummonedPetNumber) + { + Pet* NewPet = new Pet; + if(!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true)) + delete NewPet; + + m_temporaryUnsummonedPetNumber = 0; + } + } + + SetSemaphoreTeleport(false); + + if(!GetSession()->PlayerLogout()) + UpdateZone(GetZoneId()); + + // new zone + if(old_zone != GetZoneId()) + { + // honorless target + if(pvpInfo.inHostileArea) + CastSpell(this, 2479, true); + } + } + else + { + // far teleport to another map + Map* oldmap = IsInWorld() ? MapManager::Instance().GetMap(GetMapId(), this) : NULL; + // check if we can enter before stopping combat / removing pet / totems / interrupting spells + + // Check enter rights before map getting to avoid creating instance copy for player + // this check not dependent from map instance copy and same for all instance copies of selected map + if (!MapManager::Instance().CanPlayerEnter(mapid, this)) + { + SetSemaphoreTeleport(false); + return false; + } + + // If the map is not created, assume it is possible to enter it. + // It will be created in the WorldPortAck. + Map *map = MapManager::Instance().FindMap(mapid); + if (!map || map->CanEnter(this)) + { + SetSelection(0); + + CombatStop(); + + ResetContestedPvP(); + + // remove player from battleground on far teleport (when changing maps) + if(BattleGround const* bg = GetBattleGround()) + { + // Note: at battleground join battleground id set before teleport + // and we already will found "current" battleground + // just need check that this is targeted map or leave + if(bg->GetMapId() != mapid) + LeaveBattleground(false); // don't teleport to entry point + } + + // remove pet on map change + if (pet) + { + //leaving map -> delete pet right away (doing this later will cause problems) + if(pet->isControlled() && !pet->isTemporarySummoned()) + m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); + else + m_temporaryUnsummonedPetNumber = 0; + + RemovePet(pet, PET_SAVE_NOT_IN_SLOT); + } + + // remove all dyn objects + RemoveAllDynObjects(); + + // stop spellcasting + // not attempt interrupt teleportation spell at caster teleport + if(!(options & TELE_TO_SPELL)) + if(IsNonMeleeSpellCasted(true)) + InterruptNonMeleeSpells(true); + + if(!GetSession()->PlayerLogout()) + { + // send transfer packets + WorldPacket data(SMSG_TRANSFER_PENDING, (4+4+4)); + data << uint32(mapid); + if (m_transport) + { + data << m_transport->GetEntry() << GetMapId(); + } + GetSession()->SendPacket(&data); + + data.Initialize(SMSG_NEW_WORLD, (20)); + if (m_transport) + { + data << (uint32)mapid << m_movementInfo.t_x << m_movementInfo.t_y << m_movementInfo.t_z << m_movementInfo.t_o; + } + else + { + data << (uint32)mapid << (float)x << (float)y << (float)z << (float)orientation; + } + GetSession()->SendPacket( &data ); + SendSavedInstances(); + + // remove from old map now + if(oldmap) oldmap->Remove(this, false); + } + + // new final coordinates + float final_x = x; + float final_y = y; + float final_z = z; + float final_o = orientation; + + if(m_transport) + { + final_x += m_movementInfo.t_x; + final_y += m_movementInfo.t_y; + final_z += m_movementInfo.t_z; + final_o += m_movementInfo.t_o; + } + + m_teleport_dest = WorldLocation(mapid, final_x, final_y, final_z, final_o); + // if the player is saved before worldportack (at logout for example) + // this will be used instead of the current location in SaveToDB + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP); + + // move packet sent by client always after far teleport + // SetPosition(final_x, final_y, final_z, final_o, true); + SetDontMove(true); + + // code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet + } + else + return false; + } + return true; +} + +void Player::AddToWorld() +{ + ///- Do not add/remove the player from the object storage + ///- It will crash when updating the ObjectAccessor + ///- The player should only be added when logging in + Unit::AddToWorld(); + + for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++) + { + if(m_items[i]) + m_items[i]->AddToWorld(); + } +} + +void Player::RemoveFromWorld() +{ + // cleanup + if(IsInWorld()) + { + ///- Release charmed creatures, unsummon totems and remove pets/guardians + Uncharm(); + UnsummonAllTotems(); + RemoveMiniPet(); + RemoveGuardians(); + } + + for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++) + { + if(m_items[i]) + m_items[i]->RemoveFromWorld(); + } + + ///- Do not add/remove the player from the object storage + ///- It will crash when updating the ObjectAccessor + ///- The player should only be removed when logging out + Unit::RemoveFromWorld(); +} + +void Player::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ) +{ + float addRage; + + float rageconversion = ((0.0091107836 * getLevel()*getLevel())+3.225598133*getLevel())+4.2652911; + + if(attacker) + { + addRage = ((damage/rageconversion*7.5 + weaponSpeedHitFactor)/2); + + // talent who gave more rage on attack + addRage *= 1.0f + GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT) / 100.0f; + } + else + { + addRage = damage/rageconversion*2.5; + + // Berserker Rage effect + if(HasAura(18499,0)) + addRage *= 1.3; + } + + addRage *= sWorld.getRate(RATE_POWER_RAGE_INCOME); + + ModifyPower(POWER_RAGE, uint32(addRage*10)); +} + +void Player::RegenerateAll() +{ + if (m_regenTimer != 0) + return; + uint32 regenDelay = 2000; + + // Not in combat or they have regeneration + if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) || + HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT) || IsPolymorphed() ) + { + RegenerateHealth(); + if (!isInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN)) + Regenerate(POWER_RAGE); + } + + Regenerate( POWER_ENERGY ); + + Regenerate( POWER_MANA ); + + m_regenTimer = regenDelay; +} + +void Player::Regenerate(Powers power) +{ + uint32 curValue = GetPower(power); + uint32 maxValue = GetMaxPower(power); + + float addvalue = 0.0f; + + switch (power) + { + case POWER_MANA: + { + bool recentCast = IsUnderLastManaUseEffect(); + float ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA); + if (recentCast) + { + // Mangos Updates Mana in intervals of 2s, which is correct + addvalue = GetFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT) * ManaIncreaseRate * 2.00f; + } + else + { + addvalue = GetFloatValue(PLAYER_FIELD_MOD_MANA_REGEN) * ManaIncreaseRate * 2.00f; + } + } break; + case POWER_RAGE: // Regenerate rage + { + float RageDecreaseRate = sWorld.getRate(RATE_POWER_RAGE_LOSS); + addvalue = 30 * RageDecreaseRate; // 3 rage by tick + } break; + case POWER_ENERGY: // Regenerate energy (rogue) + addvalue = 20; + break; + case POWER_FOCUS: + case POWER_HAPPINESS: + break; + } + + // Mana regen calculated in Player::UpdateManaRegen() + // Exist only for POWER_MANA, POWER_ENERGY, POWER_FOCUS auras + if(power != POWER_MANA) + { + AuraList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT); + for(AuraList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i) + if ((*i)->GetModifier()->m_miscvalue == power) + addvalue *= ((*i)->GetModifier()->m_amount + 100) / 100.0f; + } + + if (power != POWER_RAGE) + { + curValue += uint32(addvalue); + if (curValue > maxValue) + curValue = maxValue; + } + else + { + if(curValue <= uint32(addvalue)) + curValue = 0; + else + curValue -= uint32(addvalue); + } + SetPower(power, curValue); +} + +void Player::RegenerateHealth() +{ + uint32 curValue = GetHealth(); + uint32 maxValue = GetMaxHealth(); + + if (curValue >= maxValue) return; + + float HealthIncreaseRate = sWorld.getRate(RATE_HEALTH); + + float addvalue = 0.0f; + + // polymorphed case + if ( IsPolymorphed() ) + addvalue = GetMaxHealth()/3; + // normal regen case (maybe partly in combat case) + else if (!isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) ) + { + addvalue = OCTRegenHPPerSpirit()* HealthIncreaseRate; + if (!isInCombat()) + { + AuraList const& mModHealthRegenPct = GetAurasByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT); + for(AuraList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i) + addvalue *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; + } + else if(HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT)) + addvalue *= GetTotalAuraModifier(SPELL_AURA_MOD_REGEN_DURING_COMBAT) / 100.0f; + + if(!IsStandState()) + addvalue *= 1.5; + } + + // always regeneration bonus (including combat) + addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT); + + if(addvalue < 0) + addvalue = 0; + + ModifyHealth(int32(addvalue)); +} + +bool Player::CanInteractWithNPCs(bool alive) const +{ + if(alive && !isAlive()) + return false; + if(isInFlight()) + return false; + + return true; +} + +bool Player::IsUnderWater() const +{ + return IsInWater() && + GetPositionZ() < (MapManager::Instance().GetBaseMap(GetMapId())->GetWaterLevel(GetPositionX(),GetPositionY())-2); +} + +void Player::SetInWater(bool apply) +{ + if(m_isInWater==apply) + return; + + //define player in water by opcodes + //move player's guid into HateOfflineList of those mobs + //which can't swim and move guid back into ThreatList when + //on surface. + //TODO: exist also swimming mobs, and function must be symmetric to enter/leave water + m_isInWater = apply; + + // remove auras that need water/land + RemoveAurasWithInterruptFlags(apply ? AURA_INTERRUPT_FLAG_NOT_ABOVEWATER : AURA_INTERRUPT_FLAG_NOT_UNDERWATER); + + getHostilRefManager().updateThreatTables(); +} + +void Player::SetGameMaster(bool on) +{ + if(on) + { + m_ExtraFlags |= PLAYER_EXTRA_GM_ON; + setFaction(35); + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); + + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); + ResetContestedPvP(); + + getHostilRefManager().setOnlineOfflineState(false); + CombatStop(); + } + else + { + m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON; + setFactionForRace(getRace()); + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); + + // restore FFA PvP Server state + if(sWorld.IsFFAPvPRealm()) + SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); + + // restore FFA PvP area state, remove not allowed for GM mounts + UpdateArea(m_areaUpdateId); + + getHostilRefManager().setOnlineOfflineState(true); + } + + ObjectAccessor::UpdateVisibilityForPlayer(this); +} + +void Player::SetGMVisible(bool on) +{ + if(on) + { + m_ExtraFlags &= ~PLAYER_EXTRA_GM_INVISIBLE; //remove flag + + // Reapply stealth/invisibility if active or show if not any + if(HasAuraType(SPELL_AURA_MOD_STEALTH)) + SetVisibility(VISIBILITY_GROUP_STEALTH); + else if(HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) + SetVisibility(VISIBILITY_GROUP_INVISIBILITY); + else + SetVisibility(VISIBILITY_ON); + } + else + { + m_ExtraFlags |= PLAYER_EXTRA_GM_INVISIBLE; //add flag + + SetAcceptWhispers(false); + SetGameMaster(true); + + SetVisibility(VISIBILITY_OFF); + } +} + +bool Player::IsGroupVisibleFor(Player* p) const +{ + switch(sWorld.getConfig(CONFIG_GROUP_VISIBILITY)) + { + default: return IsInSameGroupWith(p); + case 1: return IsInSameRaidWith(p); + case 2: return GetTeam()==p->GetTeam(); + } +} + +bool Player::IsInSameGroupWith(Player const* p) const +{ + return p==this || GetGroup() != NULL && + GetGroup() == p->GetGroup() && + GetGroup()->SameSubGroup((Player*)this, (Player*)p); +} + +///- If the player is invited, remove him. If the group if then only 1 person, disband the group. +/// \todo Shouldn't we also check if there is no other invitees before disbanding the group? +void Player::UninviteFromGroup() +{ + if(GetGroupInvite()) // uninvited invitee + { + Group* group = GetGroupInvite(); + group->RemoveInvite(this); + + if(group->GetMembersCount() <= 1) // group has just 1 member => disband + { + if(group->IsCreated()) + { + group->Disband(true); + objmgr.RemoveGroup(group); + } + else + group->RemoveAllInvites(); + + delete group; + } + } +} + +void Player::RemoveFromGroup(Group* group, uint64 guid) +{ + if(group) + { + if (group->RemoveMember(guid, 0) <= 1) + { + // group->Disband(); already disbanded in RemoveMember + objmgr.RemoveGroup(group); + delete group; + // removemember sets the player's group pointer to NULL + } + } +} + +void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 RestXP) +{ + WorldPacket data(SMSG_LOG_XPGAIN, 21); + data << uint64(victim ? victim->GetGUID() : 0); // guid + data << uint32(GivenXP+RestXP); // given experience + data << uint8(victim ? 0 : 1); // 00-kill_xp type, 01-non_kill_xp type + if(victim) + { + data << uint32(GivenXP); // experience without rested bonus + data << float(1); // 1 - none 0 - 100% group bonus output + } + data << uint8(0); // new 2.4.0 + GetSession()->SendPacket(&data); +} + +void Player::GiveXP(uint32 xp, Unit* victim) +{ + if ( xp < 1 ) + return; + + if(!isAlive()) + return; + + uint32 level = getLevel(); + + // XP to money conversion processed in Player::RewardQuest + if(level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + return; + + // handle SPELL_AURA_MOD_XP_PCT auras + Unit::AuraList const& ModXPPctAuras = GetAurasByType(SPELL_AURA_MOD_XP_PCT); + for(Unit::AuraList::const_iterator i = ModXPPctAuras.begin();i != ModXPPctAuras.end(); ++i) + xp = uint32(xp*(1.0f + (*i)->GetModifier()->m_amount / 100.0f)); + + // XP resting bonus for kill + uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0; + + SendLogXPGain(xp,victim,rested_bonus_xp); + + uint32 curXP = GetUInt32Value(PLAYER_XP); + uint32 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); + uint32 newXP = curXP + xp + rested_bonus_xp; + + while( newXP >= nextLvlXP && level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) + { + newXP -= nextLvlXP; + + if ( level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) + GiveLevel(level + 1); + + level = getLevel(); + nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); + } + + SetUInt32Value(PLAYER_XP, newXP); +} + +// Update player to next level +// Current player experience not update (must be update by caller) +void Player::GiveLevel(uint32 level) +{ + if ( level == getLevel() ) + return; + + PlayerLevelInfo info; + objmgr.GetPlayerLevelInfo(getRace(),getClass(),level,&info); + + PlayerClassLevelInfo classInfo; + objmgr.GetPlayerClassLevelInfo(getClass(),level,&classInfo); + + // send levelup info to client + WorldPacket data(SMSG_LEVELUP_INFO, (4+4+MAX_POWERS*4+MAX_STATS*4)); + data << uint32(level); + data << uint32(int32(classInfo.basehealth) - int32(GetCreateHealth())); + // for(int i = 0; i < MAX_POWERS; ++i) // Powers loop (0-6) + data << uint32(int32(classInfo.basemana) - int32(GetCreateMana())); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + // end for + for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) // Stats loop (0-4) + data << uint32(int32(info.stats[i]) - GetCreateStat(Stats(i))); + + GetSession()->SendPacket(&data); + + SetUInt32Value(PLAYER_NEXT_LEVEL_XP, MaNGOS::XP::xp_to_level(level)); + + //update level, max level of skills + if(getLevel()!= level) + m_Played_time[1] = 0; // Level Played Time reset + SetLevel(level); + UpdateMaxSkills(); + + // save base values (bonuses already included in stored stats + for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) + SetCreateStat(Stats(i), info.stats[i]); + + SetCreateHealth(classInfo.basehealth); + SetCreateMana(classInfo.basemana); + + InitTalentForLevel(); + InitTaxiNodesForLevel(); + + UpdateAllStats(); + + // set current level health and mana/energy to maximum after applying all mods. + SetHealth(GetMaxHealth()); + SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); + SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); + if(GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE)) + SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE)); + SetPower(POWER_FOCUS, 0); + SetPower(POWER_HAPPINESS, 0); + + // give level to summoned pet + Pet* pet = GetPet(); + if(pet && pet->getPetType()==SUMMON_PET) + pet->GivePetLevel(level); +} + +void Player::InitTalentForLevel() +{ + uint32 level = getLevel(); + // talents base at level diff ( talents = level - 9 but some can be used already) + if(level < 10) + { + // Remove all talent points + if(m_usedTalentCount > 0) // Free any used talents + { + resetTalents(true); + SetFreeTalentPoints(0); + } + } + else + { + uint32 talentPointsForLevel = uint32((level-9)*sWorld.getRate(RATE_TALENT)); + // if used more that have then reset + if(m_usedTalentCount > talentPointsForLevel) + { + if (GetSession()->GetSecurity() < SEC_ADMINISTRATOR) + resetTalents(true); + else + SetFreeTalentPoints(0); + } + // else update amount of free points + else + SetFreeTalentPoints(talentPointsForLevel-m_usedTalentCount); + } +} + +void Player::InitStatsForLevel(bool reapplyMods) +{ + if(reapplyMods) //reapply stats values only on .reset stats (level) command + _RemoveAllStatBonuses(); + + PlayerClassLevelInfo classInfo; + objmgr.GetPlayerClassLevelInfo(getClass(),getLevel(),&classInfo); + + PlayerLevelInfo info; + objmgr.GetPlayerLevelInfo(getRace(),getClass(),getLevel(),&info); + + SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ); + SetUInt32Value(PLAYER_NEXT_LEVEL_XP, MaNGOS::XP::xp_to_level(getLevel())); + + UpdateMaxSkills (); + + // set default cast time multiplier + SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); + + // reset size before reapply auras + SetFloatValue(OBJECT_FIELD_SCALE_X,1.0f); + + // save base values (bonuses already included in stored stats + for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) + SetCreateStat(Stats(i), info.stats[i]); + + for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) + SetStat(Stats(i), info.stats[i]); + + SetCreateHealth(classInfo.basehealth); + + //set create powers + SetCreateMana(classInfo.basemana); + + SetArmor(int32(m_createStats[STAT_AGILITY]*2)); + + InitStatBuffMods(); + + //reset rating fields values + for(uint16 index = PLAYER_FIELD_COMBAT_RATING_1; index < PLAYER_FIELD_COMBAT_RATING_1 + MAX_COMBAT_RATING; ++index) + SetUInt32Value(index, 0); + + SetUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS,0); + for (int i = 0; i < 7; i++) + { + SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i, 0); + SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, 0); + SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT+i, 1.00f); + } + + //reset attack power, damage and attack speed fields + SetFloatValue(UNIT_FIELD_BASEATTACKTIME, 2000.0f ); + SetFloatValue(UNIT_FIELD_BASEATTACKTIME + 1, 2000.0f ); // offhand attack time + SetFloatValue(UNIT_FIELD_RANGEDATTACKTIME, 2000.0f ); + + SetFloatValue(UNIT_FIELD_MINDAMAGE, 0.0f ); + SetFloatValue(UNIT_FIELD_MAXDAMAGE, 0.0f ); + SetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, 0.0f ); + SetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, 0.0f ); + SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, 0.0f ); + SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, 0.0f ); + + SetUInt32Value(UNIT_FIELD_ATTACK_POWER, 0 ); + SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, 0 ); + SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER,0.0f); + SetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, 0 ); + SetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS,0 ); + SetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER,0.0f); + + // Base crit values (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset + SetFloatValue(PLAYER_CRIT_PERCENTAGE,0.0f); + SetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE,0.0f); + SetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE,0.0f); + + // Init spell schools (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset + for (uint8 i = 0; i < 7; ++i) + SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1+i, 0.0f); + + SetFloatValue(PLAYER_PARRY_PERCENTAGE, 0.0f); + SetFloatValue(PLAYER_BLOCK_PERCENTAGE, 0.0f); + SetUInt32Value(PLAYER_SHIELD_BLOCK, 0); + + // Dodge percentage + SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.0f); + + // set armor (resistance 0) to original value (create_agility*2) + SetArmor(int32(m_createStats[STAT_AGILITY]*2)); + SetResistanceBuffMods(SpellSchools(0), true, 0.0f); + SetResistanceBuffMods(SpellSchools(0), false, 0.0f); + // set other resistance to original value (0) + for (int i = 1; i < MAX_SPELL_SCHOOL; i++) + { + SetResistance(SpellSchools(i), 0); + SetResistanceBuffMods(SpellSchools(i), true, 0.0f); + SetResistanceBuffMods(SpellSchools(i), false, 0.0f); + } + + SetUInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE,0); + SetUInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE,0); + for(int i = 0; i < MAX_SPELL_SCHOOL; ++i) + { + SetFloatValue(UNIT_FIELD_POWER_COST_MODIFIER+i,0.0f); + SetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+i,0.0f); + } + // Init data for form but skip reapply item mods for form + InitDataForForm(reapplyMods); + + // save new stats + for (int i = POWER_MANA; i < MAX_POWERS; i++) + SetMaxPower(Powers(i), uint32(GetCreatePowers(Powers(i)))); + + SetMaxHealth(classInfo.basehealth); // stamina bonus will applied later + + // cleanup mounted state (it will set correctly at aura loading if player saved at mount. + SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); + + // cleanup unit flags (will be re-applied if need at aura load). + RemoveFlag( UNIT_FIELD_FLAGS, + UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_ATTACKABLE_1 | + UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_SILENCED | UNIT_FLAG_PACIFIED | + UNIT_FLAG_DISABLE_ROTATE | UNIT_FLAG_IN_COMBAT | UNIT_FLAG_DISARMED | + UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING | UNIT_FLAG_NOT_SELECTABLE | + UNIT_FLAG_SKINNABLE | UNIT_FLAG_MOUNT | UNIT_FLAG_TAXI_FLIGHT ); + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE ); // must be set + + // cleanup player flags (will be re-applied if need at aura load), to avoid have ghost flag without ghost aura, for example. + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST | PLAYER_FLAGS_FFA_PVP); + + SetByteValue(UNIT_FIELD_BYTES_1, 2, 0x00); // one form stealth modified bytes + + // restore if need some important flags + SetUInt32Value(PLAYER_FIELD_BYTES2, 0 ); // flags empty by default + + if(reapplyMods) //reapply stats values only on .reset stats (level) command + _ApplyAllStatBonuses(); + + // set current level health and mana/energy to maximum after applying all mods. + SetHealth(GetMaxHealth()); + SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); + SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); + if(GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE)) + SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE)); + SetPower(POWER_FOCUS, 0); + SetPower(POWER_HAPPINESS, 0); +} + +void Player::SendInitialSpells() +{ + uint16 spellCount = 0; + + WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4))); + data << uint8(0); + + size_t countPos = data.wpos(); + data << uint16(spellCount); // spell count placeholder + + for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) + { + if(itr->second->state == PLAYERSPELL_REMOVED) + continue; + + if(!itr->second->active || itr->second->disabled) + continue; + + data << uint16(itr->first); + //data << uint16(itr->second->slotId); + data << uint16(0); // it's not slot id + + spellCount +=1; + } + + data.put(countPos,spellCount); // write real count value + + uint16 spellCooldowns = m_spellCooldowns.size(); + data << uint16(spellCooldowns); + for(SpellCooldowns::const_iterator itr=m_spellCooldowns.begin(); itr!=m_spellCooldowns.end(); itr++) + { + SpellEntry const *sEntry = sSpellStore.LookupEntry(itr->first); + if(!sEntry) + continue; + + data << uint16(itr->first); + + time_t cooldown = 0; + time_t curTime = time(NULL); + if(itr->second.end > curTime) + cooldown = (itr->second.end-curTime)*1000; + + data << uint16(itr->second.itemid); // cast item id + data << uint16(sEntry->Category); // spell category + if(sEntry->Category) // may be wrong, but anyway better than nothing... + { + data << uint32(0); + data << uint32(cooldown); + } + else + { + data << uint32(cooldown); + data << uint32(0); + } + } + + GetSession()->SendPacket(&data); + + sLog.outDetail( "CHARACTER: Sent Initial Spells" ); +} + +void Player::RemoveMail(uint32 id) +{ + for(PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end();++itr) + { + if ((*itr)->messageID == id) + { + //do not delete item, because Player::removeMail() is called when returning mail to sender. + m_mail.erase(itr); + return; + } + } +} + +void Player::SendMailResult(uint32 mailId, uint32 mailAction, uint32 mailError, uint32 equipError, uint32 item_guid, uint32 item_count) +{ + WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(mailError == MAIL_ERR_BAG_FULL?4:(mailAction == MAIL_ITEM_TAKEN?4+4:0)))); + data << (uint32) mailId; + data << (uint32) mailAction; + data << (uint32) mailError; + if ( mailError == MAIL_ERR_BAG_FULL ) + data << (uint32) equipError; + else if( mailAction == MAIL_ITEM_TAKEN ) + { + data << (uint32) item_guid; // item guid low? + data << (uint32) item_count; // item count? + } + GetSession()->SendPacket(&data); +} + +void Player::SendNewMail() +{ + // deliver undelivered mail + WorldPacket data(SMSG_RECEIVED_MAIL, 4); + data << (uint32) 0; + GetSession()->SendPacket(&data); +} + +void Player::UpdateNextMailTimeAndUnreads() +{ + // calculate next delivery time (min. from non-delivered mails + // and recalculate unReadMail + time_t cTime = time(NULL); + m_nextMailDelivereTime = 0; + unReadMails = 0; + for(PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) + { + if((*itr)->deliver_time > cTime) + { + if(!m_nextMailDelivereTime || m_nextMailDelivereTime > (*itr)->deliver_time) + m_nextMailDelivereTime = (*itr)->deliver_time; + } + else if(((*itr)->checked & MAIL_CHECK_MASK_READ) == 0) + ++unReadMails; + } +} + +void Player::AddNewMailDeliverTime(time_t deliver_time) +{ + if(deliver_time <= time(NULL)) // ready now + { + ++unReadMails; + SendNewMail(); + } + else // not ready and no have ready mails + { + if(!m_nextMailDelivereTime || m_nextMailDelivereTime > deliver_time) + m_nextMailDelivereTime = deliver_time; + } +} + +bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading, uint16 slot_id, bool disabled) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + if (!spellInfo) + { + // do character spell book cleanup (all characters) + if(loading && !learning) // spell load case + { + sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.",spell_id); + CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'",spell_id); + } + else + sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id); + + return false; + } + + if(!SpellMgr::IsSpellValid(spellInfo,this,false)) + { + // do character spell book cleanup (all characters) + if(loading && !learning) // spell load case + { + sLog.outError("Player::addSpell: Broken spell #%u learning not allowed, deleting for all characters in `character_spell`.",spell_id); + CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'",spell_id); + } + else + sLog.outError("Player::addSpell: Broken spell #%u learning not allowed.",spell_id); + + return false; + } + + PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED; + + bool disabled_case = false; + bool superceded_old = false; + + PlayerSpellMap::iterator itr = m_spells.find(spell_id); + if (itr != m_spells.end()) + { + // update active state for known spell + if(itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled) + { + itr->second->active = active; + + // loading && !learning == explicitly load from DB and then exist in it already and set correctly + if(loading && !learning) + itr->second->state = PLAYERSPELL_UNCHANGED; + else if(itr->second->state != PLAYERSPELL_NEW) + itr->second->state = PLAYERSPELL_CHANGED; + + if(!active) + { + WorldPacket data(SMSG_REMOVED_SPELL, 4); + data << uint16(spell_id); + GetSession()->SendPacket(&data); + } + return active; // learn (show in spell book if active now) + } + + if(itr->second->disabled != disabled && itr->second->state != PLAYERSPELL_REMOVED) + { + if(itr->second->state != PLAYERSPELL_NEW) + itr->second->state = PLAYERSPELL_CHANGED; + itr->second->disabled = disabled; + + if(disabled) + return false; + + disabled_case = true; + } + else switch(itr->second->state) + { + case PLAYERSPELL_UNCHANGED: // known saved spell + return false; + case PLAYERSPELL_REMOVED: // re-learning removed not saved spell + { + delete itr->second; + m_spells.erase(itr); + state = PLAYERSPELL_CHANGED; + break; // need re-add + } + default: // known not saved yet spell (new or modified) + { + // can be in case spell loading but learned at some previous spell loading + if(loading && !learning) + itr->second->state = PLAYERSPELL_UNCHANGED; + + return false; + } + } + } + + if(!disabled_case) // skip new spell adding if spell already known (disabled spells case) + { + // talent: unlearn all other talent ranks (high and low) + if(TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id)) + { + if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id )) + { + for(int i=0; i <5; ++i) + { + // skip learning spell and no rank spell case + uint32 rankSpellId = talentInfo->RankID[i]; + if(!rankSpellId || rankSpellId==spell_id) + continue; + + // skip unknown ranks + if(!HasSpell(rankSpellId)) + continue; + + removeSpell(rankSpellId); + } + } + } + // non talent spell: learn low ranks (recursive call) + else if(uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id)) + { + if(loading) // at spells loading, no output, but allow save + addSpell(prev_spell,active,true,loading,SPELL_WITHOUT_SLOT_ID,disabled); + else // at normal learning + learnSpell(prev_spell); + } + + PlayerSpell *newspell = new PlayerSpell; + newspell->active = active; + newspell->state = state; + newspell->disabled = disabled; + + // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible + if(newspell->active && !newspell->disabled && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) + { + for( PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr ) + { + if(itr->second->state == PLAYERSPELL_REMOVED) continue; + SpellEntry const *i_spellInfo = sSpellStore.LookupEntry(itr->first); + if(!i_spellInfo) continue; + + if( spellmgr.IsRankSpellDueToSpell(spellInfo,itr->first) ) + { + if(itr->second->active) + { + if(spellmgr.IsHighRankOfSpell(spell_id,itr->first)) + { + if(!loading) // not send spell (re-/over-)learn packets at loading + { + WorldPacket data(SMSG_SUPERCEDED_SPELL, (4)); + data << uint16(itr->first); + data << uint16(spell_id); + GetSession()->SendPacket( &data ); + } + + // mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new) + itr->second->active = false; + itr->second->state = PLAYERSPELL_CHANGED; + superceded_old = true; // new spell replace old in action bars and spell book. + } + else if(spellmgr.IsHighRankOfSpell(itr->first,spell_id)) + { + if(!loading) // not send spell (re-/over-)learn packets at loading + { + WorldPacket data(SMSG_SUPERCEDED_SPELL, (4)); + data << uint16(spell_id); + data << uint16(itr->first); + GetSession()->SendPacket( &data ); + } + + // mark new spell as disable (not learned yet for client and will not learned) + newspell->active = false; + if(newspell->state != PLAYERSPELL_NEW) + newspell->state = PLAYERSPELL_CHANGED; + } + } + } + } + } + + uint16 tmpslot=slot_id; + + if (tmpslot == SPELL_WITHOUT_SLOT_ID) + { + uint16 maxid = 0; + PlayerSpellMap::iterator itr; + for (itr = m_spells.begin(); itr != m_spells.end(); ++itr) + { + if(itr->second->state == PLAYERSPELL_REMOVED) + continue; + if (itr->second->slotId > maxid) + maxid = itr->second->slotId; + } + tmpslot = maxid + 1; + } + + newspell->slotId = tmpslot; + m_spells[spell_id] = newspell; + + // return false if spell disabled + if (newspell->disabled) + return false; + } + + uint32 talentCost = GetTalentSpellCost(spell_id); + + // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned) + // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive + if( talentCost > 0 && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_LEARN_SPELL) ) + { + // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show) + CastSpell(this, spell_id, true); + } + // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks + else if (IsPassiveSpell(spell_id)) + { + // if spell doesn't require a stance or the player is in the required stance + if( ( !spellInfo->Stances && + spell_id != 5420 && spell_id != 5419 && spell_id != 7376 && + spell_id != 7381 && spell_id != 21156 && spell_id != 21009 && + spell_id != 21178 && spell_id != 33948 && spell_id != 40121 ) || + m_form != 0 && (spellInfo->Stances & (1<<(m_form-1))) || + (spell_id == 5420 && m_form == FORM_TREE) || + (spell_id == 5419 && m_form == FORM_TRAVEL) || + (spell_id == 7376 && m_form == FORM_DEFENSIVESTANCE) || + (spell_id == 7381 && m_form == FORM_BERSERKERSTANCE) || + (spell_id == 21156 && m_form == FORM_BATTLESTANCE)|| + (spell_id == 21178 && (m_form == FORM_BEAR || m_form == FORM_DIREBEAR) ) || + (spell_id == 33948 && m_form == FORM_FLIGHT) || + (spell_id == 40121 && m_form == FORM_FLIGHT_EPIC) ) + //Check CasterAuraStates + if (!spellInfo->CasterAuraState || HasAuraState(AuraState(spellInfo->CasterAuraState))) + CastSpell(this, spell_id, true); + } + else if( IsSpellHaveEffect(spellInfo,SPELL_EFFECT_SKILL_STEP) ) + { + CastSpell(this, spell_id, true); + return false; + } + + // update used talent points count + m_usedTalentCount += talentCost; + + // update free primary prof.points (if any, can be none in case GM .learn prof. learning) + if(uint32 freeProfs = GetFreePrimaryProffesionPoints()) + { + if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) + SetFreePrimaryProffesions(freeProfs-1); + } + + // add dependent skills + uint16 maxskill = GetMaxSkillValueForLevel(); + + SpellLearnSkillNode const* spellLearnSkill = spellmgr.GetSpellLearnSkill(spell_id); + + if(spellLearnSkill) + { + uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill); + uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill); + + if(skill_value < spellLearnSkill->value) + skill_value = spellLearnSkill->value; + + uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? maxskill : spellLearnSkill->maxvalue; + + if(skill_max_value < new_skill_max_value) + skill_max_value = new_skill_max_value; + + SetSkill(spellLearnSkill->skill,skill_value,skill_max_value); + } + else + { + // not ranked skills + SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id); + SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id); + + for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) + { + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId); + if(!pSkill) + continue; + + if(HasSkill(pSkill->id)) + continue; + + if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL || + // poison special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL + pSkill->id==SKILL_POISONS && _spell_idx->second->max_value==0 || + // lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL + pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 ) + { + switch(GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0)) + { + case SKILL_RANGE_LANGUAGE: + SetSkill(pSkill->id, 300, 300 ); + break; + case SKILL_RANGE_LEVEL: + SetSkill(pSkill->id, 1, GetMaxSkillValueForLevel() ); + break; + case SKILL_RANGE_MONO: + SetSkill(pSkill->id, 1, 1 ); + break; + default: + break; + } + } + } + } + + // learn dependent spells + SpellLearnSpellMap::const_iterator spell_begin = spellmgr.GetBeginSpellLearnSpell(spell_id); + SpellLearnSpellMap::const_iterator spell_end = spellmgr.GetEndSpellLearnSpell(spell_id); + + for(SpellLearnSpellMap::const_iterator itr = spell_begin; itr != spell_end; ++itr) + { + if(!itr->second.autoLearned) + { + if(loading) // at spells loading, no output, but allow save + addSpell(itr->second.spell,true,true,loading); + else // at normal learning + learnSpell(itr->second.spell); + } + } + + // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell + return active && !disabled && !superceded_old; +} + +void Player::learnSpell(uint32 spell_id) +{ + PlayerSpellMap::iterator itr = m_spells.find(spell_id); + + bool disabled = (itr != m_spells.end()) ? itr->second->disabled : false; + bool active = disabled ? itr->second->active : true; + + bool learning = addSpell(spell_id,active); + + // learn all disabled higher ranks (recursive) + SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); + for(SpellChainMapNext::const_iterator i = nextMap.lower_bound(spell_id); i != nextMap.upper_bound(spell_id); ++i) + { + PlayerSpellMap::iterator iter = m_spells.find(i->second); + if (disabled && iter != m_spells.end() && iter->second->disabled) + learnSpell(i->second); + } + + // prevent duplicated entires in spell book + if(!learning) + return; + + WorldPacket data(SMSG_LEARNED_SPELL, 4); + data << uint32(spell_id); + GetSession()->SendPacket(&data); +} + +void Player::removeSpell(uint32 spell_id, bool disabled) +{ + PlayerSpellMap::iterator itr = m_spells.find(spell_id); + if (itr == m_spells.end()) + return; + + if(itr->second->state == PLAYERSPELL_REMOVED || disabled && itr->second->disabled) + return; + + // unlearn non talent higher ranks (recursive) + SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); + for(SpellChainMapNext::const_iterator itr2 = nextMap.lower_bound(spell_id); itr2 != nextMap.upper_bound(spell_id); ++itr2) + if(HasSpell(itr2->second) && !GetTalentSpellPos(itr2->second)) + removeSpell(itr2->second,disabled); + + // removing + WorldPacket data(SMSG_REMOVED_SPELL, 4); + data << uint16(spell_id); + GetSession()->SendPacket(&data); + + if (disabled) + { + itr->second->disabled = disabled; + if(itr->second->state != PLAYERSPELL_NEW) + itr->second->state = PLAYERSPELL_CHANGED; + } + else + { + if(itr->second->state == PLAYERSPELL_NEW) + { + delete itr->second; + m_spells.erase(itr); + } + else + itr->second->state = PLAYERSPELL_REMOVED; + } + + RemoveAurasDueToSpell(spell_id); + + // remove pet auras + if(PetAura const* petSpell = spellmgr.GetPetAura(spell_id)) + RemovePetAura(petSpell); + + // free talent points + uint32 talentCosts = GetTalentSpellCost(spell_id); + if(talentCosts > 0) + { + if(talentCosts < m_usedTalentCount) + m_usedTalentCount -= talentCosts; + else + m_usedTalentCount = 0; + } + + // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning) + if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) + { + uint32 freeProfs = GetFreePrimaryProffesionPoints()+1; + if(freeProfs <= sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)) + SetFreePrimaryProffesions(freeProfs); + } + + // remove dependent skill + SpellLearnSkillNode const* spellLearnSkill = spellmgr.GetSpellLearnSkill(spell_id); + if(spellLearnSkill) + { + uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id); + if(!prev_spell) // first rank, remove skill + SetSkill(spellLearnSkill->skill,0,0); + else + { + // search prev. skill setting by spell ranks chain + SpellLearnSkillNode const* prevSkill = spellmgr.GetSpellLearnSkill(prev_spell); + while(!prevSkill && prev_spell) + { + prev_spell = spellmgr.GetPrevSpellInChain(prev_spell); + prevSkill = spellmgr.GetSpellLearnSkill(spellmgr.GetFirstSpellInChain(prev_spell)); + } + + if(!prevSkill) // not found prev skill setting, remove skill + SetSkill(spellLearnSkill->skill,0,0); + else // set to prev. skill setting values + { + uint32 skill_value = GetPureSkillValue(prevSkill->skill); + uint32 skill_max_value = GetPureMaxSkillValue(prevSkill->skill); + + if(skill_value > prevSkill->value) + skill_value = prevSkill->value; + + uint32 new_skill_max_value = prevSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : prevSkill->maxvalue; + + if(skill_max_value > new_skill_max_value) + skill_max_value = new_skill_max_value; + + SetSkill(prevSkill->skill,skill_value,skill_max_value); + } + } + + } + else + { + // not ranked skills + SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id); + SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id); + + for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) + { + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId); + if(!pSkill) + continue; + + if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL || + // poison special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL + pSkill->id==SKILL_POISONS && _spell_idx->second->max_value==0 || + // lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL + pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 ) + { + // not reset skills for professions and racial abilities + if( (pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) && + (IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask!=0) ) + continue; + + SetSkill(pSkill->id, 0, 0 ); + } + } + } + + // remove dependent spells + SpellLearnSpellMap::const_iterator spell_begin = spellmgr.GetBeginSpellLearnSpell(spell_id); + SpellLearnSpellMap::const_iterator spell_end = spellmgr.GetEndSpellLearnSpell(spell_id); + + for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2) + removeSpell(itr2->second.spell, disabled); +} + +void Player::RemoveArenaSpellCooldowns() +{ + // remove cooldowns on spells that has < 15 min CD + SpellCooldowns::iterator itr, next; + // iterate spell cooldowns + for(itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); itr = next) + { + next = itr; + ++next; + SpellEntry const * entry = sSpellStore.LookupEntry(itr->first); + // check if spellentry is present and if the cooldown is less than 15 mins + if( entry && + entry->RecoveryTime <= 15 * MINUTE * 1000 && + entry->CategoryRecoveryTime <= 15 * MINUTE * 1000 ) + { + // notify player + WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); + data << uint32(itr->first); + data << GetGUID(); + GetSession()->SendPacket(&data); + // remove cooldown + m_spellCooldowns.erase(itr); + } + } +} + +void Player::RemoveAllSpellCooldown() +{ + if(!m_spellCooldowns.empty()) + { + for(SpellCooldowns::const_iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); ++itr) + { + WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); + data << uint32(itr->first); + data << uint64(GetGUID()); + GetSession()->SendPacket(&data); + } + m_spellCooldowns.clear(); + } +} + +void Player::_LoadSpellCooldowns(QueryResult *result) +{ + m_spellCooldowns.clear(); + + //QueryResult *result = CharacterDatabase.PQuery("SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'",GetGUIDLow()); + + if(result) + { + time_t curTime = time(NULL); + + do + { + Field *fields = result->Fetch(); + + uint32 spell_id = fields[0].GetUInt32(); + uint32 item_id = fields[1].GetUInt32(); + time_t db_time = (time_t)fields[2].GetUInt64(); + + if(!sSpellStore.LookupEntry(spell_id)) + { + sLog.outError("Player %u have unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id); + continue; + } + + // skip outdated cooldown + if(db_time <= curTime) + continue; + + AddSpellCooldown(spell_id, item_id, db_time); + + sLog.outDebug("Player (GUID: %u) spell %u, item %u cooldown loaded (%u secs).", GetGUIDLow(), spell_id, item_id, uint32(db_time-curTime)); + } + while( result->NextRow() ); + + delete result; + } +} + +void Player::_SaveSpellCooldowns() +{ + CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow()); + + time_t curTime = time(NULL); + + // remove outdated and save active + for(SpellCooldowns::iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end();) + { + if(itr->second.end <= curTime) + m_spellCooldowns.erase(itr++); + else + { + CharacterDatabase.PExecute("INSERT INTO character_spell_cooldown (guid,spell,item,time) VALUES ('%u', '%u', '%u', '" I64FMTD "')", GetGUIDLow(), itr->first, itr->second.itemid, uint64(itr->second.end)); + ++itr; + } + } +} + +uint32 Player::resetTalentsCost() const +{ + // The first time reset costs 1 gold + if(m_resetTalentsCost < 1*GOLD) + return 1*GOLD; + // then 5 gold + else if(m_resetTalentsCost < 5*GOLD) + return 5*GOLD; + // After that it increases in increments of 5 gold + else if(m_resetTalentsCost < 10*GOLD) + return 10*GOLD; + else + { + uint32 months = (sWorld.GetGameTime() - m_resetTalentsTime)/MONTH; + if(months > 0) + { + // This cost will be reduced by a rate of 5 gold per month + int32 new_cost = int32(m_resetTalentsCost) - 5*GOLD*months; + // to a minimum of 10 gold. + return (new_cost < 10*GOLD ? 10*GOLD : new_cost); + } + else + { + // After that it increases in increments of 5 gold + int32 new_cost = m_resetTalentsCost + 5*GOLD; + // until it hits a cap of 50 gold. + if(new_cost > 50*GOLD) + new_cost = 50*GOLD; + return new_cost; + } + } +} + +bool Player::resetTalents(bool no_cost) +{ + // not need after this call + if(HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) + { + m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_TALENTS; + CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_TALENTS), GetGUIDLow()); + } + + uint32 level = getLevel(); + uint32 talentPointsForLevel = level < 10 ? 0 : uint32((level-9)*sWorld.getRate(RATE_TALENT)); + + if (m_usedTalentCount == 0) + { + SetFreeTalentPoints(talentPointsForLevel); + return false; + } + + uint32 cost = 0; + + if(!no_cost) + { + cost = resetTalentsCost(); + + if (GetMoney() < cost) + { + SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0); + return false; + } + } + + for (unsigned int i = 0; i < sTalentStore.GetNumRows(); i++) + { + TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); + + if (!talentInfo) continue; + + TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab ); + + if(!talentTabInfo) + continue; + + // unlearn only talents for character class + // some spell learned by one class as normal spells or know at creation but another class learn it as talent, + // to prevent unexpected lost normal learned spell skip another class talents + if( (getClassMask() & talentTabInfo->ClassMask) == 0 ) + continue; + + for (int j = 0; j < 5; j++) + { + for(PlayerSpellMap::iterator itr = GetSpellMap().begin(); itr != GetSpellMap().end();) + { + if(itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) + { + ++itr; + continue; + } + + // remove learned spells (all ranks) + uint32 itrFirstId = spellmgr.GetFirstSpellInChain(itr->first); + + // unlearn if first rank is talent or learned by talent + if (itrFirstId == talentInfo->RankID[j] || spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId)) + { + removeSpell(itr->first,!IsPassiveSpell(itr->first)); + itr = GetSpellMap().begin(); + continue; + } + else + ++itr; + } + } + } + + SetFreeTalentPoints(talentPointsForLevel); + + if(!no_cost) + { + ModifyMoney(-(int32)cost); + + m_resetTalentsCost = cost; + m_resetTalentsTime = time(NULL); + } + + //FIXME: remove pet before or after unlearn spells? for now after unlearn to allow removing of talent related, pet affecting auras + RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true); + + return true; +} + +bool Player::_removeSpell(uint16 spell_id) +{ + PlayerSpellMap::iterator itr = m_spells.find(spell_id); + if (itr != m_spells.end()) + { + delete itr->second; + m_spells.erase(itr); + return true; + } + return false; +} + +Mail* Player::GetMail(uint32 id) +{ + for(PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); itr++) + { + if ((*itr)->messageID == id) + { + return (*itr); + } + } + return NULL; +} + +void Player::_SetCreateBits(UpdateMask *updateMask, Player *target) const +{ + if(target == this) + { + Object::_SetCreateBits(updateMask, target); + } + else + { + for(uint16 index = 0; index < m_valuesCount; index++) + { + if(GetUInt32Value(index) != 0 && updateVisualBits.GetBit(index)) + updateMask->SetBit(index); + } + } +} + +void Player::_SetUpdateBits(UpdateMask *updateMask, Player *target) const +{ + if(target == this) + { + Object::_SetUpdateBits(updateMask, target); + } + else + { + Object::_SetUpdateBits(updateMask, target); + *updateMask &= updateVisualBits; + } +} + +void Player::InitVisibleBits() +{ + updateVisualBits.SetCount(PLAYER_END); + + updateVisualBits.SetBit(OBJECT_FIELD_GUID); + updateVisualBits.SetBit(OBJECT_FIELD_TYPE); + updateVisualBits.SetBit(OBJECT_FIELD_SCALE_X); + + updateVisualBits.SetBit(UNIT_FIELD_CHARM); + updateVisualBits.SetBit(UNIT_FIELD_CHARM+1); + + updateVisualBits.SetBit(UNIT_FIELD_SUMMON); + updateVisualBits.SetBit(UNIT_FIELD_SUMMON+1); + + updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY); + + updateVisualBits.SetBit(UNIT_FIELD_TARGET); + updateVisualBits.SetBit(UNIT_FIELD_TARGET+1); + + updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT); + updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT+1); + + updateVisualBits.SetBit(UNIT_FIELD_HEALTH); + updateVisualBits.SetBit(UNIT_FIELD_POWER1); + updateVisualBits.SetBit(UNIT_FIELD_POWER2); + updateVisualBits.SetBit(UNIT_FIELD_POWER3); + updateVisualBits.SetBit(UNIT_FIELD_POWER4); + updateVisualBits.SetBit(UNIT_FIELD_POWER5); + + updateVisualBits.SetBit(UNIT_FIELD_MAXHEALTH); + updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER1); + updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER2); + updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER3); + updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER4); + updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER5); + + updateVisualBits.SetBit(UNIT_FIELD_LEVEL); + updateVisualBits.SetBit(UNIT_FIELD_FACTIONTEMPLATE); + updateVisualBits.SetBit(UNIT_FIELD_BYTES_0); + updateVisualBits.SetBit(UNIT_FIELD_FLAGS); + updateVisualBits.SetBit(UNIT_FIELD_FLAGS_2); + for(uint16 i = UNIT_FIELD_AURA; i < UNIT_FIELD_AURASTATE; ++i) + updateVisualBits.SetBit(i); + updateVisualBits.SetBit(UNIT_FIELD_AURASTATE); + updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME); + updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME + 1); + updateVisualBits.SetBit(UNIT_FIELD_RANGEDATTACKTIME); + updateVisualBits.SetBit(UNIT_FIELD_BOUNDINGRADIUS); + updateVisualBits.SetBit(UNIT_FIELD_COMBATREACH); + updateVisualBits.SetBit(UNIT_FIELD_DISPLAYID); + updateVisualBits.SetBit(UNIT_FIELD_NATIVEDISPLAYID); + updateVisualBits.SetBit(UNIT_FIELD_MOUNTDISPLAYID); + updateVisualBits.SetBit(UNIT_FIELD_BYTES_1); + updateVisualBits.SetBit(UNIT_FIELD_MOUNTDISPLAYID); + updateVisualBits.SetBit(UNIT_FIELD_PETNUMBER); + updateVisualBits.SetBit(UNIT_FIELD_PET_NAME_TIMESTAMP); + updateVisualBits.SetBit(UNIT_DYNAMIC_FLAGS); + updateVisualBits.SetBit(UNIT_CHANNEL_SPELL); + updateVisualBits.SetBit(UNIT_MOD_CAST_SPEED); + updateVisualBits.SetBit(UNIT_FIELD_BYTES_2); + + updateVisualBits.SetBit(PLAYER_FLAGS); + updateVisualBits.SetBit(PLAYER_BYTES); + updateVisualBits.SetBit(PLAYER_BYTES_2); + updateVisualBits.SetBit(PLAYER_BYTES_3); + updateVisualBits.SetBit(PLAYER_GUILDID); + updateVisualBits.SetBit(PLAYER_GUILDRANK); + updateVisualBits.SetBit(PLAYER_GUILD_TIMESTAMP); + updateVisualBits.SetBit(PLAYER_DUEL_TEAM); + updateVisualBits.SetBit(PLAYER_DUEL_ARBITER); + updateVisualBits.SetBit(PLAYER_DUEL_ARBITER+1); + + // PLAYER_QUEST_LOG_x also visible bit on official (but only on party/raid)... + for(uint16 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_2; i+=4) + updateVisualBits.SetBit(i); + + //Players visible items are not inventory stuff + //431) = 884 (0x374) = main weapon + for(uint16 i = 0; i < EQUIPMENT_SLOT_END; i++) + { + // item creator + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + (i*MAX_VISIBLE_ITEM_OFFSET) + 0); + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + (i*MAX_VISIBLE_ITEM_OFFSET) + 1); + + uint16 visual_base = PLAYER_VISIBLE_ITEM_1_0 + (i*MAX_VISIBLE_ITEM_OFFSET); + + // item entry + updateVisualBits.SetBit(visual_base + 0); + + // item enchantment IDs + for(uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) + updateVisualBits.SetBit(visual_base + 1 + j); + + // random properties + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 0 + (i*MAX_VISIBLE_ITEM_OFFSET)); + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 1 + (i*MAX_VISIBLE_ITEM_OFFSET)); + } + + updateVisualBits.SetBit(PLAYER_CHOSEN_TITLE); + + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + 1); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + 2); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 1); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 2); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 3); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 4); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_INFO + 5); +} + +void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const +{ + for(int i = 0; i < EQUIPMENT_SLOT_END; i++) + { + if(m_items[i] == NULL) + continue; + + m_items[i]->BuildCreateUpdateBlockForPlayer( data, target ); + } + + if(target == this) + { + + for(int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + if(m_items[i] == NULL) + continue; + + m_items[i]->BuildCreateUpdateBlockForPlayer( data, target ); + } + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + if(m_items[i] == NULL) + continue; + + m_items[i]->BuildCreateUpdateBlockForPlayer( data, target ); + } + } + + Unit::BuildCreateUpdateBlockForPlayer( data, target ); +} + +void Player::DestroyForPlayer( Player *target ) const +{ + Unit::DestroyForPlayer( target ); + + for(int i = 0; i < INVENTORY_SLOT_BAG_END; i++) + { + if(m_items[i] == NULL) + continue; + + m_items[i]->DestroyForPlayer( target ); + } + + if(target == this) + { + + for(int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + if(m_items[i] == NULL) + continue; + + m_items[i]->DestroyForPlayer( target ); + } + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + if(m_items[i] == NULL) + continue; + + m_items[i]->DestroyForPlayer( target ); + } + } +} + +bool Player::HasSpell(uint32 spell) const +{ + PlayerSpellMap::const_iterator itr = m_spells.find((uint16)spell); + return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled); +} + +TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell) const +{ + if (!trainer_spell) + return TRAINER_SPELL_RED; + + if (!trainer_spell->spell) + return TRAINER_SPELL_RED; + + // known spell + if(HasSpell(trainer_spell->spell)) + return TRAINER_SPELL_GRAY; + + // check race/class requirement + if(!IsSpellFitByClassAndRace(trainer_spell->spell)) + return TRAINER_SPELL_RED; + + // check level requirement + if(getLevel() < trainer_spell->reqlevel) + return TRAINER_SPELL_RED; + + if(SpellChainNode const* spell_chain = spellmgr.GetSpellChainNode(trainer_spell->spell)) + { + // check prev.rank requirement + if(spell_chain->prev && !HasSpell(spell_chain->prev)) + return TRAINER_SPELL_RED; + + // check additional spell requirement + if(spell_chain->req && !HasSpell(spell_chain->req)) + return TRAINER_SPELL_RED; + } + + // check skill requirement + if(trainer_spell->reqskill && GetBaseSkillValue(trainer_spell->reqskill) < trainer_spell->reqskillvalue) + return TRAINER_SPELL_RED; + + // exist, already checked at loading + SpellEntry const* spell = sSpellStore.LookupEntry(trainer_spell->spell); + + // secondary prof. or not prof. spell + uint32 skill = spell->EffectMiscValue[1]; + + if(spell->Effect[1] != SPELL_EFFECT_SKILL || !IsPrimaryProfessionSkill(skill)) + return TRAINER_SPELL_GREEN; + + // check primary prof. limit + if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell->Id) && GetFreePrimaryProffesionPoints() == 0) + return TRAINER_SPELL_RED; + + return TRAINER_SPELL_GREEN; +} + +void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars) +{ + uint32 guid = GUID_LOPART(playerguid); + + // convert corpse to bones if exist (to prevent exiting Corpse in World without DB entry) + // bones will be deleted by corpse/bones deleting thread shortly + ObjectAccessor::Instance().ConvertCorpseForPlayer(playerguid); + + // remove from guild + uint32 guildId = GetGuildIdFromDB(playerguid); + if(guildId != 0) + { + Guild* guild = objmgr.GetGuildById(guildId); + if(guild) + guild->DelMember(guid); + } + + // the player was uninvited already on logout so just remove from group + QueryResult *resultGroup = CharacterDatabase.PQuery("SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", guid); + if(resultGroup) + { + uint64 leaderGuid = MAKE_NEW_GUID((*resultGroup)[0].GetUInt32(), 0, HIGHGUID_PLAYER); + delete resultGroup; + Group* group = objmgr.GetGroupByLeader(leaderGuid); + if(group) + { + RemoveFromGroup(group, playerguid); + } + } + + // remove signs from petitions (also remove petitions if owner); + RemovePetitionsAndSigns(playerguid, 10); + + // return back all mails with COD and Item 0 1 2 3 4 5 6 + QueryResult *resultMail = CharacterDatabase.PQuery("SELECT id,mailTemplateId,sender,subject,itemTextId,money,has_items FROM mail WHERE receiver='%u' AND has_items<>0 AND cod<>0", guid); + if(resultMail) + { + do + { + Field *fields = resultMail->Fetch(); + + uint32 mail_id = fields[0].GetUInt32(); + uint16 mailTemplateId= fields[1].GetUInt16(); + uint32 sender = fields[2].GetUInt32(); + std::string subject = fields[3].GetCppString(); + uint32 itemTextId = fields[4].GetUInt32(); + uint32 money = fields[5].GetUInt32(); + bool has_items = fields[6].GetBool(); + + //we can return mail now + //so firstly delete the old one + CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", mail_id); + + MailItemsInfo mi; + if(has_items) + { + QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", mail_id); + if(resultItems) + { + do + { + Field *fields2 = resultItems->Fetch(); + + uint32 item_guidlow = fields2[0].GetUInt32(); + uint32 item_template = fields2[1].GetUInt32(); + + ItemPrototype const* itemProto = objmgr.GetItemPrototype(item_template); + if(!itemProto) + { + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guidlow); + continue; + } + + Item *pItem = NewItemOrBag(itemProto); + if(!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER))) + { + pItem->FSetState(ITEM_REMOVED); + pItem->SaveToDB(); // it also deletes item object ! + continue; + } + + mi.AddItem(item_guidlow, item_template, pItem); + } + while (resultItems->NextRow()); + + delete resultItems; + } + } + + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mail_id); + + uint32 pl_account = objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); + + WorldSession::SendReturnToSender(MAIL_NORMAL, pl_account, guid, sender, subject, itemTextId, &mi, money, 0, mailTemplateId); + } + while (resultMail->NextRow()); + + delete resultMail; + } + + // unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet. + // Get guids of character's pets, will deleted in transaction + QueryResult *resultPets = CharacterDatabase.PQuery("SELECT id FROM character_pet WHERE owner = '%u'",guid); + + // NOW we can finally clear other DB data related to character + CharacterDatabase.BeginTransaction(); + if (resultPets) + { + do + { + Field *fields3 = resultPets->Fetch(); + uint32 petguidlow = fields3[0].GetUInt32(); + Pet::DeleteFromDB(petguidlow); + } while (resultPets->NextRow()); + delete resultPets; + } + + CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_homebind WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_queststatus WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE owner_guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' OR friend='%u'",guid,guid); + CharacterDatabase.PExecute("DELETE FROM mail WHERE receiver = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE receiver = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u'",guid); + CharacterDatabase.CommitTransaction(); + + //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID); + if(updateRealmChars) sWorld.UpdateRealmCharCount(accountId); +} + +void Player::SetMovement(PlayerMovementType pType) +{ + WorldPacket data; + switch(pType) + { + case MOVE_ROOT: data.Initialize(SMSG_FORCE_MOVE_ROOT, GetPackGUID().size()+4); break; + case MOVE_UNROOT: data.Initialize(SMSG_FORCE_MOVE_UNROOT, GetPackGUID().size()+4); break; + case MOVE_WATER_WALK: data.Initialize(SMSG_MOVE_WATER_WALK, GetPackGUID().size()+4); break; + case MOVE_LAND_WALK: data.Initialize(SMSG_MOVE_LAND_WALK, GetPackGUID().size()+4); break; + default: + sLog.outError("Player::SetMovement: Unsupported move type (%d), data not sent to client.",pType); + return; + } + data.append(GetPackGUID()); + data << uint32(0); + GetSession()->SendPacket( &data ); +} + +/* Preconditions: + - a resurrectable corpse must not be loaded for the player (only bones) + - the player must be in world +*/ +void Player::BuildPlayerRepop() +{ + if(getRace() == RACE_NIGHTELF) + CastSpell(this, 20584, true); // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) + CastSpell(this, 8326, true); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) + + // there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_WATER_WALK + // there must be SMSG.STOP_MIRROR_TIMER + // there we must send 888 opcode + + // the player cannot have a corpse already, only bones which are not returned by GetCorpse + if(GetCorpse()) + { + sLog.outError("BuildPlayerRepop: player %s(%d) already has a corpse", GetName(), GetGUIDLow()); + assert(false); + } + + // create a corpse and place it at the player's location + CreateCorpse(); + Corpse *corpse = GetCorpse(); + if(!corpse) + { + sLog.outError("Error creating corpse for Player %s [%u]", GetName(), GetGUIDLow()); + return; + } + GetMap()->Add(corpse); + + // convert player body to ghost + SetHealth( 1 ); + + SetMovement(MOVE_WATER_WALK); + if(!GetSession()->isLogingOut()) + SetMovement(MOVE_UNROOT); + + // BG - remove insignia related + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + + SendCorpseReclaimDelay(); + + // to prevent cheating + corpse->ResetGhostTime(); + + StopMirrorTimers(); //disable timers(bars) + + SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, (float)1.0); //see radius of death player? + + SetByteValue(UNIT_FIELD_BYTES_1, 3, PLAYER_STATE_FLAG_ALWAYS_STAND); +} + +void Player::SendDelayResponse(const uint32 ml_seconds) +{ + WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 ); + data << (uint32)time(NULL); + data << (uint32)0; + GetSession()->SendPacket( &data ); +} + +void Player::ResurrectPlayer(float restore_percent, bool updateToWorld, bool applySickness) +{ + WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // remove spirit healer position + data << uint32(-1); + data << float(0); + data << float(0); + data << float(0); + GetSession()->SendPacket(&data); + + // speed change, land walk + + // remove death flag + set aura + SetByteValue(UNIT_FIELD_BYTES_1, 3, 0x00); + if(getRace() == RACE_NIGHTELF) + RemoveAurasDueToSpell(20584); // speed bonuses + RemoveAurasDueToSpell(8326); // SPELL_AURA_GHOST + + setDeathState(ALIVE); + + SetMovement(MOVE_LAND_WALK); + SetMovement(MOVE_UNROOT); + + m_deathTimer = 0; + + // set health/powers (0- will be set in caller) + if(restore_percent>0.0f) + { + SetHealth(uint32(GetMaxHealth()*restore_percent)); + SetPower(POWER_MANA, uint32(GetMaxPower(POWER_MANA)*restore_percent)); + SetPower(POWER_RAGE, 0); + SetPower(POWER_ENERGY, uint32(GetMaxPower(POWER_ENERGY)*restore_percent)); + } + + // update visbility + ObjectAccessor::UpdateVisibilityForPlayer(this); + + // some items limited to specific map + DestroyZoneLimitedItem( true, GetZoneId()); + + if(!applySickness || getLevel() <= 10) + return; + + //Characters from level 1-10 are not affected by resurrection sickness. + //Characters from level 11-19 will suffer from one minute of sickness + //for each level they are above 10. + //Characters level 20 and up suffer from ten minutes of sickness. + int32 startLevel = sWorld.getConfig(CONFIG_DEATH_SICKNESS_LEVEL); + + if(int32(getLevel()) >= startLevel) + { + // set resurrection sickness + CastSpell(this,SPELL_ID_PASSIVE_RESURRECTION_SICKNESS,true); + + // not full duration + if(int32(getLevel()) < startLevel+9) + { + int32 delta = (int32(getLevel()) - startLevel + 1)*MINUTE; + + for(int i =0; i < 3; ++i) + { + if(Aura* Aur = GetAura(SPELL_ID_PASSIVE_RESURRECTION_SICKNESS,i)) + { + Aur->SetAuraDuration(delta*1000); + Aur->UpdateAuraDuration(); + } + } + } + } +} + +void Player::KillPlayer() +{ + SetMovement(MOVE_ROOT); + + StopMirrorTimers(); //disable timers(bars) + + setDeathState(CORPSE); + //SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_IN_PVP ); + + SetFlag(UNIT_DYNAMIC_FLAGS, 0x00); + ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(GetMapId())->Instanceable()); + + // 6 minutes until repop at graveyard + m_deathTimer = 6*MINUTE*1000; + + UpdateCorpseReclaimDelay(); // dependent at use SetDeathPvP() call before kill + + // don't create corpse at this moment, player might be falling + + // update visibility + ObjectAccessor::UpdateObjectVisibility(this); +} + +void Player::CreateCorpse() +{ + // prevent existence 2 corpse for player + SpawnCorpseBones(); + + uint32 _uf, _pb, _pb2, _cfb1, _cfb2; + + Corpse *corpse = new Corpse( (m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) ? CORPSE_RESURRECTABLE_PVP : CORPSE_RESURRECTABLE_PVE ); + SetPvPDeath(false); + + if(!corpse->Create(objmgr.GenerateLowGuid(HIGHGUID_CORPSE), this, GetMapId(), GetPositionX(), + GetPositionY(), GetPositionZ(), GetOrientation())) + { + delete corpse; + return; + } + + _uf = GetUInt32Value(UNIT_FIELD_BYTES_0); + _pb = GetUInt32Value(PLAYER_BYTES); + _pb2 = GetUInt32Value(PLAYER_BYTES_2); + + uint8 race = (uint8)(_uf); + uint8 skin = (uint8)(_pb); + uint8 face = (uint8)(_pb >> 8); + uint8 hairstyle = (uint8)(_pb >> 16); + uint8 haircolor = (uint8)(_pb >> 24); + uint8 facialhair = (uint8)(_pb2); + + _cfb1 = ((0x00) | (race << 8) | (getGender() << 16) | (skin << 24)); + _cfb2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24)); + + corpse->SetUInt32Value( CORPSE_FIELD_BYTES_1, _cfb1 ); + corpse->SetUInt32Value( CORPSE_FIELD_BYTES_2, _cfb2 ); + + uint32 flags = CORPSE_FLAG_UNK2; + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) + flags |= CORPSE_FLAG_HIDE_HELM; + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) + flags |= CORPSE_FLAG_HIDE_CLOAK; + if(InBattleGround()) + flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia + corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, flags ); + + corpse->SetUInt32Value( CORPSE_FIELD_DISPLAY_ID, GetNativeDisplayId() ); + + corpse->SetUInt32Value( CORPSE_FIELD_GUILD, GetGuildId() ); + + uint32 iDisplayID; + uint16 iIventoryType; + uint32 _cfi; + for (int i = 0; i < EQUIPMENT_SLOT_END; i++) + { + if(m_items[i]) + { + iDisplayID = m_items[i]->GetProto()->DisplayInfoID; + iIventoryType = (uint16)m_items[i]->GetProto()->InventoryType; + + _cfi = (uint16(iDisplayID)) | (iIventoryType)<< 24; + corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i,_cfi); + } + } + + // we don't SaveToDB for players in battlegrounds so don't do it for corpses either + const MapEntry *entry = sMapStore.LookupEntry(corpse->GetMapId()); + assert(entry); + if(entry->map_type != MAP_BATTLEGROUND) + corpse->SaveToDB(); + + // register for player, but not show + ObjectAccessor::Instance().AddCorpse(corpse); +} + +void Player::SpawnCorpseBones() +{ + if(ObjectAccessor::Instance().ConvertCorpseForPlayer(GetGUID())) + SaveToDB(); // prevent loading as ghost without corpse +} + +Corpse* Player::GetCorpse() const +{ + return ObjectAccessor::Instance().GetCorpseForPlayerGUID(GetGUID()); +} + +void Player::DurabilityLossAll(double percent, bool inventory) +{ + for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) + if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + DurabilityLoss(pItem,percent); + + if(inventory) + { + // bags not have durability + // for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + DurabilityLoss(pItem,percent); + + // keys not have durability + //for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if(ItemPrototype const *pBagProto = pBag->GetProto()) + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + if(Item* pItem = GetItemByPos( i, j )) + DurabilityLoss(pItem,percent); + } +} + +void Player::DurabilityLoss(Item* item, double percent) +{ + if(!item ) + return; + + uint32 pMaxDurability = item ->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); + + if(!pMaxDurability) + return; + + uint32 pDurabilityLoss = uint32(pMaxDurability*percent); + + if(pDurabilityLoss < 1 ) + pDurabilityLoss = 1; + + DurabilityPointsLoss(item,pDurabilityLoss); +} + +void Player::DurabilityPointsLossAll(int32 points, bool inventory) +{ + for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) + if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + DurabilityPointsLoss(pItem,points); + + if(inventory) + { + // bags not have durability + // for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + DurabilityPointsLoss(pItem,points); + + // keys not have durability + //for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if(ItemPrototype const *pBagProto = pBag->GetProto()) + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + if(Item* pItem = GetItemByPos( i, j )) + DurabilityPointsLoss(pItem,points); + } +} + +void Player::DurabilityPointsLoss(Item* item, int32 points) +{ + int32 pMaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); + int32 pOldDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); + int32 pNewDurability = pOldDurability - points; + + if (pNewDurability < 0) + pNewDurability = 0; + else if (pNewDurability > pMaxDurability) + pNewDurability = pMaxDurability; + + if (pOldDurability != pNewDurability) + { + // modify item stats _before_ Durability set to 0 to pass _ApplyItemMods internal check + if ( pNewDurability == 0 && pOldDurability > 0 && item->IsEquipped()) + _ApplyItemMods(item,item->GetSlot(), false); + + item->SetUInt32Value(ITEM_FIELD_DURABILITY, pNewDurability); + + // modify item stats _after_ restore durability to pass _ApplyItemMods internal check + if ( pNewDurability > 0 && pOldDurability == 0 && item->IsEquipped()) + _ApplyItemMods(item,item->GetSlot(), true); + + item->SetState(ITEM_CHANGED, this); + } +} + +void Player::DurabilityPointLossForEquipSlot(EquipmentSlots slot) +{ + if(Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, slot )) + DurabilityPointsLoss(pItem,1); +} + +uint32 Player::DurabilityRepairAll(bool cost, float discountMod, bool guildBank) +{ + uint32 TotalCost = 0; + // equipped, backpack, bags itself + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) + TotalCost += DurabilityRepair(( (INVENTORY_SLOT_BAG_0 << 8) | i ),cost,discountMod, guildBank); + + // bank, buyback and keys not repaired + + // items in inventory bags + for(int j = INVENTORY_SLOT_BAG_START; j < INVENTORY_SLOT_BAG_END; j++) + for(int i = 0; i < MAX_BAG_SIZE; i++) + TotalCost += DurabilityRepair(( (j << 8) | i ),cost,discountMod, guildBank); + return TotalCost; +} + +uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool guildBank) +{ + Item* item = GetItemByPos(pos); + + uint32 TotalCost = 0; + if(!item) + return TotalCost; + + uint32 maxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); + if(!maxDurability) + return TotalCost; + + uint32 curDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); + + if(cost) + { + uint32 LostDurability = maxDurability - curDurability; + if(LostDurability>0) + { + ItemPrototype const *ditemProto = sItemStorage.LookupEntry(item->GetEntry()); + if(!ditemProto) + { + sLog.outError("ERROR: RepairDurability: Unknown item id %u", ditemProto); + return TotalCost; + } + + DurabilityCostsEntry const *dcost = sDurabilityCostsStore.LookupEntry(ditemProto->ItemLevel); + if(!dcost) + { + sLog.outError("ERROR: RepairDurability: Wrong item lvl %u", dcost); + return TotalCost; + } + + DurabilityQualityEntry const *dQualitymodEntry = sDurabilityQualityStore.LookupEntry((ditemProto->Quality+1)*2); + if(!dQualitymodEntry) + { + sLog.outError("ERROR: RepairDurability: Wrong dQualityModEntry %u", dQualitymodEntry); + return TotalCost; + } + + uint32 dmultiplier = dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class,ditemProto->SubClass)]; + uint32 costs = uint32(LostDurability*dmultiplier*double(dQualitymodEntry->quality_mod)); + + costs = uint32(costs * discountMod); + + if (costs==0) //fix for ITEM_QUALITY_ARTIFACT + costs = 1; + + if (guildBank) + { + if (GetGuildId()==0) + { + DEBUG_LOG("You are not member of a guild"); + return TotalCost; + } + + Guild *pGuild = objmgr.GetGuildById(GetGuildId()); + if (!pGuild) + return TotalCost; + + if (!pGuild->HasRankRight(GetRank(), GR_RIGHT_WITHDRAW_REPAIR)) + { + DEBUG_LOG("You do not have rights to withdraw for repairs"); + return TotalCost; + } + + if (pGuild->GetMemberMoneyWithdrawRem(GetGUIDLow()) < costs) + { + DEBUG_LOG("You do not have enough money withdraw amount remaining"); + return TotalCost; + } + + if (pGuild->GetGuildBankMoney() < costs) + { + DEBUG_LOG("There is not enough money in bank"); + return TotalCost; + } + + pGuild->MemberMoneyWithdraw(costs, GetGUIDLow()); + TotalCost = costs; + } + else if (GetMoney() < costs) + { + DEBUG_LOG("You do not have enough money"); + return TotalCost; + } + else + ModifyMoney( -int32(costs) ); + } + } + + item->SetUInt32Value(ITEM_FIELD_DURABILITY, maxDurability); + item->SetState(ITEM_CHANGED, this); + + // reapply mods for total broken and repaired item if equipped + if(IsEquipmentPos(pos) && !curDurability) + _ApplyItemMods(item,pos & 255, true); + return TotalCost; +} + +void Player::RepopAtGraveyard() +{ + // note: this can be called also when the player is alive + // for example from WorldSession::HandleMovementOpcodes + + AreaTableEntry const *zone = GetAreaEntryByAreaID(GetAreaId()); + + // Such zones are considered unreachable as a ghost and the player must be automatically revived + if(!isAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY || GetTransport()) + { + ResurrectPlayer(0.5f); + SpawnCorpseBones(); + } + + WorldSafeLocsEntry const *ClosestGrave = NULL; + + // Special handle for battleground maps + BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId()); + + if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY)) + ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam()); + else + ClosestGrave = objmgr.GetClosestGraveYard( GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam() ); + + // stop countdown until repop + m_deathTimer = 0; + + // if no grave found, stay at the current location + // and don't show spirit healer location + if(ClosestGrave) + { + TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation()); + if(isDead()) // not send if alive, because it used in TeleportTo() + { + WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // show spirit healer position on minimap + data << ClosestGrave->map_id; + data << ClosestGrave->x; + data << ClosestGrave->y; + data << ClosestGrave->z; + GetSession()->SendPacket(&data); + } + } +} + +void Player::JoinedChannel(Channel *c) +{ + m_channels.push_back(c); +} + +void Player::LeftChannel(Channel *c) +{ + m_channels.remove(c); +} + +void Player::CleanupChannels() +{ + while(!m_channels.empty()) + { + Channel* ch = *m_channels.begin(); + m_channels.erase(m_channels.begin()); // remove from player's channel list + ch->Leave(GetGUID(), false); // not send to client, not remove from player's channel list + if (ChannelMgr* cMgr = channelMgr(GetTeam())) + cMgr->LeftChannel(ch->GetName()); // deleted channel if empty + + } + sLog.outDebug("Player: channels cleaned up!"); +} + +void Player::UpdateLocalChannels(uint32 newZone ) +{ + if(m_channels.empty()) + return; + + AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone); + if(!current_zone) + return; + + ChannelMgr* cMgr = channelMgr(GetTeam()); + if(!cMgr) + return; + + std::string current_zone_name = current_zone->area_name[GetSession()->GetSessionDbcLocale()]; + + for(JoinedChannelsList::iterator i = m_channels.begin(), next; i != m_channels.end(); i = next) + { + next = i; ++next; + + // skip non built-in channels + if(!(*i)->IsConstant()) + continue; + + ChatChannelsEntry const* ch = GetChannelEntryFor((*i)->GetChannelId()); + if(!ch) + continue; + + if((ch->flags & 4) == 4) // global channel without zone name in pattern + continue; + + // new channel + char new_channel_name_buf[100]; + snprintf(new_channel_name_buf,100,ch->pattern[m_session->GetSessionDbcLocale()],current_zone_name.c_str()); + Channel* new_channel = cMgr->GetJoinChannel(new_channel_name_buf,ch->ChannelID); + + if((*i)!=new_channel) + { + new_channel->Join(GetGUID(),""); // will output Changed Channel: N. Name + + // leave old channel + (*i)->Leave(GetGUID(),false); // not send leave channel, it already replaced at client + std::string name = (*i)->GetName(); // stroe name, (*i)erase in LeftChannel + LeftChannel(*i); // remove from player's channel list + cMgr->LeftChannel(name); // delete if empty + } + } + sLog.outDebug("Player: channels cleaned up!"); +} + +void Player::LeaveLFGChannel() +{ + for(JoinedChannelsList::iterator i = m_channels.begin(); i != m_channels.end(); ++i ) + { + if((*i)->IsLFG()) + { + (*i)->Leave(GetGUID()); + break; + } + } +} + +void Player::UpdateDefense() +{ + uint32 defense_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_DEFENSE); + + if(UpdateSkill(SKILL_DEFENSE,defense_skill_gain)) + { + // update dependent from defense skill part + UpdateDefenseBonusesMod(); + } +} + +void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply, bool affectStats) +{ + if(modGroup >= BASEMOD_END || modType >= MOD_END) + { + sLog.outError("ERROR in HandleBaseModValue(): nonexisted BaseModGroup of wrong BaseModType!"); + return; + } + + float val = 1.0f; + + switch(modType) + { + case FLAT_MOD: + m_auraBaseMod[modGroup][modType] += apply ? amount : -amount; + break; + case PCT_MOD: + if(amount <= -100.0f) + amount = -200.0f; + + val = (100.0f + amount) / 100.0f; + m_auraBaseMod[modGroup][modType] *= apply ? val : (1.0f/val); + break; + } + + if(!CanModifyStats()) + return; + + switch(modGroup) + { + case CRIT_PERCENTAGE: UpdateCritPercentage(BASE_ATTACK); break; + case RANGED_CRIT_PERCENTAGE: UpdateCritPercentage(RANGED_ATTACK); break; + case OFFHAND_CRIT_PERCENTAGE: UpdateCritPercentage(OFF_ATTACK); break; + case SHIELD_BLOCK_VALUE: UpdateShieldBlockValue(); break; + default: break; + } +} + +float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const +{ + if(modGroup >= BASEMOD_END || modType > MOD_END) + { + sLog.outError("ERROR: trial to access nonexisted BaseModGroup or wrong BaseModType!"); + return 0.0f; + } + + if(modType == PCT_MOD && m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f) + return 0.0f; + + return m_auraBaseMod[modGroup][modType]; +} + +float Player::GetTotalBaseModValue(BaseModGroup modGroup) const +{ + if(modGroup >= BASEMOD_END) + { + sLog.outError("ERROR: wrong BaseModGroup in GetTotalBaseModValue()!"); + return 0.0f; + } + + if(m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f) + return 0.0f; + + return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD]; +} + +uint32 Player::GetShieldBlockValue() const +{ + BaseModGroup modGroup = SHIELD_BLOCK_VALUE; + + float value = GetTotalBaseModValue(modGroup) + GetStat(STAT_STRENGTH)/20 - 1; + + value = (value < 0) ? 0 : value; + + return uint32(value); +} + +float Player::GetMeleeCritFromAgility() +{ + uint32 level = getLevel(); + uint32 pclass = getClass(); + + if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; + + GtChanceToMeleeCritBaseEntry const *critBase = sGtChanceToMeleeCritBaseStore.LookupEntry(pclass-1); + GtChanceToMeleeCritEntry const *critRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + if (critBase==NULL || critRatio==NULL) + return 0.0f; + + float crit=critBase->base + GetStat(STAT_AGILITY)*critRatio->ratio; + return crit*100.0f; +} + +float Player::GetDodgeFromAgility() +{ + // Table for base dodge values + float dodge_base[MAX_CLASSES] = { + 0.0075f, // Warrior + 0.00652f, // Paladin + -0.0545f, // Hunter + -0.0059f, // Rogue + 0.03183f, // Priest + 0.0114f, // DK + 0.0167f, // Shaman + 0.034575f, // Mage + 0.02011f, // Warlock + 0.0f, // ?? + -0.0187f // Druid + }; + // Crit/agility to dodge/agility coefficient multipliers + float crit_to_dodge[MAX_CLASSES] = { + 1.1f, // Warrior + 1.0f, // Paladin + 1.6f, // Hunter + 2.0f, // Rogue + 1.0f, // Priest + 1.0f, // DK? + 1.0f, // Shaman + 1.0f, // Mage + 1.0f, // Warlock + 0.0f, // ?? + 1.7f // Druid + }; + + uint32 level = getLevel(); + uint32 pclass = getClass(); + + if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; + + // Dodge per agility for most classes equal crit per agility (but for some classes need apply some multiplier) + GtChanceToMeleeCritEntry const *dodgeRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + if (dodgeRatio==NULL || pclass > MAX_CLASSES) + return 0.0f; + + float dodge=dodge_base[pclass-1] + GetStat(STAT_AGILITY) * dodgeRatio->ratio * crit_to_dodge[pclass-1]; + return dodge*100.0f; +} + +float Player::GetSpellCritFromIntellect() +{ + uint32 level = getLevel(); + uint32 pclass = getClass(); + + if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; + + GtChanceToSpellCritBaseEntry const *critBase = sGtChanceToSpellCritBaseStore.LookupEntry(pclass-1); + GtChanceToSpellCritEntry const *critRatio = sGtChanceToSpellCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + if (critBase==NULL || critRatio==NULL) + return 0.0f; + + float crit=critBase->base + GetStat(STAT_INTELLECT)*critRatio->ratio; + return crit*100.0f; +} + +float Player::GetRatingCoefficient(CombatRating cr) const +{ + uint32 level = getLevel(); + + if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; + + GtCombatRatingsEntry const *Rating = sGtCombatRatingsStore.LookupEntry(cr*GT_MAX_LEVEL+level-1); + if (Rating == NULL) + return 1.0f; // By default use minimum coefficient (not must be called) + + return Rating->ratio; +} + +float Player::GetRatingBonusValue(CombatRating cr) const +{ + return float(GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr)) / GetRatingCoefficient(cr); +} + +uint32 Player::GetMeleeCritDamageReduction(uint32 damage) const +{ + float melee = GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*2.0f; + if (melee>25.0f) melee = 25.0f; + return uint32 (melee * damage /100.0f); +} + +uint32 Player::GetRangedCritDamageReduction(uint32 damage) const +{ + float ranged = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED)*2.0f; + if (ranged>25.0f) ranged=25.0f; + return uint32 (ranged * damage /100.0f); +} + +uint32 Player::GetSpellCritDamageReduction(uint32 damage) const +{ + float spell = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2.0f; + // In wow script resilience limited to 25% + if (spell>25.0f) + spell = 25.0f; + return uint32 (spell * damage / 100.0f); +} + +uint32 Player::GetDotDamageReduction(uint32 damage) const +{ + float spellDot = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); + // Dot resilience not limited (limit it by 100%) + if (spellDot > 100.0f) + spellDot = 100.0f; + return uint32 (spellDot * damage / 100.0f); +} + +float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const +{ + switch (attType) + { + case BASE_ATTACK: + return GetUInt32Value(PLAYER_EXPERTISE) / 4.0f; + case OFF_ATTACK: + return GetUInt32Value(PLAYER_OFFHAND_EXPERTISE) / 4.0f; + default: + break; + } + return 0.0f; +} + +float Player::OCTRegenHPPerSpirit() +{ + uint32 level = getLevel(); + uint32 pclass = getClass(); + + if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; + + GtOCTRegenHPEntry const *baseRatio = sGtOCTRegenHPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + GtRegenHPPerSptEntry const *moreRatio = sGtRegenHPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + if (baseRatio==NULL || moreRatio==NULL) + return 0.0f; + + // Formula from PaperDollFrame script + float spirit = GetStat(STAT_SPIRIT); + float baseSpirit = spirit; + if (baseSpirit>50) baseSpirit = 50; + float moreSpirit = spirit - baseSpirit; + float regen = baseSpirit * baseRatio->ratio + moreSpirit * moreRatio->ratio; + return regen; +} + +float Player::OCTRegenMPPerSpirit() +{ + uint32 level = getLevel(); + uint32 pclass = getClass(); + + if (level>GT_MAX_LEVEL) level = GT_MAX_LEVEL; + +// GtOCTRegenMPEntry const *baseRatio = sGtOCTRegenMPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + GtRegenMPPerSptEntry const *moreRatio = sGtRegenMPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + if (moreRatio==NULL) + return 0.0f; + + // Formula get from PaperDollFrame script + float spirit = GetStat(STAT_SPIRIT); + float regen = spirit * moreRatio->ratio; + return regen; +} + +void Player::ApplyRatingMod(CombatRating cr, int32 value, bool apply) +{ + ApplyModUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, value, apply); + + float RatingCoeffecient = GetRatingCoefficient(cr); + float RatingChange = 0.0f; + + bool affectStats = CanModifyStats(); + + switch (cr) + { + case CR_WEAPON_SKILL: // Implemented in Unit::RollMeleeOutcomeAgainst + case CR_DEFENSE_SKILL: + UpdateDefenseBonusesMod(); + break; + case CR_DODGE: + UpdateDodgePercentage(); + break; + case CR_PARRY: + UpdateParryPercentage(); + break; + case CR_BLOCK: + UpdateBlockPercentage(); + break; + case CR_HIT_MELEE: + RatingChange = value / RatingCoeffecient; + m_modMeleeHitChance += apply ? RatingChange : -RatingChange; + break; + case CR_HIT_RANGED: + RatingChange = value / RatingCoeffecient; + m_modRangedHitChance += apply ? RatingChange : -RatingChange; + break; + case CR_HIT_SPELL: + RatingChange = value / RatingCoeffecient; + m_modSpellHitChance += apply ? RatingChange : -RatingChange; + break; + case CR_CRIT_MELEE: + if(affectStats) + { + UpdateCritPercentage(BASE_ATTACK); + UpdateCritPercentage(OFF_ATTACK); + } + break; + case CR_CRIT_RANGED: + if(affectStats) + UpdateCritPercentage(RANGED_ATTACK); + break; + case CR_CRIT_SPELL: + if(affectStats) + UpdateAllSpellCritChances(); + break; + case CR_HIT_TAKEN_MELEE: // Implemented in Unit::MeleeMissChanceCalc + case CR_HIT_TAKEN_RANGED: + break; + case CR_HIT_TAKEN_SPELL: // Implemented in Unit::MagicSpellHitResult + break; + case CR_CRIT_TAKEN_MELEE: // Implemented in Unit::RollMeleeOutcomeAgainst (only for chance to crit) + case CR_CRIT_TAKEN_RANGED: + break; + case CR_CRIT_TAKEN_SPELL: // Implemented in Unit::SpellCriticalBonus (only for chance to crit) + break; + case CR_HASTE_MELEE: + RatingChange = value / RatingCoeffecient; + ApplyAttackTimePercentMod(BASE_ATTACK,RatingChange,apply); + ApplyAttackTimePercentMod(OFF_ATTACK,RatingChange,apply); + break; + case CR_HASTE_RANGED: + RatingChange = value / RatingCoeffecient; + ApplyAttackTimePercentMod(RANGED_ATTACK, RatingChange, apply); + break; + case CR_HASTE_SPELL: + RatingChange = value / RatingCoeffecient; + ApplyCastTimePercentMod(RatingChange,apply); + break; + case CR_WEAPON_SKILL_MAINHAND: // Implemented in Unit::RollMeleeOutcomeAgainst + case CR_WEAPON_SKILL_OFFHAND: + case CR_WEAPON_SKILL_RANGED: + break; + case CR_EXPERTISE: + if(affectStats) + { + UpdateExpertise(BASE_ATTACK); + UpdateExpertise(OFF_ATTACK); + } + break; + } +} + +void Player::SetRegularAttackTime() +{ + for(int i = 0; i < MAX_ATTACK; ++i) + { + Item *tmpitem = GetWeaponForAttack(WeaponAttackType(i)); + if(tmpitem && !tmpitem->IsBroken()) + { + ItemPrototype const *proto = tmpitem->GetProto(); + if(proto->Delay) + SetAttackTime(WeaponAttackType(i), proto->Delay); + else + SetAttackTime(WeaponAttackType(i), BASE_ATTACK_TIME); + } + } +} + +//skill+step, checking for max value +bool Player::UpdateSkill(uint32 skill_id, uint32 step) +{ + if(!skill_id) + return false; + + uint16 i=0; + for (; i < PLAYER_MAX_SKILLS; i++) + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill_id) + break; + + if(i>=PLAYER_MAX_SKILLS) + return false; + + uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); + uint32 value = SKILL_VALUE(data); + uint32 max = SKILL_MAX(data); + + if ((!max) || (!value) || (value >= max)) + return false; + + if (value*512 < max*urand(0,512)) + { + uint32 new_value = value+step; + if(new_value > max) + new_value = max; + + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,max)); + return true; + } + + return false; +} + +inline int SkillGainChance(uint32 SkillValue, uint32 GrayLevel, uint32 GreenLevel, uint32 YellowLevel) +{ + if ( SkillValue >= GrayLevel ) + return sWorld.getConfig(CONFIG_SKILL_CHANCE_GREY)*10; + if ( SkillValue >= GreenLevel ) + return sWorld.getConfig(CONFIG_SKILL_CHANCE_GREEN)*10; + if ( SkillValue >= YellowLevel ) + return sWorld.getConfig(CONFIG_SKILL_CHANCE_YELLOW)*10; + return sWorld.getConfig(CONFIG_SKILL_CHANCE_ORANGE)*10; +} + +bool Player::UpdateCraftSkill(uint32 spellid) +{ + sLog.outDebug("UpdateCraftSkill spellid %d", spellid); + + SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spellid); + SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spellid); + + for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) + { + if(_spell_idx->second->skillId) + { + uint32 SkillValue = GetPureSkillValue(_spell_idx->second->skillId); + + // Alchemy Discoveries here + SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellid); + if(spellEntry && spellEntry->Mechanic==MECHANIC_DISCOVERY) + { + if(uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this)) + learnSpell(discoveredSpell); + } + + uint32 craft_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_CRAFTING); + + return UpdateSkillPro(_spell_idx->second->skillId, SkillGainChance(SkillValue, + _spell_idx->second->max_value, + (_spell_idx->second->max_value + _spell_idx->second->min_value)/2, + _spell_idx->second->min_value), + craft_skill_gain); + } + } + return false; +} + +bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator ) +{ + sLog.outDebug("UpdateGatherSkill(SkillId %d SkillLevel %d RedLevel %d)", SkillId, SkillValue, RedLevel); + + uint32 gathering_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_GATHERING); + + // For skinning and Mining chance decrease with level. 1-74 - no decrease, 75-149 - 2 times, 225-299 - 8 times + switch (SkillId) + { + case SKILL_HERBALISM: + case SKILL_LOCKPICKING: + case SKILL_JEWELCRAFTING: + return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator,gathering_skill_gain); + case SKILL_SKINNING: + if( sWorld.getConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)==0) + return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator,gathering_skill_gain); + else + return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/sWorld.getConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)), gathering_skill_gain); + case SKILL_MINING: + if (sWorld.getConfig(CONFIG_SKILL_CHANCE_MINING_STEPS)==0) + return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator,gathering_skill_gain); + else + return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/sWorld.getConfig(CONFIG_SKILL_CHANCE_MINING_STEPS)),gathering_skill_gain); + } + return false; +} + +bool Player::UpdateFishingSkill() +{ + sLog.outDebug("UpdateFishingSkill"); + + uint32 SkillValue = GetPureSkillValue(SKILL_FISHING); + + int32 chance = SkillValue < 75 ? 100 : 2500/(SkillValue-50); + + uint32 gathering_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_GATHERING); + + return UpdateSkillPro(SKILL_FISHING,chance*10,gathering_skill_gain); +} + +bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) +{ + sLog.outDebug("UpdateSkillPro(SkillId %d, Chance %3.1f%%)", SkillId, Chance/10.0); + if ( !SkillId ) + return false; + + if(Chance <= 0) // speedup in 0 chance case + { + sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% missed", Chance/10.0); + return false; + } + + uint16 i=0; + for (; i < PLAYER_MAX_SKILLS; i++) + if ( SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_INDEX(i))) == SkillId ) break; + if ( i >= PLAYER_MAX_SKILLS ) + return false; + + uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); + uint16 SkillValue = SKILL_VALUE(data); + uint16 MaxValue = SKILL_MAX(data); + + if ( !MaxValue || !SkillValue || SkillValue >= MaxValue ) + return false; + + int32 Roll = irand(1,1000); + + if ( Roll <= Chance ) + { + uint32 new_value = SkillValue+step; + if(new_value > MaxValue) + new_value = MaxValue; + + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,MaxValue)); + sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% taken", Chance/10.0); + return true; + } + + sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% missed", Chance/10.0); + return false; +} + +void Player::UpdateWeaponSkill (WeaponAttackType attType) +{ + // no skill gain in pvp + Unit *pVictim = getVictim(); + if(pVictim && pVictim->GetTypeId() == TYPEID_PLAYER) + return; + + if(IsInFeralForm()) + return; // always maximized SKILL_FERAL_COMBAT in fact + + if(m_form == FORM_TREE) + return; // use weapon but not skill up + + uint32 weapon_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_WEAPON); + + switch(attType) + { + case BASE_ATTACK: + { + Item *tmpitem = GetWeaponForAttack(attType,true); + + if (!tmpitem) + UpdateSkill(SKILL_UNARMED,weapon_skill_gain); + else if(tmpitem->GetProto()->SubClass != ITEM_SUBCLASS_WEAPON_FISHING_POLE) + UpdateSkill(tmpitem->GetSkill(),weapon_skill_gain); + break; + } + case OFF_ATTACK: + case RANGED_ATTACK: + { + Item *tmpitem = GetWeaponForAttack(attType,true); + if (tmpitem) + UpdateSkill(tmpitem->GetSkill(),weapon_skill_gain); + break; + } + } + UpdateAllCritPercentages(); +} + +void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence) +{ + switch(outcome) + { + case MELEE_HIT_CRIT: + case MELEE_HIT_DODGE: + case MELEE_HIT_PARRY: + case MELEE_HIT_BLOCK: + case MELEE_HIT_BLOCK_CRIT: + return; + + default: + break; + } + + uint32 plevel = getLevel(); // if defense than pVictim == attacker + uint32 greylevel = MaNGOS::XP::GetGrayLevel(plevel); + uint32 moblevel = pVictim->getLevelForTarget(this); + if(moblevel < greylevel) + return; + + if (moblevel > plevel + 5) + moblevel = plevel + 5; + + uint32 lvldif = moblevel - greylevel; + if(lvldif < 3) + lvldif = 3; + + uint32 skilldif = 5 * plevel - (defence ? GetBaseDefenseSkillValue() : GetBaseWeaponSkillValue(attType)); + if(skilldif <= 0) + return; + + float chance = float(3 * lvldif * skilldif) / plevel; + if(!defence) + { + if(getClass() == CLASS_WARRIOR || getClass() == CLASS_ROGUE) + chance *= 0.1f * GetStat(STAT_INTELLECT); + } + + chance = chance < 1.0f ? 1.0f : chance; //minimum chance to increase skill is 1% + + if(roll_chance_f(chance)) + { + if(defence) + UpdateDefense(); + else + UpdateWeaponSkill(attType); + } + else + return; +} + +void Player::ModifySkillBonus(uint32 skillid,int32 val, bool talent) +{ + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skillid) + { + uint32 bonus_val = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); + int16 temp_bonus = SKILL_TEMP_BONUS(bonus_val); + int16 perm_bonus = SKILL_PERM_BONUS(bonus_val); + + if(talent) // permanent bonus stored in high part + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),MAKE_SKILL_BONUS(temp_bonus,perm_bonus+val)); + else // temporary/item bonus stored in low part + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),MAKE_SKILL_BONUS(temp_bonus+val,perm_bonus)); + return; + } +} + +void Player::UpdateMaxSkills() +{ + uint16 maxconfskill = sWorld.GetConfigMaxSkillValue(); + + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + if (GetUInt32Value(PLAYER_SKILL_INDEX(i))) + { + uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; + + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(pskill); + if(!pSkill) + continue; + + if(GetSkillRangeType(pSkill,false) != SKILL_RANGE_LEVEL) + continue; + + uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); + uint32 max = SKILL_MAX(data); + uint32 val = SKILL_VALUE(data); + + // update only level dependent max skill values + if(max!=1 && max != maxconfskill) + { + uint32 max_Skill = GetMaxSkillValueForLevel(); + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(val,max_Skill)); + } + } +} + +void Player::UpdateSkillsToMaxSkillsForLevel() +{ + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + if (GetUInt32Value(PLAYER_SKILL_INDEX(i))) + { + uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; + if( IsProfessionSkill(pskill) || pskill == SKILL_RIDING ) + continue; + uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); + + uint32 max = SKILL_MAX(data); + + if(max > 1) + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(max,max)); + + if(pskill == SKILL_DEFENSE) + UpdateDefenseBonusesMod(); + } +} + +// This functions sets a skill line value (and adds if doesn't exist yet) +// To "remove" a skill line, set it's values to zero +void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal) +{ + if(!id) + return; + + uint16 i=0; + for (; i < PLAYER_MAX_SKILLS; i++) + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == id) break; + + if(isecond->state == PLAYERSPELL_REMOVED) + continue; + + SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(itr->first); + SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(itr->first); + + for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) + { + if (_spell_idx->second->skillId == id) + { + // this may remove more than one spell (dependants) + removeSpell(itr->first); + next = m_spells.begin(); + break; + } + } + } + } + } + else if(currVal) //add + { + for (i=0; i < PLAYER_MAX_SKILLS; i++) + if (!GetUInt32Value(PLAYER_SKILL_INDEX(i))) + { + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); + if(!pSkill) + { + sLog.outError("Skill not found in SkillLineStore: skill #%u", id); + return; + } + // enable unlearn button for primary professions only + if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) + SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); + else + SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(currVal,maxVal)); + + // apply skill bonuses + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); + + // temporary bonuses + AuraList const& mModSkill = GetAurasByType(SPELL_AURA_MOD_SKILL); + for(AuraList::const_iterator i = mModSkill.begin(); i != mModSkill.end(); ++i) + if ((*i)->GetModifier()->m_miscvalue == int32(id)) + (*i)->ApplyModifier(true); + + // permanent bonuses + AuraList const& mModSkillTalent = GetAurasByType(SPELL_AURA_MOD_SKILL_TALENT); + for(AuraList::const_iterator i = mModSkillTalent.begin(); i != mModSkillTalent.end(); ++i) + if ((*i)->GetModifier()->m_miscvalue == int32(id)) + (*i)->ApplyModifier(true); + + // Learn all spells for skill + learnSkillRewardedSpells(id); + return; + } + } +} + +bool Player::HasSkill(uint32 skill) const +{ + if(!skill)return false; + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + { + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) + { + return true; + } + } + return false; +} + +uint16 Player::GetSkillValue(uint32 skill) const +{ + if(!skill) + return 0; + + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + { + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) + { + uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); + + int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); + result += SKILL_TEMP_BONUS(bonus); + result += SKILL_PERM_BONUS(bonus); + return result < 0 ? 0 : result; + } + } + return 0; +} + +uint16 Player::GetMaxSkillValue(uint32 skill) const +{ + if(!skill)return 0; + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + { + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) + { + uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); + + int32 result = int32(SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); + result += SKILL_TEMP_BONUS(bonus); + result += SKILL_PERM_BONUS(bonus); + return result < 0 ? 0 : result; + } + } + return 0; +} + +uint16 Player::GetPureMaxSkillValue(uint32 skill) const +{ + if(!skill)return 0; + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + { + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) + { + return SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); + } + } + return 0; +} + +uint16 Player::GetBaseSkillValue(uint32 skill) const +{ + if(!skill)return 0; + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + { + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) + { + int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); + result += SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i))); + return result < 0 ? 0 : result; + } + } + return 0; +} + +uint16 Player::GetPureSkillValue(uint32 skill) const +{ + if(!skill)return 0; + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + { + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) + { + return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); + } + } + return 0; +} + +int16 Player::GetSkillTempBonusValue(uint32 skill) const +{ + if(!skill) + return 0; + + for (int i = 0; i < PLAYER_MAX_SKILLS; i++) + { + if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) + { + return SKILL_TEMP_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i))); + } + } + + return 0; +} + +void Player::SendInitialActionButtons() +{ + sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() ); + + WorldPacket data(SMSG_ACTION_BUTTONS, (MAX_ACTION_BUTTONS*4)); + for(int button = 0; button < MAX_ACTION_BUTTONS; ++button) + { + ActionButtonList::const_iterator itr = m_actionButtons.find(button); + if(itr != m_actionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED) + { + data << uint16(itr->second.action); + data << uint8(itr->second.misc); + data << uint8(itr->second.type); + } + else + { + data << uint32(0); + } + } + + GetSession()->SendPacket( &data ); + sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() ); +} + +void Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc) +{ + if(button >= MAX_ACTION_BUTTONS) + { + sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() ); + return; + } + + // check cheating with adding non-known spells to action bar + if(type==ACTION_BUTTON_SPELL) + { + if(!sSpellStore.LookupEntry(action)) + { + sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() ); + return; + } + + if(!HasSpell(action)) + { + sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() ); + return; + } + } + + ActionButtonList::iterator buttonItr = m_actionButtons.find(button); + + if (buttonItr==m_actionButtons.end()) + { // just add new button + m_actionButtons[button] = ActionButton(action,type,misc); + } + else + { // change state of current button + ActionButtonUpdateState uState = buttonItr->second.uState; + buttonItr->second = ActionButton(action,type,misc); + if (uState != ACTIONBUTTON_NEW) buttonItr->second.uState = ACTIONBUTTON_CHANGED; + }; + + sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button ); +} + +void Player::removeActionButton(uint8 button) +{ + ActionButtonList::iterator buttonItr = m_actionButtons.find(button); + if (buttonItr==m_actionButtons.end()) + return; + + if(buttonItr->second.uState==ACTIONBUTTON_NEW) + m_actionButtons.erase(buttonItr); // new and not saved + else + buttonItr->second.uState = ACTIONBUTTON_DELETED; // saved, will deleted at next save + + sLog.outDetail( "Action Button '%u' Removed from Player '%u'", button, GetGUIDLow() ); +} + +void Player::SetDontMove(bool dontMove) +{ + m_dontMove = dontMove; +} + +bool Player::SetPosition(float x, float y, float z, float orientation, bool teleport) +{ + // prevent crash when a bad coord is sent by the client + if(!MaNGOS::IsValidMapCoord(x,y,z,orientation)) + { + sLog.outDebug("Player::SetPosition(%f, %f, %f, %f, %d) .. bad coordinates for player %d!",x,y,z,orientation,teleport,GetGUIDLow()); + return false; + } + + Map *m = MapManager::Instance().GetMap(GetMapId(), this); + + const float old_x = GetPositionX(); + const float old_y = GetPositionY(); + const float old_z = GetPositionZ(); + const float old_r = GetOrientation(); + + if( teleport || old_x != x || old_y != y || old_z != z || old_r != orientation ) + { + if (teleport || old_x != x || old_y != y || old_z != z) + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING); + else + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); + + // move and update visible state if need + m->PlayerRelocation(this, x, y, z, orientation); + + // reread after Map::Relocation + m = MapManager::Instance().GetMap(GetMapId(), this); + x = GetPositionX(); + y = GetPositionY(); + z = GetPositionZ(); + } + + // code block for underwater state update + UpdateUnderwaterState(m, x, y, z); + + + CheckExploreSystem(); + + // group update + if(GetGroup()) + SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION); + + return true; +} + +void Player::SaveRecallPosition() +{ + m_recallMap = GetMapId(); + m_recallX = GetPositionX(); + m_recallY = GetPositionY(); + m_recallZ = GetPositionZ(); + m_recallO = GetOrientation(); +} + +void Player::SendMessageToSet(WorldPacket *data, bool self) +{ + MapManager::Instance().GetMap(GetMapId(), this)->MessageBroadcast(this, data, self); +} + +void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self) +{ + MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self); +} + +void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only) +{ + MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self,own_team_only); +} + +void Player::SendDirectMessage(WorldPacket *data) +{ + GetSession()->SendPacket(data); +} + +void Player::CheckExploreSystem() +{ + if (!isAlive()) + return; + + if (isInFlight()) + return; + + uint16 areaFlag=MapManager::Instance().GetBaseMap(GetMapId())->GetAreaFlag(GetPositionX(),GetPositionY()); + if(areaFlag==0xffff) + return; + int offset = areaFlag / 32; + + if(offset >= 128) + { + sLog.outError("ERROR: Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < 64 ).",areaFlag,GetPositionX(),GetPositionY(),offset,offset); + return; + } + + uint32 val = (uint32)(1 << (areaFlag % 32)); + uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); + + if( !(currFields & val) ) + { + SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val)); + + AreaTableEntry const *p = GetAreaEntryByAreaFlagAndMap(areaFlag,GetMapId()); + if(!p) + { + sLog.outError("PLAYER: Player %u discovered unknown area (x: %f y: %f map: %u", GetGUIDLow(), GetPositionX(),GetPositionY(),GetMapId()); + } + else if(p->area_level > 0) + { + uint32 area = p->ID; + if (getLevel() >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + SendExplorationExperience(area,0); + } + else + { + int32 diff = int32(getLevel()) - p->area_level; + uint32 XP = 0; + if (diff < -5) + { + XP = uint32(objmgr.GetBaseXP(getLevel()+5)*sWorld.getRate(RATE_XP_EXPLORE)); + } + else if (diff > 5) + { + int32 exploration_percent = (100-((diff-5)*5)); + if (exploration_percent > 100) + exploration_percent = 100; + else if (exploration_percent < 0) + exploration_percent = 0; + + XP = uint32(objmgr.GetBaseXP(p->area_level)*exploration_percent/100*sWorld.getRate(RATE_XP_EXPLORE)); + } + else + { + XP = uint32(objmgr.GetBaseXP(p->area_level)*sWorld.getRate(RATE_XP_EXPLORE)); + } + + GiveXP( XP, NULL ); + SendExplorationExperience(area,XP); + } + sLog.outDetail("PLAYER: Player %u discovered a new area: %u", GetGUIDLow(), area); + } + } +} + +uint32 Player::TeamForRace(uint8 race) +{ + ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race); + if(!rEntry) + { + sLog.outError("Race %u not found in DBC: wrong DBC files?",uint32(race)); + return ALLIANCE; + } + + switch(rEntry->TeamID) + { + case 7: return ALLIANCE; + case 1: return HORDE; + } + + sLog.outError("Race %u have wrong team id in DBC: wrong DBC files?",uint32(race),rEntry->TeamID); + return ALLIANCE; +} + +uint32 Player::getFactionForRace(uint8 race) +{ + ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race); + if(!rEntry) + { + sLog.outError("Race %u not found in DBC: wrong DBC files?",uint32(race)); + return 0; + } + + return rEntry->FactionID; +} + +void Player::setFactionForRace(uint8 race) +{ + m_team = TeamForRace(race); + setFaction( getFactionForRace(race) ); +} + +void Player::UpdateReputation() const +{ + sLog.outDetail( "WORLD: Player::UpdateReputation" ); + + for(FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) + { + SendFactionState(&(itr->second)); + } +} + +void Player::SendFactionState(FactionState const* faction) const +{ + if(faction->Flags & FACTION_FLAG_VISIBLE) //If faction is visible then update it + { + WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0 + data << (float) 0; // unk 2.4.0 + data << (uint32) 1; // count + // for + data << (uint32) faction->ReputationListID; + data << (uint32) faction->Standing; + // end for + GetSession()->SendPacket(&data); + } +} + +void Player::SendInitialReputations() +{ + WorldPacket data(SMSG_INITIALIZE_FACTIONS, (4+128*5)); + data << uint32 (0x00000080); + + RepListID a = 0; + + for (FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); itr++) + { + // fill in absent fields + for (; a != itr->first; a++) + { + data << uint8 (0x00); + data << uint32 (0x00000000); + } + + // fill in encountered data + data << uint8 (itr->second.Flags); + data << uint32 (itr->second.Standing); + + ++a; + } + + // fill in absent fields + for (; a != 128; a++) + { + data << uint8 (0x00); + data << uint32 (0x00000000); + } + + GetSession()->SendPacket(&data); +} + +FactionState const* Player::GetFactionState( FactionEntry const* factionEntry) const +{ + FactionStateList::const_iterator itr = m_factions.find(factionEntry->reputationListID); + if (itr != m_factions.end()) + return &itr->second; + + return NULL; +} + +void Player::SetFactionAtWar(FactionState* faction, bool atWar) +{ + // not allow declare war to own faction + if(atWar && (faction->Flags & FACTION_FLAG_PEACE_FORCED) ) + return; + + // already set + if(((faction->Flags & FACTION_FLAG_AT_WAR) != 0) == atWar) + return; + + if( atWar ) + faction->Flags |= FACTION_FLAG_AT_WAR; + else + faction->Flags &= ~FACTION_FLAG_AT_WAR; + + faction->Changed = true; +} + +void Player::SetFactionInactive(FactionState* faction, bool inactive) +{ + // always invisible or hidden faction can't be inactive + if(inactive && ((faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) || !(faction->Flags & FACTION_FLAG_VISIBLE) ) ) + return; + + // already set + if(((faction->Flags & FACTION_FLAG_INACTIVE) != 0) == inactive) + return; + + if(inactive) + faction->Flags |= FACTION_FLAG_INACTIVE; + else + faction->Flags &= ~FACTION_FLAG_INACTIVE; + + faction->Changed = true; +} + +void Player::SetFactionVisibleForFactionTemplateId(uint32 FactionTemplateId) +{ + FactionTemplateEntry const*factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId); + + if(!factionTemplateEntry) + return; + + SetFactionVisibleForFactionId(factionTemplateEntry->faction); +} + +void Player::SetFactionVisibleForFactionId(uint32 FactionId) +{ + FactionEntry const *factionEntry = sFactionStore.LookupEntry(FactionId); + if(!factionEntry) + return; + + if(factionEntry->reputationListID < 0) + return; + + FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); + if (itr == m_factions.end()) + return; + + SetFactionVisible(&itr->second); +} + +void Player::SetFactionVisible(FactionState* faction) +{ + // always invisible or hidden faction can't be make visible + if(faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) + return; + + // already set + if(faction->Flags & FACTION_FLAG_VISIBLE) + return; + + faction->Flags |= FACTION_FLAG_VISIBLE; + faction->Changed = true; + + if(!m_session->PlayerLoading()) + { + // make faction visible in reputation list at client + WorldPacket data(SMSG_SET_FACTION_VISIBLE, 4); + data << faction->ReputationListID; + GetSession()->SendPacket(&data); + } +} + +void Player::SetInitialFactions() +{ + for(unsigned int i = 1; i < sFactionStore.GetNumRows(); i++) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry(i); + + if( factionEntry && (factionEntry->reputationListID >= 0)) + { + FactionState newFaction; + newFaction.ID = factionEntry->ID; + newFaction.ReputationListID = factionEntry->reputationListID; + newFaction.Standing = 0; + newFaction.Flags = GetDefaultReputationFlags(factionEntry); + newFaction.Changed = true; + + m_factions[newFaction.ReputationListID] = newFaction; + } + } +} + +uint32 Player::GetDefaultReputationFlags(const FactionEntry *factionEntry) const +{ + if (!factionEntry) + return 0; + + uint32 raceMask = getRaceMask(); + uint32 classMask = getClassMask(); + for (int i=0; i < 4; i++) + { + if( (factionEntry->BaseRepRaceMask[i] & raceMask) && + (factionEntry->BaseRepClassMask[i]==0 || + (factionEntry->BaseRepClassMask[i] & classMask) ) ) + return factionEntry->ReputationFlags[i]; + } + return 0; +} + +int32 Player::GetBaseReputation(const FactionEntry *factionEntry) const +{ + if (!factionEntry) + return 0; + + uint32 raceMask = getRaceMask(); + uint32 classMask = getClassMask(); + for (int i=0; i < 4; i++) + { + if( (factionEntry->BaseRepRaceMask[i] & raceMask) && + (factionEntry->BaseRepClassMask[i]==0 || + (factionEntry->BaseRepClassMask[i] & classMask) ) ) + return factionEntry->BaseRepValue[i]; + } + + // in faction.dbc exist factions with (RepListId >=0, listed in character reputation list) with all BaseRepRaceMask[i]==0 + return 0; +} + +int32 Player::GetReputation(uint32 faction_id) const +{ + FactionEntry const *factionEntry = sFactionStore.LookupEntry(faction_id); + + if (!factionEntry) + { + sLog.outError("Player::GetReputation: Can't get reputation of %s for unknown faction (faction template id) #%u.",GetName(), faction_id); + return 0; + } + + return GetReputation(factionEntry); +} + +int32 Player::GetReputation(const FactionEntry *factionEntry) const +{ + // Faction without recorded reputation. Just ignore. + if(!factionEntry) + return 0; + + FactionStateList::const_iterator itr = m_factions.find(factionEntry->reputationListID); + if (itr != m_factions.end()) + return GetBaseReputation(factionEntry) + itr->second.Standing; + + return 0; +} + +ReputationRank Player::GetReputationRank(uint32 faction) const +{ + FactionEntry const*factionEntry = sFactionStore.LookupEntry(faction); + if(!factionEntry) + return MIN_REPUTATION_RANK; + + return GetReputationRank(factionEntry); +} + +ReputationRank Player::ReputationToRank(int32 standing) const +{ + int32 Limit = Reputation_Cap + 1; + for (int i = MAX_REPUTATION_RANK-1; i >= MIN_REPUTATION_RANK; --i) + { + Limit -= ReputationRank_Length[i]; + if (standing >= Limit ) + return ReputationRank(i); + } + return MIN_REPUTATION_RANK; +} + +ReputationRank Player::GetReputationRank(const FactionEntry *factionEntry) const +{ + int32 Reputation = GetReputation(factionEntry); + return ReputationToRank(Reputation); +} + +ReputationRank Player::GetBaseReputationRank(const FactionEntry *factionEntry) const +{ + int32 Reputation = GetBaseReputation(factionEntry); + return ReputationToRank(Reputation); +} + +bool Player::ModifyFactionReputation(uint32 FactionTemplateId, int32 DeltaReputation) +{ + FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId); + + if(!factionTemplateEntry) + { + sLog.outError("Player::ModifyFactionReputation: Can't update reputation of %s for unknown faction (faction template id) #%u.", GetName(), FactionTemplateId); + return false; + } + + FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction); + + // Faction without recorded reputation. Just ignore. + if(!factionEntry) + return false; + + return ModifyFactionReputation(factionEntry, DeltaReputation); +} + +bool Player::ModifyFactionReputation(FactionEntry const* factionEntry, int32 standing) +{ + SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID); + if (flist) + { + bool res = false; + for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr) + { + FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr); + if(factionEntryCalc) + res = ModifyOneFactionReputation(factionEntryCalc, standing); + } + return res; + } + else + return ModifyOneFactionReputation(factionEntry, standing); +} + +bool Player::ModifyOneFactionReputation(FactionEntry const* factionEntry, int32 standing) +{ + FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); + if (itr != m_factions.end()) + { + int32 BaseRep = GetBaseReputation(factionEntry); + int32 new_rep = BaseRep + itr->second.Standing + standing; + + if (new_rep > Reputation_Cap) + new_rep = Reputation_Cap; + else + if (new_rep < Reputation_Bottom) + new_rep = Reputation_Bottom; + + if(ReputationToRank(new_rep) <= REP_HOSTILE) + SetFactionAtWar(&itr->second,true); + + itr->second.Standing = new_rep - BaseRep; + itr->second.Changed = true; + + SetFactionVisible(&itr->second); + + for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) + { + if(uint32 questid = GetQuestSlotQuestId(i)) + { + Quest const* qInfo = objmgr.GetQuestTemplate(questid); + if( qInfo && qInfo->GetRepObjectiveFaction() == factionEntry->ID ) + { + QuestStatusData& q_status = mQuestStatus[questid]; + if( q_status.m_status == QUEST_STATUS_INCOMPLETE ) + { + if(GetReputation(factionEntry) >= qInfo->GetRepObjectiveValue()) + if ( CanCompleteQuest( questid ) ) + CompleteQuest( questid ); + } + else if( q_status.m_status == QUEST_STATUS_COMPLETE ) + { + if(GetReputation(factionEntry) < qInfo->GetRepObjectiveValue()) + IncompleteQuest( questid ); + } + } + } + } + + SendFactionState(&(itr->second)); + + return true; + } + return false; +} + +bool Player::SetFactionReputation(uint32 FactionTemplateId, int32 standing) +{ + FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId); + + if(!factionTemplateEntry) + { + sLog.outError("Player::SetFactionReputation: Can't set reputation of %s for unknown faction (faction template id) #%u.", GetName(), FactionTemplateId); + return false; + } + + FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction); + + // Faction without recorded reputation. Just ignore. + if(!factionEntry) + return false; + + return SetFactionReputation(factionEntry, standing); +} + +bool Player::SetFactionReputation(FactionEntry const* factionEntry, int32 standing) +{ + SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID); + if (flist) + { + bool res = false; + for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr) + { + FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr); + if(factionEntryCalc) + res = SetOneFactionReputation(factionEntryCalc, standing); + } + return res; + } + else + return SetOneFactionReputation(factionEntry, standing); +} + +bool Player::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing) +{ + FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); + if (itr != m_factions.end()) + { + if (standing > Reputation_Cap) + standing = Reputation_Cap; + else + if (standing < Reputation_Bottom) + standing = Reputation_Bottom; + + int32 BaseRep = GetBaseReputation(factionEntry); + itr->second.Standing = standing - BaseRep; + itr->second.Changed = true; + + SetFactionVisible(&itr->second); + + if(ReputationToRank(standing) <= REP_HOSTILE) + SetFactionAtWar(&itr->second,true); + + SendFactionState(&(itr->second)); + return true; + } + return false; +} + +//Calculate total reputation percent player gain with quest/creature level +int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest) +{ + // for grey creature kill received 20%, in other case 100. + int32 percent = (!for_quest && (creatureOrQuestLevel <= MaNGOS::XP::GetGrayLevel(getLevel()))) ? 20 : 100; + + int32 repMod = GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN); + + percent += rep > 0 ? repMod : -repMod; + + if(percent <=0) + return 0; + + return int32(sWorld.getRate(RATE_REPUTATION_GAIN)*rep*percent/100); +} + +//Calculates how many reputation points player gains in victim's enemy factions +void Player::RewardReputation(Unit *pVictim, float rate) +{ + if(!pVictim || pVictim->GetTypeId() == TYPEID_PLAYER) + return; + + ReputationOnKillEntry const* Rep = objmgr.GetReputationOnKilEntry(pVictim->GetEntry()); + + if(!Rep) + return; + + if(Rep->repfaction1 && (!Rep->team_dependent || GetTeam()==ALLIANCE)) + { + int32 donerep1 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue1,false); + donerep1 = int32(donerep1*rate); + FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(Rep->repfaction1); + uint32 current_reputation_rank1 = GetReputationRank(factionEntry1); + if(factionEntry1 && current_reputation_rank1 <= Rep->reputation_max_cap1) + ModifyFactionReputation(factionEntry1, donerep1); + + // Wiki: Team factions value divided by 2 + if(Rep->is_teamaward1) + { + FactionEntry const *team1_factionEntry = sFactionStore.LookupEntry(factionEntry1->team); + if(team1_factionEntry) + ModifyFactionReputation(team1_factionEntry, donerep1 / 2); + } + } + + if(Rep->repfaction2 && (!Rep->team_dependent || GetTeam()==HORDE)) + { + int32 donerep2 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue2,false); + donerep2 = int32(donerep2*rate); + FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(Rep->repfaction2); + uint32 current_reputation_rank2 = GetReputationRank(factionEntry2); + if(factionEntry2 && current_reputation_rank2 <= Rep->reputation_max_cap2) + ModifyFactionReputation(factionEntry2, donerep2); + + // Wiki: Team factions value divided by 2 + if(Rep->is_teamaward2) + { + FactionEntry const *team2_factionEntry = sFactionStore.LookupEntry(factionEntry2->team); + if(team2_factionEntry) + ModifyFactionReputation(team2_factionEntry, donerep2 / 2); + } + } +} + +//Calculate how many reputation points player gain with the quest +void Player::RewardReputation(Quest const *pQuest) +{ + // quest reputation reward/loss + for(int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) + { + if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] ) + { + int32 rep = CalculateReputationGain(pQuest->GetQuestLevel(),pQuest->RewRepValue[i],true); + FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]); + if(factionEntry) + ModifyFactionReputation(factionEntry, rep); + } + } + + // TODO: implement reputation spillover +} + +void Player::UpdateArenaFields(void) +{ + /* arena calcs go here */ +} + +void Player::UpdateHonorFields() +{ + /// called when rewarding honor and at each save + uint64 now = time(NULL); + uint64 today = uint64(time(NULL) / DAY) * DAY; + + if(m_lastHonorUpdateTime < today) + { + uint64 yesterday = today - DAY; + + uint16 kills_today = PAIR32_LOPART(GetUInt32Value(PLAYER_FIELD_KILLS)); + + // update yesterday's contribution + if(m_lastHonorUpdateTime >= yesterday ) + { + SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); + + // this is the first update today, reset today's contribution + SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); + SetUInt32Value(PLAYER_FIELD_KILLS, MAKE_PAIR32(0,kills_today)); + } + else + { + // no honor/kills yesterday or today, reset + SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); + SetUInt32Value(PLAYER_FIELD_KILLS, 0); + } + } + + m_lastHonorUpdateTime = now; +} + +///Calculate the amount of honor gained based on the victim +///and the size of the group for which the honor is divided +///An exact honor value can also be given (overriding the calcs) +bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor) +{ + // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens + if(GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) + return false; + + uint64 victim_guid = 0; + uint32 victim_rank = 0; + time_t now = time(NULL); + + // need call before fields update to have chance move yesterday data to appropriate fields before today data change. + UpdateHonorFields(); + + if(honor <= 0) + { + if(!uVictim || uVictim == this || uVictim->HasAuraType(SPELL_AURA_NO_PVP_CREDIT)) + return false; + + victim_guid = uVictim->GetGUID(); + + if( uVictim->GetTypeId() == TYPEID_PLAYER ) + { + Player *pVictim = (Player *)uVictim; + + if( GetTeam() == pVictim->GetTeam() && !sWorld.IsFFAPvPRealm() ) + return false; + + float f = 1; //need for total kills (?? need more info) + uint32 k_grey = 0; + uint32 k_level = getLevel(); + uint32 v_level = pVictim->getLevel(); + + { + // PLAYER_CHOSEN_TITLE VALUES DESCRIPTION + // [0] Just name + // [1..14] Alliance honor titles and player name + // [15..28] Horde honor titles and player name + // [29..38] Other title and player name + // [39+] Nothing + uint32 victim_title = pVictim->GetUInt32Value(PLAYER_CHOSEN_TITLE); + // Get Killer titles, CharTitlesEntry::bit_index + // Ranks: + // title[1..14] -> rank[5..18] + // title[15..28] -> rank[5..18] + // title[other] -> 0 + if (victim_title == 0) + victim_guid = 0; // Don't show HK: message, only log. + else if (victim_title < 15) + victim_rank = victim_title + 4; + else if (victim_title < 29) + victim_rank = victim_title - 14 + 4; + else + victim_guid = 0; // Don't show HK: message, only log. + } + + if(k_level <= 5) + k_grey = 0; + else if( k_level <= 39 ) + k_grey = k_level - 5 - k_level/10; + else + k_grey = k_level - 1 - k_level/5; + + if(v_level<=k_grey) + return false; + + float diff_level = (k_level == k_grey) ? 1 : ((float(v_level) - float(k_grey)) / (float(k_level) - float(k_grey))); + + int32 v_rank =1; //need more info + + honor = ((f * diff_level * (190 + v_rank*10))/6); + honor *= ((float)k_level) / 70.0f; //factor of dependence on levels of the killer + + // count the number of playerkills in one day + ApplyModUInt32Value(PLAYER_FIELD_KILLS, 1, true); + // and those in a lifetime + ApplyModUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 1, true); + } + else + { + Creature *cVictim = (Creature *)uVictim; + + if (!cVictim->isRacialLeader()) + return false; + + honor = 100; // ??? need more info + victim_rank = 19; // HK: Leader + } + } + + if (uVictim != NULL) + { + honor *= sWorld.getRate(RATE_HONOR); + + if(groupsize > 1) + honor /= groupsize; + + honor *= (((float)urand(8,12))/10); // approx honor: 80% - 120% of real honor + } + + // honor - for show honor points in log + // victim_guid - for show victim name in log + // victim_rank [1..4] HK: + // victim_rank [5..19] HK: + // victim_rank [0,20+] HK: <> + WorldPacket data(SMSG_PVP_CREDIT,4+8+4); + data << (uint32) honor; + data << (uint64) victim_guid; + data << (uint32) victim_rank; + + GetSession()->SendPacket(&data); + + // add honor points + ModifyHonorPoints(int32(honor)); + + ApplyModUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, uint32(honor), true); + return true; +} + +void Player::ModifyHonorPoints( int32 value ) +{ + if(value < 0) + { + if (GetHonorPoints() > sWorld.getConfig(CONFIG_MAX_HONOR_POINTS)) + SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, sWorld.getConfig(CONFIG_MAX_HONOR_POINTS) + value); + else + SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, GetHonorPoints() > uint32(-value) ? GetHonorPoints() + value : 0); + } + else + SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, GetHonorPoints() < sWorld.getConfig(CONFIG_MAX_HONOR_POINTS) - value ? GetHonorPoints() + value : sWorld.getConfig(CONFIG_MAX_HONOR_POINTS)); +} + +void Player::ModifyArenaPoints( int32 value ) +{ + if(value < 0) + { + if (GetArenaPoints() > sWorld.getConfig(CONFIG_MAX_ARENA_POINTS)) + SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, sWorld.getConfig(CONFIG_MAX_ARENA_POINTS) + value); + else + SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, GetArenaPoints() > uint32(-value) ? GetArenaPoints() + value : 0); + } + else + SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, GetArenaPoints() < sWorld.getConfig(CONFIG_MAX_ARENA_POINTS) - value ? GetArenaPoints() + value : sWorld.getConfig(CONFIG_MAX_ARENA_POINTS)); +} + +uint32 Player::GetGuildIdFromDB(uint64 guid) +{ + std::ostringstream ss; + ss<<"SELECT guildid FROM guild_member WHERE guid='"<Fetch()[0].GetUInt32(); + delete result; + return v; + } + else + return 0; +} + +uint32 Player::GetRankFromDB(uint64 guid) +{ + std::ostringstream ss; + ss<<"SELECT rank FROM guild_member WHERE guid='"<Fetch()[0].GetUInt32(); + delete result; + return v; + } + else + return 0; +} + +uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type) +{ + // need fix it! + QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid FROM arena_team_member WHERE guid='%u'", GUID_LOPART(guid)); + if(result) + { + // init id to 0, check the arena type before assigning a value to id + uint32 id = 0; + do + { + QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM arena_team WHERE arenateamid='%u'", id); + if(result2) + { + uint8 dbtype = (*result2)[0].GetUInt32(); + delete result2; + if(dbtype == type) + { + // if the type matches, we've found the id + id = (*result)[0].GetUInt32(); + break; + } + } + } while(result->NextRow()); + delete result; + return id; + } + // no arenateam for the specified guid, return 0 + return 0; +} + +uint32 Player::GetZoneIdFromDB(uint64 guid) +{ + std::ostringstream ss; + + ss<<"SELECT zone FROM characters WHERE guid='"<Fetch(); + uint32 zone = fields[0].GetUInt32(); + delete result; + + if (!zone) + { + // stored zone is zero, use generic and slow zone detection + ss.str(""); + ss<<"SELECT map,position_x,position_y FROM characters WHERE guid='"<Fetch(); + uint32 map = fields[0].GetUInt32(); + float posx = fields[1].GetFloat(); + float posy = fields[2].GetFloat(); + delete result; + + zone = MapManager::Instance().GetZoneId(map,posx,posy); + + ss.str(""); + ss << "UPDATE characters SET zone='"<flags & AREA_FLAG_ARENA)) + { + if(!isGameMaster()) + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); + } + else + { + // remove ffa flag only if not ffapvp realm + // removal in sanctuaries and capitals is handled in zone update + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && !sWorld.IsFFAPvPRealm()) + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); + } + + UpdateAreaDependentAuras(newArea); +} + +void Player::UpdateZone(uint32 newZone) +{ + m_zoneUpdateId = newZone; + m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; + + // zone changed, so area changed as well, update it + UpdateArea(GetAreaId()); + + AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone); + if(!zone) + return; + + if (sWorld.getConfig(CONFIG_WEATHER)) + { + Weather *wth = sWorld.FindWeather(zone->ID); + if(wth) + { + wth->SendWeatherUpdateToPlayer(this); + } + else + { + if(!sWorld.AddWeather(zone->ID)) + { + // send fine weather packet to remove old zone's weather + Weather::SendFineWeatherUpdateToPlayer(this); + } + } + } + + pvpInfo.inHostileArea = + GetTeam() == ALLIANCE && zone->team == AREATEAM_HORDE || + GetTeam() == HORDE && zone->team == AREATEAM_ALLY || + sWorld.IsPvPRealm() && zone->team == AREATEAM_NONE || + InBattleGround(); // overwrite for battlegrounds, maybe batter some zone flags but current known not 100% fit to this + + if(pvpInfo.inHostileArea) // in hostile area + { + if(!IsPvP() || pvpInfo.endTimer != 0) + UpdatePvP(true, true); + } + else // in friendly area + { + if(IsPvP() && !HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_IN_PVP) && pvpInfo.endTimer == 0) + pvpInfo.endTimer = time(0); // start toggle-off + } + + if(zone->flags & AREA_FLAG_SANCTUARY) // in sanctuary + { + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY); + if(sWorld.IsFFAPvPRealm()) + RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); + } + else + { + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY); + } + + if(zone->flags & AREA_FLAG_CAPITAL) // in capital city + { + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + SetRestType(REST_TYPE_IN_CITY); + InnEnter(time(0),GetMapId(),0,0,0); + + if(sWorld.IsFFAPvPRealm()) + RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); + } + else // anywhere else + { + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) // but resting (walk from city or maybe in tavern or leave tavern recently) + { + if(GetRestType()==REST_TYPE_IN_TAVERN) // has been in tavern. Is still in? + { + if(GetMapId()!=GetInnPosMapId() || sqrt((GetPositionX()-GetInnPosX())*(GetPositionX()-GetInnPosX())+(GetPositionY()-GetInnPosY())*(GetPositionY()-GetInnPosY())+(GetPositionZ()-GetInnPosZ())*(GetPositionZ()-GetInnPosZ()))>40) + { + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + SetRestType(REST_TYPE_NO); + + if(sWorld.IsFFAPvPRealm()) + SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); + } + } + else // not in tavern (leave city then) + { + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + SetRestType(REST_TYPE_NO); + + // Set player to FFA PVP when not in rested enviroment. + if(sWorld.IsFFAPvPRealm()) + SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); + } + } + } + + // remove items with area/map limitations (delete only for alive player to allow back in ghost mode) + // if player resurrected at teleport this will be applied in resurrect code + if(isAlive()) + DestroyZoneLimitedItem( true, newZone ); + + // recent client version not send leave/join channel packets for built-in local channels + UpdateLocalChannels( newZone ); + + // group update + if(GetGroup()) + SetGroupUpdateFlag(GROUP_UPDATE_FLAG_ZONE); + + UpdateZoneDependentAuras(newZone); +} + +//If players are too far way of duel flag... then player loose the duel +void Player::CheckDuelDistance(time_t currTime) +{ + if(!duel) + return; + + uint64 duelFlagGUID = GetUInt64Value(PLAYER_DUEL_ARBITER); + GameObject* obj = ObjectAccessor::GetGameObject(*this, duelFlagGUID); + if(!obj) + return; + + if(duel->outOfBound == 0) + { + if(!IsWithinDistInMap(obj, 50)) + { + duel->outOfBound = currTime; + + WorldPacket data(SMSG_DUEL_OUTOFBOUNDS, 0); + GetSession()->SendPacket(&data); + } + } + else + { + if(IsWithinDistInMap(obj, 40)) + { + duel->outOfBound = 0; + + WorldPacket data(SMSG_DUEL_INBOUNDS, 0); + GetSession()->SendPacket(&data); + } + else if(currTime >= (duel->outOfBound+10)) + { + DuelComplete(DUEL_FLED); + } + } +} + +void Player::DuelComplete(DuelCompleteType type) +{ + // duel not requested + if(!duel) + return; + + WorldPacket data(SMSG_DUEL_COMPLETE, (1)); + data << (uint8)((type != DUEL_INTERUPTED) ? 1 : 0); + GetSession()->SendPacket(&data); + duel->opponent->GetSession()->SendPacket(&data); + + if(type != DUEL_INTERUPTED) + { + data.Initialize(SMSG_DUEL_WINNER, (1+20)); // we guess size + data << (uint8)((type==DUEL_WON) ? 0 : 1); // 0 = just won; 1 = fled + data << duel->opponent->GetName(); + data << GetName(); + SendMessageToSet(&data,true); + } + + // cool-down duel spell + /*data.Initialize(SMSG_SPELL_COOLDOWN, 17); + + data<SendPacket(&data); + data.Initialize(SMSG_SPELL_COOLDOWN, 17); + data<opponent->GetGUID(); + data<opponent->GetSession()->SendPacket(&data);*/ + + //Remove Duel Flag object + GameObject* obj = ObjectAccessor::GetGameObject(*this, GetUInt64Value(PLAYER_DUEL_ARBITER)); + if(obj) + duel->initiator->RemoveGameObject(obj,true); + + /* remove auras */ + std::vector auras2remove; + AuraMap const& vAuras = duel->opponent->GetAuras(); + for (AuraMap::const_iterator i = vAuras.begin(); i != vAuras.end(); i++) + { + if (!i->second->IsPositive() && i->second->GetCasterGUID() == GetGUID() && i->second->GetAuraApplyTime() >= duel->startTime) + auras2remove.push_back(i->second->GetId()); + } + + for(size_t i=0; iopponent->RemoveAurasDueToSpell(auras2remove[i]); + + auras2remove.clear(); + AuraMap const& auras = GetAuras(); + for (AuraMap::const_iterator i = auras.begin(); i != auras.end(); i++) + { + if (!i->second->IsPositive() && i->second->GetCasterGUID() == duel->opponent->GetGUID() && i->second->GetAuraApplyTime() >= duel->startTime) + auras2remove.push_back(i->second->GetId()); + } + for(size_t i=0; iopponent->GetGUID()) + ClearComboPoints(); + else if(GetComboTarget()==duel->opponent->GetPetGUID()) + ClearComboPoints(); + + if(duel->opponent->GetComboTarget()==GetGUID()) + duel->opponent->ClearComboPoints(); + else if(duel->opponent->GetComboTarget()==GetPetGUID()) + duel->opponent->ClearComboPoints(); + + //cleanups + SetUInt64Value(PLAYER_DUEL_ARBITER, 0); + SetUInt32Value(PLAYER_DUEL_TEAM, 0); + duel->opponent->SetUInt64Value(PLAYER_DUEL_ARBITER, 0); + duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 0); + + delete duel->opponent->duel; + duel->opponent->duel = NULL; + delete duel; + duel = NULL; +} + +//---------------------------------------------------------// + +void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply) +{ + if(slot >= INVENTORY_SLOT_BAG_END || !item) + return; + + // not apply/remove mods for broken item + if(item->IsBroken()) + return; + + ItemPrototype const *proto = item->GetProto(); + + if(!proto) + return; + + sLog.outDetail("applying mods for item %u ",item->GetGUIDLow()); + + uint32 attacktype = Player::GetAttackBySlot(slot); + if(attacktype < MAX_ATTACK) + _ApplyWeaponDependentAuraMods(item,WeaponAttackType(attacktype),apply); + + _ApplyItemBonuses(proto,slot,apply); + + if( slot==EQUIPMENT_SLOT_RANGED ) + _ApplyAmmoBonuses(); + + ApplyItemEquipSpell(item,apply); + ApplyEnchantment(item, apply); + + if(proto->Socket[0].Color) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items + CorrectMetaGemEnchants(slot, apply); + + sLog.outDebug("_ApplyItemMods complete."); +} + +void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply) +{ + if(slot >= INVENTORY_SLOT_BAG_END || !proto) + return; + + for (int i = 0; i < 10; i++) + { + float val = float (proto->ItemStat[i].ItemStatValue); + + if(val==0) + continue; + + switch (proto->ItemStat[i].ItemStatType) + { + case ITEM_MOD_MANA: + HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply); + break; + case ITEM_MOD_HEALTH: // modify HP + HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply); + break; + case ITEM_MOD_AGILITY: // modify agility + HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, val, apply); + break; + case ITEM_MOD_STRENGTH: //modify strength + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_STRENGTH, val, apply); + break; + case ITEM_MOD_INTELLECT: //modify intellect + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_INTELLECT, val, apply); + break; + case ITEM_MOD_SPIRIT: //modify spirit + HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_SPIRIT, val, apply); + break; + case ITEM_MOD_STAMINA: //modify stamina + HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_STAMINA, val, apply); + break; + case ITEM_MOD_DEFENSE_SKILL_RATING: + ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply); + break; + case ITEM_MOD_DODGE_RATING: + ApplyRatingMod(CR_DODGE, int32(val), apply); + break; + case ITEM_MOD_PARRY_RATING: + ApplyRatingMod(CR_PARRY, int32(val), apply); + break; + case ITEM_MOD_BLOCK_RATING: + ApplyRatingMod(CR_BLOCK, int32(val), apply); + break; + case ITEM_MOD_HIT_MELEE_RATING: + ApplyRatingMod(CR_HIT_MELEE, int32(val), apply); + break; + case ITEM_MOD_HIT_RANGED_RATING: + ApplyRatingMod(CR_HIT_RANGED, int32(val), apply); + break; + case ITEM_MOD_HIT_SPELL_RATING: + ApplyRatingMod(CR_HIT_SPELL, int32(val), apply); + break; + case ITEM_MOD_CRIT_MELEE_RATING: + ApplyRatingMod(CR_CRIT_MELEE, int32(val), apply); + break; + case ITEM_MOD_CRIT_RANGED_RATING: + ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply); + break; + case ITEM_MOD_CRIT_SPELL_RATING: + ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply); + break; + case ITEM_MOD_HIT_TAKEN_MELEE_RATING: + ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply); + break; + case ITEM_MOD_HIT_TAKEN_RANGED_RATING: + ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply); + break; + case ITEM_MOD_HIT_TAKEN_SPELL_RATING: + ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply); + break; + case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: + ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); + break; + case ITEM_MOD_CRIT_TAKEN_RANGED_RATING: + ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); + break; + case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: + ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); + break; + case ITEM_MOD_HASTE_MELEE_RATING: + ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply); + break; + case ITEM_MOD_HASTE_RANGED_RATING: + ApplyRatingMod(CR_HASTE_RANGED, int32(val), apply); + break; + case ITEM_MOD_HASTE_SPELL_RATING: + ApplyRatingMod(CR_HASTE_SPELL, int32(val), apply); + break; + case ITEM_MOD_HIT_RATING: + ApplyRatingMod(CR_HIT_MELEE, int32(val), apply); + ApplyRatingMod(CR_HIT_RANGED, int32(val), apply); + ApplyRatingMod(CR_HIT_SPELL, int32(val), apply); + break; + case ITEM_MOD_CRIT_RATING: + ApplyRatingMod(CR_CRIT_MELEE, int32(val), apply); + ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply); + ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply); + break; + case ITEM_MOD_HIT_TAKEN_RATING: + ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply); + ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply); + ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply); + break; + case ITEM_MOD_CRIT_TAKEN_RATING: + ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); + ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); + ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); + break; + case ITEM_MOD_RESILIENCE_RATING: + ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); + ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); + ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); + break; + case ITEM_MOD_HASTE_RATING: + ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply); + ApplyRatingMod(CR_HASTE_RANGED, int32(val), apply); + ApplyRatingMod(CR_HASTE_SPELL, int32(val), apply); + break; + case ITEM_MOD_EXPERTISE_RATING: + ApplyRatingMod(CR_EXPERTISE, int32(val), apply); + break; + } + } + + if (proto->Armor) + HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(proto->Armor), apply); + + if (proto->Block) + HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply); + + if (proto->HolyRes) + HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply); + + if (proto->FireRes) + HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply); + + if (proto->NatureRes) + HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply); + + if (proto->FrostRes) + HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply); + + if (proto->ShadowRes) + HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply); + + if (proto->ArcaneRes) + HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply); + + WeaponAttackType attType = BASE_ATTACK; + float damage = 0.0f; + + if( slot == EQUIPMENT_SLOT_RANGED && ( + proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN || + proto->InventoryType == INVTYPE_RANGEDRIGHT )) + { + attType = RANGED_ATTACK; + } + else if(slot==EQUIPMENT_SLOT_OFFHAND) + { + attType = OFF_ATTACK; + } + + if (proto->Damage[0].DamageMin > 0 ) + { + damage = apply ? proto->Damage[0].DamageMin : BASE_MINDAMAGE; + SetBaseWeaponDamage(attType, MINDAMAGE, damage); + //sLog.outError("applying mindam: assigning %f to weapon mindamage, now is: %f", damage, GetWeaponDamageRange(attType, MINDAMAGE)); + } + + if (proto->Damage[0].DamageMax > 0 ) + { + damage = apply ? proto->Damage[0].DamageMax : BASE_MAXDAMAGE; + SetBaseWeaponDamage(attType, MAXDAMAGE, damage); + } + + if(!IsUseEquipedWeapon(slot==EQUIPMENT_SLOT_MAINHAND)) + return; + + if (proto->Delay) + { + if(slot == EQUIPMENT_SLOT_RANGED) + SetAttackTime(RANGED_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME); + else if(slot==EQUIPMENT_SLOT_MAINHAND) + SetAttackTime(BASE_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME); + else if(slot==EQUIPMENT_SLOT_OFFHAND) + SetAttackTime(OFF_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME); + } + + if(CanModifyStats() && (damage || proto->Delay)) + UpdateDamagePhysical(attType); +} + +void Player::_ApplyWeaponDependentAuraMods(Item *item,WeaponAttackType attackType,bool apply) +{ + AuraList const& auraCritList = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT); + for(AuraList::const_iterator itr = auraCritList.begin(); itr!=auraCritList.end();++itr) + _ApplyWeaponDependentAuraCritMod(item,attackType,*itr,apply); + + AuraList const& auraDamageFlatList = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); + for(AuraList::const_iterator itr = auraDamageFlatList.begin(); itr!=auraDamageFlatList.end();++itr) + _ApplyWeaponDependentAuraDamageMod(item,attackType,*itr,apply); + + AuraList const& auraDamagePCTList = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + for(AuraList::const_iterator itr = auraDamagePCTList.begin(); itr!=auraDamagePCTList.end();++itr) + _ApplyWeaponDependentAuraDamageMod(item,attackType,*itr,apply); +} + +void Player::_ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply) +{ + // generic not weapon specific case processes in aura code + if(aura->GetSpellProto()->EquippedItemClass == -1) + return; + + BaseModGroup mod = BASEMOD_END; + switch(attackType) + { + case BASE_ATTACK: mod = CRIT_PERCENTAGE; break; + case OFF_ATTACK: mod = OFFHAND_CRIT_PERCENTAGE;break; + case RANGED_ATTACK: mod = RANGED_CRIT_PERCENTAGE; break; + default: return; + } + + if (item->IsFitToSpellRequirements(aura->GetSpellProto())) + { + HandleBaseModValue(mod, FLAT_MOD, float (aura->GetModifier()->m_amount), apply); + } +} + +void Player::_ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply) +{ + // ignore spell mods for not wands + Modifier const* modifier = aura->GetModifier(); + if((modifier->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)==0 && (getClassMask() & CLASSMASK_WAND_USERS)==0) + return; + + // generic not weapon specific case processes in aura code + if(aura->GetSpellProto()->EquippedItemClass == -1) + return; + + UnitMods unitMod = UNIT_MOD_END; + switch(attackType) + { + case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; + case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; + case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; + default: return; + } + + UnitModifierType unitModType = TOTAL_VALUE; + switch(modifier->m_auraname) + { + case SPELL_AURA_MOD_DAMAGE_DONE: unitModType = TOTAL_VALUE; break; + case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: unitModType = TOTAL_PCT; break; + default: return; + } + + if (item->IsFitToSpellRequirements(aura->GetSpellProto())) + { + HandleStatModifier(unitMod, unitModType, float(modifier->m_amount),apply); + } +} + +void Player::ApplyItemEquipSpell(Item *item, bool apply, bool form_change) +{ + if(!item) + return; + + ItemPrototype const *proto = item->GetProto(); + if(!proto) + return; + + for (int i = 0; i < 5; i++) + { + _Spell const& spellData = proto->Spells[i]; + + // no spell + if(!spellData.SpellId ) + continue; + + // wrong triggering type + if(apply && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_EQUIP) + continue; + + // check if it is valid spell + SpellEntry const* spellproto = sSpellStore.LookupEntry(spellData.SpellId); + if(!spellproto) + continue; + + ApplyEquipSpell(spellproto,item,apply,form_change); + } +} + +void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply, bool form_change) +{ + if(apply) + { + // Cannot be used in this stance/form + if(GetErrorAtShapeshiftedCast(spellInfo, m_form)!=0) + return; + + if(form_change) // check aura active state from other form + { + bool found = false; + for (int k=0; k < 3; ++k) + { + spellEffectPair spair = spellEffectPair(spellInfo->Id, k); + for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair); ++iter) + { + if(!item || iter->second->GetCastItemGUID() == item->GetGUID()) + { + found = true; + break; + } + } + if(found) + break; + } + + if(found) // and skip re-cast already active aura at form change + return; + } + + DEBUG_LOG("WORLD: cast %s Equip spellId - %i", (item ? "item" : "itemset"), spellInfo->Id); + + CastSpell(this,spellInfo,true,item); + } + else + { + if(form_change) // check aura compatibility + { + // Cannot be used in this stance/form + if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==0) + return; // and remove only not compatible at form change + } + + if(item) + RemoveAurasDueToItemSpell(item,spellInfo->Id); // un-apply all spells , not only at-equipped + else + RemoveAurasDueToSpell(spellInfo->Id); // un-apply spell (item set case) + } +} + +void Player::UpdateEquipSpellsAtFormChange() +{ + for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) + { + if(m_items[i] && !m_items[i]->IsBroken()) + { + ApplyItemEquipSpell(m_items[i],false,true); // remove spells that not fit to form + ApplyItemEquipSpell(m_items[i],true,true); // add spells that fit form but not active + } + } + + // item set bonuses not dependent from item broken state + for(size_t setindex = 0; setindex < ItemSetEff.size(); ++setindex) + { + ItemSetEffect* eff = ItemSetEff[setindex]; + if(!eff) + continue; + + for(uint32 y=0;y<8; ++y) + { + SpellEntry const* spellInfo = eff->spells[y]; + if(!spellInfo) + continue; + + ApplyEquipSpell(spellInfo,NULL,false,true); // remove spells that not fit to form + ApplyEquipSpell(spellInfo,NULL,true,true); // add spells that fit form but not active + } + } +} + +void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attType) +{ + if(!item || item->IsBroken()) + return; + + ItemPrototype const *proto = item->GetProto(); + if(!proto) + return; + + if (!Target || Target == this ) + return; + + for (int i = 0; i < 5; i++) + { + _Spell const& spellData = proto->Spells[i]; + + // no spell + if(!spellData.SpellId ) + continue; + + // wrong triggering type + if(spellData.SpellTrigger != ITEM_SPELLTRIGGER_CHANCE_ON_HIT) + continue; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId); + if(!spellInfo) + { + sLog.outError("WORLD: unknown Item spellid %i", spellData.SpellId); + continue; + } + + // not allow proc extra attack spell at extra attack + if( m_extraAttacks && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_ADD_EXTRA_ATTACKS) ) + return; + + float chance = spellInfo->procChance; + + if(spellData.SpellPPMRate) + { + uint32 WeaponSpeed = GetAttackTime(attType); + chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate); + } + else if(chance > 100.0f) + { + chance = GetWeaponProcChance(); + } + + if (roll_chance_f(chance)) + this->CastSpell(Target, spellInfo->Id, true, item); + } + + // item combat enchantments + for(int e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot) + { + uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot)); + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) continue; + for (int s=0;s<3;s++) + { + if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) + continue; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(pEnchant->spellid[s]); + if (!spellInfo) + { + sLog.outError("Player::CastItemCombatSpell Enchant %i, cast unknown spell %i", pEnchant->ID, pEnchant->spellid[s]); + continue; + } + + float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance(); + if (roll_chance_f(chance)) + { + if(IsPositiveSpell(pEnchant->spellid[s])) + CastSpell(this, pEnchant->spellid[s], true, item); + else + CastSpell(Target, pEnchant->spellid[s], true, item); + } + } + } +} + +void Player::_RemoveAllItemMods() +{ + sLog.outDebug("_RemoveAllItemMods start."); + + for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) + { + if(m_items[i]) + { + ItemPrototype const *proto = m_items[i]->GetProto(); + if(!proto) + continue; + + // item set bonuses not dependent from item broken state + if(proto->ItemSet) + RemoveItemsSetItem(this,proto); + + if(m_items[i]->IsBroken()) + continue; + + ApplyItemEquipSpell(m_items[i],false); + ApplyEnchantment(m_items[i], false); + } + } + + for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) + { + if(m_items[i]) + { + if(m_items[i]->IsBroken()) + continue; + ItemPrototype const *proto = m_items[i]->GetProto(); + if(!proto) + continue; + + uint32 attacktype = Player::GetAttackBySlot(i); + if(attacktype < MAX_ATTACK) + _ApplyWeaponDependentAuraMods(m_items[i],WeaponAttackType(attacktype),false); + + _ApplyItemBonuses(proto,i, false); + + if( i == EQUIPMENT_SLOT_RANGED ) + _ApplyAmmoBonuses(); + } + } + + sLog.outDebug("_RemoveAllItemMods complete."); +} + +void Player::_ApplyAllItemMods() +{ + sLog.outDebug("_ApplyAllItemMods start."); + + for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) + { + if(m_items[i]) + { + if(m_items[i]->IsBroken()) + continue; + + ItemPrototype const *proto = m_items[i]->GetProto(); + if(!proto) + continue; + + uint32 attacktype = Player::GetAttackBySlot(i); + if(attacktype < MAX_ATTACK) + _ApplyWeaponDependentAuraMods(m_items[i],WeaponAttackType(attacktype),true); + + _ApplyItemBonuses(proto,i, true); + + if( i == EQUIPMENT_SLOT_RANGED ) + _ApplyAmmoBonuses(); + } + } + + for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++) + { + if(m_items[i]) + { + ItemPrototype const *proto = m_items[i]->GetProto(); + if(!proto) + continue; + + // item set bonuses not dependent from item broken state + if(proto->ItemSet) + AddItemsSetItem(this,m_items[i]); + + if(m_items[i]->IsBroken()) + continue; + + ApplyItemEquipSpell(m_items[i],true); + ApplyEnchantment(m_items[i], true); + } + } + + sLog.outDebug("_ApplyAllItemMods complete."); +} + +void Player::_ApplyAmmoBonuses() +{ + // check ammo + uint32 ammo_id = GetUInt32Value(PLAYER_AMMO_ID); + if(!ammo_id) + return; + + float currentAmmoDPS; + + ItemPrototype const *ammo_proto = objmgr.GetItemPrototype( ammo_id ); + if( !ammo_proto || ammo_proto->Class!=ITEM_CLASS_PROJECTILE || !CheckAmmoCompatibility(ammo_proto)) + currentAmmoDPS = 0.0f; + else + currentAmmoDPS = ammo_proto->Damage[0].DamageMin; + + if(currentAmmoDPS == GetAmmoDPS()) + return; + + m_ammoDPS = currentAmmoDPS; + + if(CanModifyStats()) + UpdateDamagePhysical(RANGED_ATTACK); +} + +bool Player::CheckAmmoCompatibility(const ItemPrototype *ammo_proto) const +{ + if(!ammo_proto) + return false; + + // check ranged weapon + Item *weapon = GetWeaponForAttack( RANGED_ATTACK ); + if(!weapon || weapon->IsBroken() ) + return false; + + ItemPrototype const* weapon_proto = weapon->GetProto(); + if(!weapon_proto || weapon_proto->Class!=ITEM_CLASS_WEAPON ) + return false; + + // check ammo ws. weapon compatibility + switch(weapon_proto->SubClass) + { + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + if(ammo_proto->SubClass!=ITEM_SUBCLASS_ARROW) + return false; + break; + case ITEM_SUBCLASS_WEAPON_GUN: + if(ammo_proto->SubClass!=ITEM_SUBCLASS_BULLET) + return false; + break; + default: + return false; + } + + return true; +} + +/* If in a battleground a player dies, and an enemy removes the insignia, the player's bones is lootable + Called by remove insignia spell effect */ +void Player::RemovedInsignia(Player* looterPlr) +{ + if (!GetBattleGroundId()) + return; + + // If not released spirit, do it ! + if(m_deathTimer > 0) + { + m_deathTimer = 0; + BuildPlayerRepop(); + RepopAtGraveyard(); + } + + Corpse *corpse = GetCorpse(); + if (!corpse) + return; + + // We have to convert player corpse to bones, not to be able to resurrect there + // SpawnCorpseBones isn't handy, 'cos it saves player while he in BG + Corpse *bones = ObjectAccessor::Instance().ConvertCorpseForPlayer(GetGUID()); + if (!bones) + return; + + // Now we must make bones lootable, and send player loot + bones->SetFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); + + // We store the level of our player in the gold field + // We retrieve this information at Player::SendLoot() + bones->loot.gold = getLevel(); + bones->lootRecipient = looterPlr; + looterPlr->SendLoot(bones->GetGUID(), LOOT_INSIGNIA); +} + +/*Loot type MUST be +1-corpse, go +2-skinning +3-Fishing +*/ + +void Player::SendLootRelease( uint64 guid ) +{ + WorldPacket data( SMSG_LOOT_RELEASE_RESPONSE, (8+1) ); + data << uint64(guid) << uint8(1); + SendDirectMessage( &data ); +} + +void Player::SendLoot(uint64 guid, LootType loot_type) +{ + Loot *loot = 0; + PermissionTypes permission = ALL_PERMISSION; + + sLog.outDebug("Player::SendLoot"); + if (IS_GAMEOBJECT_GUID(guid)) + { + sLog.outDebug(" IS_GAMEOBJECT_GUID(guid)"); + GameObject *go = + ObjectAccessor::GetGameObject(*this, guid); + + // not check distance for GO in case owned GO (fishing bobber case, for example) + // And permit out of range GO with no owner in case fishing hole + if (!go || (loot_type != LOOT_FISHINGHOLE && (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this,INTERACTION_DISTANCE))) + { + SendLootRelease(guid); + return; + } + + loot = &go->loot; + + if(go->getLootState() == GO_READY) + { + uint32 lootid = go->GetLootId(); + + if(lootid) + { + sLog.outDebug(" if(lootid)"); + loot->clear(); + loot->FillLoot(lootid, LootTemplates_Gameobject, this); + } + + if(loot_type == LOOT_FISHING) + go->getFishLoot(loot); + + go->SetLootState(GO_ACTIVATED); + } + } + else if (IS_ITEM_GUID(guid)) + { + Item *item = GetItemByGuid( guid ); + + if (!item) + { + SendLootRelease(guid); + return; + } + + if(loot_type == LOOT_DISENCHANTING) + { + loot = &item->loot; + + if(!item->m_lootGenerated) + { + item->m_lootGenerated = true; + loot->clear(); + loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this); + } + } + else if(loot_type == LOOT_PROSPECTING) + { + loot = &item->loot; + + if(!item->m_lootGenerated) + { + item->m_lootGenerated = true; + loot->clear(); + loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this); + } + } + else + { + loot = &item->loot; + + if(!item->m_lootGenerated) + { + item->m_lootGenerated = true; + loot->clear(); + loot->FillLoot(item->GetEntry(), LootTemplates_Item, this); + + loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot); + } + } + } + else if (IS_CORPSE_GUID(guid)) // remove insignia + { + Corpse *bones = ObjectAccessor::GetCorpse(*this, guid); + + if (!bones || !((loot_type == LOOT_CORPSE) || (loot_type == LOOT_INSIGNIA)) || (bones->GetType() != CORPSE_BONES) ) + { + SendLootRelease(guid); + return; + } + + loot = &bones->loot; + + if (!bones->lootForBody) + { + bones->lootForBody = true; + uint32 pLevel = bones->loot.gold; + bones->loot.clear(); + // It may need a better formula + // Now it works like this: lvl10: ~6copper, lvl70: ~9silver + bones->loot.gold = (uint32)( urand(50, 150) * 0.016f * pow( ((float)pLevel)/5.76f, 2.5f) * sWorld.getRate(RATE_DROP_MONEY) ); + } + + if (bones->lootRecipient != this) + permission = NONE_PERMISSION; + } + else + { + Creature *creature = ObjectAccessor::GetCreature(*this, guid); + + // must be in range and creature must be alive for pickpocket and must be dead for another loot + if (!creature || creature->isAlive()!=(loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this,INTERACTION_DISTANCE)) + { + SendLootRelease(guid); + return; + } + + if(loot_type == LOOT_PICKPOCKETING && IsFriendlyTo(creature)) + { + SendLootRelease(guid); + return; + } + + loot = &creature->loot; + + if(loot_type == LOOT_PICKPOCKETING) + { + if ( !creature->lootForPickPocketed ) + { + creature->lootForPickPocketed = true; + loot->clear(); + + if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId) + loot->FillLoot(lootid, LootTemplates_Pickpocketing, this); + + // Generate extra money for pick pocket loot + const uint32 a = urand(0, creature->getLevel()/2); + const uint32 b = urand(0, getLevel()/2); + loot->gold = uint32(10 * (a + b) * sWorld.getRate(RATE_DROP_MONEY)); + } + } + else + { + // the player whose group may loot the corpse + Player *recipient = creature->GetLootRecipient(); + if (!recipient) + { + creature->SetLootRecipient(this); + recipient = this; + } + + if (creature->lootForPickPocketed) + { + creature->lootForPickPocketed = false; + loot->clear(); + } + + if(!creature->lootForBody) + { + creature->lootForBody = true; + loot->clear(); + + if (uint32 lootid = creature->GetCreatureInfo()->lootid) + loot->FillLoot(lootid, LootTemplates_Creature, recipient); + + loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold,creature->GetCreatureInfo()->maxgold); + + if(Group* group = recipient->GetGroup()) + { + group->UpdateLooterGuid(creature,true); + + switch (group->GetLootMethod()) + { + case GROUP_LOOT: + // GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with qualityGroupLoot(recipient->GetGUID(), loot, creature); + break; + case NEED_BEFORE_GREED: + group->NeedBeforeGreed(recipient->GetGUID(), loot, creature); + break; + case MASTER_LOOT: + group->MasterLoot(recipient->GetGUID(), loot, creature); + break; + default: + break; + } + } + } + + // possible only if creature->lootForBody && loot->empty() at spell cast check + if (loot_type == LOOT_SKINNING) + { + loot->clear(); + loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this); + } + // set group rights only for loot_type != LOOT_SKINNING + else + { + if(Group* group = GetGroup()) + { + if( group == recipient->GetGroup() ) + { + if(group->GetLootMethod() == FREE_FOR_ALL) + permission = ALL_PERMISSION; + else if(group->GetLooterGuid() == GetGUID()) + { + if(group->GetLootMethod() == MASTER_LOOT) + permission = MASTER_PERMISSION; + else + permission = ALL_PERMISSION; + } + else + permission = GROUP_PERMISSION; + } + else + permission = NONE_PERMISSION; + } + else if(recipient == this) + permission = ALL_PERMISSION; + else + permission = NONE_PERMISSION; + } + } + } + + SetLootGUID(guid); + + QuestItemList *q_list = 0; + if (permission != NONE_PERMISSION) + { + QuestItemMap const& lootPlayerQuestItems = loot->GetPlayerQuestItems(); + QuestItemMap::const_iterator itr = lootPlayerQuestItems.find(GetGUIDLow()); + if (itr == lootPlayerQuestItems.end()) + q_list = loot->FillQuestLoot(this); + else + q_list = itr->second; + } + + QuestItemList *ffa_list = 0; + if (permission != NONE_PERMISSION) + { + QuestItemMap const& lootPlayerFFAItems = loot->GetPlayerFFAItems(); + QuestItemMap::const_iterator itr = lootPlayerFFAItems.find(GetGUIDLow()); + if (itr == lootPlayerFFAItems.end()) + ffa_list = loot->FillFFALoot(this); + else + ffa_list = itr->second; + } + + QuestItemList *conditional_list = 0; + if (permission != NONE_PERMISSION) + { + QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = loot->GetPlayerNonQuestNonFFAConditionalItems(); + QuestItemMap::const_iterator itr = lootPlayerNonQuestNonFFAConditionalItems.find(GetGUIDLow()); + if (itr == lootPlayerNonQuestNonFFAConditionalItems.end()) + conditional_list = loot->FillNonQuestNonFFAConditionalLoot(this); + else + conditional_list = itr->second; + } + + // LOOT_PICKPOCKETING, LOOT_PROSPECTING, LOOT_DISENCHANTING and LOOT_INSIGNIA unsupported by client, sending LOOT_SKINNING instead + if(loot_type == LOOT_PICKPOCKETING || loot_type == LOOT_DISENCHANTING || loot_type == LOOT_PROSPECTING || loot_type == LOOT_INSIGNIA) + loot_type = LOOT_SKINNING; + + if(loot_type == LOOT_FISHINGHOLE) + loot_type = LOOT_FISHING; + + WorldPacket data(SMSG_LOOT_RESPONSE, (9+50)); // we guess size + + data << uint64(guid); + data << uint8(loot_type); + data << LootView(*loot, q_list, ffa_list, conditional_list, this, permission); + + SendDirectMessage(&data); + + // add 'this' player as one of the players that are looting 'loot' + if (permission != NONE_PERMISSION) + loot->AddLooter(GetGUID()); + + if ( loot_type == LOOT_CORPSE && !IS_ITEM_GUID(guid) ) + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); +} + +void Player::SendNotifyLootMoneyRemoved() +{ + WorldPacket data(SMSG_LOOT_CLEAR_MONEY, 0); + GetSession()->SendPacket( &data ); +} + +void Player::SendNotifyLootItemRemoved(uint8 lootSlot) +{ + WorldPacket data(SMSG_LOOT_REMOVED, 1); + data << uint8(lootSlot); + GetSession()->SendPacket( &data ); +} + +void Player::SendUpdateWorldState(uint32 Field, uint32 Value) +{ + WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); + data << Field; + data << Value; + GetSession()->SendPacket(&data); +} + +void Player::SendInitWorldStates() +{ + // data depends on zoneid/mapid... + BattleGround* bg = GetBattleGround(); + uint16 NumberOfFields = 0; + uint32 mapid = GetMapId(); + uint32 zoneid = GetZoneId(); + uint32 areaid = GetAreaId(); + sLog.outDebug("Sending SMSG_INIT_WORLD_STATES to Map:%u, Zone: %u", mapid, zoneid); + // may be exist better way to do this... + switch(zoneid) + { + case 0: + case 1: + case 4: + case 8: + case 10: + case 11: + case 12: + case 36: + case 38: + case 40: + case 41: + case 51: + case 267: + case 1519: + case 1537: + case 2257: + case 2918: + NumberOfFields = 6; + break; + case 2597: + NumberOfFields = 81; + break; + case 3277: + NumberOfFields = 14; + break; + case 3358: + case 3820: + NumberOfFields = 38; + break; + case 3483: + NumberOfFields = 22; + break; + case 3519: + NumberOfFields = 36; + break; + case 3521: + NumberOfFields = 35; + break; + case 3698: + case 3702: + case 3968: + NumberOfFields = 9; + break; + case 3703: + NumberOfFields = 9; + break; + default: + NumberOfFields = 10; + break; + } + + WorldPacket data(SMSG_INIT_WORLD_STATES, (4+4+4+2+(NumberOfFields*8))); + data << uint32(mapid); // mapid + data << uint32(zoneid); // zone id + data << uint32(areaid); // area id, new 2.1.0 + data << uint16(NumberOfFields); // count of uint64 blocks + data << uint32(0x8d8) << uint32(0x0); // 1 + data << uint32(0x8d7) << uint32(0x0); // 2 + data << uint32(0x8d6) << uint32(0x0); // 3 + data << uint32(0x8d5) << uint32(0x0); // 4 + data << uint32(0x8d4) << uint32(0x0); // 5 + data << uint32(0x8d3) << uint32(0x0); // 6 + if(mapid == 530) // Outland + { + data << uint32(0x9bf) << uint32(0x0); // 7 + data << uint32(0x9bd) << uint32(0xF); // 8 + data << uint32(0x9bb) << uint32(0xF); // 9 + } + switch(zoneid) + { + case 1: + case 11: + case 12: + case 38: + case 40: + case 51: + case 1519: + case 1537: + case 2257: + break; + case 2597: // AV + data << uint32(0x7ae) << uint32(0x1); // 7 + data << uint32(0x532) << uint32(0x1); // 8 + data << uint32(0x531) << uint32(0x0); // 9 + data << uint32(0x52e) << uint32(0x0); // 10 + data << uint32(0x571) << uint32(0x0); // 11 + data << uint32(0x570) << uint32(0x0); // 12 + data << uint32(0x567) << uint32(0x1); // 13 + data << uint32(0x566) << uint32(0x1); // 14 + data << uint32(0x550) << uint32(0x1); // 15 + data << uint32(0x544) << uint32(0x0); // 16 + data << uint32(0x536) << uint32(0x0); // 17 + data << uint32(0x535) << uint32(0x1); // 18 + data << uint32(0x518) << uint32(0x0); // 19 + data << uint32(0x517) << uint32(0x0); // 20 + data << uint32(0x574) << uint32(0x0); // 21 + data << uint32(0x573) << uint32(0x0); // 22 + data << uint32(0x572) << uint32(0x0); // 23 + data << uint32(0x56f) << uint32(0x0); // 24 + data << uint32(0x56e) << uint32(0x0); // 25 + data << uint32(0x56d) << uint32(0x0); // 26 + data << uint32(0x56c) << uint32(0x0); // 27 + data << uint32(0x56b) << uint32(0x0); // 28 + data << uint32(0x56a) << uint32(0x1); // 29 + data << uint32(0x569) << uint32(0x1); // 30 + data << uint32(0x568) << uint32(0x1); // 13 + data << uint32(0x565) << uint32(0x0); // 32 + data << uint32(0x564) << uint32(0x0); // 33 + data << uint32(0x563) << uint32(0x0); // 34 + data << uint32(0x562) << uint32(0x0); // 35 + data << uint32(0x561) << uint32(0x0); // 36 + data << uint32(0x560) << uint32(0x0); // 37 + data << uint32(0x55f) << uint32(0x0); // 38 + data << uint32(0x55e) << uint32(0x0); // 39 + data << uint32(0x55d) << uint32(0x0); // 40 + data << uint32(0x3c6) << uint32(0x4); // 41 + data << uint32(0x3c4) << uint32(0x6); // 42 + data << uint32(0x3c2) << uint32(0x4); // 43 + data << uint32(0x516) << uint32(0x1); // 44 + data << uint32(0x515) << uint32(0x0); // 45 + data << uint32(0x3b6) << uint32(0x6); // 46 + data << uint32(0x55c) << uint32(0x0); // 47 + data << uint32(0x55b) << uint32(0x0); // 48 + data << uint32(0x55a) << uint32(0x0); // 49 + data << uint32(0x559) << uint32(0x0); // 50 + data << uint32(0x558) << uint32(0x0); // 51 + data << uint32(0x557) << uint32(0x0); // 52 + data << uint32(0x556) << uint32(0x0); // 53 + data << uint32(0x555) << uint32(0x0); // 54 + data << uint32(0x554) << uint32(0x1); // 55 + data << uint32(0x553) << uint32(0x1); // 56 + data << uint32(0x552) << uint32(0x1); // 57 + data << uint32(0x551) << uint32(0x1); // 58 + data << uint32(0x54f) << uint32(0x0); // 59 + data << uint32(0x54e) << uint32(0x0); // 60 + data << uint32(0x54d) << uint32(0x1); // 61 + data << uint32(0x54c) << uint32(0x0); // 62 + data << uint32(0x54b) << uint32(0x0); // 63 + data << uint32(0x545) << uint32(0x0); // 64 + data << uint32(0x543) << uint32(0x1); // 65 + data << uint32(0x542) << uint32(0x0); // 66 + data << uint32(0x540) << uint32(0x0); // 67 + data << uint32(0x53f) << uint32(0x0); // 68 + data << uint32(0x53e) << uint32(0x0); // 69 + data << uint32(0x53d) << uint32(0x0); // 70 + data << uint32(0x53c) << uint32(0x0); // 71 + data << uint32(0x53b) << uint32(0x0); // 72 + data << uint32(0x53a) << uint32(0x1); // 73 + data << uint32(0x539) << uint32(0x0); // 74 + data << uint32(0x538) << uint32(0x0); // 75 + data << uint32(0x537) << uint32(0x0); // 76 + data << uint32(0x534) << uint32(0x0); // 77 + data << uint32(0x533) << uint32(0x0); // 78 + data << uint32(0x530) << uint32(0x0); // 79 + data << uint32(0x52f) << uint32(0x0); // 80 + data << uint32(0x52d) << uint32(0x1); // 81 + break; + case 3277: // WS + if (bg && bg->GetTypeID() == BATTLEGROUND_WS) + bg->FillInitialWorldStates(data); + else + { + data << uint32(0x62d) << uint32(0x0); // 7 1581 alliance flag captures + data << uint32(0x62e) << uint32(0x0); // 8 1582 horde flag captures + data << uint32(0x609) << uint32(0x0); // 9 1545 unk, set to 1 on alliance flag pickup... + data << uint32(0x60a) << uint32(0x0); // 10 1546 unk, set to 1 on horde flag pickup, after drop it's -1 + data << uint32(0x60b) << uint32(0x2); // 11 1547 unk + data << uint32(0x641) << uint32(0x3); // 12 1601 unk (max flag captures?) + data << uint32(0x922) << uint32(0x1); // 13 2338 horde (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing) + data << uint32(0x923) << uint32(0x1); // 14 2339 alliance (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing) + } + break; + case 3358: // AB + if (bg && bg->GetTypeID() == BATTLEGROUND_AB) + bg->FillInitialWorldStates(data); + else + { + data << uint32(0x6e7) << uint32(0x0); // 7 1767 stables alliance + data << uint32(0x6e8) << uint32(0x0); // 8 1768 stables horde + data << uint32(0x6e9) << uint32(0x0); // 9 1769 unk, ST? + data << uint32(0x6ea) << uint32(0x0); // 10 1770 stables (show/hide) + data << uint32(0x6ec) << uint32(0x0); // 11 1772 farm (0 - horde controlled, 1 - alliance controlled) + data << uint32(0x6ed) << uint32(0x0); // 12 1773 farm (show/hide) + data << uint32(0x6ee) << uint32(0x0); // 13 1774 farm color + data << uint32(0x6ef) << uint32(0x0); // 14 1775 gold mine color, may be FM? + data << uint32(0x6f0) << uint32(0x0); // 15 1776 alliance resources + data << uint32(0x6f1) << uint32(0x0); // 16 1777 horde resources + data << uint32(0x6f2) << uint32(0x0); // 17 1778 horde bases + data << uint32(0x6f3) << uint32(0x0); // 18 1779 alliance bases + data << uint32(0x6f4) << uint32(0x7d0); // 19 1780 max resources (2000) + data << uint32(0x6f6) << uint32(0x0); // 20 1782 blacksmith color + data << uint32(0x6f7) << uint32(0x0); // 21 1783 blacksmith (show/hide) + data << uint32(0x6f8) << uint32(0x0); // 22 1784 unk, bs? + data << uint32(0x6f9) << uint32(0x0); // 23 1785 unk, bs? + data << uint32(0x6fb) << uint32(0x0); // 24 1787 gold mine (0 - horde contr, 1 - alliance contr) + data << uint32(0x6fc) << uint32(0x0); // 25 1788 gold mine (0 - conflict, 1 - horde) + data << uint32(0x6fd) << uint32(0x0); // 26 1789 gold mine (1 - show/0 - hide) + data << uint32(0x6fe) << uint32(0x0); // 27 1790 gold mine color + data << uint32(0x700) << uint32(0x0); // 28 1792 gold mine color, wtf?, may be LM? + data << uint32(0x701) << uint32(0x0); // 29 1793 lumber mill color (0 - conflict, 1 - horde contr) + data << uint32(0x702) << uint32(0x0); // 30 1794 lumber mill (show/hide) + data << uint32(0x703) << uint32(0x0); // 31 1795 lumber mill color color + data << uint32(0x732) << uint32(0x1); // 32 1842 stables (1 - uncontrolled) + data << uint32(0x733) << uint32(0x1); // 33 1843 gold mine (1 - uncontrolled) + data << uint32(0x734) << uint32(0x1); // 34 1844 lumber mill (1 - uncontrolled) + data << uint32(0x735) << uint32(0x1); // 35 1845 farm (1 - uncontrolled) + data << uint32(0x736) << uint32(0x1); // 36 1846 blacksmith (1 - uncontrolled) + data << uint32(0x745) << uint32(0x2); // 37 1861 unk + data << uint32(0x7a3) << uint32(0x708); // 38 1955 warning limit (1800) + } + break; + case 3820: // EY + if (bg && bg->GetTypeID() == BATTLEGROUND_EY) + bg->FillInitialWorldStates(data); + else + { + data << uint32(0xac1) << uint32(0x0); // 7 2753 Horde Bases + data << uint32(0xac0) << uint32(0x0); // 8 2752 Alliance Bases + data << uint32(0xab6) << uint32(0x0); // 9 2742 Mage Tower - Horde conflict + data << uint32(0xab5) << uint32(0x0); // 10 2741 Mage Tower - Alliance conflict + data << uint32(0xab4) << uint32(0x0); // 11 2740 Fel Reaver - Horde conflict + data << uint32(0xab3) << uint32(0x0); // 12 2739 Fel Reaver - Alliance conflict + data << uint32(0xab2) << uint32(0x0); // 13 2738 Draenei - Alliance conflict + data << uint32(0xab1) << uint32(0x0); // 14 2737 Draenei - Horde conflict + data << uint32(0xab0) << uint32(0x0); // 15 2736 unk // 0 at start + data << uint32(0xaaf) << uint32(0x0); // 16 2735 unk // 0 at start + data << uint32(0xaad) << uint32(0x0); // 17 2733 Draenei - Horde control + data << uint32(0xaac) << uint32(0x0); // 18 2732 Draenei - Alliance control + data << uint32(0xaab) << uint32(0x1); // 19 2731 Draenei uncontrolled (1 - yes, 0 - no) + data << uint32(0xaaa) << uint32(0x0); // 20 2730 Mage Tower - Alliance control + data << uint32(0xaa9) << uint32(0x0); // 21 2729 Mage Tower - Horde control + data << uint32(0xaa8) << uint32(0x1); // 22 2728 Mage Tower uncontrolled (1 - yes, 0 - no) + data << uint32(0xaa7) << uint32(0x0); // 23 2727 Fel Reaver - Horde control + data << uint32(0xaa6) << uint32(0x0); // 24 2726 Fel Reaver - Alliance control + data << uint32(0xaa5) << uint32(0x1); // 25 2725 Fel Reaver uncontroled (1 - yes, 0 - no) + data << uint32(0xaa4) << uint32(0x0); // 26 2724 Boold Elf - Horde control + data << uint32(0xaa3) << uint32(0x0); // 27 2723 Boold Elf - Alliance control + data << uint32(0xaa2) << uint32(0x1); // 28 2722 Boold Elf uncontrolled (1 - yes, 0 - no) + data << uint32(0xac5) << uint32(0x1); // 29 2757 Flag (1 - show, 0 - hide) - doesn't work exactly this way! + data << uint32(0xad2) << uint32(0x1); // 30 2770 Horde top-stats (1 - show, 0 - hide) // 02 -> horde picked up the flag + data << uint32(0xad1) << uint32(0x1); // 31 2769 Alliance top-stats (1 - show, 0 - hide) // 02 -> alliance picked up the flag + data << uint32(0xabe) << uint32(0x0); // 32 2750 Horde resources + data << uint32(0xabd) << uint32(0x0); // 33 2749 Alliance resources + data << uint32(0xa05) << uint32(0x8e); // 34 2565 unk, constant? + data << uint32(0xaa0) << uint32(0x0); // 35 2720 Capturing progress-bar (100 -> empty (only grey), 0 -> blue|red (no grey), default 0) + data << uint32(0xa9f) << uint32(0x0); // 36 2719 Capturing progress-bar (0 - left, 100 - right) + data << uint32(0xa9e) << uint32(0x0); // 37 2718 Capturing progress-bar (1 - show, 0 - hide) + data << uint32(0xc0d) << uint32(0x17b); // 38 3085 unk + // and some more ... unknown + } + break; + case 3483: // Hellfire Peninsula + data << uint32(0x9ba) << uint32(0x1); // 10 + data << uint32(0x9b9) << uint32(0x1); // 11 + data << uint32(0x9b5) << uint32(0x0); // 12 + data << uint32(0x9b4) << uint32(0x1); // 13 + data << uint32(0x9b3) << uint32(0x0); // 14 + data << uint32(0x9b2) << uint32(0x0); // 15 + data << uint32(0x9b1) << uint32(0x1); // 16 + data << uint32(0x9b0) << uint32(0x0); // 17 + data << uint32(0x9ae) << uint32(0x0); // 18 horde pvp objectives captured + data << uint32(0x9ac) << uint32(0x0); // 19 + data << uint32(0x9a8) << uint32(0x0); // 20 + data << uint32(0x9a7) << uint32(0x0); // 21 + data << uint32(0x9a6) << uint32(0x1); // 22 + break; + case 3519: // Terokkar Forest + data << uint32(0xa41) << uint32(0x0); // 10 + data << uint32(0xa40) << uint32(0x14); // 11 + data << uint32(0xa3f) << uint32(0x0); // 12 + data << uint32(0xa3e) << uint32(0x0); // 13 + data << uint32(0xa3d) << uint32(0x5); // 14 + data << uint32(0xa3c) << uint32(0x0); // 15 + data << uint32(0xa87) << uint32(0x0); // 16 + data << uint32(0xa86) << uint32(0x0); // 17 + data << uint32(0xa85) << uint32(0x0); // 18 + data << uint32(0xa84) << uint32(0x0); // 19 + data << uint32(0xa83) << uint32(0x0); // 20 + data << uint32(0xa82) << uint32(0x0); // 21 + data << uint32(0xa81) << uint32(0x0); // 22 + data << uint32(0xa80) << uint32(0x0); // 23 + data << uint32(0xa7e) << uint32(0x0); // 24 + data << uint32(0xa7d) << uint32(0x0); // 25 + data << uint32(0xa7c) << uint32(0x0); // 26 + data << uint32(0xa7b) << uint32(0x0); // 27 + data << uint32(0xa7a) << uint32(0x0); // 28 + data << uint32(0xa79) << uint32(0x0); // 29 + data << uint32(0x9d0) << uint32(0x5); // 30 + data << uint32(0x9ce) << uint32(0x0); // 31 + data << uint32(0x9cd) << uint32(0x0); // 32 + data << uint32(0x9cc) << uint32(0x0); // 33 + data << uint32(0xa88) << uint32(0x0); // 34 + data << uint32(0xad0) << uint32(0x0); // 35 + data << uint32(0xacf) << uint32(0x1); // 36 + break; + case 3521: // Zangarmarsh + data << uint32(0x9e1) << uint32(0x0); // 10 + data << uint32(0x9e0) << uint32(0x0); // 11 + data << uint32(0x9df) << uint32(0x0); // 12 + data << uint32(0xa5d) << uint32(0x1); // 13 + data << uint32(0xa5c) << uint32(0x0); // 14 + data << uint32(0xa5b) << uint32(0x1); // 15 + data << uint32(0xa5a) << uint32(0x0); // 16 + data << uint32(0xa59) << uint32(0x1); // 17 + data << uint32(0xa58) << uint32(0x0); // 18 + data << uint32(0xa57) << uint32(0x0); // 19 + data << uint32(0xa56) << uint32(0x0); // 20 + data << uint32(0xa55) << uint32(0x1); // 21 + data << uint32(0xa54) << uint32(0x0); // 22 + data << uint32(0x9e7) << uint32(0x0); // 23 + data << uint32(0x9e6) << uint32(0x0); // 24 + data << uint32(0x9e5) << uint32(0x0); // 25 + data << uint32(0xa00) << uint32(0x0); // 26 + data << uint32(0x9ff) << uint32(0x1); // 27 + data << uint32(0x9fe) << uint32(0x0); // 28 + data << uint32(0x9fd) << uint32(0x0); // 29 + data << uint32(0x9fc) << uint32(0x1); // 30 + data << uint32(0x9fb) << uint32(0x0); // 31 + data << uint32(0xa62) << uint32(0x0); // 32 + data << uint32(0xa61) << uint32(0x1); // 33 + data << uint32(0xa60) << uint32(0x1); // 34 + data << uint32(0xa5f) << uint32(0x0); // 35 + break; + case 3698: // Nagrand Arena + data << uint32(0xa0f) << uint32(0x0); // 7 + data << uint32(0xa10) << uint32(0x0); // 8 + data << uint32(0xa11) << uint32(0x0); // 9 + break; + case 3702: // Blade's Edge Arena + data << uint32(0x9f0) << uint32(0x0); // 7 + data << uint32(0x9f1) << uint32(0x0); // 8 + data << uint32(0x9f3) << uint32(0x0); // 9 + break; + case 3968: // Ruins of Lordaeron + data << uint32(0xbb8) << uint32(0x0); // 7 + data << uint32(0xbb9) << uint32(0x0); // 8 + data << uint32(0xbba) << uint32(0x0); // 9 + break; + case 3703: // Shattrath City + break; + default: + data << uint32(0x914) << uint32(0x0); // 7 + data << uint32(0x913) << uint32(0x0); // 8 + data << uint32(0x912) << uint32(0x0); // 9 + data << uint32(0x915) << uint32(0x0); // 10 + break; + } + GetSession()->SendPacket(&data); +} + +uint32 Player::GetXPRestBonus(uint32 xp) +{ + uint32 rested_bonus = (uint32)GetRestBonus(); // xp for each rested bonus + + if(rested_bonus > xp) // max rested_bonus == xp or (r+x) = 200% xp + rested_bonus = xp; + + SetRestBonus( GetRestBonus() - rested_bonus); + + sLog.outDetail("Player gain %u xp (+ %u Rested Bonus). Rested points=%f",xp+rested_bonus,rested_bonus,GetRestBonus()); + return rested_bonus; +} + +void Player::SetBindPoint(uint64 guid) +{ + WorldPacket data(SMSG_BINDER_CONFIRM, 8); + data << uint64(guid); + GetSession()->SendPacket( &data ); +} + +void Player::SendTalentWipeConfirm(uint64 guid) +{ + WorldPacket data(MSG_TALENT_WIPE_CONFIRM, (8+4)); + data << uint64(guid); + data << uint32(resetTalentsCost()); + GetSession()->SendPacket( &data ); +} + +void Player::SendPetSkillWipeConfirm() +{ + Pet* pet = GetPet(); + if(!pet) + return; + WorldPacket data(SMSG_PET_UNLEARN_CONFIRM, (8+4)); + data << pet->GetGUID(); + data << uint32(pet->resetTalentsCost()); + GetSession()->SendPacket( &data ); +} + +/*********************************************************/ +/*** STORAGE SYSTEM ***/ +/*********************************************************/ + +void Player::SetVirtualItemSlot( uint8 i, Item* item) +{ + assert(i < 3); + if(i < 2 && item) + { + if(!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + return; + uint32 charges = item->GetEnchantmentCharges(TEMP_ENCHANTMENT_SLOT); + if(charges == 0) + return; + if(charges > 1) + item->SetEnchantmentCharges(TEMP_ENCHANTMENT_SLOT,charges-1); + else if(charges <= 1) + { + ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false); + item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); + } + } +} + +void Player::SetSheath( uint32 sheathed ) +{ + switch (sheathed) + { + case SHEATH_STATE_UNARMED: // no prepared weapon + SetVirtualItemSlot(0,NULL); + SetVirtualItemSlot(1,NULL); + SetVirtualItemSlot(2,NULL); + break; + case SHEATH_STATE_MELEE: // prepared melee weapon + { + SetVirtualItemSlot(0,GetWeaponForAttack(BASE_ATTACK,true)); + SetVirtualItemSlot(1,GetWeaponForAttack(OFF_ATTACK,true)); + SetVirtualItemSlot(2,NULL); + }; break; + case SHEATH_STATE_RANGED: // prepared ranged weapon + SetVirtualItemSlot(0,NULL); + SetVirtualItemSlot(1,NULL); + SetVirtualItemSlot(2,GetWeaponForAttack(RANGED_ATTACK,true)); + break; + default: + SetVirtualItemSlot(0,NULL); + SetVirtualItemSlot(1,NULL); + SetVirtualItemSlot(2,NULL); + break; + } + SetByteValue(UNIT_FIELD_BYTES_2, 0, sheathed); // this must visualize Sheath changing for other players... +} + +uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const +{ + uint8 pClass = getClass(); + + uint8 slots[4]; + slots[0] = NULL_SLOT; + slots[1] = NULL_SLOT; + slots[2] = NULL_SLOT; + slots[3] = NULL_SLOT; + switch( proto->InventoryType ) + { + case INVTYPE_HEAD: + slots[0] = EQUIPMENT_SLOT_HEAD; + break; + case INVTYPE_NECK: + slots[0] = EQUIPMENT_SLOT_NECK; + break; + case INVTYPE_SHOULDERS: + slots[0] = EQUIPMENT_SLOT_SHOULDERS; + break; + case INVTYPE_BODY: + slots[0] = EQUIPMENT_SLOT_BODY; + break; + case INVTYPE_CHEST: + slots[0] = EQUIPMENT_SLOT_CHEST; + break; + case INVTYPE_ROBE: + slots[0] = EQUIPMENT_SLOT_CHEST; + break; + case INVTYPE_WAIST: + slots[0] = EQUIPMENT_SLOT_WAIST; + break; + case INVTYPE_LEGS: + slots[0] = EQUIPMENT_SLOT_LEGS; + break; + case INVTYPE_FEET: + slots[0] = EQUIPMENT_SLOT_FEET; + break; + case INVTYPE_WRISTS: + slots[0] = EQUIPMENT_SLOT_WRISTS; + break; + case INVTYPE_HANDS: + slots[0] = EQUIPMENT_SLOT_HANDS; + break; + case INVTYPE_FINGER: + slots[0] = EQUIPMENT_SLOT_FINGER1; + slots[1] = EQUIPMENT_SLOT_FINGER2; + break; + case INVTYPE_TRINKET: + slots[0] = EQUIPMENT_SLOT_TRINKET1; + slots[1] = EQUIPMENT_SLOT_TRINKET2; + break; + case INVTYPE_CLOAK: + slots[0] = EQUIPMENT_SLOT_BACK; + break; + case INVTYPE_WEAPON: + { + slots[0] = EQUIPMENT_SLOT_MAINHAND; + + // suggest offhand slot only if know dual wielding + // (this will be replace mainhand weapon at auto equip instead unwonted "you don't known dual wielding" ... + if(CanDualWield()) + slots[1] = EQUIPMENT_SLOT_OFFHAND; + };break; + case INVTYPE_SHIELD: + slots[0] = EQUIPMENT_SLOT_OFFHAND; + break; + case INVTYPE_RANGED: + slots[0] = EQUIPMENT_SLOT_RANGED; + break; + case INVTYPE_2HWEAPON: + slots[0] = EQUIPMENT_SLOT_MAINHAND; + break; + case INVTYPE_TABARD: + slots[0] = EQUIPMENT_SLOT_TABARD; + break; + case INVTYPE_WEAPONMAINHAND: + slots[0] = EQUIPMENT_SLOT_MAINHAND; + break; + case INVTYPE_WEAPONOFFHAND: + slots[0] = EQUIPMENT_SLOT_OFFHAND; + break; + case INVTYPE_HOLDABLE: + slots[0] = EQUIPMENT_SLOT_OFFHAND; + break; + case INVTYPE_THROWN: + slots[0] = EQUIPMENT_SLOT_RANGED; + break; + case INVTYPE_RANGEDRIGHT: + slots[0] = EQUIPMENT_SLOT_RANGED; + break; + case INVTYPE_BAG: + slots[0] = INVENTORY_SLOT_BAG_1; + slots[1] = INVENTORY_SLOT_BAG_2; + slots[2] = INVENTORY_SLOT_BAG_3; + slots[3] = INVENTORY_SLOT_BAG_4; + break; + case INVTYPE_RELIC: + { + switch(proto->SubClass) + { + case ITEM_SUBCLASS_ARMOR_LIBRAM: + if (pClass == CLASS_PALADIN) + slots[0] = EQUIPMENT_SLOT_RANGED; + break; + case ITEM_SUBCLASS_ARMOR_IDOL: + if (pClass == CLASS_DRUID) + slots[0] = EQUIPMENT_SLOT_RANGED; + break; + case ITEM_SUBCLASS_ARMOR_TOTEM: + if (pClass == CLASS_SHAMAN) + slots[0] = EQUIPMENT_SLOT_RANGED; + break; + case ITEM_SUBCLASS_ARMOR_MISC: + if (pClass == CLASS_WARLOCK) + slots[0] = EQUIPMENT_SLOT_RANGED; + break; + } + break; + } + default : + return NULL_SLOT; + } + + if( slot != NULL_SLOT ) + { + if( swap || !GetItemByPos( INVENTORY_SLOT_BAG_0, slot ) ) + { + for (int i = 0; i < 4; i++) + { + if ( slots[i] == slot ) + return slot; + } + } + } + else + { + // search free slot at first + for (int i = 0; i < 4; i++) + { + if ( slots[i] != NULL_SLOT && !GetItemByPos( INVENTORY_SLOT_BAG_0, slots[i] ) ) + { + // in case 2hand equipped weapon offhand slot empty but not free + if(slots[i]==EQUIPMENT_SLOT_OFFHAND) + { + Item* mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ); + if(!mainItem || mainItem->GetProto()->InventoryType != INVTYPE_2HWEAPON) + return slots[i]; + } + else + return slots[i]; + } + } + + // if not found free and can swap return first appropriate from used + for (int i = 0; i < 4; i++) + { + if ( slots[i] != NULL_SLOT && swap ) + return slots[i]; + } + } + + // no free position + return NULL_SLOT; +} + +uint8 Player::CanUnequipItems( uint32 item, uint32 count ) const +{ + Item *pItem; + uint32 tempcount = 0; + + uint8 res = EQUIP_ERR_OK; + + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + uint8 ires = CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false); + if(ires==EQUIP_ERR_OK) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return EQUIP_ERR_OK; + } + else + res = ires; + } + } + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return EQUIP_ERR_OK; + } + } + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return EQUIP_ERR_OK; + } + } + Bag *pBag; + ItemPrototype const *pBagProto; + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + pItem = GetItemByPos( i, j ); + if( pItem && pItem->GetEntry() == item ) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return EQUIP_ERR_OK; + } + } + } + } + } + + // not found req. item count and have unequippable items + return res; +} + +uint32 Player::GetItemCount( uint32 item, bool inBankAlso, Item* skipItem ) const +{ + uint32 count = 0; + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem != skipItem && pItem->GetEntry() == item ) + count += pItem->GetCount(); + } + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem != skipItem && pItem->GetEntry() == item ) + count += pItem->GetCount(); + } + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + count += pBag->GetItemCount(item,skipItem); + } + + if(skipItem && skipItem->GetProto()->GemProperties) + { + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem != skipItem && pItem->GetProto()->Socket[0].Color ) + count += pItem->GetGemCountWithID(item); + } + } + + if(inBankAlso) + { + for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) + { + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem != skipItem && pItem->GetEntry() == item ) + count += pItem->GetCount(); + } + for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + count += pBag->GetItemCount(item,skipItem); + } + + if(skipItem && skipItem->GetProto()->GemProperties) + { + for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) + { + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem != skipItem && pItem->GetProto()->Socket[0].Color ) + count += pItem->GetGemCountWithID(item); + } + } + } + + return count; +} + +Item* Player::GetItemByGuid( uint64 guid ) const +{ + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetGUID() == guid ) + return pItem; + } + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetGUID() == guid ) + return pItem; + } + + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + ItemPrototype const *pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + Item* pItem = pBag->GetItemByPos( j ); + if( pItem && pItem->GetGUID() == guid ) + return pItem; + } + } + } + } + for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + ItemPrototype const *pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + Item* pItem = pBag->GetItemByPos( j ); + if( pItem && pItem->GetGUID() == guid ) + return pItem; + } + } + } + } + + return NULL; +} + +Item* Player::GetItemByPos( uint16 pos ) const +{ + uint8 bag = pos >> 8; + uint8 slot = pos & 255; + return GetItemByPos( bag, slot ); +} + +Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const +{ + if( bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END || slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END ) ) + return m_items[slot]; + else if(bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END + || bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) + { + Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); + if ( pBag ) + return pBag->GetItemByPos(slot); + } + return NULL; +} + +Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable) const +{ + uint16 slot; + switch (attackType) + { + case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break; + case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break; + case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break; + default: return NULL; + } + + Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot); + if (!item || item->GetProto()->Class != ITEM_CLASS_WEAPON) + return NULL; + + if(!useable) + return item; + + if( item->IsBroken() || !IsUseEquipedWeapon(attackType==BASE_ATTACK) ) + return NULL; + + return item; +} + +Item* Player::GetShield(bool useable) const +{ + Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + if (!item || item->GetProto()->Class != ITEM_CLASS_ARMOR) + return NULL; + + if(!useable) + return item; + + if( item->IsBroken()) + return NULL; + + return item; +} + +uint32 Player::GetAttackBySlot( uint8 slot ) +{ + switch(slot) + { + case EQUIPMENT_SLOT_MAINHAND: return BASE_ATTACK; + case EQUIPMENT_SLOT_OFFHAND: return OFF_ATTACK; + case EQUIPMENT_SLOT_RANGED: return RANGED_ATTACK; + default: return MAX_ATTACK; + } +} + +bool Player::HasBankBagSlot( uint8 slot ) const +{ + uint32 maxslot = GetByteValue(PLAYER_BYTES_2, 2) + BANK_SLOT_BAG_START; + if( slot < maxslot ) + return true; + return false; +} + +bool Player::IsInventoryPos( uint8 bag, uint8 slot ) +{ + if( bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT ) + return true; + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END ) ) + return true; + if( bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END ) + return true; + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END ) ) + return true; + return false; +} + +bool Player::IsEquipmentPos( uint8 bag, uint8 slot ) +{ + if( bag == INVENTORY_SLOT_BAG_0 && ( slot < EQUIPMENT_SLOT_END ) ) + return true; + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) ) + return true; + return false; +} + +bool Player::IsBankPos( uint8 bag, uint8 slot ) +{ + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END ) ) + return true; + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) ) + return true; + if( bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) + return true; + return false; +} + +bool Player::IsBagPos( uint16 pos ) +{ + uint8 bag = pos >> 8; + uint8 slot = pos & 255; + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) ) + return true; + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) ) + return true; + return false; +} + +bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const +{ + uint32 tempcount = 0; + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return true; + } + } + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return true; + } + } + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + { + if(ItemPrototype const *pBagProto = pBag->GetProto()) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + Item* pItem = GetItemByPos( i, j ); + if( pItem && pItem->GetEntry() == item ) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return true; + } + } + } + } + } + + if(inBankAlso) + { + for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) + { + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return true; + } + } + for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + { + if(ItemPrototype const *pBagProto = pBag->GetProto()) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + Item* pItem = GetItemByPos( i, j ); + if( pItem && pItem->GetEntry() == item ) + { + tempcount += pItem->GetCount(); + if( tempcount >= count ) + return true; + } + } + } + } + } + } + + return false; +} + +Item* Player::GetItemOrItemWithGemEquipped( uint32 item ) const +{ + Item *pItem; + for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + return pItem; + } + + ItemPrototype const *pProto = objmgr.GetItemPrototype(item); + if (pProto && pProto->GemProperties) + { + for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetProto()->Socket[0].Color ) + { + if (pItem->GetGemCountWithID(item) > 0 ) + return pItem; + } + } + } + + return NULL; +} + +uint8 Player::_CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count ) const +{ + ItemPrototype const *pProto = objmgr.GetItemPrototype(entry); + if( !pProto ) + { + if(no_space_count) + *no_space_count = count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + + // no maximum + if(pProto->MaxCount == 0) + return EQUIP_ERR_OK; + + uint32 curcount = GetItemCount(pProto->ItemId,true,pItem); + + if( curcount + count > pProto->MaxCount ) + { + if(no_space_count) + *no_space_count = count +curcount - pProto->MaxCount; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + + return EQUIP_ERR_OK; +} + +bool Player::HasItemTotemCategory( uint32 TotemCategory ) const +{ + Item *pItem; + for(uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory )) + return true; + } + for(uint8 i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory )) + return true; + } + Bag *pBag; + ItemPrototype const *pBagProto; + for(uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; ++j) + { + pItem = GetItemByPos( i, j ); + if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory )) + return true; + } + } + } + } + return false; +} + +uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool swap, Item* pSrcItem ) const +{ + Item* pItem2 = GetItemByPos( bag, slot ); + + // ignore move item (this slot will be empty at move) + if(pItem2==pSrcItem) + pItem2 = NULL; + + uint32 need_space; + + // empty specific slot - check item fit to slot + if( !pItem2 || swap ) + { + if( bag == INVENTORY_SLOT_BAG_0 ) + { + // keyring case + if(slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + // prevent cheating + if(slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + } + else + { + Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); + if( !pBag ) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + ItemPrototype const* pBagProto = pBag->GetProto(); + if( !pBagProto ) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + if( !ItemCanGoIntoBag(pProto,pBagProto) ) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + } + + // non empty stack with space + need_space = pProto->Stackable; + } + // non empty slot, check item type + else + { + // check item type + if(pItem2->GetEntry() != pProto->ItemId) + return EQUIP_ERR_ITEM_CANT_STACK; + + // check free space + if(pItem2->GetCount() >= pProto->Stackable) + return EQUIP_ERR_ITEM_CANT_STACK; + + need_space = pProto->Stackable - pItem2->GetCount(); + } + + if(need_space > count) + need_space = count; + + ItemPosCount newPosition = ItemPosCount((bag << 8) | slot, need_space); + if(!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + } + return EQUIP_ERR_OK; +} + +uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot ) const +{ + // skip specific bag already processed in first called _CanStoreItem_InBag + if(bag==skip_bag) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); + if( !pBag ) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + ItemPrototype const* pBagProto = pBag->GetProto(); + if( !pBagProto ) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + // specialized bag mode or non-specilized + if( non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER) ) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + if( !ItemCanGoIntoBag(pProto,pBagProto) ) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot + if(j==skip_slot) + continue; + + Item* pItem2 = GetItemByPos( bag, j ); + + // ignore move item (this slot will be empty at move) + if(pItem2==pSrcItem) + pItem2 = NULL; + + // if merge skip empty, if !merge skip non-empty + if((pItem2!=NULL)!=merge) + continue; + + if( pItem2 ) + { + if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->Stackable ) + { + uint32 need_space = pProto->Stackable - pItem2->GetCount(); + if(need_space > count) + need_space = count; + + ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); + if(!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + + if(count==0) + return EQUIP_ERR_OK; + } + } + } + else + { + uint32 need_space = pProto->Stackable; + if(need_space > count) + need_space = count; + + ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); + if(!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + + if(count==0) + return EQUIP_ERR_OK; + } + } + } + return EQUIP_ERR_OK; +} + +uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool merge, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot ) const +{ + for(uint32 j = slot_begin; j < slot_end; j++) + { + // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot + if(INVENTORY_SLOT_BAG_0==skip_bag && j==skip_slot) + continue; + + Item* pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, j ); + + // ignore move item (this slot will be empty at move) + if(pItem2==pSrcItem) + pItem2 = NULL; + + // if merge skip empty, if !merge skip non-empty + if((pItem2!=NULL)!=merge) + continue; + + if( pItem2 ) + { + if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->Stackable ) + { + uint32 need_space = pProto->Stackable - pItem2->GetCount(); + if(need_space > count) + need_space = count; + ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); + if(!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + + if(count==0) + return EQUIP_ERR_OK; + } + } + } + else + { + uint32 need_space = pProto->Stackable; + if(need_space > count) + need_space = count; + + ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); + if(!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + + if(count==0) + return EQUIP_ERR_OK; + } + } + } + return EQUIP_ERR_OK; +} + +uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 entry, uint32 count, Item *pItem, bool swap, uint32* no_space_count ) const +{ + sLog.outDebug( "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, entry, count); + + ItemPrototype const *pProto = objmgr.GetItemPrototype(entry); + if( !pProto ) + { + if(no_space_count) + *no_space_count = count; + return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND; + } + + if(pItem && pItem->IsBindedNotWith(GetGUID())) + { + if(no_space_count) + *no_space_count = count; + return EQUIP_ERR_DONT_OWN_THAT_ITEM; + } + + // check count of items (skip for auto move for same player from bank) + uint32 no_similar_count = 0; // can't store this amount similar items + uint8 res = _CanTakeMoreSimilarItems(entry,count,pItem,&no_similar_count); + if(res!=EQUIP_ERR_OK) + { + if(count==no_similar_count) + { + if(no_space_count) + *no_space_count = no_similar_count; + return res; + } + count -= no_similar_count; + } + + // in specific slot + if( bag != NULL_BAG && slot != NULL_SLOT ) + { + res = _CanStoreItem_InSpecificSlot(bag,slot,dest,pProto,count,swap,pItem); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + + // not specific slot or have spece for partly store only in specific slot + + // in specific bag + if( bag != NULL_BAG ) + { + // search stack in bag for merge to + if( pProto->Stackable > 1 ) + { + if( bag == INVENTORY_SLOT_BAG_0 ) // inventory + { + res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_END,dest,pProto,count,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + + res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + else // equipped bag + { + // we need check 2 time (specilized/non_specialized), use NULL_BAG to prevent skipping bag + res = _CanStoreItem_InBag(bag,dest,pProto,count,true,false,pItem,NULL_BAG,slot); + if(res!=EQUIP_ERR_OK) + res = _CanStoreItem_InBag(bag,dest,pProto,count,true,true,pItem,NULL_BAG,slot); + + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + } + + // search free slot in bag for place to + if( bag == INVENTORY_SLOT_BAG_0 ) // inventory + { + // search free slot - keyring case + if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS) + { + uint32 keyringSize = GetMaxKeyringSize(); + res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + + res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + else // equipped bag + { + res = _CanStoreItem_InBag(bag,dest,pProto,count,false,false,pItem,NULL_BAG,slot); + if(res!=EQUIP_ERR_OK) + res = _CanStoreItem_InBag(bag,dest,pProto,count,false,true,pItem,NULL_BAG,slot); + + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + } + + // not specific bag or have space for partly store only in specific bag + + // search stack for merge to + if( pProto->Stackable > 1 ) + { + res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_END,dest,pProto,count,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + + res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + + if( pProto->BagFamily ) + { + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + res = _CanStoreItem_InBag(i,dest,pProto,count,true,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + continue; + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + } + + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + res = _CanStoreItem_InBag(i,dest,pProto,count,true,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + continue; + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + } + + // search free slot - special bag case + if( pProto->BagFamily ) + { + if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS) + { + uint32 keyringSize = GetMaxKeyringSize(); + res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + res = _CanStoreItem_InBag(i,dest,pProto,count,false,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + continue; + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + } + + // search free slot + res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + res = _CanStoreItem_InBag(i,dest,pProto,count,false,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + continue; + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + + if(no_space_count) + *no_space_count = count + no_similar_count; + + return EQUIP_ERR_INVENTORY_FULL; +} + +////////////////////////////////////////////////////////////////////////// +uint8 Player::CanStoreItems( Item **pItems,int count) const +{ + Item *pItem2; + + // fill space table + int inv_slot_items[INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START]; + int inv_bags[INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE]; + int inv_keys[KEYRING_SLOT_END-KEYRING_SLOT_START]; + + memset(inv_slot_items,0,sizeof(int)*(INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START)); + memset(inv_bags,0,sizeof(int)*(INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START)*MAX_BAG_SIZE); + memset(inv_keys,0,sizeof(int)*(KEYRING_SLOT_END-KEYRING_SLOT_START)); + + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + + if (pItem2 && !pItem2->IsInTrade()) + { + inv_slot_items[i-INVENTORY_SLOT_ITEM_START] = pItem2->GetCount(); + } + } + + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + + if (pItem2 && !pItem2->IsInTrade()) + { + inv_keys[i-KEYRING_SLOT_START] = pItem2->GetCount(); + } + } + + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + Bag *pBag; + ItemPrototype const *pBagProto; + + pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + pBagProto = pBag->GetProto(); + + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + pItem2 = GetItemByPos( i, j ); + if (pItem2 && !pItem2->IsInTrade()) + { + inv_bags[i-INVENTORY_SLOT_BAG_START][j] = pItem2->GetCount(); + } + } + } + } + } + + // check free space for all items + for (int k=0;kGetEntry(), pItem->GetCount()); + ItemPrototype const *pProto = pItem->GetProto(); + + // strange item + if( !pProto ) + return EQUIP_ERR_ITEM_NOT_FOUND; + + // item it 'bind' + if(pItem->IsBindedNotWith(GetGUID())) + return EQUIP_ERR_DONT_OWN_THAT_ITEM; + + Bag *pBag; + ItemPrototype const *pBagProto; + + // item is 'one item only' + uint8 res = CanTakeMoreSimilarItems(pItem); + if(res != EQUIP_ERR_OK) + return res; + + // search stack for merge to + if( pProto->Stackable > 1 ) + { + bool b_found = false; + + for(int t = KEYRING_SLOT_START; t < KEYRING_SLOT_END; t++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_keys[t-KEYRING_SLOT_START] + pItem->GetCount() <= pProto->Stackable ) + { + inv_keys[t-KEYRING_SLOT_START] += pItem->GetCount(); + b_found = true; + break; + } + } + if (b_found) continue; + + for(int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; t++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_slot_items[t-INVENTORY_SLOT_ITEM_START] + pItem->GetCount() <= pProto->Stackable ) + { + inv_slot_items[t-INVENTORY_SLOT_ITEM_START] += pItem->GetCount(); + b_found = true; + break; + } + } + if (b_found) continue; + + for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++) + { + pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pBag ) + { + pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + pItem2 = GetItemByPos( t, j ); + if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_bags[t-INVENTORY_SLOT_BAG_START][j] + pItem->GetCount() <= pProto->Stackable ) + { + inv_bags[t-INVENTORY_SLOT_BAG_START][j] += pItem->GetCount(); + b_found = true; + break; + } + } + } + } + } + if (b_found) continue; + } + + // special bag case + if( pProto->BagFamily ) + { + bool b_found = false; + if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS) + { + uint32 keyringSize = GetMaxKeyringSize(); + for(uint32 t = KEYRING_SLOT_START; t < KEYRING_SLOT_START+keyringSize; ++t) + { + if( inv_keys[t-KEYRING_SLOT_START] == 0 ) + { + inv_keys[t-KEYRING_SLOT_START] = 1; + b_found = true; + break; + } + } + } + + if (b_found) continue; + + for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++) + { + pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pBag ) + { + pBagProto = pBag->GetProto(); + + // not plain container check + if( pBagProto && (pBagProto->Class != ITEM_CLASS_CONTAINER || pBagProto->SubClass != ITEM_SUBCLASS_CONTAINER) && + ItemCanGoIntoBag(pProto,pBagProto) ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + if( inv_bags[t-INVENTORY_SLOT_BAG_START][j] == 0 ) + { + inv_bags[t-INVENTORY_SLOT_BAG_START][j] = 1; + b_found = true; + break; + } + } + } + } + } + if (b_found) continue; + } + + // search free slot + bool b_found = false; + for(int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; t++) + { + if( inv_slot_items[t-INVENTORY_SLOT_ITEM_START] == 0 ) + { + inv_slot_items[t-INVENTORY_SLOT_ITEM_START] = 1; + b_found = true; + break; + } + } + if (b_found) continue; + + // search free slot in bags + for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++) + { + pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pBag ) + { + pBagProto = pBag->GetProto(); + if( pBagProto && ItemCanGoIntoBag(pProto,pBagProto)) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + if( inv_bags[t-INVENTORY_SLOT_BAG_START][j] == 0 ) + { + inv_bags[t-INVENTORY_SLOT_BAG_START][j] = 1; + b_found = true; + break; + } + } + } + } + } + + // no free slot found? + if (!b_found) + return EQUIP_ERR_INVENTORY_FULL; + } + + return EQUIP_ERR_OK; +} + +////////////////////////////////////////////////////////////////////////// +uint8 Player::CanEquipNewItem( uint8 slot, uint16 &dest, uint32 item, uint32 count, bool swap ) const +{ + dest = 0; + Item *pItem = Item::CreateItem( item, count, this ); + if( pItem ) + { + uint8 result = CanEquipItem(slot, dest, pItem, swap ); + delete pItem; + return result; + } + + return EQUIP_ERR_ITEM_NOT_FOUND; +} + +uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading ) const +{ + dest = 0; + if( pItem ) + { + sLog.outDebug( "STORAGE: CanEquipItem slot = %u, item = %u, count = %u", slot, pItem->GetEntry(), pItem->GetCount()); + ItemPrototype const *pProto = pItem->GetProto(); + if( pProto ) + { + if(pItem->IsBindedNotWith(GetGUID())) + return EQUIP_ERR_DONT_OWN_THAT_ITEM; + + // check count of items (skip for auto move for same player from bank) + uint8 res = CanTakeMoreSimilarItems(pItem); + if(res != EQUIP_ERR_OK) + return res; + + // do not allow equipping gear except weapons, offhands, projectiles, relics in + // - combat + // - in-progress arenas + if( !pProto->CanChangeEquipStateInCombat() ) + { + if( isInCombat() ) + return EQUIP_ERR_NOT_IN_COMBAT; + + if(BattleGround* bg = GetBattleGround()) + if( bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS ) + return EQUIP_ERR_NOT_DURING_ARENA_MATCH; + } + + if(isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer != 0) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err + + uint8 eslot = FindEquipSlot( pProto, slot, swap ); + if( eslot == NULL_SLOT ) + return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + + uint8 msg = CanUseItem( pItem , not_loading ); + if( msg != EQUIP_ERR_OK ) + return msg; + if( !swap && GetItemByPos( INVENTORY_SLOT_BAG_0, eslot ) ) + return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE; + + // check unique-equipped on item + if (pProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED) + { + // there is an equip limit on this item + Item* tItem = GetItemOrItemWithGemEquipped(pProto->ItemId); + if (tItem && (!swap || tItem->GetSlot() != eslot ) ) + return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE; + } + + // check unique-equipped on gems + for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) + { + uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot)); + if(!enchant_id) + continue; + SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!enchantEntry) + continue; + + ItemPrototype const* pGem = objmgr.GetItemPrototype(enchantEntry->GemID); + if(pGem && (pGem->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)) + { + Item* tItem = GetItemOrItemWithGemEquipped(enchantEntry->GemID); + if(tItem && (!swap || tItem->GetSlot() != eslot )) + return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE; + } + } + + // check unique-equipped special item classes + if (pProto->Class == ITEM_CLASS_QUIVER) + { + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if( Item* pBag = GetItemByPos( INVENTORY_SLOT_BAG_0, i ) ) + { + if( ItemPrototype const* pBagProto = pBag->GetProto() ) + { + if( pBagProto->Class==pProto->Class && pBagProto->SubClass==pProto->SubClass && + (!swap || pBag->GetSlot() != eslot ) ) + { + if(pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH) + return EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH; + else + return EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER; + } + } + } + } + } + + uint32 type = pProto->InventoryType; + + if(eslot == EQUIPMENT_SLOT_OFFHAND) + { + if( type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND ) + { + if(!CanDualWield()) + return EQUIP_ERR_CANT_DUAL_WIELD; + } + + Item *mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ); + if(mainItem) + { + if(mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON) + return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED; + } + } + + // equip two-hand weapon case (with possible unequip 2 items) + if( type == INVTYPE_2HWEAPON ) + { + if(eslot != EQUIPMENT_SLOT_MAINHAND) + return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + + // offhand item must can be stored in inventitory for offhand item and it also must be unequipped + Item *offItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND ); + ItemPosCountVec off_dest; + if( offItem && (!not_loading || + CanUnequipItem(uint16(INVENTORY_SLOT_BAG_0) << 8 | EQUIPMENT_SLOT_OFFHAND,false) != EQUIP_ERR_OK || + CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ) != EQUIP_ERR_OK ) ) + return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_INVENTORY_FULL; + } + dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot); + return EQUIP_ERR_OK; + } + } + if( !swap ) + return EQUIP_ERR_ITEM_NOT_FOUND; + else + return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED; +} + +uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const +{ + // Applied only to equipped items and bank bags + if(!IsEquipmentPos(pos) && !IsBagPos(pos)) + return EQUIP_ERR_OK; + + Item* pItem = GetItemByPos(pos); + + // Applied only to existed equipped item + if( !pItem ) + return EQUIP_ERR_OK; + + sLog.outDebug( "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount()); + + ItemPrototype const *pProto = pItem->GetProto(); + if( !pProto ) + return EQUIP_ERR_ITEM_NOT_FOUND; + + // do not allow unequipping gear except weapons, offhands, projectiles, relics in + // - combat + // - in-progress arenas + if( !pProto->CanChangeEquipStateInCombat() ) + { + if( isInCombat() ) + return EQUIP_ERR_NOT_IN_COMBAT; + + if(BattleGround* bg = GetBattleGround()) + if( bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS ) + return EQUIP_ERR_NOT_DURING_ARENA_MATCH; + } + + if(!swap && pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) + return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS; + + return EQUIP_ERR_OK; +} + +uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap, bool not_loading ) const +{ + if( !pItem ) + return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; + + uint32 count = pItem->GetCount(); + + sLog.outDebug( "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount()); + ItemPrototype const *pProto = pItem->GetProto(); + if( !pProto ) + return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; + + if( pItem->IsBindedNotWith(GetGUID()) ) + return EQUIP_ERR_DONT_OWN_THAT_ITEM; + + // check count of items (skip for auto move for same player from bank) + uint8 res = CanTakeMoreSimilarItems(pItem); + if(res != EQUIP_ERR_OK) + return res; + + // in specific slot + if( bag != NULL_BAG && slot != NULL_SLOT ) + { + if( pProto->InventoryType == INVTYPE_BAG ) + { + Bag *pBag = (Bag*)pItem; + if( pBag ) + { + if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) + { + if( !HasBankBagSlot( slot ) ) + return EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT; + if( uint8 cantuse = CanUseItem( pItem, not_loading ) != EQUIP_ERR_OK ) + return cantuse; + } + else + { + if( !pBag->IsEmpty() ) + return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG; + } + } + } + else + { + if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) + return EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT; + } + + res = _CanStoreItem_InSpecificSlot(bag,slot,dest,pProto,count,swap,pItem); + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + } + + // not specific slot or have spece for partly store only in specific slot + + // in specific bag + if( bag != NULL_BAG ) + { + if( pProto->InventoryType == INVTYPE_BAG ) + { + Bag *pBag = (Bag*)pItem; + if( pBag && !pBag->IsEmpty() ) + return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG; + } + + // search stack in bag for merge to + if( pProto->Stackable > 1 ) + { + if( bag == INVENTORY_SLOT_BAG_0 ) + { + res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + } + else + { + res = _CanStoreItem_InBag(bag,dest,pProto,count,true,false,pItem,NULL_BAG,slot); + if(res!=EQUIP_ERR_OK) + res = _CanStoreItem_InBag(bag,dest,pProto,count,true,true,pItem,NULL_BAG,slot); + + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + } + } + + // search free slot in bag + if( bag == INVENTORY_SLOT_BAG_0 ) + { + res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + } + else + { + res = _CanStoreItem_InBag(bag,dest,pProto,count,false,false,pItem,NULL_BAG,slot); + if(res!=EQUIP_ERR_OK) + res = _CanStoreItem_InBag(bag,dest,pProto,count,false,true,pItem,NULL_BAG,slot); + + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + } + } + + // not specific bag or have spece for partly store only in specific bag + + // search stack for merge to + if( pProto->Stackable > 1 ) + { + // in slots + res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + + // in special bags + if( pProto->BagFamily ) + { + for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + res = _CanStoreItem_InBag(i,dest,pProto,count,true,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + continue; + + if(count==0) + return EQUIP_ERR_OK; + } + } + + for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + res = _CanStoreItem_InBag(i,dest,pProto,count,true,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + continue; + + if(count==0) + return EQUIP_ERR_OK; + } + } + + // search free place in special bag + if( pProto->BagFamily ) + { + for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + res = _CanStoreItem_InBag(i,dest,pProto,count,false,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + continue; + + if(count==0) + return EQUIP_ERR_OK; + } + } + + // search free space + res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + return res; + + if(count==0) + return EQUIP_ERR_OK; + + for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) + { + res = _CanStoreItem_InBag(i,dest,pProto,count,false,true,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + continue; + + if(count==0) + return EQUIP_ERR_OK; + } + return EQUIP_ERR_BANK_FULL; +} + +uint8 Player::CanUseItem( Item *pItem, bool not_loading ) const +{ + if( pItem ) + { + sLog.outDebug( "STORAGE: CanUseItem item = %u", pItem->GetEntry()); + if( !isAlive() && not_loading ) + return EQUIP_ERR_YOU_ARE_DEAD; + //if( isStunned() ) + // return EQUIP_ERR_YOU_ARE_STUNNED; + ItemPrototype const *pProto = pItem->GetProto(); + if( pProto ) + { + if( pItem->IsBindedNotWith(GetGUID()) ) + return EQUIP_ERR_DONT_OWN_THAT_ITEM; + if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 ) + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + if( pItem->GetSkill() != 0 ) + { + if( GetSkillValue( pItem->GetSkill() ) == 0 ) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + } + if( pProto->RequiredSkill != 0 ) + { + if( GetSkillValue( pProto->RequiredSkill ) == 0 ) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank ) + return EQUIP_ERR_ERR_CANT_EQUIP_SKILL; + } + if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) ) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + if( pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank ) + return EQUIP_ERR_CANT_EQUIP_REPUTATION; + if( getLevel() < pProto->RequiredLevel ) + return EQUIP_ERR_CANT_EQUIP_LEVEL_I; + return EQUIP_ERR_OK; + } + } + return EQUIP_ERR_ITEM_NOT_FOUND; +} + +bool Player::CanUseItem( ItemPrototype const *pProto ) +{ + // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player + + if( pProto ) + { + if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 ) + return false; + if( pProto->RequiredSkill != 0 ) + { + if( GetSkillValue( pProto->RequiredSkill ) == 0 ) + return false; + else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank ) + return false; + } + if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) ) + return false; + if( getLevel() < pProto->RequiredLevel ) + return false; + return true; + } + return false; +} + +uint8 Player::CanUseAmmo( uint32 item ) const +{ + sLog.outDebug( "STORAGE: CanUseAmmo item = %u", item); + if( !isAlive() ) + return EQUIP_ERR_YOU_ARE_DEAD; + //if( isStunned() ) + // return EQUIP_ERR_YOU_ARE_STUNNED; + ItemPrototype const *pProto = objmgr.GetItemPrototype( item ); + if( pProto ) + { + if( pProto->InventoryType!= INVTYPE_AMMO ) + return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE; + if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 ) + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + if( pProto->RequiredSkill != 0 ) + { + if( GetSkillValue( pProto->RequiredSkill ) == 0 ) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank ) + return EQUIP_ERR_ERR_CANT_EQUIP_SKILL; + } + if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) ) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + /*if( GetReputation() < pProto->RequiredReputation ) + return EQUIP_ERR_CANT_EQUIP_REPUTATION; + */ + if( getLevel() < pProto->RequiredLevel ) + return EQUIP_ERR_CANT_EQUIP_LEVEL_I; + + // Requires No Ammo + if(GetDummyAura(46699)) + return EQUIP_ERR_BAG_FULL6; + + return EQUIP_ERR_OK; + } + return EQUIP_ERR_ITEM_NOT_FOUND; +} + +void Player::SetAmmo( uint32 item ) +{ + if(!item) + return; + + // already set + if( GetUInt32Value(PLAYER_AMMO_ID) == item ) + return; + + // check ammo + if(item) + { + uint8 msg = CanUseAmmo( item ); + if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, NULL, NULL ); + return; + } + } + + SetUInt32Value(PLAYER_AMMO_ID, item); + + _ApplyAmmoBonuses(); +} + +void Player::RemoveAmmo() +{ + SetUInt32Value(PLAYER_AMMO_ID, 0); + + m_ammoDPS = 0.0f; + + if(CanModifyStats()) + UpdateDamagePhysical(RANGED_ATTACK); +} + +// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. +Item* Player::StoreNewItem( ItemPosCountVec const& dest, uint32 item, bool update,int32 randomPropertyId ) +{ + uint32 count = 0; + for(ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr) + count += itr->count; + + Item *pItem = Item::CreateItem( item, count, this ); + if( pItem ) + { + ItemAddedQuestCheck( item, count ); + if(randomPropertyId) + pItem->SetItemRandomProperties(randomPropertyId); + pItem = StoreItem( dest, pItem, update ); + } + return pItem; +} + +Item* Player::StoreItem( ItemPosCountVec const& dest, Item* pItem, bool update ) +{ + if( !pItem ) + return NULL; + + Item* lastItem = pItem; + + for(ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ) + { + uint16 pos = itr->pos; + uint32 count = itr->count; + + ++itr; + + if(itr == dest.end()) + { + lastItem = _StoreItem(pos,pItem,count,false,update); + break; + } + + lastItem = _StoreItem(pos,pItem,count,true,update); + } + + return lastItem; +} + +// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. +Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update ) +{ + if( !pItem ) + return NULL; + + uint8 bag = pos >> 8; + uint8 slot = pos & 255; + + sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), count); + + Item *pItem2 = GetItemByPos( bag, slot ); + + if( !pItem2 ) + { + if(clone) + pItem = pItem->CloneItem(count,this); + else + pItem->SetCount(count); + + if(!pItem) + return NULL; + + if( pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || + pItem->GetProto()->Bonding == BIND_QUEST_ITEM || + pItem->GetProto()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos) ) + pItem->SetBinding( true ); + + if( bag == INVENTORY_SLOT_BAG_0 ) + { + m_items[slot] = pItem; + SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() ); + pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, GetGUID() ); + pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetGUID() ); + + pItem->SetSlot( slot ); + pItem->SetContainer( NULL ); + + if( IsInWorld() && update ) + { + pItem->AddToWorld(); + pItem->SendUpdateToPlayer( this ); + } + + pItem->SetState(ITEM_CHANGED, this); + } + else + { + Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); + if( pBag ) + { + pBag->StoreItem( slot, pItem, update ); + if( IsInWorld() && update ) + { + pItem->AddToWorld(); + pItem->SendUpdateToPlayer( this ); + } + pItem->SetState(ITEM_CHANGED, this); + pBag->SetState(ITEM_CHANGED, this); + } + } + + AddEnchantmentDurations(pItem); + AddItemDurations(pItem); + + return pItem; + } + else + { + if( pItem2->GetProto()->Bonding == BIND_WHEN_PICKED_UP || + pItem2->GetProto()->Bonding == BIND_QUEST_ITEM || + pItem2->GetProto()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos) ) + pItem2->SetBinding( true ); + + pItem2->SetCount( pItem2->GetCount() + count ); + if( IsInWorld() && update ) + pItem2->SendUpdateToPlayer( this ); + + if(!clone) + { + // delete item (it not in any slot currently) + if( IsInWorld() && update ) + { + pItem->RemoveFromWorld(); + pItem->DestroyForPlayer( this ); + } + + RemoveEnchantmentDurations(pItem); + RemoveItemDurations(pItem); + + pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor + pItem->SetState(ITEM_REMOVED, this); + } + // AddItemDurations(pItem2); - pItem2 already have duration listed for player + AddEnchantmentDurations(pItem2); + + pItem2->SetState(ITEM_CHANGED, this); + + return pItem2; + } +} + +Item* Player::EquipNewItem( uint16 pos, uint32 item, uint32 count, bool update ) +{ + Item *pItem = Item::CreateItem( item, count, this ); + if( pItem ) + { + ItemAddedQuestCheck( item, count ); + Item * retItem = EquipItem( pos, pItem, update ); + + return retItem; + } + return NULL; +} + +Item* Player::EquipItem( uint16 pos, Item *pItem, bool update ) +{ + if( pItem ) + { + AddEnchantmentDurations(pItem); + AddItemDurations(pItem); + + uint8 bag = pos >> 8; + uint8 slot = pos & 255; + + Item *pItem2 = GetItemByPos( bag, slot ); + + if( !pItem2 ) + { + VisualizeItem( slot, pItem); + + if(isAlive()) + { + ItemPrototype const *pProto = pItem->GetProto(); + + // item set bonuses applied only at equip and removed at unequip, and still active for broken items + if(pProto && pProto->ItemSet) + AddItemsSetItem(this,pItem); + + _ApplyItemMods(pItem, slot, true); + + if(pProto && isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer == 0) + { + m_weaponChangeTimer = DEFAULT_SWITCH_WEAPON; + if (getClass() == CLASS_ROGUE) + m_weaponChangeTimer = ROGUE_SWITCH_WEAPON; + } + } + + if( IsInWorld() && update ) + { + pItem->AddToWorld(); + pItem->SendUpdateToPlayer( this ); + } + + ApplyEquipCooldown(pItem); + + if( slot == EQUIPMENT_SLOT_MAINHAND ) + UpdateExpertise(BASE_ATTACK); + else if( slot == EQUIPMENT_SLOT_OFFHAND ) + UpdateExpertise(OFF_ATTACK); + } + else + { + pItem2->SetCount( pItem2->GetCount() + pItem->GetCount() ); + if( IsInWorld() && update ) + pItem2->SendUpdateToPlayer( this ); + + // delete item (it not in any slot currently) + //pItem->DeleteFromDB(); + if( IsInWorld() && update ) + { + pItem->RemoveFromWorld(); + pItem->DestroyForPlayer( this ); + } + + RemoveEnchantmentDurations(pItem); + RemoveItemDurations(pItem); + + pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor + pItem->SetState(ITEM_REMOVED, this); + pItem2->SetState(ITEM_CHANGED, this); + + ApplyEquipCooldown(pItem2); + + return pItem2; + } + } + + return pItem; +} + +void Player::QuickEquipItem( uint16 pos, Item *pItem) +{ + if( pItem ) + { + AddEnchantmentDurations(pItem); + AddItemDurations(pItem); + + uint8 slot = pos & 255; + VisualizeItem( slot, pItem); + + if( IsInWorld() ) + { + pItem->AddToWorld(); + pItem->SendUpdateToPlayer( this ); + } + } +} + +void Player::SetVisibleItemSlot(uint8 slot, Item *pItem) +{ + // PLAYER_VISIBLE_ITEM_i_CREATOR // Size: 2 + // PLAYER_VISIBLE_ITEM_i_0 // Size: 12 + // entry // Size: 1 + // inspected enchantments // Size: 6 + // ? // Size: 5 + // PLAYER_VISIBLE_ITEM_i_PROPERTIES // Size: 1 (property,suffix factor) + // PLAYER_VISIBLE_ITEM_i_PAD // Size: 1 + // // = 16 + + if(pItem) + { + SetUInt64Value(PLAYER_VISIBLE_ITEM_1_CREATOR + (slot * MAX_VISIBLE_ITEM_OFFSET), pItem->GetUInt64Value(ITEM_FIELD_CREATOR)); + + int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * MAX_VISIBLE_ITEM_OFFSET); + SetUInt32Value(VisibleBase + 0, pItem->GetEntry()); + + for(int i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i) + SetUInt32Value(VisibleBase + 1 + i, pItem->GetEnchantmentId(EnchantmentSlot(i))); + + // Use SetInt16Value to prevent set high part to FFFF for negative value + SetInt16Value( PLAYER_VISIBLE_ITEM_1_PROPERTIES + (slot * MAX_VISIBLE_ITEM_OFFSET), 0, pItem->GetItemRandomPropertyId()); + SetUInt32Value(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 1 + (slot * MAX_VISIBLE_ITEM_OFFSET), pItem->GetItemSuffixFactor()); + } + else + { + SetUInt64Value(PLAYER_VISIBLE_ITEM_1_CREATOR + (slot * MAX_VISIBLE_ITEM_OFFSET), 0); + + int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * MAX_VISIBLE_ITEM_OFFSET); + SetUInt32Value(VisibleBase + 0, 0); + + for(int i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i) + SetUInt32Value(VisibleBase + 1 + i, 0); + + SetUInt32Value(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 0 + (slot * MAX_VISIBLE_ITEM_OFFSET), 0); + SetUInt32Value(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 1 + (slot * MAX_VISIBLE_ITEM_OFFSET), 0); + } +} + +void Player::VisualizeItem( uint8 slot, Item *pItem) +{ + if(!pItem) + return; + + // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) + if( pItem->GetProto()->Bonding == BIND_WHEN_EQUIPED || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM ) + pItem->SetBinding( true ); + + sLog.outDebug( "STORAGE: EquipItem slot = %u, item = %u", slot, pItem->GetEntry()); + + m_items[slot] = pItem; + SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() ); + pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, GetGUID() ); + pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetGUID() ); + pItem->SetSlot( slot ); + pItem->SetContainer( NULL ); + + if( slot < EQUIPMENT_SLOT_END ) + SetVisibleItemSlot(slot,pItem); + + pItem->SetState(ITEM_CHANGED, this); +} + +void Player::RemoveItem( uint8 bag, uint8 slot, bool update ) +{ + // note: removeitem does not actually change the item + // it only takes the item out of storage temporarily + // note2: if removeitem is to be used for delinking + // the item must be removed from the player's updatequeue + + Item *pItem = GetItemByPos( bag, slot ); + if( pItem ) + { + sLog.outDebug( "STORAGE: RemoveItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry()); + + RemoveEnchantmentDurations(pItem); + RemoveItemDurations(pItem); + + if( bag == INVENTORY_SLOT_BAG_0 ) + { + if ( slot < INVENTORY_SLOT_BAG_END ) + { + ItemPrototype const *pProto = pItem->GetProto(); + // item set bonuses applied only at equip and removed at unequip, and still active for broken items + + if(pProto && pProto->ItemSet) + RemoveItemsSetItem(this,pProto); + + _ApplyItemMods(pItem, slot, false); + + // remove item dependent auras and casts (only weapon and armor slots) + if(slot < EQUIPMENT_SLOT_END) + RemoveItemDependentAurasAndCasts(pItem); + + // remove held enchantments + if ( slot == EQUIPMENT_SLOT_MAINHAND ) + { + if (pItem->GetItemSuffixFactor()) + { + pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_3); + pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_4); + } + else + { + pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_0); + pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_1); + } + } + } + + m_items[slot] = NULL; + SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0); + + if ( slot < EQUIPMENT_SLOT_END ) + SetVisibleItemSlot(slot,NULL); + } + else + { + Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); + if( pBag ) + pBag->RemoveItem(slot, update); + } + pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, 0 ); + // pItem->SetUInt64Value( ITEM_FIELD_OWNER, 0 ); not clear owner at remove (it will be set at store). This used in mail and auction code + pItem->SetSlot( NULL_SLOT ); + if( IsInWorld() && update ) + pItem->SendUpdateToPlayer( this ); + + if( slot == EQUIPMENT_SLOT_MAINHAND ) + UpdateExpertise(BASE_ATTACK); + else if( slot == EQUIPMENT_SLOT_OFFHAND ) + UpdateExpertise(OFF_ATTACK); + } +} + +// Common operation need to remove item from inventory without delete in trade, auction, guild bank, mail.... +void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update) +{ + if(Item* it = GetItemByPos(bag,slot)) + { + ItemRemovedQuestCheck(it->GetEntry(),it->GetCount()); + RemoveItem( bag,slot,update); + it->RemoveFromUpdateQueueOf(this); + if(it->IsInWorld()) + { + it->RemoveFromWorld(); + it->DestroyForPlayer( this ); + } + } +} + +// Common operation need to add item from inventory without delete in trade, guild bank, mail.... +void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB) +{ + // update quest counters + ItemAddedQuestCheck(pItem->GetEntry(),pItem->GetCount()); + + // store item + Item* pLastItem = StoreItem( dest, pItem, update); + + // only set if not merged to existed stack (pItem can be deleted already but we can compare pointers any way) + if(pLastItem==pItem) + { + // update owner for last item (this can be original item with wrong owner + if(pLastItem->GetOwnerGUID() != GetGUID()) + pLastItem->SetOwnerGUID(GetGUID()); + + // if this original item then it need create record in inventory + // in case trade we laready have item in other player inventory + pLastItem->SetState(in_characterInventoryDB ? ITEM_CHANGED : ITEM_NEW, this); + } +} + +void Player::DestroyItem( uint8 bag, uint8 slot, bool update ) +{ + Item *pItem = GetItemByPos( bag, slot ); + if( pItem ) + { + sLog.outDebug( "STORAGE: DestroyItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry()); + + // start from destroy contained items (only equipped bag can have its) + if (pItem->IsBag() && pItem->IsEquipped()) // this also prevent infinity loop if empty bag stored in bag==slot + { + for (int i = 0; i < MAX_BAG_SIZE; i++) + DestroyItem(slot,i,update); + } + + if(pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) + CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); + + ItemPrototype const *pProto = pItem->GetProto(); + + RemoveEnchantmentDurations(pItem); + RemoveItemDurations(pItem); + + ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount() ); + + if( bag == INVENTORY_SLOT_BAG_0 ) + { + + SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0); + + // equipment and equipped bags can have applied bonuses + if ( slot < INVENTORY_SLOT_BAG_END ) + { + ItemPrototype const *pProto = pItem->GetProto(); + + // item set bonuses applied only at equip and removed at unequip, and still active for broken items + if(pProto && pProto->ItemSet) + RemoveItemsSetItem(this,pProto); + + _ApplyItemMods(pItem, slot, false); + } + + if ( slot < EQUIPMENT_SLOT_END ) + { + // remove item dependent auras and casts (only weapon and armor slots) + RemoveItemDependentAurasAndCasts(pItem); + + // equipment visual show + SetVisibleItemSlot(slot,NULL); + } + + m_items[slot] = NULL; + } + else if(Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag )) + pBag->RemoveItem(slot, update); + + if( IsInWorld() && update ) + { + pItem->RemoveFromWorld(); + pItem->DestroyForPlayer(this); + } + + //pItem->SetOwnerGUID(0); + pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, 0 ); + pItem->SetSlot( NULL_SLOT ); + pItem->SetState(ITEM_REMOVED, this); + } +} + +void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check) +{ + sLog.outDebug( "STORAGE: DestroyItemCount item = %u, count = %u", item, count); + Item *pItem; + ItemPrototype const *pProto; + uint32 remcount = 0; + + // in inventory + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + if( pItem->GetCount() + remcount <= count ) + { + // all items in inventory can unequipped + remcount += pItem->GetCount(); + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + + if(remcount >=count) + return; + } + else + { + pProto = pItem->GetProto(); + ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); + pItem->SetCount( pItem->GetCount() - count + remcount ); + if( IsInWorld() & update ) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); + return; + } + } + } + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + if( pItem->GetCount() + remcount <= count ) + { + // all keys can be unequipped + remcount += pItem->GetCount(); + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + + if(remcount >=count) + return; + } + else + { + pProto = pItem->GetProto(); + ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); + pItem->SetCount( pItem->GetCount() - count + remcount ); + if( IsInWorld() & update ) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); + return; + } + } + } + + // in inventory bags + Bag *pBag; + ItemPrototype const *pBagProto; + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + pItem = pBag->GetItemByPos(j); + if( pItem && pItem->GetEntry() == item ) + { + // all items in bags can be unequipped + if( pItem->GetCount() + remcount <= count ) + { + remcount += pItem->GetCount(); + DestroyItem( i, j, update ); + + if(remcount >=count) + return; + } + else + { + pProto = pItem->GetProto(); + ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); + pItem->SetCount( pItem->GetCount() - count + remcount ); + if( IsInWorld() && update ) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); + return; + } + } + } + } + } + } + + // in equipment and bag list + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) + { + pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) + { + if( pItem->GetCount() + remcount <= count ) + { + if(!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i,false) == EQUIP_ERR_OK ) + { + remcount += pItem->GetCount(); + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + + if(remcount >=count) + return; + } + } + else + { + pProto = pItem->GetProto(); + ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount ); + pItem->SetCount( pItem->GetCount() - count + remcount ); + if( IsInWorld() & update ) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); + return; + } + } + } +} + +void Player::DestroyZoneLimitedItem( bool update, uint32 new_zone ) +{ + sLog.outDebug( "STORAGE: DestroyZoneLimitedItem in map %u and area %u", GetMapId(), new_zone ); + + // in inventory + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + } + for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + { + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + } + + // in inventory bags + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + ItemPrototype const *pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + Item* pItem = pBag->GetItemByPos(j); + if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) + DestroyItem( i, j, update); + } + } + } + } + + // in equipment and bag list + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) + { + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + } +} + +void Player::DestroyConjuredItems( bool update ) +{ + // used when entering arena + // distroys all conjured items + sLog.outDebug( "STORAGE: DestroyConjuredItems" ); + + // in inventory + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetProto() && + (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && + (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + } + + // in inventory bags + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + ItemPrototype const *pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + Item* pItem = pBag->GetItemByPos(j); + if( pItem && pItem->GetProto() && + (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && + (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) + DestroyItem( i, j, update); + } + } + } + } + + // in equipment and bag list + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++) + { + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetProto() && + (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && + (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) ) + DestroyItem( INVENTORY_SLOT_BAG_0, i, update); + } +} + +void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update ) +{ + if(!pItem) + return; + + sLog.outDebug( "STORAGE: DestroyItemCount item (GUID: %u, Entry: %u) count = %u", pItem->GetGUIDLow(),pItem->GetEntry(), count); + + if( pItem->GetCount() <= count ) + { + count-= pItem->GetCount(); + + DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), update); + } + else + { + ItemRemovedQuestCheck( pItem->GetEntry(), count); + pItem->SetCount( pItem->GetCount() - count ); + count = 0; + if( IsInWorld() & update ) + pItem->SendUpdateToPlayer( this ); + pItem->SetState(ITEM_CHANGED, this); + } +} + +void Player::SplitItem( uint16 src, uint16 dst, uint32 count ) +{ + uint8 srcbag = src >> 8; + uint8 srcslot = src & 255; + + uint8 dstbag = dst >> 8; + uint8 dstslot = dst & 255; + + Item *pSrcItem = GetItemByPos( srcbag, srcslot ); + if( !pSrcItem ) + { + SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL ); + return; + } + + // not let split all items (can be only at cheating) + if(pSrcItem->GetCount() == count) + { + SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL ); + return; + } + + // not let split more existed items (can be only at cheating) + if(pSrcItem->GetCount() < count) + { + SendEquipError( EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, NULL ); + return; + } + + if(pSrcItem->m_lootGenerated) // prevent split looting item (item + { + //best error message found for attempting to split while looting + SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL ); + return; + } + + sLog.outDebug( "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count); + Item *pNewItem = pSrcItem->CloneItem( count, this ); + if( !pNewItem ) + { + SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL ); + return; + } + + if( IsInventoryPos( dst ) ) + { + // change item amount before check (for unique max count check) + pSrcItem->SetCount( pSrcItem->GetCount() - count ); + + ItemPosCountVec dest; + uint8 msg = CanStoreItem( dstbag, dstslot, dest, pNewItem, false ); + if( msg != EQUIP_ERR_OK ) + { + delete pNewItem; + pSrcItem->SetCount( pSrcItem->GetCount() + count ); + SendEquipError( msg, pSrcItem, NULL ); + return; + } + + if( IsInWorld() ) + pSrcItem->SendUpdateToPlayer( this ); + pSrcItem->SetState(ITEM_CHANGED, this); + StoreItem( dest, pNewItem, true); + } + else if( IsBankPos ( dst ) ) + { + // change item amount before check (for unique max count check) + pSrcItem->SetCount( pSrcItem->GetCount() - count ); + + ItemPosCountVec dest; + uint8 msg = CanBankItem( dstbag, dstslot, dest, pNewItem, false ); + if( msg != EQUIP_ERR_OK ) + { + delete pNewItem; + pSrcItem->SetCount( pSrcItem->GetCount() + count ); + SendEquipError( msg, pSrcItem, NULL ); + return; + } + + if( IsInWorld() ) + pSrcItem->SendUpdateToPlayer( this ); + pSrcItem->SetState(ITEM_CHANGED, this); + BankItem( dest, pNewItem, true); + } + else if( IsEquipmentPos ( dst ) ) + { + // change item amount before check (for unique max count check), provide space for splitted items + pSrcItem->SetCount( pSrcItem->GetCount() - count ); + + uint16 dest; + uint8 msg = CanEquipItem( dstslot, dest, pNewItem, false ); + if( msg != EQUIP_ERR_OK ) + { + delete pNewItem; + pSrcItem->SetCount( pSrcItem->GetCount() + count ); + SendEquipError( msg, pSrcItem, NULL ); + return; + } + + if( IsInWorld() ) + pSrcItem->SendUpdateToPlayer( this ); + pSrcItem->SetState(ITEM_CHANGED, this); + EquipItem( dest, pNewItem, true); + AutoUnequipOffhandIfNeed(); + } +} + +void Player::SwapItem( uint16 src, uint16 dst ) +{ + uint8 srcbag = src >> 8; + uint8 srcslot = src & 255; + + uint8 dstbag = dst >> 8; + uint8 dstslot = dst & 255; + + Item *pSrcItem = GetItemByPos( srcbag, srcslot ); + Item *pDstItem = GetItemByPos( dstbag, dstslot ); + + if( !pSrcItem ) + return; + + sLog.outDebug( "STORAGE: SwapItem bag = %u, slot = %u, item = %u", dstbag, dstslot, pSrcItem->GetEntry()); + + if(!isAlive() ) + { + SendEquipError( EQUIP_ERR_YOU_ARE_DEAD, pSrcItem, pDstItem ); + return; + } + + if(pSrcItem->m_lootGenerated) // prevent swap looting item + { + //best error message found for attempting to swap while looting + SendEquipError( EQUIP_ERR_CANT_DO_RIGHT_NOW, pSrcItem, NULL ); + return; + } + + // check unequip potability for equipped items and bank bags + if(IsEquipmentPos ( src ) || IsBagPos ( src )) + { + // bags can be swapped with empty bag slots + uint8 msg = CanUnequipItem( src, !IsBagPos ( src ) || IsBagPos ( dst )); + if(msg != EQUIP_ERR_OK) + { + SendEquipError( msg, pSrcItem, pDstItem ); + return; + } + } + + // prevent put equipped/bank bag in self + if( IsBagPos ( src ) && srcslot == dstbag) + { + SendEquipError( EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem ); + return; + } + + if( !pDstItem ) + { + if( IsInventoryPos( dst ) ) + { + ItemPosCountVec dest; + uint8 msg = CanStoreItem( dstbag, dstslot, dest, pSrcItem, false ); + if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, pSrcItem, NULL ); + return; + } + + RemoveItem(srcbag, srcslot, true); + StoreItem( dest, pSrcItem, true); + } + else if( IsBankPos ( dst ) ) + { + ItemPosCountVec dest; + uint8 msg = CanBankItem( dstbag, dstslot, dest, pSrcItem, false); + if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, pSrcItem, NULL ); + return; + } + + RemoveItem(srcbag, srcslot, true); + BankItem( dest, pSrcItem, true); + } + else if( IsEquipmentPos ( dst ) ) + { + uint16 dest; + uint8 msg = CanEquipItem( dstslot, dest, pSrcItem, false ); + if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, pSrcItem, NULL ); + return; + } + + RemoveItem(srcbag, srcslot, true); + EquipItem( dest, pSrcItem, true); + AutoUnequipOffhandIfNeed(); + } + } + else // if (!pDstItem) + { + if(pDstItem->m_lootGenerated) // prevent swap looting item + { + //best error message found for attempting to swap while looting + SendEquipError( EQUIP_ERR_CANT_DO_RIGHT_NOW, pDstItem, NULL ); + return; + } + + // check unequip potability for equipped items and bank bags + if(IsEquipmentPos ( dst ) || IsBagPos ( dst )) + { + // bags can be swapped with empty bag slots + uint8 msg = CanUnequipItem( dst, !IsBagPos ( dst ) || IsBagPos ( src ) ); + if(msg != EQUIP_ERR_OK) + { + SendEquipError( msg, pSrcItem, pDstItem ); + return; + } + } + + // attempt merge to / fill target item + { + uint8 msg; + ItemPosCountVec sDest; + uint16 eDest; + if( IsInventoryPos( dst ) ) + msg = CanStoreItem( dstbag, dstslot, sDest, pSrcItem, false ); + else if( IsBankPos ( dst ) ) + msg = CanBankItem( dstbag, dstslot, sDest, pSrcItem, false ); + else if( IsEquipmentPos ( dst ) ) + msg = CanEquipItem( dstslot, eDest, pSrcItem, false ); + else + return; + + // can be merge/fill + if(msg == EQUIP_ERR_OK) + { + if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable ) + { + RemoveItem(srcbag, srcslot, true); + + if( IsInventoryPos( dst ) ) + StoreItem( sDest, pSrcItem, true); + else if( IsBankPos ( dst ) ) + BankItem( sDest, pSrcItem, true); + else if( IsEquipmentPos ( dst ) ) + { + EquipItem( eDest, pSrcItem, true); + AutoUnequipOffhandIfNeed(); + } + } + else + { + pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable ); + pDstItem->SetCount( pSrcItem->GetProto()->Stackable ); + pSrcItem->SetState(ITEM_CHANGED, this); + pDstItem->SetState(ITEM_CHANGED, this); + if( IsInWorld() ) + { + pSrcItem->SendUpdateToPlayer( this ); + pDstItem->SendUpdateToPlayer( this ); + } + } + return; + } + } + + // impossible merge/fill, do real swap + uint8 msg; + + // check src->dest move possibility + ItemPosCountVec sDest; + uint16 eDest; + if( IsInventoryPos( dst ) ) + msg = CanStoreItem( dstbag, dstslot, sDest, pSrcItem, true ); + else if( IsBankPos( dst ) ) + msg = CanBankItem( dstbag, dstslot, sDest, pSrcItem, true ); + else if( IsEquipmentPos( dst ) ) + { + msg = CanEquipItem( dstslot, eDest, pSrcItem, true ); + if( msg == EQUIP_ERR_OK ) + msg = CanUnequipItem( eDest, true ); + } + + if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, pSrcItem, pDstItem ); + return; + } + + // check dest->src move possibility + ItemPosCountVec sDest2; + uint16 eDest2; + if( IsInventoryPos( src ) ) + msg = CanStoreItem( srcbag, srcslot, sDest2, pDstItem, true ); + else if( IsBankPos( src ) ) + msg = CanBankItem( srcbag, srcslot, sDest2, pDstItem, true ); + else if( IsEquipmentPos( src ) ) + { + msg = CanEquipItem( srcslot, eDest2, pDstItem, true); + if( msg == EQUIP_ERR_OK ) + msg = CanUnequipItem( eDest2, true); + } + + if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, pDstItem, pSrcItem ); + return; + } + + // now do moves, remove... + RemoveItem(dstbag, dstslot, false); + RemoveItem(srcbag, srcslot, false); + + // add to dest + if( IsInventoryPos( dst ) ) + StoreItem(sDest, pSrcItem, true); + else if( IsBankPos( dst ) ) + BankItem(sDest, pSrcItem, true); + else if( IsEquipmentPos( dst ) ) + EquipItem(eDest, pSrcItem, true); + + // add to src + if( IsInventoryPos( src ) ) + StoreItem(sDest2, pDstItem, true); + else if( IsBankPos( src ) ) + BankItem(sDest2, pDstItem, true); + else if( IsEquipmentPos( src ) ) + EquipItem(eDest2, pDstItem, true); + + AutoUnequipOffhandIfNeed(); + } +} + +void Player::AddItemToBuyBackSlot( Item *pItem ) +{ + if( pItem ) + { + uint32 slot = m_currentBuybackSlot; + // if current back slot non-empty search oldest or free + if(m_items[slot]) + { + uint32 oldest_time = GetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 ); + uint32 oldest_slot = BUYBACK_SLOT_START; + + for(uint32 i = BUYBACK_SLOT_START+1; i < BUYBACK_SLOT_END; ++i ) + { + // found empty + if(!m_items[i]) + { + slot = i; + break; + } + + uint32 i_time = GetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + i - BUYBACK_SLOT_START); + + if(oldest_time > i_time) + { + oldest_time = i_time; + oldest_slot = i; + } + } + + // find oldest + slot = oldest_slot; + } + + RemoveItemFromBuyBackSlot( slot, true ); + sLog.outDebug( "STORAGE: AddItemToBuyBackSlot item = %u, slot = %u", pItem->GetEntry(), slot); + + m_items[slot] = pItem; + time_t base = time(NULL); + uint32 etime = uint32(base - m_logintime + (30 * 3600)); + uint32 eslot = slot - BUYBACK_SLOT_START; + + SetUInt64Value( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + eslot * 2, pItem->GetGUID() ); + ItemPrototype const *pProto = pItem->GetProto(); + if( pProto ) + SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, pProto->SellPrice * pItem->GetCount() ); + else + SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0 ); + SetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, (uint32)etime ); + + // move to next (for non filled list is move most optimized choice) + if(m_currentBuybackSlot < BUYBACK_SLOT_END-1) + ++m_currentBuybackSlot; + } +} + +Item* Player::GetItemFromBuyBackSlot( uint32 slot ) +{ + sLog.outDebug( "STORAGE: GetItemFromBuyBackSlot slot = %u", slot); + if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END ) + return m_items[slot]; + return NULL; +} + +void Player::RemoveItemFromBuyBackSlot( uint32 slot, bool del ) +{ + sLog.outDebug( "STORAGE: RemoveItemFromBuyBackSlot slot = %u", slot); + if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END ) + { + Item *pItem = m_items[slot]; + if( pItem ) + { + pItem->RemoveFromWorld(); + if(del) pItem->SetState(ITEM_REMOVED, this); + } + + m_items[slot] = NULL; + + uint32 eslot = slot - BUYBACK_SLOT_START; + SetUInt64Value( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + eslot * 2, 0 ); + SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0 ); + SetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0 ); + + // if current backslot is filled set to now free slot + if(m_items[m_currentBuybackSlot]) + m_currentBuybackSlot = slot; + } +} + +void Player::SendEquipError( uint8 msg, Item* pItem, Item *pItem2 ) +{ + sLog.outDebug( "WORLD: Sent SMSG_INVENTORY_CHANGE_FAILURE (%u)",msg); + WorldPacket data( SMSG_INVENTORY_CHANGE_FAILURE, (msg == EQUIP_ERR_CANT_EQUIP_LEVEL_I ? 22 : 18) ); + data << uint8(msg); + + if(msg) + { + data << uint64(pItem ? pItem->GetGUID() : 0); + data << uint64(pItem2 ? pItem2->GetGUID() : 0); + data << uint8(0); // not 0 there... + + if(msg == EQUIP_ERR_CANT_EQUIP_LEVEL_I) + { + uint32 level = 0; + + if(pItem) + if(ItemPrototype const* proto = pItem->GetProto()) + level = proto->RequiredLevel; + + data << uint32(level); // new 2.4.0 + } + } + GetSession()->SendPacket(&data); +} + +void Player::SendBuyError( uint8 msg, Creature* pCreature, uint32 item, uint32 param ) +{ + sLog.outDebug( "WORLD: Sent SMSG_BUY_FAILED" ); + WorldPacket data( SMSG_BUY_FAILED, (8+4+4+1) ); + data << uint64(pCreature ? pCreature->GetGUID() : 0); + data << uint32(item); + if( param > 0 ) + data << uint32(param); + data << uint8(msg); + GetSession()->SendPacket(&data); +} + +void Player::SendSellError( uint8 msg, Creature* pCreature, uint64 guid, uint32 param ) +{ + sLog.outDebug( "WORLD: Sent SMSG_SELL_ITEM" ); + WorldPacket data( SMSG_SELL_ITEM,(8+8+(param?4:0)+1)); // last check 2.0.10 + data << uint64(pCreature ? pCreature->GetGUID() : 0); + data << uint64(guid); + if( param > 0 ) + data << uint32(param); + data << uint8(msg); + GetSession()->SendPacket(&data); +} + +void Player::ClearTrade() +{ + tradeGold = 0; + acceptTrade = false; + for(int i = 0; i < TRADE_SLOT_COUNT; i++) + tradeItems[i] = NULL_SLOT; +} + +void Player::TradeCancel(bool sendback) +{ + if(pTrader) + { + // send yellow "Trade cancelled" message to both traders + WorldSession* ws; + ws = GetSession(); + if(sendback) + ws->SendCancelTrade(); + ws = pTrader->GetSession(); + if(!ws->PlayerLogout()) + ws->SendCancelTrade(); + + // cleanup + ClearTrade(); + pTrader->ClearTrade(); + // prevent loss of reference + pTrader->pTrader = NULL; + pTrader = NULL; + } +} + +void Player::UpdateItemDuration(uint32 time, bool realtimeonly) +{ + if(m_itemDuration.empty()) + return; + + sLog.outDebug("Player::UpdateItemDuration(%u,%u)", time,realtimeonly); + + for(ItemDurationList::iterator itr = m_itemDuration.begin();itr != m_itemDuration.end(); ) + { + Item* item = *itr; + ++itr; // current element can be erased in UpdateDuration + + if (realtimeonly && item->GetProto()->Duration < 0 || !realtimeonly) + item->UpdateDuration(this,time); + } +} + +void Player::UpdateEnchantTime(uint32 time) +{ + for(EnchantDurationList::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next) + { + assert(itr->item); + next=itr; + if(!itr->item->GetEnchantmentId(itr->slot)) + { + next = m_enchantDuration.erase(itr); + } + else if(itr->leftduration <= time) + { + ApplyEnchantment(itr->item,itr->slot,false,false); + itr->item->ClearEnchantment(itr->slot); + next = m_enchantDuration.erase(itr); + } + else if(itr->leftduration > time) + { + itr->leftduration -= time; + ++next; + } + } +} + +void Player::AddEnchantmentDurations(Item *item) +{ + for(int x=0;xGetEnchantmentId(EnchantmentSlot(x))) + continue; + + uint32 duration = item->GetEnchantmentDuration(EnchantmentSlot(x)); + if( duration > 0 ) + AddEnchantmentDuration(item,EnchantmentSlot(x),duration); + } +} + +void Player::RemoveEnchantmentDurations(Item *item) +{ + for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();) + { + if(itr->item == item) + { + // save duration in item + item->SetEnchantmentDuration(EnchantmentSlot(itr->slot),itr->leftduration); + itr = m_enchantDuration.erase(itr); + } + else + ++itr; + } +} + + +void Player::RemoveAllEnchantments(EnchantmentSlot slot) +{ + // remove enchantments from equipped items first to clean up the m_enchantDuration list + for(EnchantDurationList::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next) + { + next = itr; + if(itr->slot==slot) + { + if(itr->item && itr->item->GetEnchantmentId(slot)) + { + // remove from stats + ApplyEnchantment(itr->item,slot,false,false); + // remove visual + itr->item->ClearEnchantment(slot); + } + // remove from update list + next = m_enchantDuration.erase(itr); + } + else + ++next; + } + + // remove enchants from inventory items + // NOTE: no need to remove these from stats, since these aren't equipped + // in inventory + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + { + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEnchantmentId(slot) ) + pItem->ClearEnchantment(slot); + } + + // in inventory bags + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pBag ) + { + ItemPrototype const *pBagProto = pBag->GetProto(); + if( pBagProto ) + { + for(uint32 j = 0; j < pBagProto->ContainerSlots; j++) + { + Item* pItem = pBag->GetItemByPos(j); + if( pItem && pItem->GetEnchantmentId(slot) ) + pItem->ClearEnchantment(slot); + } + } + } + } +} + +// duration == 0 will remove item enchant +void Player::AddEnchantmentDuration(Item *item,EnchantmentSlot slot,uint32 duration) +{ + if(!item) + return; + + if(slot >= MAX_ENCHANTMENT_SLOT) + return; + + for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();++itr) + { + if(itr->item == item && itr->slot == slot) + { + itr->item->SetEnchantmentDuration(itr->slot,itr->leftduration); + m_enchantDuration.erase(itr); + break; + } + } + if(item && duration > 0 ) + { + GetSession()->SendItemEnchantTimeUpdate(GetGUID(), item->GetGUID(),slot,uint32(duration/1000)); + m_enchantDuration.push_back(EnchantDuration(item,slot,duration)); + } +} + +void Player::ApplyEnchantment(Item *item,bool apply) +{ + for(uint32 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) + ApplyEnchantment(item, EnchantmentSlot(slot), apply); +} + +void Player::ApplyEnchantment(Item *item,EnchantmentSlot slot,bool apply, bool apply_dur, bool ignore_condition) +{ + if(!item) + return; + + if(!item->IsEquipped()) + return; + + if(slot >= MAX_ENCHANTMENT_SLOT) + return; + + uint32 enchant_id = item->GetEnchantmentId(slot); + if(!enchant_id) + return; + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) + return; + + if(!ignore_condition && pEnchant->EnchantmentCondition && !((Player*)this)->EnchantmentFitsRequirements(pEnchant->EnchantmentCondition, -1)) + return; + + for (int s=0; s<3; s++) + { + uint32 enchant_display_type = pEnchant->type[s]; + uint32 enchant_amount = pEnchant->amount[s]; + uint32 enchant_spell_id = pEnchant->spellid[s]; + + switch(enchant_display_type) + { + case ITEM_ENCHANTMENT_TYPE_NONE: + break; + case ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL: + // processed in Player::CastItemCombatSpell + break; + case ITEM_ENCHANTMENT_TYPE_DAMAGE: + if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) + HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(enchant_amount), apply); + else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND) + HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(enchant_amount), apply); + else if (item->GetSlot() == EQUIPMENT_SLOT_RANGED) + HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(enchant_amount), apply); + break; + case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL: + if(enchant_spell_id) + { + if(apply) + { + int32 basepoints = int32(enchant_amount); + // Random Property Exist - try found basepoints for spell (basepoints depencs from item suffix factor) + if (item->GetItemRandomPropertyId() !=0 && !enchant_amount) + { + ItemRandomSuffixEntry const *item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); + if (item_rand) + { + // Search enchant_amount + for (int k=0; k<3; k++) + { + if(item_rand->enchant_id[k] == enchant_id) + { + basepoints = int32((item_rand->prefix[k]*item->GetItemSuffixFactor()) / 10000 ); + break; + } + } + } + } + // Cast custom spell vs all equal basepoints getted from enchant_amount + if (basepoints) + CastCustomSpell(this,enchant_spell_id,&basepoints,&basepoints,&basepoints,true,item); + else + CastSpell(this,enchant_spell_id,true,item); + } + else + RemoveAurasDueToItemSpell(item,enchant_spell_id); + } + break; + case ITEM_ENCHANTMENT_TYPE_RESISTANCE: + if (!enchant_amount) + { + ItemRandomSuffixEntry const *item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); + if(item_rand) + { + for (int k=0; k<3; k++) + { + if(item_rand->enchant_id[k] == enchant_id) + { + enchant_amount = uint32((item_rand->prefix[k]*item->GetItemSuffixFactor()) / 10000 ); + break; + } + } + } + } + + HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply); + break; + case ITEM_ENCHANTMENT_TYPE_STAT: + { + if (!enchant_amount) + { + ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); + if(item_rand_suffix) + { + for (int k=0; k<3; k++) + { + if(item_rand_suffix->enchant_id[k] == enchant_id) + { + enchant_amount = uint32((item_rand_suffix->prefix[k]*item->GetItemSuffixFactor()) / 10000 ); + break; + } + } + } + } + + sLog.outDebug("Adding %u to stat nb %u",enchant_amount,enchant_spell_id); + switch (enchant_spell_id) + { + case ITEM_MOD_AGILITY: + sLog.outDebug("+ %u AGILITY",enchant_amount); + HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply); + ApplyStatBuffMod(STAT_AGILITY, enchant_amount, apply); + break; + case ITEM_MOD_STRENGTH: + sLog.outDebug("+ %u STRENGTH",enchant_amount); + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply); + ApplyStatBuffMod(STAT_STRENGTH, enchant_amount, apply); + break; + case ITEM_MOD_INTELLECT: + sLog.outDebug("+ %u INTELLECT",enchant_amount); + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply); + ApplyStatBuffMod(STAT_INTELLECT, enchant_amount, apply); + break; + case ITEM_MOD_SPIRIT: + sLog.outDebug("+ %u SPIRIT",enchant_amount); + HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply); + ApplyStatBuffMod(STAT_SPIRIT, enchant_amount, apply); + break; + case ITEM_MOD_STAMINA: + sLog.outDebug("+ %u STAMINA",enchant_amount); + HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply); + ApplyStatBuffMod(STAT_STAMINA, enchant_amount, apply); + break; + case ITEM_MOD_DEFENSE_SKILL_RATING: + ((Player*)this)->ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply); + sLog.outDebug("+ %u DEFENCE", enchant_amount); + break; + case ITEM_MOD_DODGE_RATING: + ((Player*)this)->ApplyRatingMod(CR_DODGE, enchant_amount, apply); + sLog.outDebug("+ %u DODGE", enchant_amount); + break; + case ITEM_MOD_PARRY_RATING: + ((Player*)this)->ApplyRatingMod(CR_PARRY, enchant_amount, apply); + sLog.outDebug("+ %u PARRY", enchant_amount); + break; + case ITEM_MOD_BLOCK_RATING: + ((Player*)this)->ApplyRatingMod(CR_BLOCK, enchant_amount, apply); + sLog.outDebug("+ %u SHIELD_BLOCK", enchant_amount); + break; + case ITEM_MOD_HIT_MELEE_RATING: + ((Player*)this)->ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply); + sLog.outDebug("+ %u MELEE_HIT", enchant_amount); + break; + case ITEM_MOD_HIT_RANGED_RATING: + ((Player*)this)->ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply); + sLog.outDebug("+ %u RANGED_HIT", enchant_amount); + break; + case ITEM_MOD_HIT_SPELL_RATING: + ((Player*)this)->ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply); + sLog.outDebug("+ %u SPELL_HIT", enchant_amount); + break; + case ITEM_MOD_CRIT_MELEE_RATING: + ((Player*)this)->ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply); + sLog.outDebug("+ %u MELEE_CRIT", enchant_amount); + break; + case ITEM_MOD_CRIT_RANGED_RATING: + ((Player*)this)->ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply); + sLog.outDebug("+ %u RANGED_CRIT", enchant_amount); + break; + case ITEM_MOD_CRIT_SPELL_RATING: + ((Player*)this)->ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply); + sLog.outDebug("+ %u SPELL_CRIT", enchant_amount); + break; +// Values from ITEM_STAT_MELEE_HA_RATING to ITEM_MOD_HASTE_RANGED_RATING are never used +// in Enchantments +// case ITEM_MOD_HIT_TAKEN_MELEE_RATING: +// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply); +// break; +// case ITEM_MOD_HIT_TAKEN_RANGED_RATING: +// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply); +// break; +// case ITEM_MOD_HIT_TAKEN_SPELL_RATING: +// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply); +// break; +// case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: +// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); +// break; +// case ITEM_MOD_CRIT_TAKEN_RANGED_RATING: +// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); +// break; +// case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: +// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); +// break; +// case ITEM_MOD_HASTE_MELEE_RATING: +// ((Player*)this)->ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply); +// break; +// case ITEM_MOD_HASTE_RANGED_RATING: +// ((Player*)this)->ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply); +// break; + case ITEM_MOD_HASTE_SPELL_RATING: + ((Player*)this)->ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply); + break; + case ITEM_MOD_HIT_RATING: + ((Player*)this)->ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply); + ((Player*)this)->ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply); + ((Player*)this)->ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply); + sLog.outDebug("+ %u HIT", enchant_amount); + break; + case ITEM_MOD_CRIT_RATING: + ((Player*)this)->ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply); + ((Player*)this)->ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply); + ((Player*)this)->ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply); + sLog.outDebug("+ %u CRITICAL", enchant_amount); + break; +// Values ITEM_MOD_HIT_TAKEN_RATING and ITEM_MOD_CRIT_TAKEN_RATING are never used in Enchantment +// case ITEM_MOD_HIT_TAKEN_RATING: +// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply); +// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply); +// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply); +// break; +// case ITEM_MOD_CRIT_TAKEN_RATING: +// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); +// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); +// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); +// break; + case ITEM_MOD_RESILIENCE_RATING: + ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); + ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); + ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); + sLog.outDebug("+ %u RESILIENCE", enchant_amount); + break; + case ITEM_MOD_HASTE_RATING: + ((Player*)this)->ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply); + ((Player*)this)->ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply); + ((Player*)this)->ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply); + sLog.outDebug("+ %u HASTE", enchant_amount); + break; + case ITEM_MOD_EXPERTISE_RATING: + ((Player*)this)->ApplyRatingMod(CR_EXPERTISE, enchant_amount, apply); + sLog.outDebug("+ %u EXPERTISE", enchant_amount); + break; + default: + break; + } + break; + } + case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon + { + if(getClass() == CLASS_SHAMAN) + { + float addValue = 0.0f; + if(item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) + { + addValue = float(enchant_amount * item->GetProto()->Delay/1000.0f); + HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply); + } + else if(item->GetSlot() == EQUIPMENT_SLOT_OFFHAND ) + { + addValue = float(enchant_amount * item->GetProto()->Delay/1000.0f); + HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, addValue, apply); + } + } + break; + } + default: + sLog.outError("Unknown item enchantment display type: %d",enchant_display_type); + break; + } /*switch(enchant_display_type)*/ + } /*for*/ + + // visualize enchantment at player and equipped items + if(slot < MAX_INSPECTED_ENCHANTMENT_SLOT) + { + int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (item->GetSlot() * MAX_VISIBLE_ITEM_OFFSET); + SetUInt32Value(VisibleBase + 1 + slot, apply? item->GetEnchantmentId(slot) : 0); + } + + if(apply_dur) + { + if(apply) + { + // set duration + uint32 duration = item->GetEnchantmentDuration(slot); + if(duration > 0) + AddEnchantmentDuration(item,slot,duration); + } + else + { + // duration == 0 will remove EnchantDuration + AddEnchantmentDuration(item,slot,0); + } + } +} + +void Player::SendEnchantmentDurations() +{ + for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();++itr) + { + GetSession()->SendItemEnchantTimeUpdate(GetGUID(), itr->item->GetGUID(),itr->slot,uint32(itr->leftduration)/1000); + } +} + +void Player::SendItemDurations() +{ + for(ItemDurationList::iterator itr = m_itemDuration.begin();itr != m_itemDuration.end();++itr) + { + (*itr)->SendTimeUpdate(this); + } +} + +void Player::SendNewItem(Item *item, uint32 count, bool received, bool created, bool broadcast) +{ + if(!item) // prevent crash + return; + + // last check 2.0.10 + WorldPacket data( SMSG_ITEM_PUSH_RESULT, (8+4+4+4+1+4+4+4+4+4) ); + data << GetGUID(); // player GUID + data << uint32(received); // 0=looted, 1=from npc + data << uint32(created); // 0=received, 1=created + data << uint32(1); // always 0x01 (probably meant to be count of listed items) + data << (uint8)item->GetBagSlot(); // bagslot + // item slot, but when added to stack: 0xFFFFFFFF + data << (uint32) ((item->GetCount()==count) ? item->GetSlot() : -1); + data << uint32(item->GetEntry()); // item id + data << uint32(item->GetItemSuffixFactor()); // SuffixFactor + data << uint32(item->GetItemRandomPropertyId()); // random item property id + data << uint32(count); // count of items + data << GetItemCount(item->GetEntry()); // count of items in inventory + + if (broadcast && GetGroup()) + GetGroup()->BroadcastPacket(&data); + else + GetSession()->SendPacket(&data); +} + +/*********************************************************/ +/*** QUEST SYSTEM ***/ +/*********************************************************/ + +void Player::PrepareQuestMenu( uint64 guid ) +{ + Object *pObject; + QuestRelations* pObjectQR; + QuestRelations* pObjectQIR; + Creature *pCreature = ObjectAccessor::GetCreature(*this, guid); + if( pCreature ) + { + pObject = (Object*)pCreature; + pObjectQR = &objmgr.mCreatureQuestRelations; + pObjectQIR = &objmgr.mCreatureQuestInvolvedRelations; + } + else + { + GameObject *pGameObject = ObjectAccessor::GetGameObject(*this, guid); + if( pGameObject ) + { + pObject = (Object*)pGameObject; + pObjectQR = &objmgr.mGOQuestRelations; + pObjectQIR = &objmgr.mGOQuestInvolvedRelations; + } + else + return; + } + + QuestMenu &qm = PlayerTalkClass->GetQuestMenu(); + qm.ClearMenu(); + + for(QuestRelations::const_iterator i = pObjectQIR->lower_bound(pObject->GetEntry()); i != pObjectQIR->upper_bound(pObject->GetEntry()); ++i) + { + uint32 quest_id = i->second; + QuestStatus status = GetQuestStatus( quest_id ); + if ( status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus( quest_id ) ) + qm.AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP); + else if ( status == QUEST_STATUS_INCOMPLETE ) + qm.AddMenuItem(quest_id, DIALOG_STATUS_INCOMPLETE); + else if (status == QUEST_STATUS_AVAILABLE ) + qm.AddMenuItem(quest_id, DIALOG_STATUS_CHAT); + } + + for(QuestRelations::const_iterator i = pObjectQR->lower_bound(pObject->GetEntry()); i != pObjectQR->upper_bound(pObject->GetEntry()); ++i) + { + uint32 quest_id = i->second; + Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); + if(!pQuest) continue; + + QuestStatus status = GetQuestStatus( quest_id ); + + if (pQuest->IsAutoComplete() && CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP); + else if ( status == QUEST_STATUS_NONE && CanTakeQuest( pQuest, false ) ) + qm.AddMenuItem(quest_id, DIALOG_STATUS_AVAILABLE); + } +} + +void Player::SendPreparedQuest( uint64 guid ) +{ + QuestMenu& questMenu = PlayerTalkClass->GetQuestMenu(); + if( questMenu.Empty() ) + return; + + QuestMenuItem const& qmi0 = questMenu.GetItem( 0 ); + + uint32 status = qmi0.m_qIcon; + + // single element case + if ( questMenu.MenuItemCount() == 1 ) + { + // Auto open -- maybe also should verify there is no greeting + uint32 quest_id = qmi0.m_qId; + Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); + if ( pQuest ) + { + if( status == DIALOG_STATUS_REWARD_REP && !GetQuestRewardStatus( quest_id ) ) + PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanRewardQuest(pQuest,false), true ); + else if( status == DIALOG_STATUS_INCOMPLETE ) + PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, false, true ); + // Send completable on repeatable quest if player don't have quest + else if( pQuest->IsRepeatable() ) + PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanCompleteRepeatableQuest(pQuest), true ); + else + PlayerTalkClass->SendQuestGiverQuestDetails( pQuest, guid, true ); + } + } + // multiply entries + else + { + QEmote qe; + qe._Delay = 0; + qe._Emote = 0; + std::string title = ""; + Creature *pCreature = ObjectAccessor::GetCreature(*this, guid); + if( pCreature ) + { + uint32 textid = pCreature->GetNpcTextId(); + GossipText * gossiptext = objmgr.GetGossipText(textid); + if( !gossiptext ) + { + qe._Delay = 0; //TEXTEMOTE_MESSAGE; //zyg: player emote + qe._Emote = 0; //TEXTEMOTE_HELLO; //zyg: NPC emote + title = ""; + } + else + { + qe = gossiptext->Options[0].Emotes[0]; + + if(!gossiptext->Options[0].Text_0.empty()) + { + title = gossiptext->Options[0].Text_0; + + int loc_idx = GetSession()->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textid); + if (nl) + { + if (nl->Text_0[0].size() > loc_idx && !nl->Text_0[0][loc_idx].empty()) + title = nl->Text_0[0][loc_idx]; + } + } + } + else + { + title = gossiptext->Options[0].Text_1; + + int loc_idx = GetSession()->GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textid); + if (nl) + { + if (nl->Text_1[0].size() > loc_idx && !nl->Text_1[0][loc_idx].empty()) + title = nl->Text_1[0][loc_idx]; + } + } + } + } + } + PlayerTalkClass->SendQuestGiverQuestList( qe, title, guid ); + } +} + +bool Player::IsActiveQuest( uint32 quest_id ) const +{ + QuestStatusMap::const_iterator itr = mQuestStatus.find(quest_id); + + return itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE; +} + +Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest ) +{ + Object *pObject; + QuestRelations* pObjectQR; + QuestRelations* pObjectQIR; + + Creature *pCreature = ObjectAccessor::GetCreature(*this, guid); + if( pCreature ) + { + pObject = (Object*)pCreature; + pObjectQR = &objmgr.mCreatureQuestRelations; + pObjectQIR = &objmgr.mCreatureQuestInvolvedRelations; + } + else + { + GameObject *pGameObject = ObjectAccessor::GetGameObject(*this, guid); + if( pGameObject ) + { + pObject = (Object*)pGameObject; + pObjectQR = &objmgr.mGOQuestRelations; + pObjectQIR = &objmgr.mGOQuestInvolvedRelations; + } + else + return NULL; + } + + uint32 nextQuestID = pQuest->GetNextQuestInChain(); + for(QuestRelations::const_iterator itr = pObjectQR->lower_bound(pObject->GetEntry()); itr != pObjectQR->upper_bound(pObject->GetEntry()); ++itr) + { + if (itr->second == nextQuestID) + return objmgr.GetQuestTemplate(nextQuestID); + } + + return NULL; +} + +bool Player::CanSeeStartQuest( Quest const *pQuest ) +{ + if( SatisfyQuestRace( pQuest, false ) && SatisfyQuestSkillOrClass( pQuest, false ) && + SatisfyQuestExclusiveGroup( pQuest, false ) && SatisfyQuestReputation( pQuest, false ) && + SatisfyQuestPreviousQuest( pQuest, false ) && SatisfyQuestNextChain( pQuest, false ) && + SatisfyQuestPrevChain( pQuest, false ) && SatisfyQuestDay( pQuest, false ) ) + { + return getLevel() + sWorld.getConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF) >= pQuest->GetMinLevel(); + } + + return false; +} + +bool Player::CanTakeQuest( Quest const *pQuest, bool msg ) +{ + return SatisfyQuestStatus( pQuest, msg ) && SatisfyQuestExclusiveGroup( pQuest, msg ) + && SatisfyQuestRace( pQuest, msg ) && SatisfyQuestLevel( pQuest, msg ) + && SatisfyQuestSkillOrClass( pQuest, msg ) && SatisfyQuestReputation( pQuest, msg ) + && SatisfyQuestPreviousQuest( pQuest, msg ) && SatisfyQuestTimed( pQuest, msg ) + && SatisfyQuestNextChain( pQuest, msg ) && SatisfyQuestPrevChain( pQuest, msg ) + && SatisfyQuestDay( pQuest, msg ); +} + +bool Player::CanAddQuest( Quest const *pQuest, bool msg ) +{ + if( !SatisfyQuestLog( msg ) ) + return false; + + uint32 srcitem = pQuest->GetSrcItemId(); + if( srcitem > 0 ) + { + uint32 count = pQuest->GetSrcItemCount(); + ItemPosCountVec dest; + uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count ); + + // player already have max number (in most case 1) source item, no additional item needed and quest can be added. + if( msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS ) + return true; + else if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, NULL, NULL ); + return false; + } + } + return true; +} + +bool Player::CanCompleteQuest( uint32 quest_id ) +{ + if( quest_id ) + { + QuestStatusData& q_status = mQuestStatus[quest_id]; + if( q_status.m_status == QUEST_STATUS_COMPLETE ) + return false; // not allow re-complete quest + + Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); + + if(!qInfo) + return false; + + // auto complete quest + if (qInfo->IsAutoComplete() && CanTakeQuest(qInfo, false)) + return true; + + if ( q_status.m_status == QUEST_STATUS_INCOMPLETE ) + { + + if ( qInfo->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) + { + for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + { + if( qInfo->ReqItemCount[i]!= 0 && q_status.m_itemcount[i] < qInfo->ReqItemCount[i] ) + return false; + } + } + + if ( qInfo->HasFlag(QUEST_MANGOS_FLAGS_KILL_OR_CAST | QUEST_MANGOS_FLAGS_SPEAKTO) ) + { + for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + { + if( qInfo->ReqCreatureOrGOId[i] == 0 ) + continue; + + if( qInfo->ReqCreatureOrGOCount[i] != 0 && q_status.m_creatureOrGOcount[i] < qInfo->ReqCreatureOrGOCount[i] ) + return false; + } + } + + if ( qInfo->HasFlag( QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT ) && !q_status.m_explored ) + return false; + + if ( qInfo->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) && q_status.m_timer == 0 ) + return false; + + if ( qInfo->GetRewOrReqMoney() < 0 ) + { + if ( GetMoney() < uint32(-qInfo->GetRewOrReqMoney()) ) + return false; + } + + uint32 repFacId = qInfo->GetRepObjectiveFaction(); + if ( repFacId && GetReputation(repFacId) < qInfo->GetRepObjectiveValue() ) + return false; + + return true; + } + } + return false; +} + +bool Player::CanCompleteRepeatableQuest( Quest const *pQuest ) +{ + // Solve problem that player don't have the quest and try complete it. + // if repeatable she must be able to complete event if player don't have it. + // Seem that all repeatable quest are DELIVER Flag so, no need to add more. + if( !CanTakeQuest(pQuest, false) ) + return false; + + if (pQuest->HasFlag( QUEST_MANGOS_FLAGS_DELIVER) ) + for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + if( pQuest->ReqItemId[i] && pQuest->ReqItemCount[i] && !HasItemCount(pQuest->ReqItemId[i],pQuest->ReqItemCount[i]) ) + return false; + + if( !CanRewardQuest(pQuest, false) ) + return false; + + return true; +} + +bool Player::CanRewardQuest( Quest const *pQuest, bool msg ) +{ + // not auto complete quest and not completed quest (only cheating case, then ignore without message) + if(!pQuest->IsAutoComplete() && GetQuestStatus(pQuest->GetQuestId()) != QUEST_STATUS_COMPLETE) + return false; + + // daily quest can't be rewarded (10 daily quest already completed) + if(!SatisfyQuestDay(pQuest,true)) + return false; + + // rewarded and not repeatable quest (only cheating case, then ignore without message) + if(GetQuestRewardStatus(pQuest->GetQuestId())) + return false; + + // prevent receive reward with quest items in bank + if ( pQuest->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) + { + for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + { + if( pQuest->ReqItemCount[i]!= 0 && + GetItemCount(pQuest->ReqItemId[i]) < pQuest->ReqItemCount[i] ) + { + if(msg) + SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); + return false; + } + } + } + + // prevent receive reward with low money and GetRewOrReqMoney() < 0 + if(pQuest->GetRewOrReqMoney() < 0 && GetMoney() < uint32(-pQuest->GetRewOrReqMoney()) ) + return false; + + return true; +} + +bool Player::CanRewardQuest( Quest const *pQuest, uint32 reward, bool msg ) +{ + // prevent receive reward with quest items in bank or for not completed quest + if(!CanRewardQuest(pQuest,msg)) + return false; + + if ( pQuest->GetRewChoiceItemsCount() > 0 ) + { + if( pQuest->RewChoiceItemId[reward] ) + { + ItemPosCountVec dest; + uint8 res = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ); + if( res != EQUIP_ERR_OK ) + { + SendEquipError( res, NULL, NULL ); + return false; + } + } + } + + if ( pQuest->GetRewItemsCount() > 0 ) + { + for (uint32 i = 0; i < pQuest->GetRewItemsCount(); ++i) + { + if( pQuest->RewItemId[i] ) + { + ItemPosCountVec dest; + uint8 res = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ); + if( res != EQUIP_ERR_OK ) + { + SendEquipError( res, NULL, NULL ); + return false; + } + } + } + } + + return true; +} + +void Player::AddQuest( Quest const *pQuest, Object *questGiver ) +{ + uint16 log_slot = FindQuestSlot( 0 ); + assert(log_slot < MAX_QUEST_LOG_SIZE); + + uint32 quest_id = pQuest->GetQuestId(); + + // if not exist then created with set uState==NEW and rewarded=false + QuestStatusData& questStatusData = mQuestStatus[quest_id]; + if (questStatusData.uState != QUEST_NEW) + questStatusData.uState = QUEST_CHANGED; + + // check for repeatable quests status reset + questStatusData.m_status = QUEST_STATUS_INCOMPLETE; + questStatusData.m_explored = false; + + if ( pQuest->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) + { + for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + questStatusData.m_itemcount[i] = 0; + } + + if ( pQuest->HasFlag(QUEST_MANGOS_FLAGS_KILL_OR_CAST | QUEST_MANGOS_FLAGS_SPEAKTO) ) + { + for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + questStatusData.m_creatureOrGOcount[i] = 0; + } + + GiveQuestSourceItem( pQuest ); + AdjustQuestReqItemCount( pQuest ); + + if( pQuest->GetRepObjectiveFaction() ) + SetFactionVisibleForFactionId(pQuest->GetRepObjectiveFaction()); + + uint32 qtime = 0; + if( pQuest->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) ) + { + uint32 limittime = pQuest->GetLimitTime(); + + // shared timed quest + if(questGiver && questGiver->GetTypeId()==TYPEID_PLAYER) + limittime = ((Player*)questGiver)->getQuestStatusMap()[quest_id].m_timer / 1000; + + AddTimedQuest( quest_id ); + questStatusData.m_timer = limittime * 1000; + qtime = static_cast(time(NULL)) + limittime; + } + else + questStatusData.m_timer = 0; + + SetQuestSlot(log_slot, quest_id, qtime); + + //starting initial quest script + if(questGiver && pQuest->GetQuestStartScript()!=0) + sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this); + + UpdateForQuestsGO(); +} + +void Player::CompleteQuest( uint32 quest_id ) +{ + if( quest_id ) + { + SetQuestStatus( quest_id, QUEST_STATUS_COMPLETE ); + + uint16 log_slot = FindQuestSlot( quest_id ); + if( log_slot < MAX_QUEST_LOG_SIZE) + SetQuestSlotState(log_slot,QUEST_STATE_COMPLETE); + + if(Quest const* qInfo = objmgr.GetQuestTemplate(quest_id)) + { + if( qInfo->HasFlag(QUEST_FLAGS_AUTO_REWARDED) ) + RewardQuest(qInfo,0,this,false); + else + SendQuestComplete( quest_id ); + } + } +} + +void Player::IncompleteQuest( uint32 quest_id ) +{ + if( quest_id ) + { + SetQuestStatus( quest_id, QUEST_STATUS_INCOMPLETE ); + + uint16 log_slot = FindQuestSlot( quest_id ); + if( log_slot < MAX_QUEST_LOG_SIZE) + RemoveQuestSlotState(log_slot,QUEST_STATE_COMPLETE); + } +} + +void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce ) +{ + uint32 quest_id = pQuest->GetQuestId(); + + for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++ ) + { + if ( pQuest->ReqItemId[i] ) + DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true); + } + + //if( qInfo->HasSpecialFlag( QUEST_FLAGS_TIMED ) ) + // SetTimedQuest( 0 ); + m_timedquests.erase(pQuest->GetQuestId()); + + if ( pQuest->GetRewChoiceItemsCount() > 0 ) + { + if( pQuest->RewChoiceItemId[reward] ) + { + ItemPosCountVec dest; + if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK ) + { + Item* item = StoreNewItem( dest, pQuest->RewChoiceItemId[reward], true); + SendNewItem(item, pQuest->RewChoiceItemCount[reward], true, false); + } + } + } + + if ( pQuest->GetRewItemsCount() > 0 ) + { + for (uint32 i=0; i < pQuest->GetRewItemsCount(); ++i) + { + if( pQuest->RewItemId[i] ) + { + ItemPosCountVec dest; + if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ) == EQUIP_ERR_OK ) + { + Item* item = StoreNewItem( dest, pQuest->RewItemId[i], true); + SendNewItem(item, pQuest->RewItemCount[i], true, false); + } + } + } + } + + RewardReputation( pQuest ); + + if( pQuest->GetRewSpellCast() > 0 ) + CastSpell( this, pQuest->GetRewSpellCast(), true); + else if( pQuest->GetRewSpell() > 0) + CastSpell( this, pQuest->GetRewSpell(), true); + + uint16 log_slot = FindQuestSlot( quest_id ); + if( log_slot < MAX_QUEST_LOG_SIZE) + SetQuestSlot(log_slot,0); + + QuestStatusData& q_status = mQuestStatus[quest_id]; + + // Not give XP in case already completed once repeatable quest + uint32 XP = q_status.m_rewarded ? 0 : uint32(pQuest->XPValue( this )*sWorld.getRate(RATE_XP_QUEST)); + + if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) + GiveXP( XP , NULL ); + else + ModifyMoney( int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)) ); + + // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative + ModifyMoney( pQuest->GetRewOrReqMoney() ); + + // title reward + if(pQuest->GetCharTitleId()) + { + if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId())) + SetFlag64(PLAYER__FIELD_KNOWN_TITLES, (uint64(1) << titleEntry->bit_index)); + } + + // Send reward mail + if(pQuest->GetRewMailTemplateId()) + { + MailMessageType mailType; + uint32 senderGuidOrEntry; + switch(questGiver->GetTypeId()) + { + case TYPEID_UNIT: + mailType = MAIL_CREATURE; + senderGuidOrEntry = questGiver->GetEntry(); + break; + case TYPEID_GAMEOBJECT: + mailType = MAIL_GAMEOBJECT; + senderGuidOrEntry = questGiver->GetEntry(); + break; + case TYPEID_ITEM: + mailType = MAIL_ITEM; + senderGuidOrEntry = questGiver->GetEntry(); + break; + case TYPEID_PLAYER: + mailType = MAIL_NORMAL; + senderGuidOrEntry = questGiver->GetGUIDLow(); + break; + default: + mailType = MAIL_NORMAL; + senderGuidOrEntry = GetGUIDLow(); + break; + } + + Loot questMailLoot; + + questMailLoot.FillLoot(pQuest->GetQuestId(), LootTemplates_QuestMail, this); + + // fill mail + MailItemsInfo mi; // item list preparing + + for(size_t i = 0; mi.size() < MAX_MAIL_ITEMS && i < questMailLoot.items.size(); ++i) + { + if(LootItem* lootitem = questMailLoot.LootItemInSlot(i,this)) + { + if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this)) + { + item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted + mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); + } + } + } + + for(size_t i = 0; mi.size() < MAX_MAIL_ITEMS && i < questMailLoot.quest_items.size(); ++i) + { + if(LootItem* lootitem = questMailLoot.LootItemInSlot(i+questMailLoot.items.size(),this)) + { + if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this)) + { + item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted + mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); + } + } + } + + WorldSession::SendMailTo(this, mailType, MAIL_STATIONERY_NORMAL, senderGuidOrEntry, GetGUIDLow(), "", 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE,pQuest->GetRewMailDelaySecs(),pQuest->GetRewMailTemplateId()); + } + + if(pQuest->IsDaily()) + SetDailyQuestStatus(quest_id); + + if ( !pQuest->IsRepeatable() ) + SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE); + else + SetQuestStatus(quest_id, QUEST_STATUS_NONE); + + q_status.m_rewarded = true; + + if(announce) + SendQuestReward( pQuest, XP, questGiver ); + + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; +} + +void Player::FailQuest( uint32 quest_id ) +{ + if( quest_id ) + { + IncompleteQuest( quest_id ); + + uint16 log_slot = FindQuestSlot( quest_id ); + if( log_slot < MAX_QUEST_LOG_SIZE) + { + SetQuestSlotTimer(log_slot, 1 ); + SetQuestSlotState(log_slot,QUEST_STATE_FAIL); + } + SendQuestFailed( quest_id ); + } +} + +void Player::FailTimedQuest( uint32 quest_id ) +{ + if( quest_id ) + { + QuestStatusData& q_status = mQuestStatus[quest_id]; + + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + q_status.m_timer = 0; + + IncompleteQuest( quest_id ); + + uint16 log_slot = FindQuestSlot( quest_id ); + if( log_slot < MAX_QUEST_LOG_SIZE) + { + SetQuestSlotTimer(log_slot, 1 ); + SetQuestSlotState(log_slot,QUEST_STATE_FAIL); + } + SendQuestTimerFailed( quest_id ); + } +} + +bool Player::SatisfyQuestSkillOrClass( Quest const* qInfo, bool msg ) +{ + int32 zoneOrSort = qInfo->GetZoneOrSort(); + int32 skillOrClass = qInfo->GetSkillOrClass(); + + // skip zone zoneOrSort and 0 case skillOrClass + if( zoneOrSort >= 0 && skillOrClass == 0 ) + return true; + + int32 questSort = -zoneOrSort; + uint8 reqSortClass = ClassByQuestSort(questSort); + + // check class sort cases in zoneOrSort + if( reqSortClass != 0 && getClass() != reqSortClass) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + + // check class + if( skillOrClass < 0 ) + { + uint8 reqClass = -int32(skillOrClass); + if(getClass() != reqClass) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + } + // check skill + else if( skillOrClass > 0 ) + { + uint32 reqSkill = skillOrClass; + if( GetSkillValue( reqSkill ) < qInfo->GetRequiredSkillValue() ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + } + + return true; +} + +bool Player::SatisfyQuestLevel( Quest const* qInfo, bool msg ) +{ + if( getLevel() < qInfo->GetMinLevel() ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + return true; +} + +bool Player::SatisfyQuestLog( bool msg ) +{ + // exist free slot + if( FindQuestSlot(0) < MAX_QUEST_LOG_SIZE ) + return true; + + if( msg ) + { + WorldPacket data( SMSG_QUESTLOG_FULL, 0 ); + GetSession()->SendPacket( &data ); + sLog.outDebug( "WORLD: Sent QUEST_LOG_FULL_MESSAGE" ); + } + return false; +} + +bool Player::SatisfyQuestPreviousQuest( Quest const* qInfo, bool msg ) +{ + // No previous quest (might be first quest in a series) + if( qInfo->prevQuests.empty()) + return true; + + for(Quest::PrevQuests::const_iterator iter = qInfo->prevQuests.begin(); iter != qInfo->prevQuests.end(); ++iter ) + { + uint32 prevId = abs(*iter); + + QuestStatusMap::iterator i_prevstatus = mQuestStatus.find( prevId ); + Quest const* qPrevInfo = objmgr.GetQuestTemplate(prevId); + + if( qPrevInfo && i_prevstatus != mQuestStatus.end() ) + { + // If any of the positive previous quests completed, return true + if( *iter > 0 && i_prevstatus->second.m_rewarded ) + { + // skip one-from-all exclusive group + if(qPrevInfo->GetExclusiveGroup() >= 0) + return true; + + // each-from-all exclusive group ( < 0) + // can be start if only all quests in prev quest exclusive group complited and rewarded + ObjectMgr::ExclusiveQuestGroups::iterator iter = objmgr.mExclusiveQuestGroups.lower_bound(qPrevInfo->GetExclusiveGroup()); + ObjectMgr::ExclusiveQuestGroups::iterator end = objmgr.mExclusiveQuestGroups.upper_bound(qPrevInfo->GetExclusiveGroup()); + + assert(iter!=end); // always must be found if qPrevInfo->ExclusiveGroup != 0 + + for(; iter != end; ++iter) + { + uint32 exclude_Id = iter->second; + + // skip checked quest id, only state of other quests in group is interesting + if(exclude_Id == prevId) + continue; + + QuestStatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id ); + + // alternative quest from group also must be completed and rewarded(reported) + if( i_exstatus == mQuestStatus.end() || !i_exstatus->second.m_rewarded ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + } + return true; + } + // If any of the negative previous quests active, return true + if( *iter < 0 && (i_prevstatus->second.m_status == QUEST_STATUS_INCOMPLETE + || (i_prevstatus->second.m_status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(prevId)))) + { + // skip one-from-all exclusive group + if(qPrevInfo->GetExclusiveGroup() >= 0) + return true; + + // each-from-all exclusive group ( < 0) + // can be start if only all quests in prev quest exclusive group active + ObjectMgr::ExclusiveQuestGroups::iterator iter = objmgr.mExclusiveQuestGroups.lower_bound(qPrevInfo->GetExclusiveGroup()); + ObjectMgr::ExclusiveQuestGroups::iterator end = objmgr.mExclusiveQuestGroups.upper_bound(qPrevInfo->GetExclusiveGroup()); + + assert(iter!=end); // always must be found if qPrevInfo->ExclusiveGroup != 0 + + for(; iter != end; ++iter) + { + uint32 exclude_Id = iter->second; + + // skip checked quest id, only state of other quests in group is interesting + if(exclude_Id == prevId) + continue; + + QuestStatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id ); + + // alternative quest from group also must be active + if( i_exstatus == mQuestStatus.end() || + i_exstatus->second.m_status != QUEST_STATUS_INCOMPLETE && + (i_prevstatus->second.m_status != QUEST_STATUS_COMPLETE || GetQuestRewardStatus(prevId)) ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + } + return true; + } + } + } + + // Has only positive prev. quests in non-rewarded state + // and negative prev. quests in non-active state + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + + return false; +} + +bool Player::SatisfyQuestRace( Quest const* qInfo, bool msg ) +{ + uint32 reqraces = qInfo->GetRequiredRaces(); + if ( reqraces == 0 ) + return true; + if( (reqraces & getRaceMask()) == 0 ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_QUEST_FAILED_WRONG_RACE ); + return false; + } + return true; +} + +bool Player::SatisfyQuestReputation( Quest const* qInfo, bool msg ) +{ + uint32 fIdMin = qInfo->GetRequiredMinRepFaction(); //Min required rep + if(fIdMin && GetReputation(fIdMin) < qInfo->GetRequiredMinRepValue()) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + + uint32 fIdMax = qInfo->GetRequiredMaxRepFaction(); //Max required rep + if(fIdMax && GetReputation(fIdMax) >= qInfo->GetRequiredMaxRepValue()) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + + return true; +} + +bool Player::SatisfyQuestStatus( Quest const* qInfo, bool msg ) +{ + QuestStatusMap::iterator itr = mQuestStatus.find( qInfo->GetQuestId() ); + if ( itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_QUEST_ALREADY_ON ); + return false; + } + return true; +} + +bool Player::SatisfyQuestTimed( Quest const* qInfo, bool msg ) +{ + if ( (find(m_timedquests.begin(), m_timedquests.end(), qInfo->GetQuestId()) != m_timedquests.end()) && qInfo->HasFlag(QUEST_MANGOS_FLAGS_TIMED) ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_QUEST_ONLY_ONE_TIMED ); + return false; + } + return true; +} + +bool Player::SatisfyQuestExclusiveGroup( Quest const* qInfo, bool msg ) +{ + // non positive exclusive group, if > 0 then can be start if any other quest in exclusive group already started/completed + if(qInfo->GetExclusiveGroup() <= 0) + return true; + + ObjectMgr::ExclusiveQuestGroups::iterator iter = objmgr.mExclusiveQuestGroups.lower_bound(qInfo->GetExclusiveGroup()); + ObjectMgr::ExclusiveQuestGroups::iterator end = objmgr.mExclusiveQuestGroups.upper_bound(qInfo->GetExclusiveGroup()); + + assert(iter!=end); // always must be found if qInfo->ExclusiveGroup != 0 + + for(; iter != end; ++iter) + { + uint32 exclude_Id = iter->second; + + // skip checked quest id, only state of other quests in group is interesting + if(exclude_Id == qInfo->GetQuestId()) + continue; + + QuestStatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id ); + + // alternative quest already started or completed + if( i_exstatus != mQuestStatus.end() + && (i_exstatus->second.m_status == QUEST_STATUS_COMPLETE || i_exstatus->second.m_status == QUEST_STATUS_INCOMPLETE) ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + } + return true; +} + +bool Player::SatisfyQuestNextChain( Quest const* qInfo, bool msg ) +{ + if(!qInfo->GetNextQuestInChain()) + return true; + + // next quest in chain already started or completed + QuestStatusMap::iterator itr = mQuestStatus.find( qInfo->GetNextQuestInChain() ); + if( itr != mQuestStatus.end() + && (itr->second.m_status == QUEST_STATUS_COMPLETE || itr->second.m_status == QUEST_STATUS_INCOMPLETE) ) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + + // check for all quests further up the chain + // only necessary if there are quest chains with more than one quest that can be skipped + //return SatisfyQuestNextChain( qInfo->GetNextQuestInChain(), msg ); + return true; +} + +bool Player::SatisfyQuestPrevChain( Quest const* qInfo, bool msg ) +{ + // No previous quest in chain + if( qInfo->prevChainQuests.empty()) + return true; + + for(Quest::PrevChainQuests::const_iterator iter = qInfo->prevChainQuests.begin(); iter != qInfo->prevChainQuests.end(); ++iter ) + { + uint32 prevId = *iter; + + QuestStatusMap::iterator i_prevstatus = mQuestStatus.find( prevId ); + + if( i_prevstatus != mQuestStatus.end() ) + { + // If any of the previous quests in chain active, return false + if( i_prevstatus->second.m_status == QUEST_STATUS_INCOMPLETE + || (i_prevstatus->second.m_status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(prevId))) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ ); + return false; + } + } + + // check for all quests further down the chain + // only necessary if there are quest chains with more than one quest that can be skipped + //if( !SatisfyQuestPrevChain( prevId, msg ) ) + // return false; + } + + // No previous quest in chain active + return true; +} + +bool Player::SatisfyQuestDay( Quest const* qInfo, bool msg ) +{ + if(!qInfo->IsDaily()) + return true; + + bool have_slot = false; + for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) + { + uint32 id = GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx); + if(qInfo->GetQuestId()==id) + return false; + + if(!id) + have_slot = true; + } + + if(!have_slot) + { + if( msg ) + SendCanTakeQuestResponse( INVALIDREASON_DAILY_QUESTS_REMAINING ); + return false; + } + + return true; +} + +bool Player::GiveQuestSourceItem( Quest const *pQuest ) +{ + uint32 srcitem = pQuest->GetSrcItemId(); + if( srcitem > 0 ) + { + uint32 count = pQuest->GetSrcItemCount(); + if( count <= 0 ) + count = 1; + + ItemPosCountVec dest; + uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count ); + if( msg == EQUIP_ERR_OK ) + { + Item * item = StoreNewItem(dest, srcitem, true); + SendNewItem(item, count, true, false); + return true; + } + // player already have max amount required item, just report success + else if( msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS ) + return true; + else + SendEquipError( msg, NULL, NULL ); + return false; + } + + return true; +} + +bool Player::TakeQuestSourceItem( uint32 quest_id, bool msg ) +{ + Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); + if( qInfo ) + { + uint32 srcitem = qInfo->GetSrcItemId(); + if( srcitem > 0 ) + { + uint32 count = qInfo->GetSrcItemCount(); + if( count <= 0 ) + count = 1; + + // exist one case when destroy source quest item not possible: + // non un-equippable item (equipped non-empty bag, for example) + uint8 res = CanUnequipItems(srcitem,count); + if(res != EQUIP_ERR_OK) + { + if(msg) + SendEquipError( res, NULL, NULL ); + return false; + } + + DestroyItemCount(srcitem, count, true, true); + } + } + return true; +} + +bool Player::GetQuestRewardStatus( uint32 quest_id ) const +{ + Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); + if( qInfo ) + { + // for repeatable quests: rewarded field is set after first reward only to prevent getting XP more than once + QuestStatusMap::const_iterator itr = mQuestStatus.find( quest_id ); + if( itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE + && !qInfo->IsRepeatable() ) + return itr->second.m_rewarded; + + return false; + } + return false; +} + +QuestStatus Player::GetQuestStatus( uint32 quest_id ) const +{ + if( quest_id ) + { + QuestStatusMap::const_iterator itr = mQuestStatus.find( quest_id ); + if( itr != mQuestStatus.end() ) + return itr->second.m_status; + } + return QUEST_STATUS_NONE; +} + +bool Player::CanShareQuest(uint32 quest_id) const +{ + Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); + if( qInfo && qInfo->HasFlag(QUEST_FLAGS_SHARABLE) ) + { + QuestStatusMap::const_iterator itr = mQuestStatus.find( quest_id ); + if( itr != mQuestStatus.end() ) + return itr->second.m_status == QUEST_STATUS_NONE || itr->second.m_status == QUEST_STATUS_INCOMPLETE; + } + return false; +} + +void Player::SetQuestStatus( uint32 quest_id, QuestStatus status ) +{ + Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); + if( qInfo ) + { + if( status == QUEST_STATUS_NONE || status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE ) + { + if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) ) + m_timedquests.erase(qInfo->GetQuestId()); + } + + QuestStatusData& q_status = mQuestStatus[quest_id]; + + q_status.m_status = status; + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + } + + UpdateForQuestsGO(); +} + +// not used in MaNGOS, but used in scripting code +uint32 Player::GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry) +{ + Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); + if( !qInfo ) + return 0; + + for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) + if ( qInfo->ReqCreatureOrGOId[j] == entry ) + return mQuestStatus[quest_id].m_creatureOrGOcount[j]; + + return 0; +} + +void Player::AdjustQuestReqItemCount( Quest const* pQuest ) +{ + if ( pQuest->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) + { + for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + { + uint32 reqitemcount = pQuest->ReqItemCount[i]; + if( reqitemcount != 0 ) + { + uint32 quest_id = pQuest->GetQuestId(); + uint32 curitemcount = GetItemCount(pQuest->ReqItemId[i],true); + + QuestStatusData& q_status = mQuestStatus[quest_id]; + q_status.m_itemcount[i] = std::min(curitemcount, reqitemcount); + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + } + } + } +} + +uint16 Player::FindQuestSlot( uint32 quest_id ) const +{ + for ( uint16 i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) + if ( GetQuestSlotQuestId(i) == quest_id ) + return i; + + return MAX_QUEST_LOG_SIZE; +} + +void Player::AreaExploredOrEventHappens( uint32 questId ) +{ + if( questId ) + { + uint16 log_slot = FindQuestSlot( questId ); + if( log_slot < MAX_QUEST_LOG_SIZE) + { + QuestStatusData& q_status = mQuestStatus[questId]; + + if(!q_status.m_explored) + { + q_status.m_explored = true; + if (q_status.uState != QUEST_NEW) + q_status.uState = QUEST_CHANGED; + } + } + if( CanCompleteQuest( questId ) ) + CompleteQuest( questId ); + } +} + +//not used in mangosd, function for external script library +void Player::GroupEventHappens( uint32 questId, WorldObject const* pEventObject ) +{ + if( Group *pGroup = GetGroup() ) + { + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *pGroupGuy = itr->getSource(); + + // for any leave or dead (with not released body) group member at appropriate distance + if( pGroupGuy && pGroupGuy->IsAtGroupRewardDistance(pEventObject) && !pGroupGuy->GetCorpse() ) + pGroupGuy->AreaExploredOrEventHappens(questId); + } + } + else + AreaExploredOrEventHappens(questId); +} + +void Player::ItemAddedQuestCheck( uint32 entry, uint32 count ) +{ + for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) + { + uint32 questid = GetQuestSlotQuestId(i); + if ( questid == 0 ) + continue; + + QuestStatusData& q_status = mQuestStatus[questid]; + + if ( q_status.m_status != QUEST_STATUS_INCOMPLETE ) + continue; + + Quest const* qInfo = objmgr.GetQuestTemplate(questid); + if( !qInfo || !qInfo->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) + continue; + + for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) + { + uint32 reqitem = qInfo->ReqItemId[j]; + if ( reqitem == entry ) + { + uint32 reqitemcount = qInfo->ReqItemCount[j]; + uint32 curitemcount = q_status.m_itemcount[j]; + if ( curitemcount < reqitemcount ) + { + uint32 additemcount = ( curitemcount + count <= reqitemcount ? count : reqitemcount - curitemcount); + q_status.m_itemcount[j] += additemcount; + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + + SendQuestUpdateAddItem( qInfo, j, additemcount ); + } + if ( CanCompleteQuest( questid ) ) + CompleteQuest( questid ); + return; + } + } + } + UpdateForQuestsGO(); +} + +void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count ) +{ + for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) + { + uint32 questid = GetQuestSlotQuestId(i); + if(!questid) + continue; + Quest const* qInfo = objmgr.GetQuestTemplate(questid); + if ( !qInfo ) + continue; + if( !qInfo->HasFlag( QUEST_MANGOS_FLAGS_DELIVER ) ) + continue; + + for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) + { + uint32 reqitem = qInfo->ReqItemId[j]; + if ( reqitem == entry ) + { + QuestStatusData& q_status = mQuestStatus[questid]; + + uint32 reqitemcount = qInfo->ReqItemCount[j]; + uint32 curitemcount; + if( q_status.m_status != QUEST_STATUS_COMPLETE ) + curitemcount = q_status.m_itemcount[j]; + else + curitemcount = GetItemCount(entry,true); + if ( curitemcount < reqitemcount + count ) + { + uint32 remitemcount = ( curitemcount <= reqitemcount ? count : count + reqitemcount - curitemcount); + q_status.m_itemcount[j] = curitemcount - remitemcount; + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + + IncompleteQuest( questid ); + } + return; + } + } + } + UpdateForQuestsGO(); +} + +void Player::KilledMonster( uint32 entry, uint64 guid ) +{ + uint32 addkillcount = 1; + for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) + { + uint32 questid = GetQuestSlotQuestId(i); + if(!questid) + continue; + + Quest const* qInfo = objmgr.GetQuestTemplate(questid); + if( !qInfo ) + continue; + // just if !ingroup || !noraidgroup || raidgroup + QuestStatusData& q_status = mQuestStatus[questid]; + if( q_status.m_status == QUEST_STATUS_INCOMPLETE && (!GetGroup() || !GetGroup()->isRaidGroup() || qInfo->GetType() == QUEST_TYPE_RAID)) + { + if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_KILL_OR_CAST) ) + { + for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) + { + // skip GO activate objective or none + if(qInfo->ReqCreatureOrGOId[j] <=0) + continue; + + // skip Cast at creature objective + if(qInfo->ReqSpell[j] !=0 ) + continue; + + uint32 reqkill = qInfo->ReqCreatureOrGOId[j]; + + if ( reqkill == entry ) + { + uint32 reqkillcount = qInfo->ReqCreatureOrGOCount[j]; + uint32 curkillcount = q_status.m_creatureOrGOcount[j]; + if ( curkillcount < reqkillcount ) + { + q_status.m_creatureOrGOcount[j] = curkillcount + addkillcount; + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + + SendQuestUpdateAddCreatureOrGo( qInfo, guid, j, curkillcount, addkillcount); + } + if ( CanCompleteQuest( questid ) ) + CompleteQuest( questid ); + + // same objective target can be in many active quests, but not in 2 objectives for single quest (code optimization). + continue; + } + } + } + } + } +} + +void Player::CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id ) +{ + bool isCreature = IS_CREATURE_GUID(guid); + + uint32 addCastCount = 1; + for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) + { + uint32 questid = GetQuestSlotQuestId(i); + if(!questid) + continue; + + Quest const* qInfo = objmgr.GetQuestTemplate(questid); + if ( !qInfo ) + continue; + + QuestStatusData& q_status = mQuestStatus[questid]; + + if ( q_status.m_status == QUEST_STATUS_INCOMPLETE ) + { + if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_KILL_OR_CAST ) ) + { + for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) + { + // skip kill creature objective (0) or wrong spell casts + if(qInfo->ReqSpell[j] != spell_id ) + continue; + + uint32 reqTarget = 0; + + if(isCreature) + { + // creature activate objectives + if(qInfo->ReqCreatureOrGOId[j] > 0) + // checked at quest_template loading + reqTarget = qInfo->ReqCreatureOrGOId[j]; + } + else + { + // GO activate objective + if(qInfo->ReqCreatureOrGOId[j] < 0) + // checked at quest_template loading + reqTarget = - qInfo->ReqCreatureOrGOId[j]; + } + + // other not this creature/GO related objectives + if( reqTarget != entry ) + continue; + + uint32 reqCastCount = qInfo->ReqCreatureOrGOCount[j]; + uint32 curCastCount = q_status.m_creatureOrGOcount[j]; + if ( curCastCount < reqCastCount ) + { + q_status.m_creatureOrGOcount[j] = curCastCount + addCastCount; + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + + SendQuestUpdateAddCreatureOrGo( qInfo, guid, j, curCastCount, addCastCount); + } + + if ( CanCompleteQuest( questid ) ) + CompleteQuest( questid ); + + // same objective target can be in many active quests, but not in 2 objectives for single quest (code optimization). + break; + } + } + } + } +} + +void Player::TalkedToCreature( uint32 entry, uint64 guid ) +{ + uint32 addTalkCount = 1; + for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) + { + uint32 questid = GetQuestSlotQuestId(i); + if(!questid) + continue; + + Quest const* qInfo = objmgr.GetQuestTemplate(questid); + if ( !qInfo ) + continue; + + QuestStatusData& q_status = mQuestStatus[questid]; + + if ( q_status.m_status == QUEST_STATUS_INCOMPLETE ) + { + if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_KILL_OR_CAST | QUEST_MANGOS_FLAGS_SPEAKTO ) ) + { + for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) + { + // skip spell casts and Gameobject objectives + if(qInfo->ReqSpell[j] > 0 || qInfo->ReqCreatureOrGOId[j] < 0) + continue; + + uint32 reqTarget = 0; + + if(qInfo->ReqCreatureOrGOId[j] > 0) // creature activate objectives + // checked at quest_template loading + reqTarget = qInfo->ReqCreatureOrGOId[j]; + else + continue; + + if ( reqTarget == entry ) + { + uint32 reqTalkCount = qInfo->ReqCreatureOrGOCount[j]; + uint32 curTalkCount = q_status.m_creatureOrGOcount[j]; + if ( curTalkCount < reqTalkCount ) + { + q_status.m_creatureOrGOcount[j] = curTalkCount + addTalkCount; + if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + + SendQuestUpdateAddCreatureOrGo( qInfo, guid, j, curTalkCount, addTalkCount); + } + if ( CanCompleteQuest( questid ) ) + CompleteQuest( questid ); + + // same objective target can be in many active quests, but not in 2 objectives for single quest (code optimization). + continue; + } + } + } + } + } +} + +void Player::MoneyChanged( uint32 count ) +{ + for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ ) + { + uint32 questid = GetQuestSlotQuestId(i); + if (!questid) + continue; + + Quest const* qInfo = objmgr.GetQuestTemplate(questid); + if( qInfo && qInfo->GetRewOrReqMoney() < 0 ) + { + QuestStatusData& q_status = mQuestStatus[questid]; + + if( q_status.m_status == QUEST_STATUS_INCOMPLETE ) + { + if(int32(count) >= -qInfo->GetRewOrReqMoney()) + { + if ( CanCompleteQuest( questid ) ) + CompleteQuest( questid ); + } + } + else if( q_status.m_status == QUEST_STATUS_COMPLETE ) + { + if(int32(count) < -qInfo->GetRewOrReqMoney()) + IncompleteQuest( questid ); + } + } + } +} + +bool Player::HasQuestForItem( uint32 itemid ) const +{ + for( QuestStatusMap::const_iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i ) + { + QuestStatusData const& q_status = i->second; + + if (q_status.m_status == QUEST_STATUS_INCOMPLETE) + { + Quest const* qinfo = objmgr.GetQuestTemplate(i->first); + if(!qinfo) + continue; + + // hide quest if player is in raid-group and quest is no raid quest + if(GetGroup() && GetGroup()->isRaidGroup() && qinfo->GetType() != QUEST_TYPE_RAID) + continue; + + // There should be no mixed ReqItem/ReqSource drop + // This part for ReqItem drop + for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) + { + if(itemid == qinfo->ReqItemId[j] && q_status.m_itemcount[j] < qinfo->ReqItemCount[j] ) + return true; + } + // This part - for ReqSource + for (int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; j++) + { + // examined item is a source item + if (qinfo->ReqSourceId[j] == itemid && qinfo->ReqSourceRef[j] > 0 && qinfo->ReqSourceRef[j] <= QUEST_OBJECTIVES_COUNT) + { + uint32 idx = qinfo->ReqSourceRef[j]-1; + + // total count of created ReqItems and SourceItems is less than ReqItemCount + if(qinfo->ReqItemId[idx] != 0 && + q_status.m_itemcount[idx] * qinfo->ReqSourceCount[j] + GetItemCount(itemid,true) < qinfo->ReqItemCount[idx] * qinfo->ReqSourceCount[j]) + return true; + + // total count of casted ReqCreatureOrGOs and SourceItems is less than ReqCreatureOrGOCount + if (qinfo->ReqCreatureOrGOId[idx] != 0) + { + if(q_status.m_creatureOrGOcount[idx] * qinfo->ReqSourceCount[j] + GetItemCount(itemid,true) < qinfo->ReqCreatureOrGOCount[idx] * qinfo->ReqSourceCount[j]) + return true; + } + // spell with SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT (with script) case + else if(qinfo->ReqSpell[idx] != 0) + { + // not casted and need more reagents/item for use. + if(!q_status.m_explored && GetItemCount(itemid,true) < qinfo->ReqSourceCount[j]) + return true; + } + } + } + } + } + return false; +} + +void Player::SendQuestComplete( uint32 quest_id ) +{ + if( quest_id ) + { + WorldPacket data( SMSG_QUESTUPDATE_COMPLETE, 4 ); + data << quest_id; + GetSession()->SendPacket( &data ); + sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_COMPLETE quest = %u", quest_id ); + } +} + +void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGiver ) +{ + uint32 questid = pQuest->GetQuestId(); + sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid ); + WorldPacket data( SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4+4+pQuest->GetRewItemsCount()*8) ); + data << questid; + data << uint32(0x03); + + if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) + { + data << XP; + data << uint32(pQuest->GetRewOrReqMoney()); + } + else + { + data << uint32(0); + data << uint32(pQuest->GetRewOrReqMoney() + int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY))); + } + data << uint32(0); // new 2.3.0, HonorPoints? + data << uint32( pQuest->GetRewItemsCount() ); // max is 5 + + for (uint32 i = 0; i < pQuest->GetRewItemsCount(); ++i) + { + if ( pQuest->RewItemId[i] > 0 ) + data << pQuest->RewItemId[i] << pQuest->RewItemCount[i]; + else + data << uint32(0) << uint32(0); + } + GetSession()->SendPacket( &data ); + + if (pQuest->GetQuestCompleteScript() != 0) + sWorld.ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this); +} + +void Player::SendQuestFailed( uint32 quest_id ) +{ + if( quest_id ) + { + WorldPacket data( SMSG_QUESTGIVER_QUEST_FAILED, 4 ); + data << quest_id; + GetSession()->SendPacket( &data ); + sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED"); + } +} + +void Player::SendQuestTimerFailed( uint32 quest_id ) +{ + if( quest_id ) + { + WorldPacket data( SMSG_QUESTUPDATE_FAILEDTIMER, 4 ); + data << quest_id; + GetSession()->SendPacket( &data ); + sLog.outDebug("WORLD: Sent SMSG_QUESTUPDATE_FAILEDTIMER"); + } +} + +void Player::SendCanTakeQuestResponse( uint32 msg ) +{ + WorldPacket data( SMSG_QUESTGIVER_QUEST_INVALID, 4 ); + data << uint32(msg); + GetSession()->SendPacket( &data ); + sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_INVALID"); +} + +void Player::SendPushToPartyResponse( Player *pPlayer, uint32 msg ) +{ + if( pPlayer ) + { + WorldPacket data( MSG_QUEST_PUSH_RESULT, (8+1) ); + data << uint64(pPlayer->GetGUID()); + data << uint8(msg); // valid values: 0-8 + GetSession()->SendPacket( &data ); + sLog.outDebug("WORLD: Sent MSG_QUEST_PUSH_RESULT"); + } +} + +void Player::SendQuestUpdateAddItem( Quest const* pQuest, uint32 item_idx, uint32 count ) +{ + WorldPacket data( SMSG_QUESTUPDATE_ADD_ITEM, (4+4) ); + sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_ITEM" ); + data << pQuest->ReqItemId[item_idx]; + data << count; + GetSession()->SendPacket( &data ); +} + +void Player::SendQuestUpdateAddCreatureOrGo( Quest const* pQuest, uint64 guid, uint32 creatureOrGO_idx, uint32 old_count, uint32 add_count ) +{ + assert(old_count + add_count < 256 && "mob/GO count store in 8 bits 2^8 = 256 (0..256)"); + + int32 entry = pQuest->ReqCreatureOrGOId[ creatureOrGO_idx ]; + if (entry < 0) + // client expected gameobject template id in form (id|0x80000000) + entry = (-entry) | 0x80000000; + + WorldPacket data( SMSG_QUESTUPDATE_ADD_KILL, (4*4+8) ); + sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_KILL" ); + data << uint32(pQuest->GetQuestId()); + data << uint32(entry); + data << uint32(old_count + add_count); + data << uint32(pQuest->ReqCreatureOrGOCount[ creatureOrGO_idx ]); + data << uint64(guid); + GetSession()->SendPacket(&data); + + uint16 log_slot = FindQuestSlot( pQuest->GetQuestId() ); + if( log_slot < MAX_QUEST_LOG_SIZE) + SetQuestSlotCounter(log_slot,creatureOrGO_idx,GetQuestSlotCounter(log_slot,creatureOrGO_idx)+add_count); +} + +/*********************************************************/ +/*** LOAD SYSTEM ***/ +/*********************************************************/ + +bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid ) +{ + bool delete_result = true; + if(!result) + { + // 0 1 2 3 4 5 6 7 8 + result = CharacterDatabase.PQuery("SELECT data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login FROM characters WHERE guid = '%u'",guid); + if(!result) return false; + } + else delete_result = false; + + Field *fields = result->Fetch(); + + if(!LoadValues( fields[0].GetString())) + { + sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid)); + if(delete_result) delete result; + return false; + } + + // overwrite possible wrong/corrupted guid + SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); + + m_name = fields[1].GetCppString(); + + Relocate(fields[2].GetFloat(),fields[3].GetFloat(),fields[4].GetFloat()); + SetMapId(fields[5].GetUInt32()); + // the instance id is not needed at character enum + + m_Played_time[0] = fields[6].GetUInt32(); + m_Played_time[1] = fields[7].GetUInt32(); + + m_atLoginFlags = fields[8].GetUInt32(); + + // I don't see these used anywhere .. + /*_LoadGroup(); + + _LoadBoundInstances();*/ + + if (delete_result) delete result; + + for (int i = 0; i < PLAYER_SLOTS_COUNT; i++) + m_items[i] = NULL; + + if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST) ) + m_deathState = DEAD; + + return true; +} + +void Player::_LoadDeclinedNames(QueryResult* result) +{ + if(!result) + return; + + if(m_declinedname) + delete m_declinedname; + + m_declinedname = new DeclinedName; + Field *fields = result->Fetch(); + for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + m_declinedname->name[i] = fields[i].GetCppString(); + + delete result; +} + +bool Player::LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid) +{ + QueryResult *result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,taxi_path FROM characters WHERE guid = '%u'",GUID_LOPART(guid)); + if(!result) + return false; + + Field *fields = result->Fetch(); + + x = fields[0].GetFloat(); + y = fields[1].GetFloat(); + z = fields[2].GetFloat(); + o = fields[3].GetFloat(); + mapid = fields[4].GetUInt32(); + in_flight = !fields[5].GetCppString().empty(); + + delete result; + return true; +} + +bool Player::LoadValuesArrayFromDB(Tokens& data, uint64 guid) +{ + QueryResult *result = CharacterDatabase.PQuery("SELECT data FROM characters WHERE guid='%u'",GUID_LOPART(guid)); + if( !result ) + return false; + + Field *fields = result->Fetch(); + + data = StrSplit(fields[0].GetCppString(), " "); + + delete result; + + return true; +} + +uint32 Player::GetUInt32ValueFromArray(Tokens const& data, uint16 index) +{ + if(index >= data.size()) + return 0; + + return (uint32)atoi(data[index].c_str()); +} + +float Player::GetFloatValueFromArray(Tokens const& data, uint16 index) +{ + float result; + uint32 temp = Player::GetUInt32ValueFromArray(data,index); + memcpy(&result, &temp, sizeof(result)); + + return result; +} + +uint32 Player::GetUInt32ValueFromDB(uint16 index, uint64 guid) +{ + Tokens data; + if(!LoadValuesArrayFromDB(data,guid)) + return 0; + + return GetUInt32ValueFromArray(data,index); +} + +float Player::GetFloatValueFromDB(uint16 index, uint64 guid) +{ + float result; + uint32 temp = Player::GetUInt32ValueFromDB(index, guid); + memcpy(&result, &temp, sizeof(result)); + + return result; +} + +bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) +{ + //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [28] [29] 30 31 32 + //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, gmstate, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty FROM characters WHERE guid = '%u'", guid); + QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM); + + if(!result) + { + sLog.outError("ERROR: Player (GUID: %u) not found in table `characters`, can't load. ",guid); + return false; + } + + Field *fields = result->Fetch(); + + uint32 dbAccountId = fields[1].GetUInt32(); + + // check if the character's account in the db and the logged in account match. + // player should be able to load/delete character only with correct account! + if( dbAccountId != GetSession()->GetAccountId() ) + { + sLog.outError("ERROR: Player (GUID: %u) loading from wrong account (is: %u, should be: %u)",guid,GetSession()->GetAccountId(),dbAccountId); + delete result; + return false; + } + + Object::_Create( guid, 0, HIGHGUID_PLAYER ); + + m_name = fields[3].GetCppString(); + + // check name limitations + if(!ObjectMgr::IsValidName(m_name) || GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name)) + { + delete result; + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid); + return false; + } + + if(!LoadValues( fields[2].GetString())) + { + sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid)); + delete result; + return false; + } + + // overwrite possible wrong/corrupted guid + SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); + + // cleanup inventory related item value fields (its will be filled correctly in _LoadInventory) + for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) + { + SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), 0 ); + SetVisibleItemSlot(slot,NULL); + + if (m_items[slot]) + { + delete m_items[slot]; + m_items[slot] = NULL; + } + } + + // update money limits + if(GetMoney() > MAX_MONEY_AMOUNT) + SetMoney(MAX_MONEY_AMOUNT); + + sLog.outDebug("Load Basic value of player %s is: ", m_name.c_str()); + outDebugValues(); + + m_race = fields[4].GetUInt8(); + //Need to call it to initialize m_team (m_team can be calculated from m_race) + //Other way is to saves m_team into characters table. + setFactionForRace(m_race); + SetCharm(0); + + m_class = fields[5].GetUInt8(); + + PlayerInfo const *info = objmgr.GetPlayerInfo(m_race, m_class); + if(!info) + { + sLog.outError("Player have incorrect race/class pair. Can't be loaded."); + delete result; + return false; + } + + InitPrimaryProffesions(); // to max set before any spell loaded + + uint32 transGUID = fields[24].GetUInt32(); + Relocate(fields[6].GetFloat(),fields[7].GetFloat(),fields[8].GetFloat(),fields[10].GetFloat()); + SetMapId(fields[9].GetUInt32()); + SetDifficulty(fields[32].GetUInt32()); // may be changed in _LoadGroup + + _LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP)); + + // check arena teams integrity + for(uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) + { + uint32 arena_team_id = GetArenaTeamId(arena_slot); + if(!arena_team_id) + continue; + + if(ArenaTeam * at = objmgr.GetArenaTeamById(arena_team_id)) + if(at->HaveMember(GetGUID())) + continue; + + // arena team not exist or not member, cleanup fields + for(int j =0; j < 6; ++j) + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arena_slot * 6 + j, 0); + } + + _LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES)); + + if(!IsPositionValid()) + { + sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + + SetMapId(info->mapId); + Relocate(info->positionX,info->positionY,info->positionZ,0.0f); + + transGUID = 0; + + m_movementInfo.t_x = 0.0f; + m_movementInfo.t_y = 0.0f; + m_movementInfo.t_z = 0.0f; + m_movementInfo.t_o = 0.0f; + } + + // load the player's map here if it's not already loaded + Map *map = GetMap(); + // since the player may not be bound to the map yet, make sure subsequent + // getmap calls won't create new maps + SetInstanceId(map->GetInstanceId()); + + SaveRecallPosition(); + + if (transGUID != 0) + { + m_movementInfo.t_x = fields[20].GetFloat(); + m_movementInfo.t_y = fields[21].GetFloat(); + m_movementInfo.t_z = fields[22].GetFloat(); + m_movementInfo.t_o = fields[23].GetFloat(); + + if( !MaNGOS::IsValidMapCoord( + GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y, + GetPositionZ()+m_movementInfo.t_z,GetOrientation()+m_movementInfo.t_o) || + // transport size limited + m_movementInfo.t_x > 50 || m_movementInfo.t_y > 50 || m_movementInfo.t_z > 50 ) + { + sLog.outError("ERROR: Player (guidlow %d) have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.", + guid,GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y, + GetPositionZ()+m_movementInfo.t_z,GetOrientation()+m_movementInfo.t_o); + + SetMapId(info->mapId); + Relocate(info->positionX,info->positionY,info->positionZ,0.0f); + + m_movementInfo.t_x = 0.0f; + m_movementInfo.t_y = 0.0f; + m_movementInfo.t_z = 0.0f; + m_movementInfo.t_o = 0.0f; + + transGUID = 0; + } + } + + if (transGUID != 0) + { + for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) + { + if( (*iter)->GetGUIDLow() == transGUID) + { + m_transport = *iter; + m_transport->AddPassenger(this); + SetMapId(m_transport->GetMapId()); + break; + } + } + + if(!m_transport) + { + sLog.outError("ERROR: Player (guidlow %d) have invalid transport guid (%u). Teleport to default race/class locations.", + guid,transGUID); + + SetMapId(info->mapId); + Relocate(info->positionX,info->positionY,info->positionZ,0.0f); + + m_movementInfo.t_x = 0.0f; + m_movementInfo.t_y = 0.0f; + m_movementInfo.t_z = 0.0f; + m_movementInfo.t_o = 0.0f; + + transGUID = 0; + } + } + + time_t now = time(NULL); + time_t logoutTime = time_t(fields[16].GetUInt64()); + + // since last logout (in seconds) + uint64 time_diff = uint64(now - logoutTime); + + // set value, including drunk invisibility detection + // calculate sobering. after 15 minutes logged out, the player will be sober again + float soberFactor; + if(time_diff > 15*MINUTE) + soberFactor = 0; + else + soberFactor = 1-time_diff/(15.0f*MINUTE); + uint16 newDrunkenValue = uint16(soberFactor*(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE)); + SetDrunkValue(newDrunkenValue); + + m_rest_bonus = fields[15].GetFloat(); + //speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour) + float bubble0 = 0.031; + //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour) + float bubble1 = 0.125; + + if((int32)fields[16].GetUInt32() > 0) + { + float bubble = fields[17].GetUInt32() > 0 + ? bubble1*sWorld.getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY) + : bubble0*sWorld.getRate(RATE_REST_OFFLINE_IN_WILDERNESS); + + SetRestBonus(GetRestBonus()+ time_diff*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble); + } + + m_cinematic = fields[12].GetUInt32(); + m_Played_time[0]= fields[13].GetUInt32(); + m_Played_time[1]= fields[14].GetUInt32(); + + m_resetTalentsCost = fields[18].GetUInt32(); + m_resetTalentsTime = time_t(fields[19].GetUInt64()); + + // reserve some flags + uint32 old_safe_flags = GetUInt32Value(PLAYER_FLAGS) & ( PLAYER_FLAGS_HIDE_CLOAK | PLAYER_FLAGS_HIDE_HELM ); + + if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM) ) + SetUInt32Value(PLAYER_FLAGS, 0 | old_safe_flags); + + m_taxi.LoadTaxiMask( fields[11].GetString() ); // must be before InitTaxiNodesForLevel + + uint32 gmstate = fields[25].GetUInt32(); + + m_stableSlots = fields[26].GetUInt32(); + if(m_stableSlots > 2) + { + sLog.outError("Player can have not more 2 stable slots, but have in DB %u",uint32(m_stableSlots)); + m_stableSlots = 2; + } + + m_atLoginFlags = fields[27].GetUInt32(); + + // Honor system + // Update Honor kills data + m_lastHonorUpdateTime = logoutTime; + UpdateHonorFields(); + + m_deathExpireTime = (time_t)fields[30].GetUInt64(); + if(m_deathExpireTime > now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP) + m_deathExpireTime = now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP-1; + + std::string taxi_nodes = fields[31].GetCppString(); + + delete result; + + // clear channel spell data (if saved at channel spell casting) + SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0); + SetUInt32Value(UNIT_CHANNEL_SPELL,0); + + // clear charm/summon related fields + SetUInt64Value(UNIT_FIELD_CHARM,0); + SetUInt64Value(UNIT_FIELD_SUMMON,0); + SetUInt64Value(UNIT_FIELD_CHARMEDBY,0); + SetUInt64Value(UNIT_FIELD_SUMMONEDBY,0); + SetUInt64Value(UNIT_FIELD_CREATEDBY,0); + + // reset some aura modifiers before aura apply + SetUInt64Value(PLAYER_FARSIGHT, 0); + SetUInt32Value(PLAYER_TRACK_CREATURES, 0 ); + SetUInt32Value(PLAYER_TRACK_RESOURCES, 0 ); + + // reset skill modifiers and set correct unlearn flags + for (uint32 i = 0; i < PLAYER_MAX_SKILLS; i++) + { + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); + + // set correct unlearn bit + uint32 id = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; + if(!id) continue; + + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); + if(!pSkill) continue; + + // enable unlearn button for primary professions only + if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) + SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); + else + SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); + } + + // make sure the unit is considered out of combat for proper loading + ClearInCombat(); + + // make sure the unit is considered not in duel for proper loading + SetUInt64Value(PLAYER_DUEL_ARBITER, 0); + SetUInt32Value(PLAYER_DUEL_TEAM, 0); + + // remember loaded power/health values to restore after stats initialization and modifier applying + uint32 savedHealth = GetHealth(); + uint32 savedPower[MAX_POWERS]; + for(uint32 i = 0; i < MAX_POWERS; ++i) + savedPower[i] = GetPower(Powers(i)); + + // reset stats before loading any modifiers + InitStatsForLevel(); + InitTaxiNodesForLevel(); + + // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods() + + //mails are loaded only when needed ;-) - when player in game click on mailbox. + //_LoadMail(); + + _LoadAuras(holder->GetResult(PLAYER_LOGIN_QUERY_LOADAURAS), time_diff); + + // add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura) + if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST) ) + m_deathState = DEAD; + + _LoadSpells(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSPELLS)); + + // after spell load + InitTalentForLevel(); + learnSkillRewardedSpells(); + + // after spell load, learn rewarded spell if need also + _LoadQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS)); + _LoadDailyQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS)); + + _LoadTutorials(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTUTORIALS)); + + // must be before inventory (some items required reputation check) + _LoadReputation(holder->GetResult(PLAYER_LOGIN_QUERY_LOADREPUTATION)); + + _LoadInventory(holder->GetResult(PLAYER_LOGIN_QUERY_LOADINVENTORY), time_diff); + + // update items with duration and realtime + UpdateItemDuration(time_diff, true); + + _LoadActions(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACTIONS)); + + // unread mails and next delivery time, actual mails not loaded + _LoadMailInit(holder->GetResult(PLAYER_LOGIN_QUERY_LOADMAILCOUNT), holder->GetResult(PLAYER_LOGIN_QUERY_LOADMAILDATE)); + + m_social = sSocialMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSOCIALLIST), GetGUIDLow()); + + if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND))) + return false; + + // check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES + // note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded + if(uint32 curTitle = GetUInt32Value(PLAYER_CHOSEN_TITLE)) + { + if(!HasFlag64(PLAYER__FIELD_KNOWN_TITLES,uint64(1) << curTitle)) + SetUInt32Value(PLAYER_CHOSEN_TITLE,0); + } + + // Not finish taxi flight path + if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes)) + { + // problems with taxi path loading + TaxiNodesEntry const* nodeEntry = NULL; + if(uint32 node_id = m_taxi.GetTaxiSource()) + nodeEntry = sTaxiNodesStore.LookupEntry(node_id); + + if(!nodeEntry) // don't know taxi start node, to homebind + { + sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow()); + SetMapId(m_homebindMapId); + Relocate( m_homebindX, m_homebindY, m_homebindZ,0.0f); + SaveRecallPosition(); // save as recall also to prevent recall and fall from sky + } + else // have start node, to it + { + sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow()); + SetMapId(nodeEntry->map_id); + Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f); + SaveRecallPosition(); // save as recall also to prevent recall and fall from sky + } + m_taxi.ClearTaxiDestinations(); + } + else if(uint32 node_id = m_taxi.GetTaxiSource()) + { + // save source node as recall coord to prevent recall and fall from sky + TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id); + assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString + m_recallMap = nodeEntry->map_id; + m_recallX = nodeEntry->x; + m_recallY = nodeEntry->y; + m_recallZ = nodeEntry->z; + + // flight will started later + } + + _LoadSpellCooldowns(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS)); + + // Spell code allow apply any auras to dead character in load time in aura/spell/item loading + // Do now before stats re-calculation cleanup for ghost state unexpected auras + if(!isAlive()) + RemoveAllAurasOnDeath(); + + //apply all stat bonuses from items and auras + SetCanModifyStats(true); + UpdateAllStats(); + + // restore remembered power/health values (but not more max values) + SetHealth(savedHealth > GetMaxHealth() ? GetMaxHealth() : savedHealth); + for(uint32 i = 0; i < MAX_POWERS; ++i) + SetPower(Powers(i),savedPower[i] > GetMaxPower(Powers(i)) ? GetMaxPower(Powers(i)) : savedPower[i]); + + sLog.outDebug("The value of player %s after load item and aura is: ", m_name.c_str()); + outDebugValues(); + + // GM state + if(GetSession()->GetSecurity() > SEC_PLAYER) + { + switch(sWorld.getConfig(CONFIG_GM_LOGIN_STATE)) + { + case 0: // disable + break; + case 1: // enable + SetGameMaster(true); + break; + case 2: // save state + if(gmstate) + SetGameMaster(true); + break; + default: + break; + } + } + + _LoadDeclinedNames(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES)); + + return true; +} + +bool Player::isAllowedToLoot(Creature* creature) +{ + if(Player* recipient = creature->GetLootRecipient()) + { + if (recipient == this) + return true; + if( Group* otherGroup = recipient->GetGroup()) + { + Group* thisGroup = GetGroup(); + if(!thisGroup) + return false; + return thisGroup == otherGroup; + } + return false; + } + else + // prevent other players from looting if the recipient got disconnected + return !creature->hasLootRecipient(); +} + +void Player::_LoadActions(QueryResult *result) +{ + m_actionButtons.clear(); + + //QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button",GetGUIDLow()); + + if(result) + { + do + { + Field *fields = result->Fetch(); + + uint8 button = fields[0].GetUInt8(); + + addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8()); + + m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED; + } + while( result->NextRow() ); + + delete result; + } +} + +void Player::_LoadAuras(QueryResult *result, uint32 timediff) +{ + m_Auras.clear(); + for (int i = 0; i < TOTAL_AURAS; i++) + m_modAuras[i].clear(); + + // all aura related fields + for(int i = UNIT_FIELD_AURA; i <= UNIT_FIELD_AURASTATE; ++i) + SetUInt32Value(i, 0); + + //QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'",GetGUIDLow()); + + if(result) + { + do + { + Field *fields = result->Fetch(); + uint64 caster_guid = fields[0].GetUInt64(); + uint32 spellid = fields[1].GetUInt32(); + uint32 effindex = fields[2].GetUInt32(); + int32 damage = (int32)fields[3].GetUInt32(); + int32 maxduration = (int32)fields[4].GetUInt32(); + int32 remaintime = (int32)fields[5].GetUInt32(); + int32 remaincharges = (int32)fields[6].GetUInt32(); + + SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid); + if(!spellproto) + { + sLog.outError("Unknown aura (spellid %u, effindex %u), ignore.",spellid,effindex); + continue; + } + + if(effindex >= 3) + { + sLog.outError("Invalid effect index (spellid %u, effindex %u), ignore.",spellid,effindex); + continue; + } + + // negative effects should continue counting down after logout + if (remaintime != -1 && !IsPositiveEffect(spellid, effindex)) + { + if(remaintime <= int32(timediff)) + continue; + + remaintime -= timediff; + } + + // prevent wrong values of remaincharges + if(spellproto->procCharges) + { + if(remaincharges <= 0 || remaincharges > spellproto->procCharges) + remaincharges = spellproto->procCharges; + } + else + remaincharges = -1; + + //do not load single target auras (unless they were cast by the player) + if (caster_guid != GetGUID() && IsSingleTargetSpell(spellproto)) + continue; + + Aura* aura = CreateAura(spellproto, effindex, NULL, this, NULL); + if(!damage) + damage = aura->GetModifier()->m_amount; + aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges); + AddAura(aura); + } + while( result->NextRow() ); + + delete result; + } + + if(m_class == CLASS_WARRIOR) + CastSpell(this,SPELL_ID_PASSIVE_BATTLE_STANCE,true); +} + +void Player::LoadCorpse() +{ + if( isAlive() ) + { + ObjectAccessor::Instance().ConvertCorpseForPlayer(GetGUID()); + } + else + { + if(Corpse *corpse = GetCorpse()) + { + ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, corpse && !sMapStore.LookupEntry(corpse->GetMapId())->Instanceable() ); + } + else + { + //Prevent Dead Player login without corpse + ResurrectPlayer(0.5f); + } + } +} + +void Player::_LoadInventory(QueryResult *result, uint32 timediff) +{ + //QueryResult *result = CharacterDatabase.PQuery("SELECT data,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GetGUIDLow()); + std::map bagMap; // fast guid lookup for bags + //NOTE: the "order by `bag`" is important because it makes sure + //the bagMap is filled before items in the bags are loaded + //NOTE2: the "order by `slot`" is needed becaue mainhand weapons are (wrongly?) + //expected to be equipped before offhand items (TODO: fixme) + + uint32 zone = GetZoneId(); + + if (result) + { + std::list problematicItems; + + // prevent items from being added to the queue when stored + m_itemUpdateQueueBlocked = true; + do + { + Field *fields = result->Fetch(); + uint32 bag_guid = fields[1].GetUInt32(); + uint8 slot = fields[2].GetUInt8(); + uint32 item_guid = fields[3].GetUInt32(); + uint32 item_id = fields[4].GetUInt32(); + + ItemPrototype const * proto = objmgr.GetItemPrototype(item_id); + + if(!proto) + { + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid); + sLog.outError( "Player::_LoadInventory: Player %s has an unknown item (id: #%u) in inventory, deleted.", GetName(),item_id ); + continue; + } + + Item *item = NewItemOrBag(proto); + + if(!item->LoadFromDB(item_guid, GetGUID(), result)) + { + sLog.outError( "Player::_LoadInventory: Player %s has broken item (id: #%u) in inventory, deleted.", GetName(),item_id ); + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); + item->FSetState(ITEM_REMOVED); + item->SaveToDB(); // it also deletes item object ! + continue; + } + + // not allow have in alive state item limited to another map/zone + if(isAlive() && item->IsLimitedToAnotherMapOrZone(GetMapId(),zone) ) + { + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); + item->FSetState(ITEM_REMOVED); + item->SaveToDB(); // it also deletes item object ! + continue; + } + + // "Conjured items disappear if you are logged out for more than 15 minutes" + if ((timediff > 15*60) && (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED))) + { + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); + item->FSetState(ITEM_REMOVED); + item->SaveToDB(); // it also deletes item object ! + continue; + } + + bool success = true; + + if (!bag_guid) + { + // the item is not in a bag + item->SetContainer( NULL ); + item->SetSlot(slot); + + if( IsInventoryPos( INVENTORY_SLOT_BAG_0, slot ) ) + { + ItemPosCountVec dest; + if( CanStoreItem( INVENTORY_SLOT_BAG_0, slot, dest, item, false ) == EQUIP_ERR_OK ) + item = StoreItem(dest, item, true); + else + success = false; + } + else if( IsEquipmentPos( INVENTORY_SLOT_BAG_0, slot ) ) + { + uint16 dest; + if( CanEquipItem( slot, dest, item, false, false ) == EQUIP_ERR_OK ) + QuickEquipItem(dest, item); + else + success = false; + } + else if( IsBankPos( INVENTORY_SLOT_BAG_0, slot ) ) + { + ItemPosCountVec dest; + if( CanBankItem( INVENTORY_SLOT_BAG_0, slot, dest, item, false, false ) == EQUIP_ERR_OK ) + item = BankItem(dest, item, true); + else + success = false; + } + + if(success) + { + // store bags that may contain items in them + if(item->IsBag() && IsBagPos(item->GetPos())) + bagMap[item_guid] = (Bag*)item; + } + } + else + { + item->SetSlot(NULL_SLOT); + // the item is in a bag, find the bag + std::map::iterator itr = bagMap.find(bag_guid); + if(itr != bagMap.end()) + itr->second->StoreItem(slot, item, true ); + else + success = false; + } + + // item's state may have changed after stored + if (success) + item->SetState(ITEM_UNCHANGED, this); + else + { + sLog.outError("Player::_LoadInventory: Player %s has item (GUID: %u Entry: %u) can't be loaded to inventory (Bag GUID: %u Slot: %u) by some reason, will send by mail.", GetName(),item_guid, item_id, bag_guid, slot); + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid); + problematicItems.push_back(item); + } + } while (result->NextRow()); + + delete result; + m_itemUpdateQueueBlocked = false; + + // send by mail problematic items + while(!problematicItems.empty()) + { + // fill mail + MailItemsInfo mi; // item list prepering + + for(int i = 0; !problematicItems.empty() && i < MAX_MAIL_ITEMS; ++i) + { + Item* item = problematicItems.front(); + problematicItems.pop_front(); + + mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); + } + + std::string subject = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM); + + WorldSession::SendMailTo(this, MAIL_NORMAL, MAIL_STATIONERY_GM, GetGUIDLow(), GetGUIDLow(), subject, 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE); + } + } + //if(isAlive()) + _ApplyAllItemMods(); +} + +// load mailed item which should receive current player +void Player::_LoadMailedItems(Mail *mail) +{ + QueryResult* result = CharacterDatabase.PQuery("SELECT item_guid, item_template FROM mail_items WHERE mail_id='%u'", mail->messageID); + if(!result) + return; + + do + { + Field *fields = result->Fetch(); + uint32 item_guid_low = fields[0].GetUInt32(); + uint32 item_template = fields[1].GetUInt32(); + + mail->AddItem(item_guid_low, item_template); + + ItemPrototype const *proto = objmgr.GetItemPrototype(item_template); + + if(!proto) + { + sLog.outError( "Player %u have unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID); + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low); + continue; + } + + Item *item = NewItemOrBag(proto); + + if(!item->LoadFromDB(item_guid_low, 0)) + { + sLog.outError( "Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, item_guid_low); + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); + item->FSetState(ITEM_REMOVED); + item->SaveToDB(); // it also deletes item object ! + continue; + } + + AddMItem(item); + } while (result->NextRow()); + + delete result; +} + +void Player::_LoadMailInit(QueryResult *resultUnread, QueryResult *resultDelivery) +{ + //set a count of unread mails + //QueryResult *resultMails = CharacterDatabase.PQuery("SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" I64FMTD "'", GUID_LOPART(playerGuid),(uint64)cTime); + if (resultUnread) + { + Field *fieldMail = resultUnread->Fetch(); + unReadMails = fieldMail[0].GetUInt8(); + delete resultUnread; + } + + // store nearest delivery time (it > 0 and if it < current then at next player update SendNewMaill will be called) + //resultMails = CharacterDatabase.PQuery("SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(playerGuid)); + if (resultDelivery) + { + Field *fieldMail = resultDelivery->Fetch(); + m_nextMailDelivereTime = (time_t)fieldMail[0].GetUInt64(); + delete resultDelivery; + } +} + +void Player::_LoadMail() +{ + m_mail.clear(); + //mails are in right order 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + QueryResult *result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,subject,itemTextId,has_items,expire_time,deliver_time,money,cod,checked,stationery,mailTemplateId FROM mail WHERE receiver = '%u' ORDER BY id DESC",GetGUIDLow()); + if(result) + { + do + { + Field *fields = result->Fetch(); + Mail *m = new Mail; + m->messageID = fields[0].GetUInt32(); + m->messageType = fields[1].GetUInt8(); + m->sender = fields[2].GetUInt32(); + m->receiver = fields[3].GetUInt32(); + m->subject = fields[4].GetCppString(); + m->itemTextId = fields[5].GetUInt32(); + bool has_items = fields[6].GetBool(); + m->expire_time = (time_t)fields[7].GetUInt64(); + m->deliver_time = (time_t)fields[8].GetUInt64(); + m->money = fields[9].GetUInt32(); + m->COD = fields[10].GetUInt32(); + m->checked = fields[11].GetUInt32(); + m->stationery = fields[12].GetUInt8(); + m->mailTemplateId = fields[13].GetInt16(); + + if(m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId)) + { + sLog.outError( "Player::_LoadMail - Mail (%u) have not existed MailTemplateId (%u), remove at load", m->messageID, m->mailTemplateId); + m->mailTemplateId = 0; + } + + m->state = MAIL_STATE_UNCHANGED; + + if (has_items) + _LoadMailedItems(m); + + m_mail.push_back(m); + } while( result->NextRow() ); + delete result; + } + m_mailsLoaded = true; +} + +void Player::LoadPet() +{ + //fixme: the pet should still be loaded if the player is not in world + // just not added to the map + if(IsInWorld()) + { + Pet *pet = new Pet; + if(!pet->LoadPetFromDB(this,0,0,true)) + delete pet; + } +} + +void Player::_LoadQuestStatus(QueryResult *result) +{ + mQuestStatus.clear(); + + uint32 slot = 0; + + //// 0 1 2 3 4 5 6 7 8 9 10 11 12 + //QueryResult *result = CharacterDatabase.PQuery("SELECT quest, status, rewarded, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, itemcount1, itemcount2, itemcount3, itemcount4 FROM character_queststatus WHERE guid = '%u'", GetGUIDLow()); + + if(result) + { + do + { + Field *fields = result->Fetch(); + + uint32 quest_id = fields[0].GetUInt32(); + // used to be new, no delete? + Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); + if( pQuest ) + { + // find or create + QuestStatusData& questStatusData = mQuestStatus[quest_id]; + + uint32 qstatus = fields[1].GetUInt32(); + if(qstatus < MAX_QUEST_STATUS) + questStatusData.m_status = QuestStatus(qstatus); + else + { + questStatusData.m_status = QUEST_STATUS_NONE; + sLog.outError("Player %s have invalid quest %d status (%d), replaced by QUEST_STATUS_NONE(0).",GetName(),quest_id,qstatus); + } + + questStatusData.m_rewarded = ( fields[2].GetUInt8() > 0 ); + questStatusData.m_explored = ( fields[3].GetUInt8() > 0 ); + + time_t quest_time = time_t(fields[4].GetUInt64()); + + if( pQuest->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) && !GetQuestRewardStatus(quest_id) && questStatusData.m_status != QUEST_STATUS_NONE ) + { + AddTimedQuest( quest_id ); + + if (quest_time <= sWorld.GetGameTime()) + questStatusData.m_timer = 1; + else + questStatusData.m_timer = (quest_time - sWorld.GetGameTime()) * 1000; + } + else + quest_time = 0; + + questStatusData.m_creatureOrGOcount[0] = fields[5].GetUInt32(); + questStatusData.m_creatureOrGOcount[1] = fields[6].GetUInt32(); + questStatusData.m_creatureOrGOcount[2] = fields[7].GetUInt32(); + questStatusData.m_creatureOrGOcount[3] = fields[8].GetUInt32(); + questStatusData.m_itemcount[0] = fields[9].GetUInt32(); + questStatusData.m_itemcount[1] = fields[10].GetUInt32(); + questStatusData.m_itemcount[2] = fields[11].GetUInt32(); + questStatusData.m_itemcount[3] = fields[12].GetUInt32(); + + questStatusData.uState = QUEST_UNCHANGED; + + // add to quest log + if( slot < MAX_QUEST_LOG_SIZE && + ( questStatusData.m_status==QUEST_STATUS_INCOMPLETE || + questStatusData.m_status==QUEST_STATUS_COMPLETE && !questStatusData.m_rewarded ) ) + { + SetQuestSlot(slot,quest_id,quest_time); + + if(questStatusData.m_status == QUEST_STATUS_COMPLETE) + SetQuestSlotState(slot,QUEST_STATE_COMPLETE); + + for(uint8 idx = 0; idx < QUEST_OBJECTIVES_COUNT; ++idx) + if(questStatusData.m_creatureOrGOcount[idx]) + SetQuestSlotCounter(slot,idx,questStatusData.m_creatureOrGOcount[idx]); + + ++slot; + } + + if(questStatusData.m_rewarded) + { + // learn rewarded spell if unknown + learnQuestRewardedSpells(pQuest); + + // set rewarded title if any + if(pQuest->GetCharTitleId()) + { + if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId())) + SetFlag64(PLAYER__FIELD_KNOWN_TITLES, (uint64(1) << titleEntry->bit_index)); + } + } + + sLog.outDebug("Quest status is {%u} for quest {%u} for player (GUID: %u)", questStatusData.m_status, quest_id, GetGUIDLow()); + } + } + while( result->NextRow() ); + + delete result; + } + + // clear quest log tail + for ( uint16 i = slot; i < MAX_QUEST_LOG_SIZE; ++i ) + SetQuestSlot(i,0); +} + +void Player::_LoadDailyQuestStatus(QueryResult *result) +{ + for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) + SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,0); + + //QueryResult *result = CharacterDatabase.PQuery("SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GetGUIDLow()); + + if(result) + { + uint32 quest_daily_idx = 0; + + do + { + if(quest_daily_idx >= PLAYER_MAX_DAILY_QUESTS) // max amount with exist data in query + { + sLog.outError("Player (GUID: %u) have more 25 daily quest records in `charcter_queststatus_daily`",GetGUIDLow()); + break; + } + + Field *fields = result->Fetch(); + + uint32 quest_id = fields[0].GetUInt32(); + + // save _any_ from daily quest times (it must be after last reset anyway) + m_lastDailyQuestTime = (time_t)fields[1].GetUInt64(); + + Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); + if( !pQuest ) + continue; + + SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,quest_id); + ++quest_daily_idx; + + sLog.outDebug("Daily quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUIDLow()); + } + while( result->NextRow() ); + + delete result; + } + + m_DailyQuestChanged = false; +} + +void Player::_LoadReputation(QueryResult *result) +{ + m_factions.clear(); + + // Set initial reputations (so everything is nifty before DB data load) + SetInitialFactions(); + + //QueryResult *result = CharacterDatabase.PQuery("SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'",GetGUIDLow()); + + if(result) + { + do + { + Field *fields = result->Fetch(); + + FactionEntry const *factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt32()); + if( factionEntry && (factionEntry->reputationListID >= 0)) + { + FactionState* faction = &m_factions[factionEntry->reputationListID]; + + // update standing to current + faction->Standing = int32(fields[1].GetUInt32()); + + uint32 dbFactionFlags = fields[2].GetUInt32(); + + if( dbFactionFlags & FACTION_FLAG_VISIBLE ) + SetFactionVisible(faction); // have internal checks for forced invisibility + + if( dbFactionFlags & FACTION_FLAG_INACTIVE) + SetFactionInactive(faction,true); // have internal checks for visibility requirement + + if( dbFactionFlags & FACTION_FLAG_AT_WAR ) // DB at war + SetFactionAtWar(faction,true); // have internal checks for FACTION_FLAG_PEACE_FORCED + else // DB not at war + { + // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN) + if( faction->Flags & FACTION_FLAG_VISIBLE ) + SetFactionAtWar(faction,false); // have internal checks for FACTION_FLAG_PEACE_FORCED + } + + // set atWar for hostile + if(GetReputationRank(factionEntry) <= REP_HOSTILE) + SetFactionAtWar(faction,true); + + // reset changed flag if values similar to saved in DB + if(faction->Flags==dbFactionFlags) + faction->Changed = false; + } + } + while( result->NextRow() ); + + delete result; + } +} + +void Player::_LoadSpells(QueryResult *result) +{ + for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) + delete itr->second; + m_spells.clear(); + + //QueryResult *result = CharacterDatabase.PQuery("SELECT spell,slot,active FROM character_spell WHERE guid = '%u'",GetGUIDLow()); + + if(result) + { + do + { + Field *fields = result->Fetch(); + + addSpell(fields[0].GetUInt16(), fields[2].GetBool(), false, true, fields[1].GetUInt16(), fields[3].GetBool()); + } + while( result->NextRow() ); + + delete result; + } +} + +void Player::_LoadTutorials(QueryResult *result) +{ + //QueryResult *result = CharacterDatabase.PQuery("SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetAccountId(), realmid); + + if(result) + { + do + { + Field *fields = result->Fetch(); + + for (int iI=0; iI<8; iI++) + m_Tutorials[iI] = fields[iI].GetUInt32(); + } + while( result->NextRow() ); + + delete result; + } + + m_TutorialsChanged = false; +} + +void Player::_LoadGroup(QueryResult *result) +{ + //QueryResult *result = CharacterDatabase.PQuery("SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", GetGUIDLow()); + if(result) + { + uint64 leaderGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); + delete result; + Group* group = objmgr.GetGroupByLeader(leaderGuid); + if(group) + { + uint8 subgroup = group->GetMemberGroup(GetGUID()); + SetGroup(group, subgroup); + if(getLevel() >= LEVELREQUIREMENT_HEROIC) + { + // the group leader may change the instance difficulty while the player is offline + SetDifficulty(group->GetDifficulty()); + } + } + } +} + +void Player::_LoadBoundInstances(QueryResult *result) +{ + for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) + m_boundInstances[i].clear(); + + Group *group = GetGroup(); + + //QueryResult *result = CharacterDatabase.PQuery("SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid)); + if(result) + { + do + { + Field *fields = result->Fetch(); + bool perm = fields[1].GetBool(); + uint32 mapId = fields[2].GetUInt32(); + uint32 instanceId = fields[0].GetUInt32(); + uint8 difficulty = fields[3].GetUInt8(); + time_t resetTime = (time_t)fields[4].GetUInt64(); + // the resettime for normal instances is only saved when the InstanceSave is unloaded + // so the value read from the DB may be wrong here but only if the InstanceSave is loaded + // and in that case it is not used + + if(!perm && group) + { + sLog.outError("_LoadBoundInstances: player %s(%d) is in group %d but has a non-permanent character bind to map %d,%d,%d", GetName(), GetGUIDLow(), GUID_LOPART(group->GetLeaderGUID()), mapId, instanceId, difficulty); + CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId); + continue; + } + + // since non permanent binds are always solo bind, they can always be reset + InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapId, instanceId, difficulty, resetTime, !perm, true); + if(save) BindToInstance(save, perm, true); + } while(result->NextRow()); + delete result; + } +} + +InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) +{ + // some instances only have one difficulty + const MapEntry* entry = sMapStore.LookupEntry(mapid); + if(!entry || !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; + + BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); + if(itr != m_boundInstances[difficulty].end()) + return &itr->second; + else + return NULL; +} + +void Player::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload) +{ + BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); + UnbindInstance(itr, difficulty, unload); +} + +void Player::UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload) +{ + if(itr != m_boundInstances[difficulty].end()) + { + if(!unload) CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u' AND instance = '%u'", GetGUIDLow(), itr->second.save->GetInstanceId()); + itr->second.save->RemovePlayer(this); // save can become invalid + m_boundInstances[difficulty].erase(itr++); + } +} + +InstancePlayerBind* Player::BindToInstance(InstanceSave *save, bool permanent, bool load) +{ + if(save) + { + InstancePlayerBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()]; + if(bind.save) + { + // update the save when the group kills a boss + if(permanent != bind.perm || save != bind.save) + if(!load) CharacterDatabase.PExecute("UPDATE character_instance SET instance = '%u', permanent = '%u' WHERE guid = '%u' AND instance = '%u'", save->GetInstanceId(), permanent, GetGUIDLow(), bind.save->GetInstanceId()); + } + else + if(!load) CharacterDatabase.PExecute("INSERT INTO character_instance (guid, instance, permanent) VALUES ('%u', '%u', '%u')", GetGUIDLow(), save->GetInstanceId(), permanent); + + if(bind.save != save) + { + if(bind.save) bind.save->RemovePlayer(this); + save->AddPlayer(this); + } + + if(permanent) save->SetCanReset(false); + + bind.save = save; + bind.perm = permanent; + if(!load) sLog.outDebug("Player::BindToInstance: %s(%d) is now bound to map %d, instance %d, difficulty %d", GetName(), GetGUIDLow(), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty()); + return &bind; + } + else + return NULL; +} + +void Player::SendRaidInfo() +{ + WorldPacket data(SMSG_RAID_INSTANCE_INFO, 4); + + uint32 counter = 0, i; + for(i = 0; i < TOTAL_DIFFICULTIES; i++) + for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); itr++) + if(itr->second.perm) counter++; + + data << counter; + for(i = 0; i < TOTAL_DIFFICULTIES; i++) + { + for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); itr++) + { + if(itr->second.perm) + { + InstanceSave *save = itr->second.save; + data << (save->GetMapId()); + data << (uint32)(save->GetResetTime() - time(NULL)); + data << save->GetInstanceId(); + data << uint32(counter); + counter--; + } + } + } + GetSession()->SendPacket(&data); +} + +/* +- called on every successful teleportation to a map +*/ +void Player::SendSavedInstances() +{ + bool hasBeenSaved = false; + WorldPacket data; + + for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) + { + for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) + { + if(itr->second.perm) // only permanent binds are sent + { + hasBeenSaved = true; + break; + } + } + } + + //Send opcode 811. true or flase means, whether you have current raid/heroic instances + data.Initialize(SMSG_UPDATE_INSTANCE_OWNERSHIP); + data << uint32(hasBeenSaved); + GetSession()->SendPacket(&data); + + if(!hasBeenSaved) + return; + + for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) + { + for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) + { + if(itr->second.perm) + { + data.Initialize(SMSG_UPDATE_LAST_INSTANCE); + data << uint32(itr->second.save->GetMapId()); + GetSession()->SendPacket(&data); + } + } + } +} + +/// convert the player's binds to the group +void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player_guid) +{ + bool has_binds = false; + bool has_solo = false; + + if(player) { player_guid = player->GetGUID(); if(!group) group = player->GetGroup(); } + assert(player_guid); + + // copy all binds to the group, when changing leader it's assumed the character + // will not have any solo binds + + if(player) + { + for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++) + { + for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) + { + has_binds = true; + if(group) group->BindToInstance(itr->second.save, itr->second.perm, true); + // permanent binds are not removed + if(!itr->second.perm) + { + player->UnbindInstance(itr, i, true); // increments itr + has_solo = true; + } + else + ++itr; + } + } + } + + // if the player's not online we don't know what binds it has + if(!player || !group || has_binds) CharacterDatabase.PExecute("INSERT INTO group_instance SELECT guid, instance, permanent FROM character_instance WHERE guid = '%u'", GUID_LOPART(player_guid)); + // the following should not get executed when changing leaders + if(!player || has_solo) CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND permanent = 0", GUID_LOPART(player_guid)); +} + +bool Player::_LoadHomeBind(QueryResult *result) +{ + bool ok = false; + //QueryResult *result = CharacterDatabase.PQuery("SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(playerGuid)); + if (result) + { + Field *fields = result->Fetch(); + m_homebindMapId = fields[0].GetUInt32(); + m_homebindZoneId = fields[1].GetUInt16(); + m_homebindX = fields[2].GetFloat(); + m_homebindY = fields[3].GetFloat(); + m_homebindZ = fields[4].GetFloat(); + delete result; + + // accept saved data only for valid position (and non instanceable) + if( MapManager::IsValidMapCoord(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ) && + !sMapStore.LookupEntry(m_homebindMapId)->Instanceable() ) + { + ok = true; + } + else + CharacterDatabase.PExecute("DELETE FROM character_homebind WHERE guid = '%u'", GetGUIDLow()); + } + + if(!ok) + { + PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass()); + if(!info) return false; + + m_homebindMapId = info->mapId; + m_homebindZoneId = info->zoneId; + m_homebindX = info->positionX; + m_homebindY = info->positionY; + m_homebindZ = info->positionZ; + + CharacterDatabase.PExecute("INSERT INTO character_homebind (guid,map,zone,position_x,position_y,position_z) VALUES ('%u', '%u', '%u', '%f', '%f', '%f')", GetGUIDLow(), m_homebindMapId, (uint32)m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ); + } + + DEBUG_LOG("Setting player home position: mapid is: %u, zoneid is %u, X is %f, Y is %f, Z is %f\n", + m_homebindMapId, m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ); + + return true; +} + +/*********************************************************/ +/*** SAVE SYSTEM ***/ +/*********************************************************/ + +void Player::SaveToDB() +{ + // delay auto save at any saves (manual, in code, or autosave) + m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE); + + // first save/honor gain after midnight will also update the player's honor fields + UpdateHonorFields(); + + // Must saved before enter into BattleGround + if(InBattleGround()) + return; + + int is_save_resting = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0; + //save, far from tavern/city + //save, but in tavern/city + sLog.outDebug("The value of player %s at save: ", m_name.c_str()); + outDebugValues(); + + // save state (after auras removing), if aura remove some flags then it must set it back by self) + uint32 tmp_bytes = GetUInt32Value(UNIT_FIELD_BYTES_1); + uint32 tmp_bytes2 = GetUInt32Value(UNIT_FIELD_BYTES_2); + uint32 tmp_flags = GetUInt32Value(UNIT_FIELD_FLAGS); + uint32 tmp_pflags = GetUInt32Value(PLAYER_FLAGS); + uint32 tmp_displayid = GetDisplayId(); + + // Set player sit state to standing on save, also stealth and shifted form + SetByteValue(UNIT_FIELD_BYTES_1, 0, 0); // stand state + SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift + SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); // stand flags? + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE); + SetDisplayId(GetNativeDisplayId()); + + bool inworld = IsInWorld(); + + CharacterDatabase.BeginTransaction(); + + CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",GetGUIDLow()); + + std::string sql_name = m_name; + CharacterDatabase.escape_string(sql_name); + + std::ostringstream ss; + ss << "INSERT INTO characters (guid,account,name,race,class," + "map, dungeon_difficulty, position_x, position_y, position_z, orientation, data, " + "taximask, online, cinematic, " + "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, " + "trans_x, trans_y, trans_z, trans_o, transguid, gmstate, stable_slots, at_login, zone, " + "death_expire_time, taxi_path) VALUES (" + << GetGUIDLow() << ", " + << GetSession()->GetAccountId() << ", '" + << sql_name << "', " + << m_race << ", " + << m_class << ", "; + + bool save_to_dest = false; + if(IsBeingTeleported()) + { + // don't save to battlegrounds or arenas + const MapEntry *entry = sMapStore.LookupEntry(GetTeleportDest().mapid); + if(entry && entry->map_type != MAP_BATTLEGROUND && entry->map_type != MAP_ARENA) + save_to_dest = true; + } + + if(!save_to_dest) + { + ss << GetMapId() << ", " + << (uint32)GetDifficulty() << ", " + << finiteAlways(GetPositionX()) << ", " + << finiteAlways(GetPositionY()) << ", " + << finiteAlways(GetPositionZ()) << ", " + << finiteAlways(GetOrientation()) << ", '"; + } + else + { + ss << GetTeleportDest().mapid << ", " + << (uint32)GetDifficulty() << ", " + << finiteAlways(GetTeleportDest().x) << ", " + << finiteAlways(GetTeleportDest().y) << ", " + << finiteAlways(GetTeleportDest().z) << ", " + << finiteAlways(GetTeleportDest().o) << ", '"; + } + + uint16 i; + for( i = 0; i < m_valuesCount; i++ ) + { + ss << GetUInt32Value(i) << " "; + } + + ss << "', '"; + + for( i = 0; i < 8; i++ ) + ss << m_taxi.GetTaximask(i) << " "; + + ss << "', "; + ss << (inworld ? 1 : 0); + + ss << ", "; + ss << m_cinematic; + + ss << ", "; + ss << m_Played_time[0]; + ss << ", "; + ss << m_Played_time[1]; + + ss << ", "; + ss << finiteAlways(m_rest_bonus); + ss << ", "; + ss << (uint64)time(NULL); + ss << ", "; + ss << is_save_resting; + ss << ", "; + ss << m_resetTalentsCost; + ss << ", "; + ss << (uint64)m_resetTalentsTime; + + ss << ", "; + ss << finiteAlways(m_movementInfo.t_x); + ss << ", "; + ss << finiteAlways(m_movementInfo.t_y); + ss << ", "; + ss << finiteAlways(m_movementInfo.t_z); + ss << ", "; + ss << finiteAlways(m_movementInfo.t_o); + ss << ", "; + if (m_transport) + ss << m_transport->GetGUIDLow(); + else + ss << "0"; + + ss << ", "; + ss << (isGameMaster()? 1 : 0); + + ss << ", "; + ss << uint32(m_stableSlots); // to prevent save uint8 as char + + ss << ", "; + ss << uint32(m_atLoginFlags); + + ss << ", "; + ss << GetZoneId(); + + ss << ", "; + ss << (uint64)m_deathExpireTime; + + ss << ", '"; + ss << m_taxi.SaveTaxiDestinationsToString(); + ss << "' )"; + + CharacterDatabase.Execute( ss.str().c_str() ); + + if(m_mailsUpdated) //save mails only when needed + _SaveMail(); + + _SaveInventory(); + _SaveQuestStatus(); + _SaveDailyQuestStatus(); + _SaveTutorials(); + _SaveSpells(); + _SaveSpellCooldowns(); + _SaveActions(); + _SaveAuras(); + _SaveReputation(); + + CharacterDatabase.CommitTransaction(); + + // restore state (before aura apply, if aura remove flag then aura must set it ack by self) + SetDisplayId(tmp_displayid); + SetUInt32Value(UNIT_FIELD_BYTES_1, tmp_bytes); + SetUInt32Value(UNIT_FIELD_BYTES_2, tmp_bytes2); + SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags); + SetUInt32Value(PLAYER_FLAGS, tmp_pflags); + + // save pet (hunter pet level and experience and all type pets health/mana). + if(Pet* pet = GetPet()) + pet->SavePetToDB(PET_SAVE_AS_CURRENT); +} + +// fast save function for item/money cheating preventing - save only inventory and money state +void Player::SaveInventoryAndGoldToDB() +{ + _SaveInventory(); + SetUInt32ValueInDB(PLAYER_FIELD_COINAGE,GetMoney(),GetGUID()); +} + +void Player::_SaveActions() +{ + for(ActionButtonList::iterator itr = m_actionButtons.begin(); itr != m_actionButtons.end(); ) + { + switch (itr->second.uState) + { + case ACTIONBUTTON_NEW: + CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type,misc) VALUES ('%u', '%u', '%u', '%u', '%u')", + GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc ); + itr->second.uState = ACTIONBUTTON_UNCHANGED; + ++itr; + break; + case ACTIONBUTTON_CHANGED: + CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u', misc= '%u' WHERE guid= '%u' AND button= '%u' ", + (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc, GetGUIDLow(), (uint32)itr->first ); + itr->second.uState = ACTIONBUTTON_UNCHANGED; + ++itr; + break; + case ACTIONBUTTON_DELETED: + CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u' and button = '%u'", GetGUIDLow(), (uint32)itr->first ); + m_actionButtons.erase(itr++); + break; + default: + ++itr; + break; + }; + } +} + +void Player::_SaveAuras() +{ + CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",GetGUIDLow()); + + AuraMap const& auras = GetAuras(); + for(AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + SpellEntry const *spellInfo = itr->second->GetSpellProto(); + + //skip all auras from spells that are passive or need a shapeshift + if (itr->second->IsPassive() || itr->second->IsRemovedOnShapeLost()) + continue; + + //do not save single target auras (unless they were cast by the player) + if (itr->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(spellInfo)) + continue; + + uint8 i; + // or apply at cast SPELL_AURA_MOD_SHAPESHIFT or SPELL_AURA_MOD_STEALTH auras + for (i = 0; i < 3; i++) + if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT || + spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH) + break; + + if (i == 3) + { + CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u' and spell = '%u' and effect_index= '%u'",GetGUIDLow(),(uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex()); + CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges) " + "VALUES ('%u', '" I64FMTD "' ,'%u', '%u', '%d', '%d', '%d', '%d')", + GetGUIDLow(), itr->second->GetCasterGUID(), (uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(), (*itr).second->GetModifier()->m_amount,int((*itr).second->GetAuraMaxDuration()),int((*itr).second->GetAuraDuration()),int((*itr).second->m_procCharges)); + } + } +} + +void Player::_SaveInventory() +{ + // force items in buyback slots to new state + // and remove those that aren't already + for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; i++) + { + Item *item = m_items[i]; + if (!item || item->GetState() == ITEM_NEW) continue; + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow()); + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item->GetGUIDLow()); + m_items[i]->FSetState(ITEM_NEW); + } + + // update enchantment durations + for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();++itr) + { + itr->item->SetEnchantmentDuration(itr->slot,itr->leftduration); + } + + // if no changes + if (m_itemUpdateQueue.empty()) return; + + // do not save if the update queue is corrupt + bool error = false; + for(size_t i = 0; i < m_itemUpdateQueue.size(); i++) + { + Item *item = m_itemUpdateQueue[i]; + if(!item || item->GetState() == ITEM_REMOVED) continue; + Item *test = GetItemByPos( item->GetBagSlot(), item->GetSlot()); + + if (test == NULL) + { + sLog.outError("Player(GUID: %u Name: %s)::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", GetGUIDLow(), GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); + error = true; + } + else if (test != item) + { + sLog.outError("Player(GUID: %u Name: %s)::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", GetGUIDLow(), GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); + error = true; + } + } + + if (error) + { + sLog.outError("Player::_SaveInventory - one or more errors occurred save aborted!"); + ChatHandler(this).SendSysMessage(LANG_ITEM_SAVE_FAILED); + return; + } + + for(size_t i = 0; i < m_itemUpdateQueue.size(); i++) + { + Item *item = m_itemUpdateQueue[i]; + if(!item) continue; + + Bag *container = item->GetContainer(); + uint32 bag_guid = container ? container->GetGUIDLow() : 0; + + switch(item->GetState()) + { + case ITEM_NEW: + CharacterDatabase.PExecute("INSERT INTO character_inventory (guid,bag,slot,item,item_template) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetGUIDLow(), item->GetEntry()); + break; + case ITEM_CHANGED: + CharacterDatabase.PExecute("UPDATE character_inventory SET guid='%u', bag='%u', slot='%u', item_template='%u' WHERE item='%u'", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetEntry(), item->GetGUIDLow()); + break; + case ITEM_REMOVED: + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow()); + break; + case ITEM_UNCHANGED: + break; + } + + item->SaveToDB(); // item have unchanged inventory record and can be save standalone + } + m_itemUpdateQueue.clear(); +} + +void Player::_SaveMail() +{ + if (!m_mailsLoaded) + return; + + for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); itr++) + { + Mail *m = (*itr); + if (m->state == MAIL_STATE_CHANGED) + { + CharacterDatabase.PExecute("UPDATE mail SET itemTextId = '%u',has_items = '%u',expire_time = '" I64FMTD "', deliver_time = '" I64FMTD "',money = '%u',cod = '%u',checked = '%u' WHERE id = '%u'", + m->itemTextId, m->HasItems() ? 1 : 0, (uint64)m->expire_time, (uint64)m->deliver_time, m->money, m->COD, m->checked, m->messageID); + if(m->removedItems.size()) + { + for(std::vector::iterator itr2 = m->removedItems.begin(); itr2 != m->removedItems.end(); ++itr2) + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", *itr2); + m->removedItems.clear(); + } + m->state = MAIL_STATE_UNCHANGED; + } + else if (m->state == MAIL_STATE_DELETED) + { + if (m->HasItems()) + for(std::vector::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid); + if (m->itemTextId) + CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId); + CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID); + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", m->messageID); + } + } + + //deallocate deleted mails... + for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ) + { + if ((*itr)->state == MAIL_STATE_DELETED) + { + Mail* m = *itr; + m_mail.erase(itr); + delete m; + itr = m_mail.begin(); + } + else + ++itr; + } + + m_mailsUpdated = false; +} + +void Player::_SaveQuestStatus() +{ + // we don't need transactions here. + for( QuestStatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i ) + { + switch (i->second.uState) + { + case QUEST_NEW : + CharacterDatabase.PExecute("INSERT INTO character_queststatus (guid,quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4) " + "VALUES ('%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", + GetGUIDLow(), i->first, i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3]); + break; + case QUEST_CHANGED : + CharacterDatabase.PExecute("UPDATE character_queststatus SET status = '%u',rewarded = '%u',explored = '%u',timer = '" I64FMTD "',mobcount1 = '%u',mobcount2 = '%u',mobcount3 = '%u',mobcount4 = '%u',itemcount1 = '%u',itemcount2 = '%u',itemcount3 = '%u',itemcount4 = '%u' WHERE guid = '%u' AND quest = '%u' ", + i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3], GetGUIDLow(), i->first ); + break; + case QUEST_UNCHANGED: + break; + }; + i->second.uState = QUEST_UNCHANGED; + } +} + +void Player::_SaveDailyQuestStatus() +{ + if(!m_DailyQuestChanged) + return; + + m_DailyQuestChanged = false; + + // save last daily quest time for all quests: we need only mostly reset time for reset check anyway + + // we don't need transactions here. + CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",GetGUIDLow()); + for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) + if(GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)) + CharacterDatabase.PExecute("INSERT INTO character_queststatus_daily (guid,quest,time) VALUES ('%u', '%u','" I64FMTD "')", + GetGUIDLow(), GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx),uint64(m_lastDailyQuestTime)); +} + +void Player::_SaveReputation() +{ + for(FactionStateList::iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) + { + if (itr->second.Changed) + { + CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u' AND faction='%u'", GetGUIDLow(), itr->second.ID); + CharacterDatabase.PExecute("INSERT INTO character_reputation (guid,faction,standing,flags) VALUES ('%u', '%u', '%i', '%u')", GetGUIDLow(), itr->second.ID, itr->second.Standing, itr->second.Flags); + itr->second.Changed = false; + } + } +} + +void Player::_SaveSpells() +{ + for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next) + { + ++next; + if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED) + CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first); + if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED) + CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,slot,active,disabled) VALUES ('%u', '%u', '%u','%u','%u')", GetGUIDLow(), itr->first, itr->second->slotId,itr->second->active ? 1 : 0,itr->second->disabled ? 1 : 0); + + if (itr->second->state == PLAYERSPELL_REMOVED) + _removeSpell(itr->first); + else + itr->second->state = PLAYERSPELL_UNCHANGED; + } +} + +void Player::_SaveTutorials() +{ + if(!m_TutorialsChanged) + return; + + uint32 Rows=0; + // it's better than rebuilding indexes multiple times + QueryResult *result = CharacterDatabase.PQuery("SELECT count(*) AS r FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetSession()->GetAccountId(), realmID ); + if(result) + { + Rows = result->Fetch()[0].GetUInt32(); + delete result; + } + + if (Rows) + { + CharacterDatabase.PExecute("UPDATE character_tutorial SET tut0='%u', tut1='%u', tut2='%u', tut3='%u', tut4='%u', tut5='%u', tut6='%u', tut7='%u' WHERE account = '%u' AND realmid = '%u'", + m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7], GetSession()->GetAccountId(), realmID ); + } + else + { + CharacterDatabase.PExecute("INSERT INTO character_tutorial (account,realmid,tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", GetSession()->GetAccountId(), realmID, m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7]); + }; + + m_TutorialsChanged = false; +} + +void Player::outDebugValues() const +{ + if(!sLog.IsOutDebug()) // optimize disabled debug output + return; + + sLog.outDebug("HP is: \t\t\t%u\t\tMP is: \t\t\t%u",GetMaxHealth(), GetMaxPower(POWER_MANA)); + sLog.outDebug("AGILITY is: \t\t%f\t\tSTRENGTH is: \t\t%f",GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH)); + sLog.outDebug("INTELLECT is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_INTELLECT), GetStat(STAT_SPIRIT)); + sLog.outDebug("STAMINA is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_STAMINA), GetStat(STAT_SPIRIT)); + sLog.outDebug("Armor is: \t\t%u\t\tBlock is: \t\t%f",GetArmor(), GetFloatValue(PLAYER_BLOCK_PERCENTAGE)); + sLog.outDebug("HolyRes is: \t\t%u\t\tFireRes is: \t\t%u",GetResistance(SPELL_SCHOOL_HOLY), GetResistance(SPELL_SCHOOL_FIRE)); + sLog.outDebug("NatureRes is: \t\t%u\t\tFrostRes is: \t\t%u",GetResistance(SPELL_SCHOOL_NATURE), GetResistance(SPELL_SCHOOL_FROST)); + sLog.outDebug("ShadowRes is: \t\t%u\t\tArcaneRes is: \t\t%u",GetResistance(SPELL_SCHOOL_SHADOW), GetResistance(SPELL_SCHOOL_ARCANE)); + sLog.outDebug("MIN_DAMAGE is: \t\t%f\tMAX_DAMAGE is: \t\t%f",GetFloatValue(UNIT_FIELD_MINDAMAGE), GetFloatValue(UNIT_FIELD_MAXDAMAGE)); + sLog.outDebug("MIN_OFFHAND_DAMAGE is: \t%f\tMAX_OFFHAND_DAMAGE is: \t%f",GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE), GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)); + sLog.outDebug("MIN_RANGED_DAMAGE is: \t%f\tMAX_RANGED_DAMAGE is: \t%f",GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE), GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE)); + sLog.outDebug("ATTACK_TIME is: \t%u\t\tRANGE_ATTACK_TIME is: \t%u",GetAttackTime(BASE_ATTACK), GetAttackTime(RANGED_ATTACK)); +} + +/*********************************************************/ +/*** FLOOD FILTER SYSTEM ***/ +/*********************************************************/ + +void Player::UpdateSpeakTime() +{ + // ignore chat spam protection for GMs in any mode + if(GetSession()->GetSecurity() > SEC_PLAYER) + return; + + time_t current = time (NULL); + if(m_speakTime > current) + { + uint32 max_count = sWorld.getConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT); + if(!max_count) + return; + + ++m_speakCount; + if(m_speakCount >= max_count) + { + // prevent overwrite mute time, if message send just before mutes set, for example. + time_t new_mute = current + sWorld.getConfig(CONFIG_CHATFLOOD_MUTE_TIME); + if(GetSession()->m_muteTime < new_mute) + GetSession()->m_muteTime = new_mute; + + m_speakCount = 0; + } + } + else + m_speakCount = 0; + + m_speakTime = current + sWorld.getConfig(CONFIG_CHATFLOOD_MESSAGE_DELAY); +} + +bool Player::CanSpeak() const +{ + return GetSession()->m_muteTime <= time (NULL); +} + +/*********************************************************/ +/*** LOW LEVEL FUNCTIONS:Notifiers ***/ +/*********************************************************/ + +void Player::SendAttackSwingNotInRange() +{ + WorldPacket data(SMSG_ATTACKSWING_NOTINRANGE, 0); + GetSession()->SendPacket( &data ); +} + +void Player::SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint32 zone,uint64 guid) +{ + std::ostringstream ss; + ss << "UPDATE characters SET position_x='"<= tokens.size()) + return; + + tokens[index] = buf; +} + +void Player::SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid) +{ + Tokens tokens; + if(!LoadValuesArrayFromDB(tokens,guid)) + return; + + if(index >= tokens.size()) + return; + + char buf[11]; + snprintf(buf,11,"%u",value); + tokens[index] = buf; + + SaveValuesArrayInDB(tokens,guid); +} + +void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid) +{ + uint32 temp; + memcpy(&temp, &value, sizeof(value)); + Player::SetUInt32ValueInDB(index, temp, guid); +} + +void Player::SendAttackSwingNotStanding() +{ + WorldPacket data(SMSG_ATTACKSWING_NOTSTANDING, 0); + GetSession()->SendPacket( &data ); +} + +void Player::SendAttackSwingDeadTarget() +{ + WorldPacket data(SMSG_ATTACKSWING_DEADTARGET, 0); + GetSession()->SendPacket( &data ); +} + +void Player::SendAttackSwingCantAttack() +{ + WorldPacket data(SMSG_ATTACKSWING_CANT_ATTACK, 0); + GetSession()->SendPacket( &data ); +} + +void Player::SendAttackSwingCancelAttack() +{ + WorldPacket data(SMSG_CANCEL_COMBAT, 0); + GetSession()->SendPacket( &data ); +} + +void Player::SendAttackSwingBadFacingAttack() +{ + WorldPacket data(SMSG_ATTACKSWING_BADFACING, 0); + GetSession()->SendPacket( &data ); +} + +void Player::SendAutoRepeatCancel() +{ + WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, 0); + GetSession()->SendPacket( &data ); +} + +void Player::PlaySound(uint32 Sound, bool OnlySelf) +{ + WorldPacket data(SMSG_PLAY_SOUND, 4); + data << Sound; + if (OnlySelf) + GetSession()->SendPacket( &data ); + else + SendMessageToSet( &data, true ); +} + +void Player::SendExplorationExperience(uint32 Area, uint32 Experience) +{ + WorldPacket data( SMSG_EXPLORATION_EXPERIENCE, 8 ); + data << Area; + data << Experience; + GetSession()->SendPacket(&data); +} + +void Player::SendDungeonDifficulty(bool IsInGroup) +{ + uint8 val = 0x00000001; + WorldPacket data(MSG_SET_DUNGEON_DIFFICULTY, 12); + data << (uint32)GetDifficulty(); + data << uint32(val); + data << uint32(IsInGroup); + GetSession()->SendPacket(&data); +} + +void Player::SendResetFailedNotify(uint32 mapid) +{ + WorldPacket data(SMSG_RESET_FAILED_NOTIFY, 4); + data << uint32(mapid); + GetSession()->SendPacket(&data); +} + +/// Reset all solo instances and optionally send a message on success for each +void Player::ResetInstances(uint8 method) +{ + // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_JOIN + + // we assume that when the difficulty changes, all instances that can be reset will be + uint8 dif = GetDifficulty(); + + for (BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();) + { + InstanceSave *p = itr->second.save; + const MapEntry *entry = sMapStore.LookupEntry(itr->first); + if(!entry || !p->CanReset()) + { + ++itr; + continue; + } + + if(method == INSTANCE_RESET_ALL) + { + // the "reset all instances" method can only reset normal maps + if(dif == DIFFICULTY_HEROIC || entry->map_type == MAP_RAID) + { + ++itr; + continue; + } + } + + // if the map is loaded, reset it + Map *map = MapManager::Instance().FindMap(p->GetMapId(), p->GetInstanceId()); + if(map && map->IsDungeon()) + ((InstanceMap*)map)->Reset(method); + + // since this is a solo instance there should not be any players inside + if(method == INSTANCE_RESET_ALL || method == INSTANCE_RESET_CHANGE_DIFFICULTY) + SendResetInstanceSuccess(p->GetMapId()); + + p->DeleteFromDB(); + m_boundInstances[dif].erase(itr++); + + // the following should remove the instance save from the manager and delete it as well + p->RemovePlayer(this); + } +} + +void Player::SendResetInstanceSuccess(uint32 MapId) +{ + WorldPacket data(SMSG_INSTANCE_RESET, 4); + data << MapId; + GetSession()->SendPacket(&data); +} + +void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) +{ + // TODO: find what other fail reasons there are besides players in the instance + WorldPacket data(SMSG_INSTANCE_RESET_FAILED, 4); + data << reason; + data << MapId; + GetSession()->SendPacket(&data); +} + +/*********************************************************/ +/*** Update timers ***/ +/*********************************************************/ + +///checks the 15 afk reports per 5 minutes limit +void Player::UpdateAfkReport(time_t currTime) +{ + if(m_bgAfkReportedTimer <= currTime) + { + m_bgAfkReportedCount = 0; + m_bgAfkReportedTimer = currTime+5*MINUTE; + } +} + +void Player::UpdateContestedPvP(uint32 diff) +{ + if(!m_contestedPvPTimer||isInCombat()) + return; + if(m_contestedPvPTimer <= diff) + { + ResetContestedPvP(); + } + else + m_contestedPvPTimer -= diff; +} + +void Player::UpdatePvPFlag(time_t currTime) +{ + if(!IsPvP()) + return; + if(pvpInfo.endTimer == 0 || currTime < (pvpInfo.endTimer + 300)) + return; + + UpdatePvP(false); +} + +void Player::UpdateDuelFlag(time_t currTime) +{ + if(!duel || duel->startTimer == 0 ||currTime < duel->startTimer + 3) + return; + + SetUInt32Value(PLAYER_DUEL_TEAM, 1); + duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 2); + + duel->startTimer = 0; + duel->startTime = currTime; + duel->opponent->duel->startTimer = 0; + duel->opponent->duel->startTime = currTime; +} + +void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) +{ + if(!pet) + pet = GetPet(); + + if(returnreagent && (pet || m_temporaryUnsummonedPetNumber)) + { + //returning of reagents only for players, so best done here + uint32 spellId = pet ? pet->GetUInt32Value(UNIT_CREATED_BY_SPELL) : m_oldpetspell; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + + if(spellInfo) + { + for(uint32 i = 0; i < 7; ++i) + { + if(spellInfo->Reagent[i] > 0) + { + ItemPosCountVec dest; //for succubus, voidwalker, felhunter and felguard credit soulshard when despawn reason other than death (out of range, logout) + uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, spellInfo->Reagent[i], spellInfo->ReagentCount[i] ); + if( msg == EQUIP_ERR_OK ) + { + Item* item = StoreNewItem( dest, spellInfo->Reagent[i], true); + if(IsInWorld()) + SendNewItem(item,spellInfo->ReagentCount[i],true,false); + } + } + } + } + m_temporaryUnsummonedPetNumber = 0; + } + + if(!pet || pet->GetOwnerGUID()!=GetGUID()) + return; + + // only if current pet in slot + switch(pet->getPetType()) + { + case MINI_PET: + m_miniPet = 0; + break; + case GUARDIAN_PET: + m_guardianPets.erase(pet->GetGUID()); + break; + default: + if(GetPetGUID()==pet->GetGUID()) + SetPet(0); + break; + } + + pet->CombatStop(); + + if(returnreagent) + { + switch(pet->GetEntry()) + { + //warlock pets except imp are removed(?) when logging out + case 1860: + case 1863: + case 417: + case 17252: + mode = PET_SAVE_NOT_IN_SLOT; + break; + } + } + + pet->SavePetToDB(mode); + + pet->CleanupsBeforeDelete(); + pet->AddObjectToRemoveList(); + pet->m_removed = true; + + if(pet->isControlled()) + { + WorldPacket data(SMSG_PET_SPELLS, 8); + data << uint64(0); + GetSession()->SendPacket(&data); + + if(GetGroup()) + SetGroupUpdateFlag(GROUP_UPDATE_PET); + } +} + + +void Player::RemoveMiniPet() +{ + if(Pet* pet = GetMiniPet()) + { + pet->Remove(PET_SAVE_AS_DELETED); + m_miniPet = 0; + } +} + +Pet* Player::GetMiniPet() +{ + if(!m_miniPet) + return NULL; + return ObjectAccessor::GetPet(m_miniPet); +} + +void Player::RemoveGuardians() +{ + while(!m_guardianPets.empty()) + { + uint64 guid = *m_guardianPets.begin(); + if(Pet* pet = ObjectAccessor::GetPet(guid)) + pet->Remove(PET_SAVE_AS_DELETED); + + m_guardianPets.erase(guid); + } +} + +bool Player::HasGuardianWithEntry(uint32 entry) +{ + // pet guid middle part is entry (and creature also) + // and in guardian list must be guardians with same entry _always_ + for(GuardianPetList::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) + if(GUID_ENPART(*itr)==entry) + return true; + + return false; +} + +void Player::Uncharm() +{ + Unit* charm = GetCharm(); + if(!charm) + return; + + charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM); + charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS); +} + +void Player::BuildPlayerChat(WorldPacket *data, uint8 msgtype, std::string text, uint32 language) const +{ + *data << (uint8)msgtype; + *data << (uint32)language; + *data << (uint64)GetGUID(); + *data << (uint32)language; //language 2.1.0 ? + *data << (uint64)GetGUID(); + *data << (uint32)(text.length()+1); + *data << text; + *data << (uint8)chatTag(); +} + +void Player::Say(const std::string text, const uint32 language) +{ + WorldPacket data(SMSG_MESSAGECHAT, 200); + BuildPlayerChat(&data, CHAT_MSG_SAY, text, language); + SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),true); +} + +void Player::Yell(const std::string text, const uint32 language) +{ + WorldPacket data(SMSG_MESSAGECHAT, 200); + BuildPlayerChat(&data, CHAT_MSG_YELL, text, language); + SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),true); +} + +void Player::TextEmote(const std::string text) +{ + WorldPacket data(SMSG_MESSAGECHAT, 200); + BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL); + SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true, !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) ); +} + +void Player::Whisper(std::string text, uint32 language,uint64 receiver) +{ + if (language != LANG_ADDON) // if not addon data + language = LANG_UNIVERSAL; // whispers should always be readable + + Player *rPlayer = objmgr.GetPlayer(receiver); + + // when player you are whispering to is dnd, he cannot receive your message, unless you are in gm mode + if(!rPlayer->isDND() || isGameMaster()) + { + WorldPacket data(SMSG_MESSAGECHAT, 200); + BuildPlayerChat(&data, CHAT_MSG_WHISPER, text, language); + rPlayer->GetSession()->SendPacket(&data); + + data.Initialize(SMSG_MESSAGECHAT, 200); + rPlayer->BuildPlayerChat(&data, CHAT_MSG_REPLY, text, language); + GetSession()->SendPacket(&data); + } + else + { + // announce to player that player he is whispering to is dnd and cannot receive his message + ChatHandler(this).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName(), rPlayer->dndMsg.c_str()); + } + + if(!isAcceptWhispers()) + { + SetAcceptWhispers(true); + ChatHandler(this).SendSysMessage(LANG_COMMAND_WHISPERON); + } + + // announce to player that player he is whispering to is afk + if(rPlayer->isAFK()) + ChatHandler(this).PSendSysMessage(LANG_PLAYER_AFK, rPlayer->GetName(), rPlayer->afkMsg.c_str()); + + // if player whisper someone, auto turn of dnd to be able to receive an answer + if(isDND() && !rPlayer->isGameMaster()) + ToggleDND(); +} + +void Player::PetSpellInitialize() +{ + Pet* pet = GetPet(); + + if(pet) + { + uint8 addlist = 0; + + sLog.outDebug("Pet Spells Groups"); + + CreatureInfo const *cinfo = pet->GetCreatureInfo(); + + if(pet->isControlled() && (pet->getPetType() == HUNTER_PET || cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)) + { + for(PetSpellMap::iterator itr = pet->m_spells.begin();itr != pet->m_spells.end();itr++) + { + if(itr->second->state == PETSPELL_REMOVED) + continue; + ++addlist; + } + } + + // first line + actionbar + spellcount + spells + last adds + WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25); + + CharmInfo *charmInfo = pet->GetCharmInfo(); + + //16 + data << (uint64)pet->GetGUID() << uint32(0x00000000) << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); + + for(uint32 i = 0; i < 10; i++) //40 + { + data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); + } + + data << uint8(addlist); //1 + + if(addlist && pet->isControlled()) + { + for (PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr) + { + if(itr->second->state == PETSPELL_REMOVED) + continue; + + data << uint16(itr->first); + data << uint16(itr->second->active); // pet spell active state isn't boolean + } + } + + //data << uint8(0x01) << uint32(0x6010) << uint32(0x01) << uint32(0x05) << uint16(0x00); //15 + uint8 count = 3; //1+8+8+8=25 + + // if count = 0, then end of packet... + data << count; + // uint32 value is spell id... + // uint64 value is constant 0, unknown... + data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3 + //data << uint32(0x5fd1) << uint64(0); // if count = 2 + data << uint32(0x8e8c) << uint64(0); // if count = 3 + data << uint32(0x8e8b) << uint64(0); // if count = 3 + + GetSession()->SendPacket(&data); + } +} + +void Player::PossessSpellInitialize() +{ + Unit* charm = GetCharm(); + + if(!charm) + return; + + CharmInfo *charmInfo = charm->GetCharmInfo(); + + if(!charmInfo) + { + sLog.outError("Player::PossessSpellInitialize(): charm ("I64FMTD") has no charminfo!", charm->GetGUID()); + return; + } + + uint8 addlist = 0; + WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds + + //16 + data << (uint64)charm->GetGUID() << uint32(0x00000000) << uint8(0) << uint8(0) << uint16(0); + + for(uint32 i = 0; i < 10; i++) //40 + { + data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); + } + + data << uint8(addlist); //1 + + uint8 count = 3; + data << count; + data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3 + data << uint32(0x8e8c) << uint64(0); // if count = 3 + data << uint32(0x8e8b) << uint64(0); // if count = 3 + + GetSession()->SendPacket(&data); +} + +void Player::CharmSpellInitialize() +{ + Unit* charm = GetCharm(); + + if(!charm) + return; + + CharmInfo *charmInfo = charm->GetCharmInfo(); + if(!charmInfo) + { + sLog.outError("Player::CharmSpellInitialize(): the player's charm ("I64FMTD") has no charminfo!", charm->GetGUID()); + return; + } + + uint8 addlist = 0; + + if(charm->GetTypeId() != TYPEID_PLAYER) + { + CreatureInfo const *cinfo = ((Creature*)charm)->GetCreatureInfo(); + + if(cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK) + { + for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) + { + if(charmInfo->GetCharmSpell(i)->spellId) + ++addlist; + } + } + } + + WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds + + data << (uint64)charm->GetGUID() << uint32(0x00000000); + + if(charm->GetTypeId() != TYPEID_PLAYER) + data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()); + else + data << uint8(0) << uint8(0); + + data << uint16(0); + + for(uint32 i = 0; i < 10; i++) //40 + { + data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); + } + + data << uint8(addlist); //1 + + if(addlist) + { + for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) + { + CharmSpellEntry *cspell = charmInfo->GetCharmSpell(i); + if(cspell->spellId) + { + data << uint16(cspell->spellId); + data << uint16(cspell->active); + } + } + } + + uint8 count = 3; + data << count; + data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3 + data << uint32(0x8e8c) << uint64(0); // if count = 3 + data << uint32(0x8e8b) << uint64(0); // if count = 3 + + GetSession()->SendPacket(&data); +} + +int32 Player::GetTotalFlatMods(uint32 spellId, SpellModOp op) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo) return 0; + int32 total = 0; + for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr) + { + SpellModifier *mod = *itr; + + if(!IsAffectedBySpellmod(spellInfo,mod)) + continue; + + if (mod->type == SPELLMOD_FLAT) + total += mod->value; + } + return total; +} + +int32 Player::GetTotalPctMods(uint32 spellId, SpellModOp op) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo) return 0; + int32 total = 0; + for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr) + { + SpellModifier *mod = *itr; + + if(!IsAffectedBySpellmod(spellInfo,mod)) + continue; + + if (mod->type == SPELLMOD_PCT) + total += mod->value; + } + return total; +} + +bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell) +{ + if (!mod || !spellInfo) + return false; + + if(mod->charges == -1 && mod->lastAffected ) // marked as expired but locked until spell casting finish + { + // prevent apply to any spell except spell that trigger expire + if(spell) + { + if(mod->lastAffected != spell) + return false; + } + else if(mod->lastAffected != FindCurrentSpellBySpellId(spellInfo->Id)) + return false; + } + + return spellmgr.IsAffectedBySpell(spellInfo,mod->spellId,mod->effectId,mod->mask); +} + +void Player::AddSpellMod(SpellModifier* mod, bool apply) +{ + uint16 Opcode= (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; + + for(int eff=0;eff<64;++eff) + { + uint64 _mask = uint64(1) << eff; + if ( mod->mask & _mask) + { + int32 val = 0; + for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr) + { + if ((*itr)->type == mod->type && (*itr)->mask & _mask) + val += (*itr)->value; + } + val += apply ? mod->value : -(mod->value); + WorldPacket data(Opcode, (1+1+4)); + data << uint8(eff); + data << uint8(mod->op); + data << int32(val); + SendDirectMessage(&data); + } + } + + if (apply) + m_spellMods[mod->op].push_back(mod); + else + { + if (mod->charges == -1) + --m_SpellModRemoveCount; + m_spellMods[mod->op].remove(mod); + delete mod; + } +} + +void Player::RemoveSpellMods(Spell const* spell) +{ + if(!spell || (m_SpellModRemoveCount == 0)) + return; + + for(int i=0;icharges == -1 && (mod->lastAffected == spell || mod->lastAffected==NULL)) + { + RemoveAurasDueToSpell(mod->spellId); + if (m_spellMods[i].empty()) + break; + else + itr = m_spellMods[i].begin(); + } + } + } +} + +// send Proficiency +void Player::SendProficiency(uint8 pr1, uint32 pr2) +{ + WorldPacket data(SMSG_SET_PROFICIENCY, 8); + data << pr1 << pr2; + GetSession()->SendPacket (&data); +} + +void Player::RemovePetitionsAndSigns(uint64 guid, uint32 type) +{ + QueryResult *result = NULL; + if(type==10) + result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid)); + else + result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); + if(result) + { + do // this part effectively does nothing, since the deletion / modification only takes place _after_ the PetitionQuery. Though I don't know if the result remains intact if I execute the delete query beforehand. + { // and SendPetitionQueryOpcode reads data from the DB + Field *fields = result->Fetch(); + uint64 ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + uint64 petitionguid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_ITEM); + + // send update if charter owner in game + Player* owner = objmgr.GetPlayer(ownerguid); + if(owner) + owner->GetSession()->SendPetitionQueryOpcode(petitionguid); + + } while ( result->NextRow() ); + + delete result; + + if(type==10) + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid)); + else + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); + } + + CharacterDatabase.BeginTransaction(); + if(type == 10) + { + CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u'", GUID_LOPART(guid)); + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u'", GUID_LOPART(guid)); + } + else + { + CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); + } + CharacterDatabase.CommitTransaction(); +} + +void Player::SetRestBonus (float rest_bonus_new) +{ + // Prevent resting on max level + if(getLevel() >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + rest_bonus_new = 0; + + if(rest_bonus_new < 0) + rest_bonus_new = 0; + + float rest_bonus_max = (float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)*1.5/2; + + if(rest_bonus_new > rest_bonus_max) + m_rest_bonus = rest_bonus_max; + else + m_rest_bonus = rest_bonus_new; + + // update data for client + if(m_rest_bonus>10) + SetByteValue(PLAYER_BYTES_2, 3, 0x01); // Set Reststate = Rested + else if(m_rest_bonus<=1) + SetByteValue(PLAYER_BYTES_2, 3, 0x02); // Set Reststate = Normal + + //RestTickUpdate + SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus)); +} + +void Player::HandleStealthedUnitsDetection() +{ + std::list stealthedUnits; + + CellPair p(MaNGOS::ComputeCellPair(GetPositionX(),GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::AnyStealthedCheck u_check; + MaNGOS::UnitListSearcher searcher(stealthedUnits, u_check); + + TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); + TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); + cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); + + for (std::list::iterator i = stealthedUnits.begin(); i != stealthedUnits.end();) + { + if((*i)==this) + { + i = stealthedUnits.erase(i); + continue; + } + + if ((*i)->isVisibleForOrDetect(this,true)) + { + + (*i)->SendUpdateToPlayer(this); + m_clientGUIDs.insert((*i)->GetGUID()); + + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) + sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i)); + #endif + + // target aura duration for caster show only if target exist at caster client + // send data at target visibility change (adding to client) + if((*i)!=this && (*i)->isType(TYPEMASK_UNIT)) + SendAuraDurationsForTarget(*i); + + i = stealthedUnits.erase(i); + continue; + } + + ++i; + } +} + +bool Player::ActivateTaxiPathTo(std::vector const& nodes, uint32 mount_id, Creature* npc) +{ + if(nodes.size() < 2) + return false; + + // not let cheating with start flight mounted + if(IsMounted()) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIPLAYERALREADYMOUNTED); + GetSession()->SendPacket(&data); + return false; + } + + if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW ) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIPLAYERSHAPESHIFTED); + GetSession()->SendPacket(&data); + return false; + } + + // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi + if(GetSession()->isLogingOut() || + (!m_currentSpells[CURRENT_GENERIC_SPELL] || + m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Effect[0] != SPELL_EFFECT_SEND_TAXI)&& + IsNonMeleeSpellCasted(false) || + isInCombat()) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIPLAYERBUSY); + GetSession()->SendPacket(&data); + return false; + } + + if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) + return false; + + uint32 sourcenode = nodes[0]; + + // starting node too far away (cheat?) + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(sourcenode); + if( !node || node->map_id != GetMapId() || + (node->x - GetPositionX())*(node->x - GetPositionX())+ + (node->y - GetPositionY())*(node->y - GetPositionY())+ + (node->z - GetPositionZ())*(node->z - GetPositionZ()) > + (2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE) ) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR); + GetSession()->SendPacket(&data); + return false; + } + + // Prepare to flight start now + + // stop combat at start taxi flight if any + CombatStop(); + + // stop trade (client cancel trade at taxi map open but cheating tools can be used for reopen it) + TradeCancel(true); + + // clean not finished taxi path if any + m_taxi.ClearTaxiDestinations(); + + // 0 element current node + m_taxi.AddTaxiDestination(sourcenode); + + // fill destinations path tail + uint32 sourcepath = 0; + uint32 totalcost = 0; + + uint32 prevnode = sourcenode; + uint32 lastnode = 0; + + for(uint32 i = 1; i < nodes.size(); ++i) + { + uint32 path, cost; + + lastnode = nodes[i]; + objmgr.GetTaxiPath(prevnode, lastnode, path, cost); + + if(!path) + { + m_taxi.ClearTaxiDestinations(); + return false; + } + + totalcost += cost; + + if(prevnode == sourcenode) + sourcepath = path; + + m_taxi.AddTaxiDestination(lastnode); + + prevnode = lastnode; + } + + if(!mount_id) // if not provide then attempt use default. + mount_id = objmgr.GetTaxiMount(sourcenode, GetTeam()); + + if (mount_id == 0 || sourcepath == 0) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR); + GetSession()->SendPacket(&data); + m_taxi.ClearTaxiDestinations(); + return false; + } + + uint32 money = GetMoney(); + + if(npc) + { + totalcost = (uint32)ceil(totalcost*GetReputationPriceDiscount(npc)); + } + + if(money < totalcost) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXINOTENOUGHMONEY); + GetSession()->SendPacket(&data); + m_taxi.ClearTaxiDestinations(); + return false; + } + + //Checks and preparations done, DO FLIGHT + ModifyMoney(-(int32)totalcost); + + // prevent stealth flight + RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIOK); + GetSession()->SendPacket(&data); + + sLog.outDebug("WORLD: Sent SMSG_ACTIVATETAXIREPLY"); + + GetSession()->SendDoFlight(mount_id, sourcepath); + + return true; +} + +void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ) +{ + // last check 2.0.10 + WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+m_spells.size()*8); + data << GetGUID(); + data << uint8(0x0); + time_t curTime = time(NULL); + for(PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) + { + if (itr->second->state == PLAYERSPELL_REMOVED) + continue; + uint32 unSpellId = itr->first; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(unSpellId); + if (!spellInfo) + { + ASSERT(spellInfo); + continue; + } + + // Not send cooldown for this spells + if (spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) + continue; + + if((idSchoolMask & GetSpellSchoolMask(spellInfo)) && GetSpellCooldownDelay(unSpellId) < unTimeMs ) + { + data << unSpellId; + data << unTimeMs; // in m.secs + AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/1000); + } + } + GetSession()->SendPacket(&data); +} + +void Player::InitDataForForm(bool reapplyMods) +{ + SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(m_form); + if(ssEntry && ssEntry->attackSpeed) + { + SetAttackTime(BASE_ATTACK,ssEntry->attackSpeed); + SetAttackTime(OFF_ATTACK,ssEntry->attackSpeed); + SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME); + } + else + SetRegularAttackTime(); + + switch(m_form) + { + case FORM_CAT: + { + if(getPowerType()!=POWER_ENERGY) + setPowerType(POWER_ENERGY); + break; + } + case FORM_BEAR: + case FORM_DIREBEAR: + { + if(getPowerType()!=POWER_RAGE) + setPowerType(POWER_RAGE); + break; + } + default: // 0, for example + { + ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(getClass()); + if(cEntry && cEntry->powerType < MAX_POWERS && uint32(getPowerType()) != cEntry->powerType) + setPowerType(Powers(cEntry->powerType)); + break; + } + } + + // update auras at form change, ignore this at mods reapply (.reset stats/etc) when form not change. + if (!reapplyMods) + UpdateEquipSpellsAtFormChange(); + + UpdateAttackPowerAndDamage(); + UpdateAttackPowerAndDamage(true); +} + +// Return true is the bought item has a max count to force refresh of window by caller +bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot) +{ + // cheating attempt + if(count < 1) count = 1; + + if(!isAlive()) + return false; + + ItemPrototype const *pProto = objmgr.GetItemPrototype( item ); + if( !pProto ) + { + SendBuyError( BUY_ERR_CANT_FIND_ITEM, NULL, item, 0); + return false; + } + + Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*this, vendorguid,UNIT_NPC_FLAG_VENDOR); + if (!pCreature) + { + sLog.outDebug( "WORLD: BuyItemFromVendor - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) ); + SendBuyError( BUY_ERR_DISTANCE_TOO_FAR, NULL, item, 0); + return false; + } + + // load vendor items if not yet + pCreature->LoadGoods(); + + CreatureItem* crItem = pCreature->FindItem(item); + if(!crItem) + { + SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0); + return false; + } + + if( crItem->maxcount != 0 && crItem->count < count ) + { + SendBuyError( BUY_ERR_ITEM_ALREADY_SOLD, pCreature, item, 0); + return false; + } + + if( uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank) + { + SendBuyError( BUY_ERR_REPUTATION_REQUIRE, pCreature, item, 0); + return false; + } + + if(crItem->ExtendedCost) + { + ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); + if(!iece) + { + sLog.outError("Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); + return false; + } + + // honor points price + if(GetHonorPoints() < (iece->reqhonorpoints * count)) + { + SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL); + return false; + } + + // arena points price + if(GetArenaPoints() < (iece->reqarenapoints * count)) + { + SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL); + return false; + } + + // item base price + for (uint8 i = 0; i < 5; ++i) + { + if(iece->reqitem[i] && !HasItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count))) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); + return false; + } + } + + // check for personal arena rating requirement + if( GetMaxPersonalArenaRatingRequirement() < iece->reqpersonalarenarating ) + { + // probably not the proper equip err + SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK,NULL,NULL); + return false; + } + } + + uint32 price = pProto->BuyPrice * count; + + // reputation discount + price = uint32(floor(price * GetReputationPriceDiscount(pCreature))); + + if( GetMoney() < price ) + { + SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, item, 0); + return false; + } + + uint8 bag = 0; // init for case invalid bagGUID + + if (bagguid != NULL_BAG && slot != NULL_SLOT) + { + Bag *pBag; + if( bagguid == GetGUID() ) + { + bag = INVENTORY_SLOT_BAG_0; + } + else + { + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;i++) + { + pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0,i); + if( pBag ) + { + if( bagguid == pBag->GetGUID() ) + { + bag = i; + break; + } + } + } + } + } + + if( IsInventoryPos( bag, slot ) || (bagguid == NULL_BAG && slot == NULL_SLOT) ) + { + ItemPosCountVec dest; + uint8 msg = CanStoreNewItem( bag, slot, dest, item, pProto->BuyCount * count ); + if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, NULL, NULL ); + return false; + } + + ModifyMoney( -(int32)price ); + if(crItem->ExtendedCost) // case for new honor system + { + ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); + if(iece->reqhonorpoints) + ModifyHonorPoints( - int32(iece->reqhonorpoints * count)); + if(iece->reqarenapoints) + ModifyArenaPoints( - int32(iece->reqarenapoints * count)); + for (uint8 i = 0; i < 5; ++i) + { + if(iece->reqitem[i]) + DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true); + } + } + + if(Item *it = StoreNewItem( dest, item, true )) + { + if( crItem->maxcount != 0 ) + crItem->count -= pProto->BuyCount * count; + + WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); + data << pCreature->GetGUID(); + data << (uint32)crItem->id; // entry + data << (uint32)crItem->count; + data << (uint32)count; + GetSession()->SendPacket(&data); + + SendNewItem(it, count, true, false, false); + } + } + else if( IsEquipmentPos( bag, slot ) ) + { + uint16 dest; + uint8 msg = CanEquipNewItem( slot, dest, item, pProto->BuyCount * count, false ); + if( msg != EQUIP_ERR_OK ) + { + SendEquipError( msg, NULL, NULL ); + return false; + } + + ModifyMoney( -(int32)price ); + if(crItem->ExtendedCost) // case for new honor system + { + ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); + if(iece->reqhonorpoints) + ModifyHonorPoints( - int32(iece->reqhonorpoints)); + if(iece->reqarenapoints) + ModifyArenaPoints( - int32(iece->reqarenapoints)); + for (uint8 i = 0; i < 5; ++i) + { + if(iece->reqitem[i]) + DestroyItemCount(iece->reqitem[i], iece->reqitemcount[i], true); + } + } + + if(Item *it = EquipNewItem( dest, item, pProto->BuyCount * count, true )) + { + if( crItem->maxcount != 0 ) + crItem->count -= pProto->BuyCount * count; + + WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); + data << pCreature->GetGUID(); + data << (uint32)crItem->id; // entry + data << (uint32)crItem->count; + data << (uint32)count; + GetSession()->SendPacket(&data); + + SendNewItem(it, count, true, false, false); + + AutoUnequipOffhandIfNeed(); + } + } + else + { + SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL ); + return false; + } + + return crItem->maxcount!=0?true:false; +} + +uint32 Player::GetMaxPersonalArenaRatingRequirement() +{ + // returns the maximal personal arena rating that can be used to purchase items requiring this condition + // the personal rating of the arena team must match the required limit as well + // so return max[in arenateams](min(personalrating[teamtype], teamrating[teamtype])) + uint32 max_personal_rating = 0; + for(int i = 0; i < MAX_ARENA_SLOT; ++i) + { + if(ArenaTeam * at = objmgr.GetArenaTeamById(GetArenaTeamId(i))) + { + uint32 p_rating = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (i * 6) + 5); + uint32 t_rating = at->GetRating(); + p_rating = p_ratingSendPacket(&data); + } + // instance is valid, reset homebind timer + m_HomebindTimer = 0; + } + else if (m_HomebindTimer > 0) + { + if (time >= m_HomebindTimer) + { + // teleport to homebind location + TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); + } + else + m_HomebindTimer -= time; + } + else + { + // instance is invalid, start homebind timer + m_HomebindTimer = 60000; + // send message to player + WorldPacket data(SMSG_RAID_GROUP_ONLY, 4+4); + data << m_HomebindTimer; + data << uint32(1); + GetSession()->SendPacket(&data); + sLog.outDebug("PLAYER: Player '%s' (GUID: %u) will be teleported to homebind in 60 seconds", GetName(),GetGUIDLow()); + } +} + +void Player::UpdatePvP(bool state, bool ovrride) +{ + if(!state || ovrride) + { + SetPvP(state); + if(Pet* pet = GetPet()) + pet->SetPvP(state); + if(Unit* charmed = GetCharm()) + charmed->SetPvP(state); + + pvpInfo.endTimer = 0; + } + else + { + if(pvpInfo.endTimer != 0) + pvpInfo.endTimer = time(NULL); + else + { + SetPvP(state); + + if(Pet* pet = GetPet()) + pet->SetPvP(state); + if(Unit* charmed = GetCharm()) + charmed->SetPvP(state); + } + } +} + +void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time) +{ + SpellCooldown sc; + sc.end = end_time; + sc.itemid = itemid; + m_spellCooldowns[spellid] = sc; +} + +void Player::SendCooldownEvent(SpellEntry const *spellInfo) +{ + if ( !(spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) ) + return; + + // Get spell cooldwn + int32 cooldown = GetSpellRecoveryTime(spellInfo); + // Apply spellmods + ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown); + if (cooldown < 0) + cooldown = 0; + // Add cooldown + AddSpellCooldown(spellInfo->Id, 0, time(NULL) + cooldown / 1000); + // Send activate + WorldPacket data(SMSG_COOLDOWN_EVENT, (4+8)); + data << spellInfo->Id; + data << GetGUID(); + SendDirectMessage(&data); +} + //slot to be excluded while counting +bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) +{ + if(!enchantmentcondition) + return true; + + SpellItemEnchantmentConditionEntry const *Condition = sSpellItemEnchantmentConditionStore.LookupEntry(enchantmentcondition); + + if(!Condition) + return true; + + uint8 curcount[4] = {0, 0, 0, 0}; + + //counting current equipped gem colors + for(uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) + { + if(i == slot) + continue; + Item *pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if(pItem2 && pItem2->GetProto()->Socket[0].Color) + { + for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) + { + uint32 enchant_id = pItem2->GetEnchantmentId(EnchantmentSlot(enchant_slot)); + if(!enchant_id) + continue; + + SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!enchantEntry) + continue; + + uint32 gemid = enchantEntry->GemID; + if(!gemid) + continue; + + ItemPrototype const* gemProto = sItemStorage.LookupEntry(gemid); + if(!gemProto) + continue; + + GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GemProperties); + if(!gemProperty) + continue; + + uint8 GemColor = gemProperty->color; + + for(uint8 b = 0, tmpcolormask = 1; b < 4; b++, tmpcolormask <<= 1) + { + if(tmpcolormask & GemColor) + ++curcount[b]; + } + } + } + } + + bool activate = true; + + for(int i = 0; i < 5; i++) + { + if(!Condition->Color[i]) + continue; + + uint32 _cur_gem = curcount[Condition->Color[i] - 1]; + + // if have use them as count, else use from Condition + uint32 _cmp_gem = Condition->CompareColor[i] ? curcount[Condition->CompareColor[i] - 1]: Condition->Value[i]; + + switch(Condition->Comparator[i]) + { + case 2: // requires less than ( || ) gems + activate &= (_cur_gem < _cmp_gem) ? true : false; + break; + case 3: // requires more than ( || ) gems + activate &= (_cur_gem > _cmp_gem) ? true : false; + break; + case 5: // requires at least than ( || ) gems + activate &= (_cur_gem >= _cmp_gem) ? true : false; + break; + } + } + + sLog.outDebug("Checking Condition %u, there are %u Meta Gems, %u Red Gems, %u Yellow Gems and %u Blue Gems, Activate:%s", enchantmentcondition, curcount[0], curcount[1], curcount[2], curcount[3], activate ? "yes" : "no"); + + return activate; +} + +void Player::CorrectMetaGemEnchants(uint8 exceptslot, bool apply) +{ + //cycle all equipped items + for(uint32 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) + { + //enchants for the slot being socketed are handled by Player::ApplyItemMods + if(slot == exceptslot) + continue; + + Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, slot ); + + if(!pItem || !pItem->GetProto()->Socket[0].Color) + continue; + + for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) + { + uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot)); + if(!enchant_id) + continue; + + SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!enchantEntry) + continue; + + uint32 condition = enchantEntry->EnchantmentCondition; + if(condition) + { + //was enchant active with/without item? + bool wasactive = EnchantmentFitsRequirements(condition, apply ? exceptslot : -1); + //should it now be? + if(wasactive ^ EnchantmentFitsRequirements(condition, apply ? -1 : exceptslot)) + { + // ignore item gem conditions + //if state changed, (dis)apply enchant + ApplyEnchantment(pItem,EnchantmentSlot(enchant_slot),!wasactive,true,true); + } + } + } + } +} + + //if false -> then toggled off if was on| if true -> toggled on if was off AND meets requirements +void Player::ToggleMetaGemsActive(uint8 exceptslot, bool apply) +{ + //cycle all equipped items + for(int slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) + { + //enchants for the slot being socketed are handled by WorldSession::HandleSocketOpcode(WorldPacket& recv_data) + if(slot == exceptslot) + continue; + + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, slot ); + + if(!pItem || !pItem->GetProto()->Socket[0].Color) //if item has no sockets or no item is equipped go to next item + continue; + + //cycle all (gem)enchants + for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) + { + uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot)); + if(!enchant_id) //if no enchant go to next enchant(slot) + continue; + + SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!enchantEntry) + continue; + + //only metagems to be (de)activated, so only enchants with condition + uint32 condition = enchantEntry->EnchantmentCondition; + if(condition) + ApplyEnchantment(pItem,EnchantmentSlot(enchant_slot), apply); + } + } +} + +void Player::LeaveBattleground(bool teleportToEntryPoint) +{ + if(BattleGround *bg = GetBattleGround()) + { + bool need_debuf = bg->isBattleGround() && (bg->GetStatus() == STATUS_IN_PROGRESS) && sWorld.getConfig(CONFIG_BATTLEGROUND_CAST_DESERTER); + + bg->RemovePlayerAtLeave(GetGUID(), teleportToEntryPoint, true); + + // call after remove to be sure that player resurrected for correct cast + if(need_debuf) + CastSpell(this, 26013, true); // Deserter + } +} + +bool Player::CanJoinToBattleground() const +{ + // check Deserter debuff + if(GetDummyAura(26013)) + return false; + + return true; +} + +bool Player::CanReportAfkDueToLimit() +{ + // a player can complain about 15 people per 5 minutes + if(m_bgAfkReportedCount >= 15) + return false; + ++m_bgAfkReportedCount; + return true; +} + +///This player has been blamed to be inactive in a battleground +void Player::ReportedAfkBy(Player* reporter) +{ + BattleGround *bg = GetBattleGround(); + if(!bg || bg != reporter->GetBattleGround() || GetTeam() != reporter->GetTeam()) + return; + + // check if player has 'Idle' or 'Inactive' debuff + if(m_bgAfkReporter.find(reporter->GetGUIDLow())==m_bgAfkReporter.end() && !HasAura(43680,0) && !HasAura(43681,0) && reporter->CanReportAfkDueToLimit()) + { + m_bgAfkReporter.insert(reporter->GetGUIDLow()); + // 3 players have to complain to apply debuff + if(m_bgAfkReporter.size() >= 3) + { + // cast 'Idle' spell + CastSpell(this, 43680, true); + m_bgAfkReporter.clear(); + } + } +} + +bool Player::IsVisibleInGridForPlayer( Player* pl ) const +{ + // gamemaster in GM mode see all, including ghosts + if(pl->isGameMaster() && GetSession()->GetSecurity() <= pl->GetSession()->GetSecurity()) + return true; + + // It seems in battleground everyone sees everyone, except the enemy-faction ghosts + if (InBattleGround()) + { + if (!(isAlive() || m_deathTimer > 0) && !IsFriendlyTo(pl) ) + return false; + return true; + } + + // Live player see live player or dead player with not realized corpse + if(pl->isAlive() || pl->m_deathTimer > 0) + { + return isAlive() || m_deathTimer > 0; + } + + // Ghost see other friendly ghosts, that's for sure + if(!(isAlive() || m_deathTimer > 0) && IsFriendlyTo(pl)) + return true; + + // Dead player see live players near own corpse + if(isAlive()) + { + Corpse *corpse = pl->GetCorpse(); + if(corpse) + { + // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level + if(corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO))) + return true; + } + } + + // and not see any other + return false; +} + +bool Player::IsVisibleGloballyFor( Player* u ) const +{ + if(!u) + return false; + + // Always can see self + if (u==this) + return true; + + // Visible units, always are visible for all players + if (GetVisibility() == VISIBILITY_ON) + return true; + + // GMs are visible for higher gms (or players are visible for gms) + if (u->GetSession()->GetSecurity() > SEC_PLAYER) + return GetSession()->GetSecurity() <= u->GetSession()->GetSecurity(); + + // non faction visibility non-breakable for non-GMs + if (GetVisibility() == VISIBILITY_OFF) + return false; + + // non-gm stealth/invisibility not hide from global player lists + return true; +} + +void Player::UpdateVisibilityOf(WorldObject* target) +{ + if(HaveAtClient(target)) + { + if(!target->isVisibleForInState(this,true)) + { + target->DestroyForPlayer(this); + m_clientGUIDs.erase(target->GetGUID()); + + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) + sLog.outDebug("Object %u (Type: %u) out of range for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),GetGUIDLow(),GetDistance(target)); + #endif + } + } + else + { + if(target->isVisibleForInState(this,false)) + { + target->SendUpdateToPlayer(this); + if(target->GetTypeId()!=TYPEID_GAMEOBJECT||!((GameObject*)target)->IsTransport()) + m_clientGUIDs.insert(target->GetGUID()); + + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) + sLog.outDebug("Object %u (Type: %u) is visible now for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),GetGUIDLow(),GetDistance(target)); + #endif + + // target aura duration for caster show only if target exist at caster client + // send data at target visibility change (adding to client) + if(target!=this && target->isType(TYPEMASK_UNIT)) + SendAuraDurationsForTarget((Unit*)target); + + if(target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isAlive()) + ((Creature*)target)->SendMonsterMoveWithSpeedToCurrentDestination(this); + } + } +} + +template +inline void UpdateVisibilityOf_helper(std::set& s64, T* target) +{ + s64.insert(target->GetGUID()); +} + +template<> +inline void UpdateVisibilityOf_helper(std::set& s64, GameObject* target) +{ + if(!target->IsTransport()) + s64.insert(target->GetGUID()); +} + +template +void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow) +{ + if(HaveAtClient(target)) + { + if(!target->isVisibleForInState(this,true)) + { + target->BuildOutOfRangeUpdateBlock(&data); + m_clientGUIDs.erase(target->GetGUID()); + + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) + sLog.outDebug("Object %u (Type: %u, Entry: %u) is out of range for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),target->GetEntry(),GetGUIDLow(),GetDistance(target)); + #endif + } + } + else + { + if(target->isVisibleForInState(this,false)) + { + visibleNow.insert(target); + target->BuildUpdate(data_updates); + target->BuildCreateUpdateBlockForPlayer(&data, this); + UpdateVisibilityOf_helper(m_clientGUIDs,target); + + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) + sLog.outDebug("Object %u (Type: %u, Entry: %u) is visible now for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),target->GetEntry(),GetGUIDLow(),GetDistance(target)); + #endif + } + } +} + +template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); + +void Player::InitPrimaryProffesions() +{ + SetFreePrimaryProffesions(sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)); +} + +void Player::SendComboPoints() +{ + Unit *combotarget = ObjectAccessor::GetUnit(*this, m_comboTarget); + if (combotarget) + { + WorldPacket data(SMSG_UPDATE_COMBO_POINTS, combotarget->GetPackGUID().size()+1); + data.append(combotarget->GetPackGUID()); + data << uint8(m_comboPoints); + GetSession()->SendPacket(&data); + } +} + +void Player::AddComboPoints(Unit* target, int8 count) +{ + if(!count) + return; + + // without combo points lost (duration checked in aura) + RemoveSpellsCausingAura(SPELL_AURA_RETAIN_COMBO_POINTS); + + if(target->GetGUID() == m_comboTarget) + { + m_comboPoints += count; + } + else + { + if(m_comboTarget) + if(Unit* target = ObjectAccessor::GetUnit(*this,m_comboTarget)) + target->RemoveComboPointHolder(GetGUIDLow()); + + m_comboTarget = target->GetGUID(); + m_comboPoints = count; + + target->AddComboPointHolder(GetGUIDLow()); + } + + if (m_comboPoints > 5) m_comboPoints = 5; + if (m_comboPoints < 0) m_comboPoints = 0; + + SendComboPoints(); +} + +void Player::ClearComboPoints() +{ + if(!m_comboTarget) + return; + + // without combopoints lost (duration checked in aura) + RemoveSpellsCausingAura(SPELL_AURA_RETAIN_COMBO_POINTS); + + m_comboPoints = 0; + + SendComboPoints(); + + if(Unit* target = ObjectAccessor::GetUnit(*this,m_comboTarget)) + target->RemoveComboPointHolder(GetGUIDLow()); + + m_comboTarget = 0; +} + +void Player::SetGroup(Group *group, int8 subgroup) +{ + if(group == NULL) m_group.unlink(); + else + { + // never use SetGroup without a subgroup unless you specify NULL for group + assert(subgroup >= 0); + m_group.link(group, this); + m_group.setSubGroup((uint8)subgroup); + } +} + +void Player::SendInitialPacketsBeforeAddToMap() +{ + WorldPacket data(SMSG_SET_REST_START, 4); + data << uint32(0); // unknown, may be rest state time or expirience + GetSession()->SendPacket(&data); + + // Homebind + data.Initialize(SMSG_BINDPOINTUPDATE, 5*4); + data << m_homebindX << m_homebindY << m_homebindZ; + data << (uint32) m_homebindMapId; + data << (uint32) m_homebindZoneId; + GetSession()->SendPacket(&data); + + // SMSG_SET_PROFICIENCY + // SMSG_UPDATE_AURA_DURATION + + // tutorial stuff + data.Initialize(SMSG_TUTORIAL_FLAGS, 8*4); + for (int i = 0; i < 8; ++i) + data << uint32( GetTutorialInt(i) ); + GetSession()->SendPacket(&data); + + SendInitialSpells(); + + data.Initialize(SMSG_SEND_UNLEARN_SPELLS, 4); + data << uint32(0); // count, for(count) uint32; + GetSession()->SendPacket(&data); + + SendInitialActionButtons(); + SendInitialReputations(); + UpdateZone(GetZoneId()); + SendInitWorldStates(); + + // SMSG_SET_AURA_SINGLE + + data.Initialize(SMSG_LOGIN_SETTIMESPEED, 8); + data << uint32(secsToTimeBitFields(sWorld.GetGameTime())); + data << (float)0.01666667f; // game speed + GetSession()->SendPacket( &data ); + + // set fly flag if in fly form or taxi flight to prevent visually drop at ground in showup moment + if(HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED) || isInFlight()) + SetUnitMovementFlags(GetUnitMovementFlags() | MOVEMENTFLAG_FLYING2); +} + +void Player::SendInitialPacketsAfterAddToMap() +{ + CastSpell(this, 836, true); // LOGINEFFECT + + // set some aura effects that send packet to player client after add player to map + // SendMessageToSet not send it to player not it map, only for aura that not changed anything at re-apply + // same auras state lost at far teleport, send it one more time in this case also + static const AuraType auratypes[] = + { + SPELL_AURA_MOD_FEAR, SPELL_AURA_TRANSFORM, SPELL_AURA_WATER_WALK, + SPELL_AURA_FEATHER_FALL, SPELL_AURA_HOVER, SPELL_AURA_SAFE_FALL, + SPELL_AURA_FLY, SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED, SPELL_AURA_NONE + }; + for(AuraType const* itr = &auratypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr) + { + Unit::AuraList const& auraList = GetAurasByType(*itr); + if(!auraList.empty()) + auraList.front()->ApplyModifier(true,true); + } + + if(HasAuraType(SPELL_AURA_MOD_STUN)) + SetMovement(MOVE_ROOT); + + // manual send package (have code in ApplyModifier(true,true); that don't must be re-applied. + if(HasAuraType(SPELL_AURA_MOD_ROOT)) + { + WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10); + data.append(GetPackGUID()); + data << (uint32)2; + SendMessageToSet(&data,true); + } + + SendEnchantmentDurations(); // must be after add to map + SendItemDurations(); // must be after add to map +} + +void Player::SendUpdateToOutOfRangeGroupMembers() +{ + if (m_groupUpdateMask == GROUP_UPDATE_FLAG_NONE) + return; + if(Group* group = GetGroup()) + group->UpdatePlayerOutOfRange(this); + + m_groupUpdateMask = GROUP_UPDATE_FLAG_NONE; + m_auraUpdateMask = 0; + if(Pet *pet = GetPet()) + pet->ResetAuraUpdateMask(); +} + +void Player::SendTransferAborted(uint32 mapid, uint16 reason) +{ + WorldPacket data(SMSG_TRANSFER_ABORTED, 4+2); + data << uint32(mapid); + data << uint16(reason); // transfer abort reason + GetSession()->SendPacket(&data); +} + +void Player::SendInstanceResetWarning(uint32 mapid, uint32 time) +{ + // type of warning, based on the time remaining until reset + uint32 type; + if(time > 3600) + type = RAID_INSTANCE_WELCOME; + else if(time > 900 && time <= 3600) + type = RAID_INSTANCE_WARNING_HOURS; + else if(time > 300 && time <= 900) + type = RAID_INSTANCE_WARNING_MIN; + else + type = RAID_INSTANCE_WARNING_MIN_SOON; + WorldPacket data(SMSG_RAID_INSTANCE_MESSAGE, 4+4+4); + data << uint32(type); + data << uint32(mapid); + data << uint32(time); + GetSession()->SendPacket(&data); +} + +void Player::ApplyEquipCooldown( Item * pItem ) +{ + for(int i = 0; i <5; ++i) + { + _Spell const& spellData = pItem->GetProto()->Spells[i]; + + // no spell + if( !spellData.SpellId ) + continue; + + // wrong triggering type (note: ITEM_SPELLTRIGGER_ON_NO_DELAY_USE not have cooldown) + if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE ) + continue; + + AddSpellCooldown(spellData.SpellId, pItem->GetEntry(), time(NULL) + 30); + + WorldPacket data(SMSG_ITEM_COOLDOWN, 12); + data << pItem->GetGUID(); + data << uint32(spellData.SpellId); + GetSession()->SendPacket(&data); + } +} + +void Player::resetSpells() +{ + // not need after this call + if(HasAtLoginFlag(AT_LOGIN_RESET_SPELLS)) + { + m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_SPELLS; + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_SPELLS), GetGUIDLow()); + } + + // make full copy of map (spells removed and marked as deleted at another spell remove + // and we can't use original map for safe iterative with visit each spell at loop end + PlayerSpellMap smap = GetSpellMap(); + + for(PlayerSpellMap::const_iterator iter = smap.begin();iter != smap.end(); ++iter) + removeSpell(iter->first); // only iter->first can be accessed, object by iter->second can be deleted already + + learnDefaultSpells(); + learnQuestRewardedSpells(); +} + +void Player::learnDefaultSpells(bool loading) +{ + // learn default race/class spells + PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(),getClass()); + std::list::const_iterator spell_itr; + for (spell_itr = info->spell.begin(); spell_itr!=info->spell.end(); ++spell_itr) + { + uint16 tspell = spell_itr->first; + if (tspell) + { + sLog.outDebug("PLAYER: Adding initial spell, id = %u",tspell); + if(loading || !spell_itr->second) // not care about passive spells or loading case + addSpell(tspell,spell_itr->second); + else // but send in normal spell in game learn case + learnSpell(tspell); + } + } +} + +void Player::learnQuestRewardedSpells(Quest const* quest) +{ + uint32 spell_id = quest->GetRewSpellCast(); + + // skip quests without rewarded spell + if( !spell_id ) + return; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + if(!spellInfo) + return; + + // check learned spells state + bool found = false; + for(int i=0; i < 3; ++i) + { + if(spellInfo->Effect[i] == SPELL_EFFECT_LEARN_SPELL && !HasSpell(spellInfo->EffectTriggerSpell[i])) + { + found = true; + break; + } + } + + // skip quests with not teaching spell or already known spell + if(!found) + return; + + // prevent learn non first rank unknown profession and second specialization for same profession) + uint32 learned_0 = spellInfo->EffectTriggerSpell[0]; + if( spellmgr.GetSpellRank(learned_0) > 1 && !HasSpell(learned_0) ) + { + // not have first rank learned (unlearned prof?) + uint32 first_spell = spellmgr.GetFirstSpellInChain(learned_0); + if( !HasSpell(first_spell) ) + return; + + SpellEntry const *learnedInfo = sSpellStore.LookupEntry(learned_0); + if(!learnedInfo) + return; + + // specialization + if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0) + { + // search other specialization for same prof + for(PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) + { + if(itr->second->state == PLAYERSPELL_REMOVED || itr->first==learned_0) + continue; + + SpellEntry const *itrInfo = sSpellStore.LookupEntry(itr->first); + if(!itrInfo) + return; + + // compare only specializations + if(itrInfo->Effect[0]!=SPELL_EFFECT_TRADE_SKILL || itrInfo->Effect[1]!=0) + continue; + + // compare same chain spells + if(spellmgr.GetFirstSpellInChain(itr->first) != first_spell) + continue; + + // now we have 2 specialization, learn possible only if found is lesser specialization rank + if(!spellmgr.IsHighRankOfSpell(learned_0,itr->first)) + return; + } + } + } + + CastSpell( this, spell_id, true); +} + +void Player::learnQuestRewardedSpells() +{ + // learn spells received from quest completing + for(QuestStatusMap::const_iterator itr = mQuestStatus.begin(); itr != mQuestStatus.end(); ++itr) + { + // skip no rewarded quests + if(!itr->second.m_rewarded) + continue; + + Quest const* quest = objmgr.GetQuestTemplate(itr->first); + if( !quest ) + continue; + + learnQuestRewardedSpells(quest); + } +} + +void Player::learnSkillRewardedSpells(uint32 skill_id ) +{ + uint32 raceMask = getRaceMask(); + uint32 classMask = getClassMask(); + for (uint32 j=0; jskillId!=skill_id || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL) + continue; + // Check race if set + if (pAbility->racemask && !(pAbility->racemask & raceMask)) + continue; + // Check class if set + if (pAbility->classmask && !(pAbility->classmask & classMask)) + continue; + + if (SpellEntry const* spellentry = sSpellStore.LookupEntry(pAbility->spellId)) + { + // Ok need learn spell + learnSpell(pAbility->spellId); + } + } +} + +void Player::learnSkillRewardedSpells() +{ + for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) + { + if(!GetUInt32Value(PLAYER_SKILL_INDEX(i))) + continue; + + uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; + + learnSkillRewardedSpells(pskill); + } +} + +void Player::SendAuraDurationsForTarget(Unit* target) +{ + for(Unit::AuraMap::const_iterator itr = target->GetAuras().begin(); itr != target->GetAuras().end(); ++itr) + { + Aura* aura = itr->second; + if(aura->GetAuraSlot() >= MAX_AURAS || aura->IsPassive() || aura->GetCasterGUID()!=GetGUID()) + continue; + + aura->SendAuraDurationForCaster(this); + } +} + +void Player::SetDailyQuestStatus( uint32 quest_id ) +{ + for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) + { + if(!GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)) + { + SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,quest_id); + m_lastDailyQuestTime = time(NULL); // last daily quest time + m_DailyQuestChanged = true; + break; + } + } +} + +void Player::ResetDailyQuestStatus() +{ + for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) + SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,0); + + // DB data deleted in caller + m_DailyQuestChanged = false; + m_lastDailyQuestTime = 0; +} + +BattleGround* Player::GetBattleGround() const +{ + if(GetBattleGroundId()==0) + return NULL; + + return sBattleGroundMgr.GetBattleGround(GetBattleGroundId()); +} + +bool Player::InArena() const +{ + BattleGround *bg = GetBattleGround(); + if(!bg || !bg->isArena()) + return false; + + return true; +} + +bool Player::GetBGAccessByLevel(uint32 bgTypeId) const +{ + BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId); + if(!bg) + return false; + + if(getLevel() < bg->GetMinLevel() || getLevel() > bg->GetMaxLevel()) + return false; + + return true; +} + +uint32 Player::GetMinLevelForBattleGroundQueueId(uint32 queue_id) +{ + if(queue_id < 1) + return 0; + + if(queue_id >=6) + queue_id = 6; + + return 10*(queue_id+1); +} + +uint32 Player::GetMaxLevelForBattleGroundQueueId(uint32 queue_id) +{ + if(queue_id >=6) + return 255; // hardcoded max level + + return 10*(queue_id+2)-1; +} + +uint32 Player::GetBattleGroundQueueIdFromLevel() const +{ + uint32 level = getLevel(); + if(level <= 19) + return 0; + else if (level > 69) + return 6; + else + return level/10 - 1; // 20..29 -> 1, 30-39 -> 2, ... +} + +float Player::GetReputationPriceDiscount( Creature const* pCreature ) const +{ + FactionTemplateEntry const* vendor_faction = pCreature->getFactionTemplateEntry(); + if(!vendor_faction) + return 1.0f; + + ReputationRank rank = GetReputationRank(vendor_faction->faction); + if(rank <= REP_NEUTRAL) + return 1.0f; + + return 1.0f - 0.05f* (rank - REP_NEUTRAL); +} + +bool Player::IsSpellFitByClassAndRace( uint32 spell_id ) const +{ + uint32 racemask = getRaceMask(); + uint32 classmask = getClassMask(); + + SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id); + SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id); + + for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) + { + // skip wrong race skills + if( _spell_idx->second->racemask && (_spell_idx->second->racemask & racemask) == 0) + return false; + + // skip wrong class skills + if( _spell_idx->second->classmask && (_spell_idx->second->classmask & classmask) == 0) + return false; + } + return true; +} + +bool Player::HasQuestForGO(int32 GOId) +{ + for( QuestStatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i ) + { + QuestStatusData qs=i->second; + if (qs.m_status == QUEST_STATUS_INCOMPLETE) + { + Quest const* qinfo = objmgr.GetQuestTemplate(i->first); + if(!qinfo) + continue; + + if(GetGroup() && GetGroup()->isRaidGroup() && qinfo->GetType() != QUEST_TYPE_RAID) + continue; + + for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) + { + if (qinfo->ReqCreatureOrGOId[j]>=0) //skip non GO case + continue; + + if((-1)*GOId == qinfo->ReqCreatureOrGOId[j] && qs.m_creatureOrGOcount[j] < qinfo->ReqCreatureOrGOCount[j]) + return true; + } + } + } + return false; +} + +void Player::UpdateForQuestsGO() +{ + if(m_clientGUIDs.empty()) + return; + + UpdateData udata; + WorldPacket packet; + for(ClientGUIDs::iterator itr=m_clientGUIDs.begin(); itr!=m_clientGUIDs.end(); ++itr) + { + if(IS_GAMEOBJECT_GUID(*itr)) + { + GameObject *obj = HashMapHolder::Find(*itr); + if(obj) + obj->BuildValuesUpdateBlockForPlayer(&udata,this); + } + } + udata.BuildPacket(&packet); + GetSession()->SendPacket(&packet); +} + +void Player::SummonIfPossible(bool agree) +{ + if(!agree) + { + m_summon_expire = 0; + return; + } + + // expire and auto declined + if(m_summon_expire < time(NULL)) + return; + + // stop taxi flight at summon + if(isInFlight()) + { + GetMotionMaster()->MovementExpired(); + m_taxi.ClearTaxiDestinations(); + } + + // drop flag at summon + if(BattleGround *bg = GetBattleGround()) + bg->EventPlayerDroppedFlag(this); + + m_summon_expire = 0; + + TeleportTo(m_summon_mapid, m_summon_x, m_summon_y, m_summon_z,GetOrientation()); +} + +void Player::RemoveItemDurations( Item *item ) +{ + for(ItemDurationList::iterator itr = m_itemDuration.begin();itr != m_itemDuration.end(); ++itr) + { + if(*itr==item) + { + m_itemDuration.erase(itr); + break; + } + } +} + +void Player::AddItemDurations( Item *item ) +{ + if(item->GetUInt32Value(ITEM_FIELD_DURATION)) + { + m_itemDuration.push_back(item); + item->SendTimeUpdate(this); + } +} + +void Player::AutoUnequipOffhandIfNeed() +{ + Item *offItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND ); + if(!offItem) + return; + + Item *mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ); + + if(!mainItem || mainItem->GetProto()->InventoryType != INVTYPE_2HWEAPON) + return; + + ItemPosCountVec off_dest; + uint8 off_msg = CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ); + if( off_msg == EQUIP_ERR_OK ) + { + RemoveItem(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND, true); + StoreItem( off_dest, offItem, true ); + } + else + { + sLog.outError("Player::EquipItem: Can's store offhand item at 2hand item equip for player (GUID: %u).",GetGUIDLow()); + } +} + +bool Player::HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item const* ignoreItem) +{ + if(spellInfo->EquippedItemClass < 0) + return true; + + // scan other equipped items for same requirements (mostly 2 daggers/etc) + // for optimize check 2 used cases only + switch(spellInfo->EquippedItemClass) + { + case ITEM_CLASS_WEAPON: + { + for(int i= EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_TABARD; ++i) + if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo)) + return true; + break; + } + case ITEM_CLASS_ARMOR: + { + // tabard not have dependent spells + for(int i= EQUIPMENT_SLOT_START; i< EQUIPMENT_SLOT_MAINHAND; ++i) + if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, i )) + if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo)) + return true; + + // shields can be equipped to offhand slot + if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) + if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo)) + return true; + + // ranged slot can have some armor subclasses + if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED)) + if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo)) + return true; + + break; + } + default: + sLog.outError("HasItemFitToSpellReqirements: Not handeled spell reqirement for item class %u",spellInfo->EquippedItemClass); + break; + } + + return false; +} + +void Player::RemoveItemDependentAurasAndCasts( Item * pItem ) +{ + AuraMap& auras = GetAuras(); + for(AuraMap::iterator itr = auras.begin(); itr != auras.end(); ) + { + Aura* aura = itr->second; + + // skip passive (passive item dependent spells work in another way) and not self applied auras + SpellEntry const* spellInfo = aura->GetSpellProto(); + if(aura->IsPassive() || aura->GetCasterGUID()!=GetGUID()) + { + ++itr; + continue; + } + + // skip if not item dependent or have alternative item + if(HasItemFitToSpellReqirements(spellInfo,pItem)) + { + ++itr; + continue; + } + + // no alt item, remove aura, restart check + RemoveAurasDueToSpell(aura->GetId()); + itr = auras.begin(); + } + + // currently casted spells can be dependent from item + for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) + { + if( m_currentSpells[i] && m_currentSpells[i]->getState()!=SPELL_STATE_DELAYED && + !HasItemFitToSpellReqirements(m_currentSpells[i]->m_spellInfo,pItem) ) + InterruptSpell(i); + } +} + +uint32 Player::GetResurrectionSpellId() +{ + // search priceless resurrection possabilities + uint32 prio = 0; + uint32 spell_id = 0; + AuraList const& dummyAuras = GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr) + { + // Soulstone Resurrection // prio: 3 (max, non death persistent) + if( prio < 2 && (*itr)->GetSpellProto()->SpellVisual == 99 && (*itr)->GetSpellProto()->SpellIconID == 92 ) + { + switch((*itr)->GetId()) + { + case 20707: spell_id = 3026; break; // rank 1 + case 20762: spell_id = 20758; break; // rank 2 + case 20763: spell_id = 20759; break; // rank 3 + case 20764: spell_id = 20760; break; // rank 4 + case 20765: spell_id = 20761; break; // rank 5 + case 27239: spell_id = 27240; break; // rank 6 + default: + sLog.outError("Unhandled spell %%u: S.Resurrection",(*itr)->GetId()); + continue; + } + + prio = 3; + } + // Twisting Nether // prio: 2 (max) + else if((*itr)->GetId()==23701 && roll_chance_i(10)) + { + prio = 2; + spell_id = 23700; + } + } + + // Reincarnation (passive spell) // prio: 1 + if(prio < 1 && HasSpell(20608) && !HasSpellCooldown(21169) && HasItemCount(17030,1)) + spell_id = 21169; + + return spell_id; +} + +bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim) +{ + bool PvP = pVictim->isCharmedOwnedByPlayerOrPlayer(); + + // prepare data for near group iteration (PvP and !PvP cases) + uint32 xp = 0; + bool honored_kill = false; + + if(Group *pGroup = GetGroup()) + { + uint32 count = 0; + uint32 sum_level = 0; + Player* member_with_max_level = NULL; + + pGroup->GetDataForXPAtKill(pVictim,count,sum_level,member_with_max_level); + + if(member_with_max_level) + { + xp = PvP ? 0 : MaNGOS::XP::Gain(member_with_max_level, pVictim); + + // skip in check PvP case (for speed, not used) + bool is_raid = PvP ? false : sMapStore.LookupEntry(GetMapId())->IsRaid() && pGroup->isRaidGroup(); + bool is_dungeon = PvP ? false : sMapStore.LookupEntry(GetMapId())->IsDungeon(); + float group_rate = MaNGOS::XP::xp_in_group_rate(count,is_raid); + + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* pGroupGuy = itr->getSource(); + if(!pGroupGuy) + continue; + + if(!pGroupGuy->IsAtGroupRewardDistance(pVictim)) + continue; // member (alive or dead) or his corpse at req. distance + + // honor can be in PvP and !PvP (racial leader) cases (for alive) + if(pGroupGuy->isAlive() && pGroupGuy->RewardHonor(pVictim,count) && pGroupGuy==this) + honored_kill = true; + + // xp and reputation only in !PvP case + if(!PvP) + { + float rate = group_rate * float(pGroupGuy->getLevel()) / sum_level; + + // if is in dungeon then all receive full reputation at kill + // rewarded any alive/dead/near_corpse group member + pGroupGuy->RewardReputation(pVictim,is_dungeon ? 1.0f : rate); + + // XP updated only for alive group member + if(pGroupGuy->isAlive()) + { + uint32 itr_xp = uint32(xp*rate); + + pGroupGuy->GiveXP(itr_xp, pVictim); + if(Pet* pet = pGroupGuy->GetPet()) + pet->GivePetXP(itr_xp/2); + } + + // quest objectives updated only for alive group member or dead but with not released body + if(pGroupGuy->isAlive()|| !pGroupGuy->GetCorpse()) + { + // normal creature (not pet/etc) can be only in !PvP case + if(pVictim->GetTypeId()==TYPEID_UNIT) + pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID()); + } + } + } + } + } + else // if (!pGroup) + { + xp = PvP ? 0 : MaNGOS::XP::Gain(this, pVictim); + + // honor can be in PvP and !PvP (racial leader) cases + if(RewardHonor(pVictim,1)) + honored_kill = true; + + // xp and reputation only in !PvP case + if(!PvP) + { + RewardReputation(pVictim,1); + GiveXP(xp, pVictim); + + if(Pet* pet = GetPet()) + pet->GivePetXP(xp); + + // normal creature (not pet/etc) can be only in !PvP case + if(pVictim->GetTypeId()==TYPEID_UNIT) + KilledMonster(pVictim->GetEntry(),pVictim->GetGUID()); + } + } + return xp || honored_kill; +} + +bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const +{ + if(pRewardSource->GetDistance(this) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + return true; + + if(isAlive()) + return false; + + Corpse* corpse = GetCorpse(); + if(!corpse) + return false; + + return pRewardSource->GetDistance(corpse) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE); +} + +uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const +{ + Item* item = GetWeaponForAttack(attType,true); + + // unarmmed only with base attack + if(attType != BASE_ATTACK && !item) + return 0; + + // weapon skill or (unarmed for base attack) + uint32 skill = item ? item->GetSkill() : SKILL_UNARMED; + return GetBaseSkillValue(skill); +} + +void Player::ResurectUsingRequestData() +{ + ResurrectPlayer(0.0f,false); + + if(GetMaxHealth() > m_resurrectHealth) + SetHealth( m_resurrectHealth ); + else + SetHealth( GetMaxHealth() ); + + if(GetMaxPower(POWER_MANA) > m_resurrectMana) + SetPower(POWER_MANA, m_resurrectMana ); + else + SetPower(POWER_MANA, GetMaxPower(POWER_MANA) ); + + SetPower(POWER_RAGE, 0 ); + + SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY) ); + + SpawnCorpseBones(); + + TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation()); +} + +void Player::SetClientControl(Unit* target, uint8 allowMove) +{ + WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, target->GetPackGUID().size()+1); + data.append(target->GetPackGUID()); + data << uint8(allowMove); + GetSession()->SendPacket(&data); +} + +void Player::UpdateZoneDependentAuras( uint32 newZone ) +{ + // remove new continent flight forms + if( !isGameMaster() && + GetVirtualMapForMapAndZone(GetMapId(),newZone) != 530) + { + RemoveSpellsCausingAura(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED); + RemoveSpellsCausingAura(SPELL_AURA_FLY); + } + + // Some spells applied at enter into zone (with subzones) + // Human Illusion + // NOTE: these are removed by RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP); + if ( newZone == 2367 ) // Old Hillsbrad Foothills + { + uint32 spellid = 0; + // all horde races + if( GetTeam() == HORDE ) + spellid = getGender() == GENDER_FEMALE ? 35481 : 35480; + // and some alliance races + else if( getRace() == RACE_NIGHTELF || getRace() == RACE_DRAENEI ) + spellid = getGender() == GENDER_FEMALE ? 35483 : 35482; + + if(spellid && !HasAura(spellid,0) ) + CastSpell(this,spellid,true); + } +} + +void Player::UpdateAreaDependentAuras( uint32 newArea ) +{ + // remove auras from spells with area limitations + for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) + { + // use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date + if(!IsSpellAllowedInLocation(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea)) + RemoveAura(iter); + else + ++iter; + } + + // unmount if enter in this subzone + if( newArea == 35) + RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); + // Dragonmaw Illusion + else if( newArea == 3759 || newArea == 3966 || newArea == 3939 ) + { + if( GetDummyAura(40214) ) + { + if( !HasAura(40216,0) ) + CastSpell(this,40216,true); + if( !HasAura(42016,0) ) + CastSpell(this,42016,true); + } + } +} + +uint32 Player::GetCorpseReclaimDelay(bool pvp) const +{ + if( pvp && !sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP) || + !pvp && !sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE) ) + { + return copseReclaimDelay[0]; + } + + time_t now = time(NULL); + // 0..2 full period + uint32 count = (now < m_deathExpireTime) ? (m_deathExpireTime - now)/DEATH_EXPIRE_STEP : 0; + return copseReclaimDelay[count]; +} + +void Player::UpdateCorpseReclaimDelay() +{ + bool pvp = m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH; + + if( pvp && !sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP) || + !pvp && !sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE) ) + return; + + time_t now = time(NULL); + if(now < m_deathExpireTime) + { + // full and partly periods 1..3 + uint32 count = (m_deathExpireTime - now)/DEATH_EXPIRE_STEP +1; + if(count < MAX_DEATH_COUNT) + m_deathExpireTime = now+(count+1)*DEATH_EXPIRE_STEP; + else + m_deathExpireTime = now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP; + } + else + m_deathExpireTime = now+DEATH_EXPIRE_STEP; +} + +void Player::SendCorpseReclaimDelay(bool load) +{ + Corpse* corpse = GetCorpse(); + if(!corpse) + return; + + uint32 delay; + if(load) + { + if(corpse->GetGhostTime() > m_deathExpireTime) + return; + + bool pvp = corpse->GetType()==CORPSE_RESURRECTABLE_PVP; + + uint32 count; + if( pvp && sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP) || + !pvp && sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE) ) + { + count = (m_deathExpireTime-corpse->GetGhostTime())/DEATH_EXPIRE_STEP; + if(count>=MAX_DEATH_COUNT) + count = MAX_DEATH_COUNT-1; + } + else + count=0; + + time_t expected_time = corpse->GetGhostTime()+copseReclaimDelay[count]; + + time_t now = time(NULL); + if(now >= expected_time) + return; + + delay = expected_time-now; + } + else + delay = GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP); + + //! corpse reclaim delay 30 * 1000ms or longer at often deaths + WorldPacket data(SMSG_CORPSE_RECLAIM_DELAY, 4); + data << uint32(delay*1000); + GetSession()->SendPacket( &data ); +} + +Player* Player::GetNextRandomRaidMember(float radius) +{ + Group *pGroup = GetGroup(); + if(!pGroup) + return NULL; + + std::vector nearMembers; + nearMembers.reserve(pGroup->GetMembersCount()); + + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* Target = itr->getSource(); + + // IsHostileTo check duel and controlled by enemy + if( Target && Target != this && IsWithinDistInMap(Target, radius) && + !Target->HasInvisibilityAura() && !IsHostileTo(Target) ) + nearMembers.push_back(Target); + } + + if (nearMembers.empty()) + return NULL; + + uint32 randTarget = urand(0,nearMembers.size()-1); + return nearMembers[randTarget]; +} + +void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) +{ + float water_z = m->GetWaterLevel(x,y); + float height_z = m->GetHeight(x,y,z, false); // use .map base surface height + uint8 flag1 = m->GetTerrainType(x,y); + + //!Underwater check, not in water if underground or above water level + if (height_z <= INVALID_HEIGHT || z < (height_z-2) || z > (water_z - 2) ) + m_isunderwater &= 0x7A; + else if ((z < (water_z - 2)) && (flag1 & 0x01)) + m_isunderwater |= 0x01; + + //!in lava check, anywhere under lava level + if ((height_z <= INVALID_HEIGHT || z < (height_z - 0)) && (flag1 == 0x00) && IsInWater()) + m_isunderwater |= 0x80; +} + +void Player::SetCanParry( bool value ) +{ + if(m_canParry==value) + return; + + m_canParry = value; + UpdateParryPercentage(); +} + +void Player::SetCanBlock( bool value ) +{ + if(m_canBlock==value) + return; + + m_canBlock = value; + UpdateBlockPercentage(); +} + +bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const +{ + for(ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr) + if(itr->pos == this->pos) + return true; + + return false; +} diff --git a/src/game/Player.h b/src/game/Player.h index d30d8e56622..199d816863a 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1,2310 +1,2313 @@ -/* - * Copyright (C) 2005-2008 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 _PLAYER_H -#define _PLAYER_H - -#include "Common.h" -#include "ItemPrototype.h" -#include "Unit.h" -#include "Item.h" - -#include "Database/DatabaseEnv.h" -#include "NPCHandler.h" -#include "QuestDef.h" -#include "Group.h" -#include "Bag.h" -#include "WorldSession.h" -#include "Pet.h" -#include "Util.h" // for Tokens typedef - -#include -#include - -struct Mail; -class Channel; -class DynamicObject; -class Creature; -class Pet; -class PlayerMenu; -class Transport; -class UpdateMask; -class PlayerSocial; - -typedef std::deque PlayerMails; - -#define PLAYER_MAX_SKILLS 127 -#define PLAYER_MAX_DAILY_QUESTS 25 - -// Note: SPELLMOD_* values is aura types in fact -enum SpellModType -{ - SPELLMOD_FLAT = 107, // SPELL_AURA_ADD_FLAT_MODIFIER - SPELLMOD_PCT = 108 // SPELL_AURA_ADD_PCT_MODIFIER -}; - -enum PlayerSpellState -{ - PLAYERSPELL_UNCHANGED = 0, - PLAYERSPELL_CHANGED = 1, - PLAYERSPELL_NEW = 2, - PLAYERSPELL_REMOVED = 3 -}; - -struct PlayerSpell -{ - uint16 slotId : 16; - PlayerSpellState state : 8; - bool active : 1; - bool disabled : 1; -}; - -#define SPELL_WITHOUT_SLOT_ID uint16(-1) - -struct SpellModifier -{ - SpellModOp op : 8; - SpellModType type : 8; - int16 charges : 16; - int32 value; - uint64 mask; - uint32 spellId; - uint32 effectId; - Spell const* lastAffected; -}; - -typedef HM_NAMESPACE::hash_map PlayerSpellMap; -typedef std::list SpellModList; - -struct SpellCooldown -{ - time_t end; - uint16 itemid; -}; - -typedef std::map SpellCooldowns; - -enum TrainerSpellState -{ - TRAINER_SPELL_GREEN = 0, - TRAINER_SPELL_RED = 1, - TRAINER_SPELL_GRAY = 2 -}; - -enum ActionButtonUpdateState -{ - ACTIONBUTTON_UNCHANGED = 0, - ACTIONBUTTON_CHANGED = 1, - ACTIONBUTTON_NEW = 2, - ACTIONBUTTON_DELETED = 3 -}; - -struct ActionButton -{ - ActionButton() : action(0), type(0), misc(0), uState( ACTIONBUTTON_NEW ) {} - ActionButton(uint16 _action, uint8 _type, uint8 _misc) : action(_action), type(_type), misc(_misc), uState( ACTIONBUTTON_NEW ) {} - - uint16 action; - uint8 type; - uint8 misc; - ActionButtonUpdateState uState; -}; - -enum ActionButtonType -{ - ACTION_BUTTON_SPELL = 0, - ACTION_BUTTON_MACRO = 64, - ACTION_BUTTON_CMACRO= 65, - ACTION_BUTTON_ITEM = 128 -}; - -#define MAX_ACTION_BUTTONS 132 //checked in 2.3.0 - -typedef std::map ActionButtonList; - -typedef std::pair CreateSpellPair; - -struct PlayerCreateInfoItem -{ - PlayerCreateInfoItem(uint32 id, uint32 amount) : item_id(id), item_amount(amount) {} - - uint32 item_id; - uint32 item_amount; -}; - -typedef std::list PlayerCreateInfoItems; - -struct PlayerClassLevelInfo -{ - PlayerClassLevelInfo() : basehealth(0), basemana(0) {} - uint16 basehealth; - uint16 basemana; -}; - -struct PlayerClassInfo -{ - PlayerClassInfo() : levelInfo(NULL) { } - - PlayerClassLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1 -}; - -struct PlayerLevelInfo -{ - PlayerLevelInfo() { for(int i=0; i < MAX_STATS; ++i ) stats[i] = 0; } - - uint8 stats[MAX_STATS]; -}; - -struct PlayerInfo -{ - // existence checked by displayId != 0 // existence checked by displayId != 0 - PlayerInfo() : displayId_m(0),displayId_f(0),levelInfo(NULL) - { - } - - uint32 mapId; - uint32 zoneId; - float positionX; - float positionY; - float positionZ; - uint16 displayId_m; - uint16 displayId_f; - PlayerCreateInfoItems item; - std::list spell; - std::list action[4]; - - PlayerLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1 -}; - -struct PvPInfo -{ - PvPInfo() : inHostileArea(false), endTimer(0) {} - - bool inHostileArea; - time_t endTimer; -}; - -struct DuelInfo -{ - DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0) {} - - Player *initiator; - Player *opponent; - time_t startTimer; - time_t startTime; - time_t outOfBound; -}; - -struct Areas -{ - uint32 areaID; - uint32 areaFlag; - float x1; - float x2; - float y1; - float y2; -}; - -enum FactionFlags -{ - FACTION_FLAG_VISIBLE = 0x01, // makes visible in client (set or can be set at interaction with target of this faction) - FACTION_FLAG_AT_WAR = 0x02, // enable AtWar-button in client. player controlled (except opposition team always war state), Flag only set on initial creation - FACTION_FLAG_HIDDEN = 0x04, // hidden faction from reputation pane in client (player can gain reputation, but this update not sent to client) - FACTION_FLAG_INVISIBLE_FORCED = 0x08, // always overwrite FACTION_FLAG_VISIBLE and hide faction in rep.list, used for hide opposite team factions - FACTION_FLAG_PEACE_FORCED = 0x10, // always overwrite FACTION_FLAG_AT_WAR, used for prevent war with own team factions - FACTION_FLAG_INACTIVE = 0x20, // player controlled, state stored in characters.data ( CMSG_SET_FACTION_INACTIVE ) - FACTION_FLAG_RIVAL = 0x40 // flag for the two competing outland factions -}; - -typedef uint32 RepListID; -struct FactionState -{ - uint32 ID; - RepListID ReputationListID; - uint32 Flags; - int32 Standing; - bool Changed; -}; - -typedef std::map FactionStateList; - -typedef std::map ForcedReactions; - -typedef std::set GuardianPetList; - -struct EnchantDuration -{ - EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) {}; - EnchantDuration(Item * _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot), leftduration(_leftduration) { assert(item); }; - - Item * item; - EnchantmentSlot slot; - uint32 leftduration; -}; - -typedef std::list EnchantDurationList; -typedef std::list ItemDurationList; - -struct LookingForGroupSlot -{ - LookingForGroupSlot() : entry(0), type(0) {} - bool Empty() const { return !entry && !type; } - void Clear() { entry = 0; type = 0; } - void Set(uint32 _entry, uint32 _type ) { entry = _entry; type = _type; } - bool Is(uint32 _entry, uint32 _type) const { return entry==_entry && type==_type; } - bool canAutoJoin() const { return entry && (type == 1 || type == 5); } - - uint32 entry; - uint32 type; -}; - -#define MAX_LOOKING_FOR_GROUP_SLOT 3 - -struct LookingForGroup -{ - LookingForGroup() {} - bool HaveInSlot(LookingForGroupSlot const& slot) const { return HaveInSlot(slot.entry,slot.type); } - bool HaveInSlot(uint32 _entry, uint32 _type) const - { - for(int i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) - if(slots[i].Is(_entry,_type)) - return true; - return false; - } - - bool canAutoJoin() const - { - for(int i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) - if(slots[i].canAutoJoin()) - return true; - return false; - } - - bool Empty() const - { - for(int i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) - if(!slots[i].Empty()) - return false; - return more.Empty(); - } - - LookingForGroupSlot slots[MAX_LOOKING_FOR_GROUP_SLOT]; - LookingForGroupSlot more; - std::string comment; -}; - -enum PlayerMovementType -{ - MOVE_ROOT = 1, - MOVE_UNROOT = 2, - MOVE_WATER_WALK = 3, - MOVE_LAND_WALK = 4 -}; - -enum DrunkenState -{ - DRUNKEN_SOBER = 0, - DRUNKEN_TIPSY = 1, - DRUNKEN_DRUNK = 2, - DRUNKEN_SMASHED = 3 -}; - -enum PlayerStateType -{ - /* - PLAYER_STATE_DANCE - PLAYER_STATE_SLEEP - PLAYER_STATE_SIT - PLAYER_STATE_STAND - PLAYER_STATE_READYUNARMED - PLAYER_STATE_WORK - PLAYER_STATE_POINT(DNR) - PLAYER_STATE_NONE // not used or just no state, just standing there? - PLAYER_STATE_STUN - PLAYER_STATE_DEAD - PLAYER_STATE_KNEEL - PLAYER_STATE_USESTANDING - PLAYER_STATE_STUN_NOSHEATHE - PLAYER_STATE_USESTANDING_NOSHEATHE - PLAYER_STATE_WORK_NOSHEATHE - PLAYER_STATE_SPELLPRECAST - PLAYER_STATE_READYRIFLE - PLAYER_STATE_WORK_NOSHEATHE_MINING - PLAYER_STATE_WORK_NOSHEATHE_CHOPWOOD - PLAYER_STATE_AT_EASE - PLAYER_STATE_READY1H - PLAYER_STATE_SPELLKNEELSTART - PLAYER_STATE_SUBMERGED - */ - - PLAYER_STATE_NONE = 0, - PLAYER_STATE_SIT = 1, - PLAYER_STATE_SIT_CHAIR = 2, - PLAYER_STATE_SLEEP = 3, - PLAYER_STATE_SIT_LOW_CHAIR = 4, - PLAYER_STATE_SIT_MEDIUM_CHAIR = 5, - PLAYER_STATE_SIT_HIGH_CHAIR = 6, - PLAYER_STATE_DEAD = 7, - PLAYER_STATE_KNEEL = 8, - - PLAYER_STATE_FORM_ALL = 0x00FF0000, - - PLAYER_STATE_FLAG_ALWAYS_STAND = 0x01, // byte 4 - PLAYER_STATE_FLAG_CREEP = 0x02000000, - PLAYER_STATE_FLAG_UNTRACKABLE = 0x04000000, - PLAYER_STATE_FLAG_ALL = 0xFF000000, -}; - -enum PlayerFlags -{ - PLAYER_FLAGS_GROUP_LEADER = 0x00000001, - PLAYER_FLAGS_AFK = 0x00000002, - PLAYER_FLAGS_DND = 0x00000004, - PLAYER_FLAGS_GM = 0x00000008, - PLAYER_FLAGS_GHOST = 0x00000010, - PLAYER_FLAGS_RESTING = 0x00000020, - PLAYER_FLAGS_FFA_PVP = 0x00000080, - PLAYER_FLAGS_CONTESTED_PVP = 0x00000100, // Player has been involved in a PvP combat and will be attacked by contested guards - PLAYER_FLAGS_IN_PVP = 0x00000200, - PLAYER_FLAGS_HIDE_HELM = 0x00000400, - PLAYER_FLAGS_HIDE_CLOAK = 0x00000800, - PLAYER_FLAGS_UNK1 = 0x00001000, // played long time - PLAYER_FLAGS_UNK2 = 0x00002000, // played too long time - PLAYER_FLAGS_UNK3 = 0x00008000, // strange visual effect (2.0.1), looks like PLAYER_FLAGS_GHOST flag - PLAYER_FLAGS_SANCTUARY = 0x00010000, // player entered sanctuary - PLAYER_FLAGS_UNK4 = 0x00020000, // taxi benchmark mode (on/off) (2.0.1) - PLAYER_UNK = 0x00040000, // 2.0.8... -}; - -// used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1< QuestStatusMap; - -enum QuestSlotOffsets -{ - QUEST_ID_OFFSET = 0, - QUEST_STATE_OFFSET = 1, - QUEST_COUNTS_OFFSET = 2, - QUEST_TIME_OFFSET = 3 -}; - -#define MAX_QUEST_OFFSET 4 - -enum QuestSlotStateMask -{ - QUEST_STATE_NONE = 0x0000, - QUEST_STATE_COMPLETE = 0x0001, - QUEST_STATE_FAIL = 0x0002 -}; - -class Quest; -class Spell; -class Item; -class WorldSession; - -enum PlayerSlots -{ - // first slot for item stored (in any way in player m_items data) - PLAYER_SLOT_START = 0, - // last+1 slot for item stored (in any way in player m_items data) - PLAYER_SLOT_END = 118, - PLAYER_SLOTS_COUNT = (PLAYER_SLOT_END - PLAYER_SLOT_START) -}; - -enum EquipmentSlots -{ - EQUIPMENT_SLOT_START = 0, - EQUIPMENT_SLOT_HEAD = 0, - EQUIPMENT_SLOT_NECK = 1, - EQUIPMENT_SLOT_SHOULDERS = 2, - EQUIPMENT_SLOT_BODY = 3, - EQUIPMENT_SLOT_CHEST = 4, - EQUIPMENT_SLOT_WAIST = 5, - EQUIPMENT_SLOT_LEGS = 6, - EQUIPMENT_SLOT_FEET = 7, - EQUIPMENT_SLOT_WRISTS = 8, - EQUIPMENT_SLOT_HANDS = 9, - EQUIPMENT_SLOT_FINGER1 = 10, - EQUIPMENT_SLOT_FINGER2 = 11, - EQUIPMENT_SLOT_TRINKET1 = 12, - EQUIPMENT_SLOT_TRINKET2 = 13, - EQUIPMENT_SLOT_BACK = 14, - EQUIPMENT_SLOT_MAINHAND = 15, - EQUIPMENT_SLOT_OFFHAND = 16, - EQUIPMENT_SLOT_RANGED = 17, - EQUIPMENT_SLOT_TABARD = 18, - EQUIPMENT_SLOT_END = 19 -}; - -enum InventorySlots -{ - INVENTORY_SLOT_BAG_0 = 255, - INVENTORY_SLOT_BAG_START = 19, - INVENTORY_SLOT_BAG_1 = 19, - INVENTORY_SLOT_BAG_2 = 20, - INVENTORY_SLOT_BAG_3 = 21, - INVENTORY_SLOT_BAG_4 = 22, - INVENTORY_SLOT_BAG_END = 23, - - INVENTORY_SLOT_ITEM_START = 23, - INVENTORY_SLOT_ITEM_1 = 23, - INVENTORY_SLOT_ITEM_2 = 24, - INVENTORY_SLOT_ITEM_3 = 25, - INVENTORY_SLOT_ITEM_4 = 26, - INVENTORY_SLOT_ITEM_5 = 27, - INVENTORY_SLOT_ITEM_6 = 28, - INVENTORY_SLOT_ITEM_7 = 29, - INVENTORY_SLOT_ITEM_8 = 30, - INVENTORY_SLOT_ITEM_9 = 31, - INVENTORY_SLOT_ITEM_10 = 32, - INVENTORY_SLOT_ITEM_11 = 33, - INVENTORY_SLOT_ITEM_12 = 34, - INVENTORY_SLOT_ITEM_13 = 35, - INVENTORY_SLOT_ITEM_14 = 36, - INVENTORY_SLOT_ITEM_15 = 37, - INVENTORY_SLOT_ITEM_16 = 38, - INVENTORY_SLOT_ITEM_END = 39 -}; - -enum BankSlots -{ - BANK_SLOT_ITEM_START = 39, - BANK_SLOT_ITEM_1 = 39, - BANK_SLOT_ITEM_2 = 40, - BANK_SLOT_ITEM_3 = 41, - BANK_SLOT_ITEM_4 = 42, - BANK_SLOT_ITEM_5 = 43, - BANK_SLOT_ITEM_6 = 44, - BANK_SLOT_ITEM_7 = 45, - BANK_SLOT_ITEM_8 = 46, - BANK_SLOT_ITEM_9 = 47, - BANK_SLOT_ITEM_10 = 48, - BANK_SLOT_ITEM_11 = 49, - BANK_SLOT_ITEM_12 = 50, - BANK_SLOT_ITEM_13 = 51, - BANK_SLOT_ITEM_14 = 52, - BANK_SLOT_ITEM_15 = 53, - BANK_SLOT_ITEM_16 = 54, - BANK_SLOT_ITEM_17 = 55, - BANK_SLOT_ITEM_18 = 56, - BANK_SLOT_ITEM_19 = 57, - BANK_SLOT_ITEM_20 = 58, - BANK_SLOT_ITEM_21 = 59, - BANK_SLOT_ITEM_22 = 60, - BANK_SLOT_ITEM_23 = 61, - BANK_SLOT_ITEM_24 = 62, - BANK_SLOT_ITEM_25 = 63, - BANK_SLOT_ITEM_26 = 64, - BANK_SLOT_ITEM_27 = 65, - BANK_SLOT_ITEM_28 = 66, - BANK_SLOT_ITEM_END = 67, - - BANK_SLOT_BAG_START = 67, - BANK_SLOT_BAG_1 = 67, - BANK_SLOT_BAG_2 = 68, - BANK_SLOT_BAG_3 = 69, - BANK_SLOT_BAG_4 = 70, - BANK_SLOT_BAG_5 = 71, - BANK_SLOT_BAG_6 = 72, - BANK_SLOT_BAG_7 = 73, - BANK_SLOT_BAG_END = 74 -}; - -enum BuyBackSlots -{ - // stored in m_buybackitems - BUYBACK_SLOT_START = 74, - BUYBACK_SLOT_1 = 74, - BUYBACK_SLOT_2 = 75, - BUYBACK_SLOT_3 = 76, - BUYBACK_SLOT_4 = 77, - BUYBACK_SLOT_5 = 78, - BUYBACK_SLOT_6 = 79, - BUYBACK_SLOT_7 = 80, - BUYBACK_SLOT_8 = 81, - BUYBACK_SLOT_9 = 82, - BUYBACK_SLOT_10 = 83, - BUYBACK_SLOT_11 = 84, - BUYBACK_SLOT_12 = 85, - BUYBACK_SLOT_END = 86 -}; - -enum KeyRingSlots -{ - KEYRING_SLOT_START = 86, - KEYRING_SLOT_END = 118 -}; - -struct ItemPosCount -{ - ItemPosCount(uint16 _pos, uint8 _count) : pos(_pos), count(_count) {} - bool isContainedIn(std::vector&); - uint16 pos; - uint8 count; -}; -typedef std::vector ItemPosCountVec; - -enum SwitchWeapon -{ - DEFAULT_SWITCH_WEAPON = 1500, //cooldown in ms - ROGUE_SWITCH_WEAPON = 1000 -}; - -enum TradeSlots -{ - TRADE_SLOT_COUNT = 7, - TRADE_SLOT_TRADED_COUNT = 6, - TRADE_SLOT_NONTRADED = 6 -}; - -enum TransferAbortReason -{ - TRANSFER_ABORT_MAX_PLAYERS = 0x0001, // Transfer Aborted: instance is full - TRANSFER_ABORT_NOT_FOUND = 0x0002, // Transfer Aborted: instance not found - TRANSFER_ABORT_TOO_MANY_INSTANCES = 0x0003, // You have entered too many instances recently. - TRANSFER_ABORT_ZONE_IN_COMBAT = 0x0005, // Unable to zone in while an encounter is in progress. - TRANSFER_ABORT_INSUF_EXPAN_LVL1 = 0x0106, // You must have TBC expansion installed to access this area. - TRANSFER_ABORT_DIFFICULTY1 = 0x0007, // Normal difficulty mode is not available for %s. - TRANSFER_ABORT_DIFFICULTY2 = 0x0107, // Heroic difficulty mode is not available for %s. - TRANSFER_ABORT_DIFFICULTY3 = 0x0207 // Epic difficulty mode is not available for %s. -}; - -enum InstanceResetWarningType -{ - RAID_INSTANCE_WARNING_HOURS = 1, // WARNING! %s is scheduled to reset in %d hour(s). - RAID_INSTANCE_WARNING_MIN = 2, // WARNING! %s is scheduled to reset in %d minute(s)! - RAID_INSTANCE_WARNING_MIN_SOON = 3, // WARNING! %s is scheduled to reset in %d minute(s). Please exit the zone or you will be returned to your bind location! - RAID_INSTANCE_WELCOME = 4 // Welcome to %s. This raid instance is scheduled to reset in %s. -}; - -struct MovementInfo -{ - // common - //uint32 flags; - uint8 unk1; - uint32 time; - float x, y, z, o; - // transport - uint64 t_guid; - float t_x, t_y, t_z, t_o; - uint32 t_time; - // swimming and unk - float s_pitch; - // last fall time - uint32 fallTime; - // jumping - float j_unk, j_sinAngle, j_cosAngle, j_xyspeed; - // spline - float u_unk1; - - MovementInfo() - { - //flags = - time = t_time = fallTime = 0; - unk1 = 0; - x = y = z = o = t_x = t_y = t_z = t_o = s_pitch = j_unk = j_sinAngle = j_cosAngle = j_xyspeed = u_unk1 = 0.0f; - t_guid = 0; - } - - /*void SetMovementFlags(uint32 _flags) - { - flags = _flags; - }*/ -}; - -// flags that use in movement check for example at spell casting -MovementFlags const movementFlagsMask = MovementFlags( - MOVEMENTFLAG_FORWARD |MOVEMENTFLAG_BACKWARD |MOVEMENTFLAG_STRAFE_LEFT|MOVEMENTFLAG_STRAFE_RIGHT| - MOVEMENTFLAG_PITCH_UP|MOVEMENTFLAG_PITCH_DOWN|MOVEMENTFLAG_FLY_UNK1 | - MOVEMENTFLAG_JUMPING |MOVEMENTFLAG_FALLING |MOVEMENTFLAG_FLY_UP | - MOVEMENTFLAG_FLYING |MOVEMENTFLAG_SPLINE -); - -MovementFlags const movementOrTurningFlagsMask = MovementFlags( - movementFlagsMask | MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT -); -class InstanceSave; - -enum RestType -{ - REST_TYPE_NO = 0, - REST_TYPE_IN_TAVERN = 1, - REST_TYPE_IN_CITY = 2 -}; - -enum DuelCompleteType -{ - DUEL_INTERUPTED = 0, - DUEL_WON = 1, - DUEL_FLED = 2 -}; - -enum TeleportToOptions -{ - TELE_TO_GM_MODE = 0x01, - TELE_TO_NOT_LEAVE_TRANSPORT = 0x02, - TELE_TO_NOT_LEAVE_COMBAT = 0x04, - TELE_TO_NOT_UNSUMMON_PET = 0x08, - TELE_TO_SPELL = 0x10, -}; - -/// Type of environmental damages -enum EnviromentalDamage -{ - DAMAGE_EXHAUSTED = 0, - DAMAGE_DROWNING = 1, - DAMAGE_FALL = 2, - DAMAGE_LAVA = 3, - DAMAGE_SLIME = 4, - DAMAGE_FIRE = 5, - DAMAGE_FALL_TO_VOID = 6 // custom case for fall without durability loss -}; - -// used at player loading query list preparing, and later result selection -enum PlayerLoginQueryIndex -{ - PLAYER_LOGIN_QUERY_LOADFROM = 0, - PLAYER_LOGIN_QUERY_LOADGROUP = 1, - PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES = 2, - PLAYER_LOGIN_QUERY_LOADAURAS = 3, - PLAYER_LOGIN_QUERY_LOADSPELLS = 4, - PLAYER_LOGIN_QUERY_LOADQUESTSTATUS = 5, - PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS = 6, - PLAYER_LOGIN_QUERY_LOADTUTORIALS = 7, // common for all characters for some account at specific realm - PLAYER_LOGIN_QUERY_LOADREPUTATION = 8, - PLAYER_LOGIN_QUERY_LOADINVENTORY = 9, - PLAYER_LOGIN_QUERY_LOADACTIONS = 10, - PLAYER_LOGIN_QUERY_LOADMAILCOUNT = 11, - PLAYER_LOGIN_QUERY_LOADMAILDATE = 12, - PLAYER_LOGIN_QUERY_LOADSOCIALLIST = 13, - PLAYER_LOGIN_QUERY_LOADHOMEBIND = 14, - PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS = 15, - PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES = 16, - PLAYER_LOGIN_QUERY_LOADGUILD = 17, -}; - -#define MAX_PLAYER_LOGIN_QUERY 18 - -// Player summoning auto-decline time (in secs) -#define MAX_PLAYER_SUMMON_DELAY (2*MINUTE) -#define MAX_MONEY_AMOUNT (0x7FFFFFFF-1) - -struct InstancePlayerBind -{ - InstanceSave *save; - bool perm; - /* permanent PlayerInstanceBinds are created in Raid/Heroic instances for players - that aren't already permanently bound when they are inside when a boss is killed - or when they enter an instance that the group leader is permanently bound to. */ - InstancePlayerBind() : save(NULL), perm(false) {} -}; - -class MANGOS_DLL_SPEC PlayerTaxi -{ - public: - PlayerTaxi(); - ~PlayerTaxi() {} - // Nodes - void InitTaxiNodesForLevel(uint32 race, uint32 level); - void LoadTaxiMask(const char* data); - void SaveTaxiMask(const char* data); - - uint32 GetTaximask( uint8 index ) const { return m_taximask[index]; } - bool IsTaximaskNodeKnown(uint32 nodeidx) const - { - uint8 field = uint8((nodeidx - 1) / 32); - uint32 submask = 1<<((nodeidx-1)%32); - return (m_taximask[field] & submask) == submask; - } - bool SetTaximaskNode(uint32 nodeidx) - { - uint8 field = uint8((nodeidx - 1) / 32); - uint32 submask = 1<<((nodeidx-1)%32); - if ((m_taximask[field] & submask) != submask ) - { - m_taximask[field] |= submask; - return true; - } - else - return false; - } - void AppendTaximaskTo(ByteBuffer& data,bool all); - - // Destinations - bool LoadTaxiDestinationsFromString(std::string values); - std::string SaveTaxiDestinationsToString(); - - void ClearTaxiDestinations() { m_TaxiDestinations.clear(); } - void AddTaxiDestination(uint32 dest) { m_TaxiDestinations.push_back(dest); } - uint32 GetTaxiSource() const { return m_TaxiDestinations.empty() ? 0 : m_TaxiDestinations.front(); } - uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() < 2 ? 0 : m_TaxiDestinations[1]; } - uint32 GetCurrentTaxiPath() const; - uint32 NextTaxiDestination() - { - m_TaxiDestinations.pop_front(); - return GetTaxiDestination(); - } - bool empty() const { return m_TaxiDestinations.empty(); } - private: - TaxiMask m_taximask; - std::deque m_TaxiDestinations; -}; - -class MANGOS_DLL_SPEC Player : public Unit -{ - friend class WorldSession; - friend void Item::AddToUpdateQueueOf(Player *player); - friend void Item::RemoveFromUpdateQueueOf(Player *player); - public: - explicit Player (WorldSession *session); - ~Player ( ); - - void CleanupsBeforeDelete(); - - static UpdateMask updateVisualBits; - static void InitVisibleBits(); - - void AddToWorld(); - void RemoveFromWorld(); - - bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0); - - bool TeleportTo(WorldLocation const &loc, uint32 options = 0) - { - return TeleportTo(loc.mapid, loc.x, loc.y, loc.z, options); - } - - void SetSummonPoint(uint32 mapid, float x, float y, float z) - { - m_summon_expire = time(NULL) + MAX_PLAYER_SUMMON_DELAY; - m_summon_mapid = mapid; - m_summon_x = x; - m_summon_y = y; - m_summon_z = z; - } - void SummonIfPossible(bool agree); - - bool Create( uint32 guidlow, std::string name, uint8 race, uint8 class_, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair, uint8 outfitId ); - - void Update( uint32 time ); - - void BuildEnumData( QueryResult * result, WorldPacket * p_data ); - - void SetInWater(bool apply); - - bool IsInWater() const { return m_isInWater; } - bool IsUnderWater() const; - - void SendInitialPacketsBeforeAddToMap(); - void SendInitialPacketsAfterAddToMap(); - void SendTransferAborted(uint32 mapid, uint16 reason); - void SendInstanceResetWarning(uint32 mapid, uint32 time); - - bool CanInteractWithNPCs(bool alive = true) const; - - bool ToggleAFK(); - bool ToggleDND(); - bool isAFK() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK); }; - bool isDND() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND); }; - uint8 chatTag() const; - std::string afkMsg; - std::string dndMsg; - - PlayerSocial *GetSocial() { return m_social; } - - PlayerTaxi m_taxi; - void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(),getLevel()); } - bool ActivateTaxiPathTo(std::vector const& nodes, uint32 mount_id = 0 , Creature* npc = NULL); - // mount_id can be used in scripting calls - bool isAcceptTickets() const { return GetSession()->GetSecurity() >= SEC_GAMEMASTER && (m_ExtraFlags & PLAYER_EXTRA_GM_ACCEPT_TICKETS); } - void SetAcceptTicket(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_GM_ACCEPT_TICKETS; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_ACCEPT_TICKETS; } - bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; } - void SetAcceptWhispers(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; } - bool isGameMaster() const { return m_ExtraFlags & PLAYER_EXTRA_GM_ON; } - void SetGameMaster(bool on); - bool isTaxiCheater() const { return m_ExtraFlags & PLAYER_EXTRA_TAXICHEAT; } - void SetTaxiCheater(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_TAXICHEAT; else m_ExtraFlags &= ~PLAYER_EXTRA_TAXICHEAT; } - bool isGMVisible() const { return !(m_ExtraFlags & PLAYER_EXTRA_GM_INVISIBLE); } - void SetGMVisible(bool on); - void SetPvPDeath(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_PVP_DEATH; else m_ExtraFlags &= ~PLAYER_EXTRA_PVP_DEATH; } - - void GiveXP(uint32 xp, Unit* victim); - void GiveLevel(uint32 level); - void InitStatsForLevel(bool reapplyMods = false); - - // Played Time Stuff - time_t m_logintime; - time_t m_Last_tick; - uint32 m_Played_time[2]; - uint32 GetTotalPlayedTime() { return m_Played_time[0]; }; - uint32 GetLevelPlayedTime() { return m_Played_time[1]; }; - - void setDeathState(DeathState s); // overwrite Unit::setDeathState - - void InnEnter (int time,uint32 mapid, float x,float y,float z) - { - inn_pos_mapid = mapid; - inn_pos_x = x; - inn_pos_y = y; - inn_pos_z = z; - time_inn_enter = time; - }; - - float GetRestBonus() const { return m_rest_bonus; }; - void SetRestBonus(float rest_bonus_new); - - RestType GetRestType() const { return rest_type; }; - void SetRestType(RestType n_r_type) { rest_type = n_r_type; }; - - uint32 GetInnPosMapId() const { return inn_pos_mapid; }; - float GetInnPosX() const { return inn_pos_x; }; - float GetInnPosY() const { return inn_pos_y; }; - float GetInnPosZ() const { return inn_pos_z; }; - - int GetTimeInnEnter() const { return time_inn_enter; }; - void UpdateInnerTime (int time) { time_inn_enter = time; }; - - void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false); - void RemoveMiniPet(); - Pet* GetMiniPet(); - void SetMiniPet(Pet* pet) { m_miniPet = pet->GetGUID(); } - void RemoveGuardians(); - bool HasGuardianWithEntry(uint32 entry); - void AddGuardian(Pet* pet) { m_guardianPets.insert(pet->GetGUID()); } - GuardianPetList const& GetGuardians() const { return m_guardianPets; } - void Uncharm(); - - void Say(std::string text, const uint32 language); - void Yell(std::string text, const uint32 language); - void TextEmote(std::string text); - void Whisper(std::string text, const uint32 language,uint64 receiver); - void BuildPlayerChat(WorldPacket *data, uint8 msgtype, std::string text, uint32 language) const; - - /*********************************************************/ - /*** STORAGE SYSTEM ***/ - /*********************************************************/ - - void SetVirtualItemSlot( uint8 i, Item* item); - void SetSheath( uint32 sheathed ); - uint8 FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const; - uint32 GetItemCount( uint32 item, bool inBankAlso = false, Item* skipItem = NULL ) const; - Item* GetItemByGuid( uint64 guid ) const; - Item* GetItemByPos( uint16 pos ) const; - Item* GetItemByPos( uint8 bag, uint8 slot ) const; - Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const; - Item* GetShield(bool useable = false) const; - static uint32 GetAttackBySlot( uint8 slot ); // MAX_ATTACK if not weapon slot - std::vector &GetItemUpdateQueue() { return m_itemUpdateQueue; } - static bool IsInventoryPos( uint16 pos ) { return IsInventoryPos(pos >> 8,pos & 255); } - static bool IsInventoryPos( uint8 bag, uint8 slot ); - static bool IsEquipmentPos( uint16 pos ) { return IsEquipmentPos(pos >> 8,pos & 255); } - static bool IsEquipmentPos( uint8 bag, uint8 slot ); - static bool IsBagPos( uint16 pos ); - static bool IsBankPos( uint16 pos ) { return IsBankPos(pos >> 8,pos & 255); } - static bool IsBankPos( uint8 bag, uint8 slot ); - bool HasBankBagSlot( uint8 slot ) const; - bool HasItemCount( uint32 item, uint32 count, bool inBankAlso = false ) const; - bool HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item const* ignoreItem = NULL); - Item* GetItemOrItemWithGemEquipped( uint32 item ) const; - uint8 CanTakeMoreSimilarItems(Item* pItem) const { return _CanTakeMoreSimilarItems(pItem->GetEntry(),pItem->GetCount(),pItem); } - uint8 CanTakeMoreSimilarItems(uint32 entry, uint32 count) const { return _CanTakeMoreSimilarItems(entry,count,NULL); } - uint8 CanStoreNewItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = NULL ) const - { - return _CanStoreItem(bag, slot, dest, item, count, NULL, false, no_space_count ); - } - uint8 CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, Item *pItem, bool swap = false ) const - { - if(!pItem) - return EQUIP_ERR_ITEM_NOT_FOUND; - uint32 count = pItem->GetCount(); - return _CanStoreItem( bag, slot, dest, pItem->GetEntry(), count, pItem, swap, NULL ); - - } - uint8 CanStoreItems( Item **pItem,int count) const; - uint8 CanEquipNewItem( uint8 slot, uint16 &dest, uint32 item, uint32 count, bool swap ) const; - uint8 CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading = true ) const; - uint8 CanUnequipItems( uint32 item, uint32 count ) const; - uint8 CanUnequipItem( uint16 src, bool swap ) const; - uint8 CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, Item *pItem, bool swap, bool not_loading = true ) const; - uint8 CanUseItem( Item *pItem, bool not_loading = true ) const; - bool HasItemTotemCategory( uint32 TotemCategory ) const; - bool CanUseItem( ItemPrototype const *pItem ); - uint8 CanUseAmmo( uint32 item ) const; - Item* StoreNewItem( ItemPosCountVec const& pos, uint32 item, bool update,int32 randomPropertyId = 0 ); - Item* StoreItem( ItemPosCountVec const& pos, Item *pItem, bool update ); - Item* EquipNewItem( uint16 pos, uint32 item, uint32 count, bool update ); - Item* EquipItem( uint16 pos, Item *pItem, bool update ); - void AutoUnequipOffhandIfNeed(); - - uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const; - uint8 _CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL ) const; - - void ApplyEquipCooldown( Item * pItem ); - void SetAmmo( uint32 item ); - void RemoveAmmo(); - float GetAmmoDPS() const { return m_ammoDPS; } - bool CheckAmmoCompatibility(const ItemPrototype *ammo_proto) const; - void QuickEquipItem( uint16 pos, Item *pItem); - void VisualizeItem( uint8 slot, Item *pItem); - void SetVisibleItemSlot(uint8 slot, Item *pItem); - Item* BankItem( ItemPosCountVec const& dest, Item *pItem, bool update ) - { - return StoreItem( dest, pItem, update); - } - Item* BankItem( uint16 pos, Item *pItem, bool update ); - void RemoveItem( uint8 bag, uint8 slot, bool update ); - void MoveItemFromInventory(uint8 bag, uint8 slot, bool update); - // in trade, auction, guild bank, mail.... - void MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB = false); - // in trade, guild bank, mail.... - void RemoveItemDependentAurasAndCasts( Item * pItem ); - void DestroyItem( uint8 bag, uint8 slot, bool update ); - void DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check = false); - void DestroyItemCount( Item* item, uint32& count, bool update ); - void DestroyConjuredItems( bool update ); - void DestroyZoneLimitedItem( bool update, uint32 new_zone ); - void SplitItem( uint16 src, uint16 dst, uint32 count ); - void SwapItem( uint16 src, uint16 dst ); - void AddItemToBuyBackSlot( Item *pItem ); - Item* GetItemFromBuyBackSlot( uint32 slot ); - void RemoveItemFromBuyBackSlot( uint32 slot, bool del ); - uint32 GetMaxKeyringSize() const { return KEYRING_SLOT_END-KEYRING_SLOT_START; } - void SendEquipError( uint8 msg, Item* pItem, Item *pItem2 ); - void SendBuyError( uint8 msg, Creature* pCreature, uint32 item, uint32 param ); - void SendSellError( uint8 msg, Creature* pCreature, uint64 guid, uint32 param ); - void AddWeaponProficiency(uint32 newflag) { m_WeaponProficiency |= newflag; } - void AddArmorProficiency(uint32 newflag) { m_ArmorProficiency |= newflag; } - uint32 GetWeaponProficiency() const { return m_WeaponProficiency; } - uint32 GetArmorProficiency() const { return m_ArmorProficiency; } - bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; } - bool IsUseEquipedWeapon( bool mainhand ) const - { - // disarm applied only to mainhand weapon - return !IsInFeralForm() && (!mainhand || !HasFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISARMED) ); - } - void SendNewItem( Item *item, uint32 count, bool received, bool created, bool broadcast = false ); - bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot); - - float GetReputationPriceDiscount( Creature const* pCreature ) const; - Player* GetTrader() const { return pTrader; } - void ClearTrade(); - void TradeCancel(bool sendback); - uint16 GetItemPosByTradeSlot(uint32 slot) const { return tradeItems[slot]; } - - void UpdateEnchantTime(uint32 time); - void UpdateItemDuration(uint32 time, bool realtimeonly=false); - void AddEnchantmentDurations(Item *item); - void RemoveEnchantmentDurations(Item *item); - void RemoveAllEnchantments(EnchantmentSlot slot); - void AddEnchantmentDuration(Item *item,EnchantmentSlot slot,uint32 duration); - void ApplyEnchantment(Item *item,EnchantmentSlot slot,bool apply, bool apply_dur = true, bool ignore_condition = false); - void ApplyEnchantment(Item *item,bool apply); - void SendEnchantmentDurations(); - void AddItemDurations(Item *item); - void RemoveItemDurations(Item *item); - void SendItemDurations(); - void LoadCorpse(); - void LoadPet(); - - uint32 m_stableSlots; - - /*********************************************************/ - /*** QUEST SYSTEM ***/ - /*********************************************************/ - - void PrepareQuestMenu( uint64 guid ); - void SendPreparedQuest( uint64 guid ); - bool IsActiveQuest( uint32 quest_id ) const; - Quest const *GetNextQuest( uint64 guid, Quest const *pQuest ); - bool CanSeeStartQuest( Quest const *pQuest ); - bool CanTakeQuest( Quest const *pQuest, bool msg ); - bool CanAddQuest( Quest const *pQuest, bool msg ); - bool CanCompleteQuest( uint32 quest_id ); - bool CanCompleteRepeatableQuest(Quest const *pQuest); - bool CanRewardQuest( Quest const *pQuest, bool msg ); - bool CanRewardQuest( Quest const *pQuest, uint32 reward, bool msg ); - void AddQuest( Quest const *pQuest, Object *questGiver ); - void CompleteQuest( uint32 quest_id ); - void IncompleteQuest( uint32 quest_id ); - void RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce = true ); - void FailQuest( uint32 quest_id ); - void FailTimedQuest( uint32 quest_id ); - bool SatisfyQuestSkillOrClass( Quest const* qInfo, bool msg ); - bool SatisfyQuestLevel( Quest const* qInfo, bool msg ); - bool SatisfyQuestLog( bool msg ); - bool SatisfyQuestPreviousQuest( Quest const* qInfo, bool msg ); - bool SatisfyQuestRace( Quest const* qInfo, bool msg ); - bool SatisfyQuestReputation( Quest const* qInfo, bool msg ); - bool SatisfyQuestStatus( Quest const* qInfo, bool msg ); - bool SatisfyQuestTimed( Quest const* qInfo, bool msg ); - bool SatisfyQuestExclusiveGroup( Quest const* qInfo, bool msg ); - bool SatisfyQuestNextChain( Quest const* qInfo, bool msg ); - bool SatisfyQuestPrevChain( Quest const* qInfo, bool msg ); - bool SatisfyQuestDay( Quest const* qInfo, bool msg ); - bool GiveQuestSourceItem( Quest const *pQuest ); - bool TakeQuestSourceItem( uint32 quest_id, bool msg ); - bool GetQuestRewardStatus( uint32 quest_id ) const; - QuestStatus GetQuestStatus( uint32 quest_id ) const; - void SetQuestStatus( uint32 quest_id, QuestStatus status ); - - void SetDailyQuestStatus( uint32 quest_id ); - void ResetDailyQuestStatus(); - - uint16 FindQuestSlot( uint32 quest_id ) const; - uint32 GetQuestSlotQuestId(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_ID_OFFSET); } - uint32 GetQuestSlotState(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_STATE_OFFSET); } - uint32 GetQuestSlotCounters(uint16 slot)const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET); } - uint8 GetQuestSlotCounter(uint16 slot,uint8 counter) const { return GetByteValue(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET,counter); } - uint32 GetQuestSlotTime(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_TIME_OFFSET); } - void SetQuestSlot(uint16 slot,uint32 quest_id, uint32 timer = 0) - { - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_ID_OFFSET,quest_id); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_STATE_OFFSET,0); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET,0); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_TIME_OFFSET,timer); - } - void SetQuestSlotCounter(uint16 slot,uint8 counter,uint8 count) { SetByteValue(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET,counter,count); } - void SetQuestSlotState(uint16 slot,uint32 state) { SetFlag(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_STATE_OFFSET,state); } - void RemoveQuestSlotState(uint16 slot,uint32 state) { RemoveFlag(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_STATE_OFFSET,state); } - void SetQuestSlotTimer(uint16 slot,uint32 timer) { SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_TIME_OFFSET,timer); } - void SwapQuestSlot(uint16 slot1,uint16 slot2) - { - for (int i = 0; i < MAX_QUEST_OFFSET ; ++i ) - { - uint32 temp1 = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET *slot1 + i); - uint32 temp2 = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET *slot2 + i); - - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET *slot1 + i, temp2); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET *slot2 + i, temp1); - } - } - uint32 GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry); - void AdjustQuestReqItemCount( Quest const* pQuest ); - void AreaExploredOrEventHappens( uint32 questId ); - void GroupEventHappens( uint32 questId, WorldObject const* pEventObject ); - void ItemAddedQuestCheck( uint32 entry, uint32 count ); - void ItemRemovedQuestCheck( uint32 entry, uint32 count ); - void KilledMonster( uint32 entry, uint64 guid ); - void CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id ); - void TalkedToCreature( uint32 entry, uint64 guid ); - void MoneyChanged( uint32 value ); - bool HasQuestForItem( uint32 itemid ) const; - bool HasQuestForGO(int32 GOId); - void UpdateForQuestsGO(); - bool CanShareQuest(uint32 quest_id) const; - - void SendQuestComplete( uint32 quest_id ); - void SendQuestReward( Quest const *pQuest, uint32 XP, Object* questGiver ); - void SendQuestFailed( uint32 quest_id ); - void SendQuestTimerFailed( uint32 quest_id ); - void SendCanTakeQuestResponse( uint32 msg ); - void SendPushToPartyResponse( Player *pPlayer, uint32 msg ); - void SendQuestUpdateAddItem( Quest const* pQuest, uint32 item_idx, uint32 count ); - void SendQuestUpdateAddCreatureOrGo( Quest const* pQuest, uint64 guid, uint32 creatureOrGO_idx, uint32 old_count, uint32 add_count ); - - uint64 GetDivider() { return m_divider; }; - void SetDivider( uint64 guid ) { m_divider = guid; }; - - uint32 GetInGameTime() { return m_ingametime; }; - - void SetInGameTime( uint32 time ) { m_ingametime = time; }; - - void AddTimedQuest( uint32 quest_id ) { m_timedquests.insert(quest_id); } - - /*********************************************************/ - /*** LOAD SYSTEM ***/ - /*********************************************************/ - - bool LoadFromDB(uint32 guid, SqlQueryHolder *holder); - bool MinimalLoadFromDB(QueryResult *result, uint32 guid); - static bool LoadValuesArrayFromDB(Tokens& data,uint64 guid); - static uint32 GetUInt32ValueFromArray(Tokens const& data, uint16 index); - static float GetFloatValueFromArray(Tokens const& data, uint16 index); - static uint32 GetUInt32ValueFromDB(uint16 index, uint64 guid); - static float GetFloatValueFromDB(uint16 index, uint64 guid); - static uint32 GetZoneIdFromDB(uint64 guid); - static bool LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid); - - /*********************************************************/ - /*** SAVE SYSTEM ***/ - /*********************************************************/ - - void SaveToDB(); - void SaveInventoryAndGoldToDB(); // fast save function for item/money cheating preventing - void SaveGoldToDB() { SetUInt32ValueInDB(PLAYER_FIELD_COINAGE,GetMoney(),GetGUID()); } - static bool SaveValuesArrayInDB(Tokens const& data,uint64 guid); - static void SetUInt32ValueInArray(Tokens& data,uint16 index, uint32 value); - static void SetFloatValueInArray(Tokens& data,uint16 index, float value); - static void SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid); - static void SetFloatValueInDB(uint16 index, float value, uint64 guid); - static void SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint32 zone,uint64 guid); - - bool m_mailsLoaded; - bool m_mailsUpdated; - - void SetBindPoint(uint64 guid); - void SendTalentWipeConfirm(uint64 guid); - void RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ); - void SendPetSkillWipeConfirm(); - void CalcRage( uint32 damage,bool attacker ); - void RegenerateAll(); - void Regenerate(Powers power); - void RegenerateHealth(); - void setRegenTimer(uint32 time) {m_regenTimer = time;} - void setWeaponChangeTimer(uint32 time) {m_weaponChangeTimer = time;} - - uint32 GetMoney() { return GetUInt32Value (PLAYER_FIELD_COINAGE); } - void ModifyMoney( int32 d ) - { - if(d < 0) - SetMoney (GetMoney() > uint32(-d) ? GetMoney() + d : 0); - else - SetMoney (GetMoney() < MAX_MONEY_AMOUNT - d ? GetMoney() + d : MAX_MONEY_AMOUNT); - - // "At Gold Limit" - if(GetMoney() >= MAX_MONEY_AMOUNT) - SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD,NULL,NULL); - } - void SetMoney( uint32 value ) - { - SetUInt32Value (PLAYER_FIELD_COINAGE, value); - MoneyChanged( value ); - } - - uint32 GetTutorialInt(uint32 intId ) - { - ASSERT( (intId < 8) ); - return m_Tutorials[intId]; - } - - void SetTutorialInt(uint32 intId, uint32 value) - { - ASSERT( (intId < 8) ); - if(m_Tutorials[intId]!=value) - { - m_Tutorials[intId] = value; - m_TutorialsChanged = true; - } - } - - QuestStatusMap& getQuestStatusMap() { return mQuestStatus; }; - - const uint64& GetSelection( ) const { return m_curSelection; } - void SetSelection(const uint64 &guid) { m_curSelection = guid; SetUInt64Value(UNIT_FIELD_TARGET, guid); } - - uint8 GetComboPoints() { return m_comboPoints; } - uint64 GetComboTarget() { return m_comboTarget; } - - void AddComboPoints(Unit* target, int8 count); - void ClearComboPoints(); - void SendComboPoints(); - - void SendMailResult(uint32 mailId, uint32 mailAction, uint32 mailError, uint32 equipError = 0, uint32 item_guid = 0, uint32 item_count = 0); - void SendNewMail(); - void UpdateNextMailTimeAndUnreads(); - void AddNewMailDeliverTime(time_t deliver_time); - bool IsMailsLoaded() const { return m_mailsLoaded; } - - //void SetMail(Mail *m); - void RemoveMail(uint32 id); - - void AddMail(Mail* mail) { m_mail.push_front(mail);}// for call from WorldSession::SendMailTo - uint32 GetMailSize() { return m_mail.size();}; - Mail* GetMail(uint32 id); - - PlayerMails::iterator GetmailBegin() { return m_mail.begin();}; - PlayerMails::iterator GetmailEnd() { return m_mail.end();}; - - /*********************************************************/ - /*** MAILED ITEMS SYSTEM ***/ - /*********************************************************/ - - uint8 unReadMails; - time_t m_nextMailDelivereTime; - - typedef HM_NAMESPACE::hash_map ItemMap; - - ItemMap mMitems; //template defined in objectmgr.cpp - - Item* GetMItem(uint32 id) - { - ItemMap::const_iterator itr = mMitems.find(id); - if (itr != mMitems.end()) - return itr->second; - - return NULL; - } - - void AddMItem(Item* it) - { - ASSERT( it ); - //assert deleted, because items can be added before loading - mMitems[it->GetGUIDLow()] = it; - } - - bool RemoveMItem(uint32 id) - { - ItemMap::iterator i = mMitems.find(id); - if (i == mMitems.end()) - return false; - - mMitems.erase(i); - return true; - } - - void PetSpellInitialize(); - void CharmSpellInitialize(); - void PossessSpellInitialize(); - bool HasSpell(uint32 spell) const; - TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const; - bool IsSpellFitByClassAndRace( uint32 spell_id ) const; - - void SendProficiency(uint8 pr1, uint32 pr2); - void SendInitialSpells(); - bool addSpell(uint32 spell_id, bool active, bool learning = true, bool loading = false, uint16 slot_id=SPELL_WITHOUT_SLOT_ID, bool disabled = false); - void learnSpell(uint32 spell_id); - void removeSpell(uint32 spell_id, bool disabled = false); - void resetSpells(); - void learnDefaultSpells(bool loading = false); - void learnQuestRewardedSpells(); - void learnQuestRewardedSpells(Quest const* quest); - - uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); } - void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS1,points); } - bool resetTalents(bool no_cost = false); - uint32 resetTalentsCost() const; - void InitTalentForLevel(); - - uint32 GetFreePrimaryProffesionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS2); } - void SetFreePrimaryProffesions(uint16 profs) { SetUInt32Value(PLAYER_CHARACTER_POINTS2,profs); } - void InitPrimaryProffesions(); - - PlayerSpellMap const& GetSpellMap() const { return m_spells; } - PlayerSpellMap & GetSpellMap() { return m_spells; } - - void AddSpellMod(SpellModifier* mod, bool apply); - int32 GetTotalFlatMods(uint32 spellId, SpellModOp op); - int32 GetTotalPctMods(uint32 spellId, SpellModOp op); - bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell = NULL); - template T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell = NULL); - void RemoveSpellMods(Spell const* spell); - - bool HasSpellCooldown(uint32 spell_id) const - { - SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); - return itr != m_spellCooldowns.end() && itr->second.end > time(NULL); - } - uint32 GetSpellCooldownDelay(uint32 spell_id) const - { - SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); - time_t t = time(NULL); - return itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0; - } - void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time); - void SendCooldownEvent(SpellEntry const *spellInfo); - void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ); - void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); } - void RemoveArenaSpellCooldowns(); - void RemoveAllSpellCooldown(); - void _LoadSpellCooldowns(QueryResult *result); - void _SaveSpellCooldowns(); - - void setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana) - { - m_resurrectGUID = guid; - m_resurrectMap = mapId; - m_resurrectX = X; - m_resurrectY = Y; - m_resurrectZ = Z; - m_resurrectHealth = health; - m_resurrectMana = mana; - }; - void clearResurrectRequestData() { setResurrectRequestData(0,0,0.0f,0.0f,0.0f,0,0); } - bool isRessurectRequestedBy(uint64 guid) const { return m_resurrectGUID == guid; } - bool isRessurectRequested() const { return m_resurrectGUID != 0; } - void ResurectUsingRequestData(); - - int getCinematic() - { - return m_cinematic; - } - void setCinematic(int cine) - { - m_cinematic = cine; - } - - void addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc); - void removeActionButton(uint8 button); - void SendInitialActionButtons(); - - PvPInfo pvpInfo; - void UpdatePvP(bool state, bool ovrride=false); - void UpdateZone(uint32 newZone); - void UpdateArea(uint32 newArea); - - void UpdateZoneDependentAuras( uint32 zone_id ); // zones - void UpdateAreaDependentAuras( uint32 area_id ); // subzones - - void UpdateAfkReport(time_t currTime); - void UpdatePvPFlag(time_t currTime); - void UpdateContestedPvP(uint32 currTime); - void SetContestedPvPTimer(uint32 newTime) {m_contestedPvPTimer = newTime;} - void ResetContestedPvP() - { - clearUnitState(UNIT_STAT_ATTACK_PLAYER); - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP); - m_contestedPvPTimer = 0; - } - - /** todo: -maybe move UpdateDuelFlag+DuelComplete to independent DuelHandler.. **/ - DuelInfo *duel; - void UpdateDuelFlag(time_t currTime); - void CheckDuelDistance(time_t currTime); - void DuelComplete(DuelCompleteType type); - - bool IsGroupVisibleFor(Player* p) const; - bool IsInSameGroupWith(Player const* p) const; - bool IsInSameRaidWith(Player const* p) const { return p==this || (GetGroup() != NULL && GetGroup() == p->GetGroup()); } - void UninviteFromGroup(); - static void RemoveFromGroup(Group* group, uint64 guid); - void RemoveFromGroup() { RemoveFromGroup(GetGroup(),GetGUID()); } - void SendUpdateToOutOfRangeGroupMembers(); - - void SetInGuild(uint32 GuildId) { SetUInt32Value(PLAYER_GUILDID, GuildId); Player::SetUInt32ValueInDB(PLAYER_GUILDID, GuildId, this->GetGUID()); } - void SetRank(uint32 rankId){ SetUInt32Value(PLAYER_GUILDRANK, rankId); Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, rankId, this->GetGUID()); } - void SetGuildIdInvited(uint32 GuildId) { m_GuildIdInvited = GuildId; } - uint32 GetGuildId() { return GetUInt32Value(PLAYER_GUILDID); } - static uint32 GetGuildIdFromDB(uint64 guid); - uint32 GetRank(){ return GetUInt32Value(PLAYER_GUILDRANK); } - static uint32 GetRankFromDB(uint64 guid); - int GetGuildIdInvited() { return m_GuildIdInvited; } - static void RemovePetitionsAndSigns(uint64 guid, uint32 type); - - // Arena Team - void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot) - { - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId); - SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId, this->GetGUID()); - } - uint32 GetArenaTeamId(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6)); } - static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot); - void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; } - uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; } - - void SetDifficulty(uint32 dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } - uint8 GetDifficulty() { return m_dungeonDifficulty; } - - bool UpdateSkill(uint32 skill_id, uint32 step); - bool UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step); - - bool UpdateCraftSkill(uint32 spellid); - bool UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator = 1); - bool UpdateFishingSkill(); - - uint32 GetBaseDefenseSkillValue() const { return GetBaseSkillValue(SKILL_DEFENSE); } - uint32 GetBaseWeaponSkillValue(WeaponAttackType attType) const; - - uint32 GetSpellByProto(ItemPrototype *proto); - - float GetHealthBonusFromStamina(); - float GetManaBonusFromIntellect(); - - bool UpdateStats(Stats stat); - bool UpdateAllStats(); - void UpdateResistances(uint32 school); - void UpdateArmor(); - void UpdateMaxHealth(); - void UpdateMaxPower(Powers power); - void UpdateAttackPowerAndDamage(bool ranged = false); - void UpdateShieldBlockValue(); - void UpdateDamagePhysical(WeaponAttackType attType); - void UpdateSpellDamageAndHealingBonus(); - - void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage); - - void UpdateDefenseBonusesMod(); - void ApplyRatingMod(CombatRating cr, int32 value, bool apply); - float GetMeleeCritFromAgility(); - float GetDodgeFromAgility(); - float GetSpellCritFromIntellect(); - float OCTRegenHPPerSpirit(); - float OCTRegenMPPerSpirit(); - float GetRatingCoefficient(CombatRating cr) const; - float GetRatingBonusValue(CombatRating cr) const; - uint32 GetMeleeCritDamageReduction(uint32 damage) const; - uint32 GetRangedCritDamageReduction(uint32 damage) const; - uint32 GetSpellCritDamageReduction(uint32 damage) const; - uint32 GetDotDamageReduction(uint32 damage) const; - - float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const; - void UpdateBlockPercentage(); - void UpdateCritPercentage(WeaponAttackType attType); - void UpdateAllCritPercentages(); - void UpdateParryPercentage(); - void UpdateDodgePercentage(); - void UpdateAllSpellCritChances(); - void UpdateSpellCritChance(uint32 school); - void UpdateExpertise(WeaponAttackType attType); - void UpdateManaRegen(); - - const uint64& GetLootGUID() const { return m_lootGuid; } - void SetLootGUID(const uint64 &guid) { m_lootGuid = guid; } - - void RemovedInsignia(Player* looterPlr); - - WorldSession* GetSession() const { return m_session; } - void SetSession(WorldSession *s) { m_session = s; } - - void BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const; - void DestroyForPlayer( Player *target ) const; - void SendDelayResponse(const uint32); - void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP); - - //Low Level Packets - void PlaySound(uint32 Sound, bool OnlySelf); - //notifiers - void SendAttackSwingCantAttack(); - void SendAttackSwingCancelAttack(); - void SendAttackSwingDeadTarget(); - void SendAttackSwingNotStanding(); - void SendAttackSwingNotInRange(); - void SendAttackSwingBadFacingAttack(); - void SendAutoRepeatCancel(); - void SendExplorationExperience(uint32 Area, uint32 Experience); - - void SendDungeonDifficulty(bool IsInGroup); - void ResetInstances(uint8 method); - void SendResetInstanceSuccess(uint32 MapId); - void SendResetInstanceFailed(uint32 reason, uint32 MapId); - void SendResetFailedNotify(uint32 mapid); - - bool SetPosition(float x, float y, float z, float orientation, bool teleport = false); - void UpdateUnderwaterState( Map * m, float x, float y, float z ); - - void SendMessageToSet(WorldPacket *data, bool self);// overwrite Object::SendMessageToSet - void SendMessageToSetInRange(WorldPacket *data, float fist, bool self); - // overwrite Object::SendMessageToSetInRange - void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only); - - static void DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars = true); - - Corpse *GetCorpse() const; - void SpawnCorpseBones(); - void CreateCorpse(); - void KillPlayer(); - uint32 GetResurrectionSpellId(); - void ResurrectPlayer(float restore_percent, bool updateToWorld = true, bool applySickness = false); - void BuildPlayerRepop(); - void RepopAtGraveyard(); - - void DurabilityLossAll(double percent, bool inventory); - void DurabilityLoss(Item* item, double percent); - void DurabilityPointsLossAll(int32 points, bool inventory); - void DurabilityPointsLoss(Item* item, int32 points); - void DurabilityPointLossForEquipSlot(EquipmentSlots slot); - uint32 DurabilityRepairAll(bool cost, float discountMod, bool guildBank); - uint32 DurabilityRepair(uint16 pos, bool cost, float discountMod, bool guildBank); - - void StopMirrorTimers() - { - StopMirrorTimer(FATIGUE_TIMER); - StopMirrorTimer(BREATH_TIMER); - StopMirrorTimer(FIRE_TIMER); - } - - void SetMovement(PlayerMovementType pType); - - void JoinedChannel(Channel *c); - void LeftChannel(Channel *c); - void CleanupChannels(); - void UpdateLocalChannels( uint32 newZone ); - void LeaveLFGChannel(); - - void UpdateDefense(); - void UpdateWeaponSkill (WeaponAttackType attType); - void UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence); - - void SetSkill(uint32 id, uint16 currVal, uint16 maxVal); - uint16 GetMaxSkillValue(uint32 skill) const; // max + perm. bonus - uint16 GetPureMaxSkillValue(uint32 skill) const; // max - uint16 GetSkillValue(uint32 skill) const; // skill value + perm. bonus + temp bonus - uint16 GetBaseSkillValue(uint32 skill) const; // skill value + perm. bonus - uint16 GetPureSkillValue(uint32 skill) const; // skill value - int16 GetSkillTempBonusValue(uint32 skill) const; - bool HasSkill(uint32 skill) const; - void learnSkillRewardedSpells( uint32 id ); - void learnSkillRewardedSpells(); - - void SetDontMove(bool dontMove); - bool GetDontMove() const { return m_dontMove; } - - void CheckExploreSystem(void); - - static uint32 TeamForRace(uint8 race); - uint32 GetTeam() const { return m_team; } - static uint32 getFactionForRace(uint8 race); - void setFactionForRace(uint8 race); - - bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const; - bool RewardPlayerAndGroupAtKill(Unit* pVictim); - - FactionStateList m_factions; - ForcedReactions m_forcedReactions; - uint32 GetDefaultReputationFlags(const FactionEntry *factionEntry) const; - int32 GetBaseReputation(const FactionEntry *factionEntry) const; - int32 GetReputation(uint32 faction_id) const; - int32 GetReputation(const FactionEntry *factionEntry) const; - ReputationRank GetReputationRank(uint32 faction) const; - ReputationRank GetReputationRank(const FactionEntry *factionEntry) const; - ReputationRank GetBaseReputationRank(const FactionEntry *factionEntry) const; - ReputationRank ReputationToRank(int32 standing) const; - const static int32 ReputationRank_Length[MAX_REPUTATION_RANK]; - const static int32 Reputation_Cap = 42999; - const static int32 Reputation_Bottom = -42000; - bool ModifyFactionReputation(uint32 FactionTemplateId, int32 DeltaReputation); - bool ModifyFactionReputation(FactionEntry const* factionEntry, int32 standing); - bool ModifyOneFactionReputation(FactionEntry const* factionEntry, int32 standing); - bool SetFactionReputation(uint32 FactionTemplateId, int32 standing); - bool SetFactionReputation(FactionEntry const* factionEntry, int32 standing); - bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing); - int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest); - void RewardReputation(Unit *pVictim, float rate); - void RewardReputation(Quest const *pQuest); - void SetInitialFactions(); - void UpdateReputation() const; - void SendFactionState(FactionState const* faction) const; - void SendInitialReputations(); - FactionState const* GetFactionState( FactionEntry const* factionEntry) const; - void SetFactionAtWar(FactionState* faction, bool atWar); - void SetFactionInactive(FactionState* faction, bool inactive); - void SetFactionVisible(FactionState* faction); - void SetFactionVisibleForFactionTemplateId(uint32 FactionTemplateId); - void SetFactionVisibleForFactionId(uint32 FactionId); - void UpdateMaxSkills(); - void UpdateSkillsToMaxSkillsForLevel(); // for .levelup - void ModifySkillBonus(uint32 skillid,int32 val, bool talent); - - /*********************************************************/ - /*** PVP SYSTEM ***/ - /*********************************************************/ - void UpdateArenaFields(); - void UpdateHonorFields(); - bool RewardHonor(Unit *pVictim, uint32 groupsize, float honor = -1); - uint32 GetHonorPoints() { return GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY); } - uint32 GetArenaPoints() { return GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY); } - void ModifyHonorPoints( int32 value ); - void ModifyArenaPoints( int32 value ); - uint32 GetMaxPersonalArenaRatingRequirement(); - - //End of PvP System - - void SetDrunkValue(uint16 newDrunkValue, uint32 itemid=0); - uint16 GetDrunkValue() const { return m_drunk; } - static DrunkenState GetDrunkenstateByValue(uint16 value); - - uint32 GetDeathTimer() const { return m_deathTimer; } - uint32 GetCorpseReclaimDelay(bool pvp) const; - void UpdateCorpseReclaimDelay(); - void SendCorpseReclaimDelay(bool load = false); - - uint32 GetShieldBlockValue() const; // overwrite Unit version (virtual) - bool CanParry() const { return m_canParry; } - void SetCanParry(bool value) { m_canParry = value; } - bool CanDualWield() const { return m_canDualWield; } - void SetCanDualWield(bool value) { m_canDualWield = value; } - - void SetRegularAttackTime(); - void SetBaseModValue(BaseModGroup modGroup, BaseModType modType, float value) { m_auraBaseMod[modGroup][modType] = value; } - void HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply, bool affectStats = true); - float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const; - float GetTotalBaseModValue(BaseModGroup modGroup) const; - float GetTotalPercentageModValue(BaseModGroup modGroup) const { return m_auraBaseMod[modGroup][FLAT_MOD] + m_auraBaseMod[modGroup][PCT_MOD]; } - void _ApplyAllStatBonuses(); - void _RemoveAllStatBonuses(); - - void _ApplyWeaponDependentAuraMods(Item *item,WeaponAttackType attackType,bool apply); - void _ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply); - void _ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply); - - void _ApplyItemMods(Item *item,uint8 slot,bool apply); - void _RemoveAllItemMods(); - void _ApplyAllItemMods(); - void _ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply); - void _ApplyAmmoBonuses(); - bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot); - void ToggleMetaGemsActive(uint8 exceptslot, bool apply); - void CorrectMetaGemEnchants(uint8 slot, bool apply); - void InitDataForForm(bool reapplyMods = false); - - void ApplyItemEquipSpell(Item *item, bool apply, bool form_change = false); - void ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply, bool form_change = false); - void UpdateEquipSpellsAtFormChange(); - void CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attType); - - void SendInitWorldStates(); - void SendUpdateWorldState(uint32 Field, uint32 Value); - void SendDirectMessage(WorldPacket *data); - - void SendAuraDurationsForTarget(Unit* target); - - PlayerMenu* PlayerTalkClass; - std::vector ItemSetEff; - - void SendLoot(uint64 guid, LootType loot_type); - void SendLootRelease( uint64 guid ); - void SendNotifyLootItemRemoved(uint8 lootSlot); - void SendNotifyLootMoneyRemoved(); - - /*********************************************************/ - /*** BATTLEGROUND SYSTEM ***/ - /*********************************************************/ - - bool InBattleGround() const { return m_bgBattleGroundID != 0; } - uint32 GetBattleGroundId() const { return m_bgBattleGroundID; } - BattleGround* GetBattleGround() const; - bool InArena() const; - - static uint32 GetMinLevelForBattleGroundQueueId(uint32 queue_id); - static uint32 GetMaxLevelForBattleGroundQueueId(uint32 queue_id); - uint32 GetBattleGroundQueueIdFromLevel() const; - - uint32 GetBattleGroundQueueId(uint32 index) const { return m_bgBattleGroundQueueID[index].bgType; } - uint32 GetBattleGroundQueueIndex(uint32 bgType) const - { - for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) - if (m_bgBattleGroundQueueID[i].bgType == bgType) - return i; - return PLAYER_MAX_BATTLEGROUND_QUEUES; - } - bool IsInvitedForBattleGroundType(uint32 bgType) const - { - for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) - if (m_bgBattleGroundQueueID[i].bgType == bgType) - return m_bgBattleGroundQueueID[i].invited; - return PLAYER_MAX_BATTLEGROUND_QUEUES; - } - bool InBattleGroundQueueForBattleGroundType(uint32 bgType) const - { - return GetBattleGroundQueueIndex(bgType) < PLAYER_MAX_BATTLEGROUND_QUEUES; - } - - void SetBattleGroundId(uint32 val) { m_bgBattleGroundID = val; } - uint32 AddBattleGroundQueueId(uint32 val) - { - for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) - { - if (m_bgBattleGroundQueueID[i].bgType == 0 || m_bgBattleGroundQueueID[i].bgType == val) - { - m_bgBattleGroundQueueID[i].bgType = val; - m_bgBattleGroundQueueID[i].invited = false; - return i; - } - } - return PLAYER_MAX_BATTLEGROUND_QUEUES; - } - void RemoveBattleGroundQueueId(uint32 val) - { - for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) - { - if (m_bgBattleGroundQueueID[i].bgType == val) - { - m_bgBattleGroundQueueID[i].bgType = 0; - m_bgBattleGroundQueueID[i].invited = false; - return; - } - } - } - void SetInviteForBattleGroundType(uint32 bgType) - { - for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) - if (m_bgBattleGroundQueueID[i].bgType == bgType) - m_bgBattleGroundQueueID[i].invited = true; - } - - uint32 GetBattleGroundEntryPointMap() const { return m_bgEntryPointMap; } - float GetBattleGroundEntryPointX() const { return m_bgEntryPointX; } - float GetBattleGroundEntryPointY() const { return m_bgEntryPointY; } - float GetBattleGroundEntryPointZ() const { return m_bgEntryPointZ; } - float GetBattleGroundEntryPointO() const { return m_bgEntryPointO; } - void SetBattleGroundEntryPoint(uint32 Map, float PosX, float PosY, float PosZ, float PosO ) - { - m_bgEntryPointMap = Map; - m_bgEntryPointX = PosX; - m_bgEntryPointY = PosY; - m_bgEntryPointZ = PosZ; - m_bgEntryPointO = PosO; - } - - void SetBGTeam(uint32 team) { m_bgTeam = team; } - uint32 GetBGTeam() const { return m_bgTeam ? m_bgTeam : GetTeam(); } - - void LeaveBattleground(bool teleportToEntryPoint = true); - bool CanJoinToBattleground() const; - bool CanReportAfkDueToLimit(); - void ReportedAfkBy(Player* reporter); - void ClearAfkReports() { m_bgAfkReporter.clear(); } - - bool GetBGAccessByLevel(uint32 bgTypeId) const; - - /*********************************************************/ - /*** REST SYSTEM ***/ - /*********************************************************/ - - bool isRested() const { return GetRestTime() >= 10000; } - uint32 GetXPRestBonus(uint32 xp); - uint32 GetRestTime() const { return m_restTime;}; - void SetRestTime(uint32 v) { m_restTime = v;}; - - /*********************************************************/ - /*** ENVIROMENTAL SYSTEM ***/ - /*********************************************************/ - - void EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 damage); - - /*********************************************************/ - /*** FLOOD FILTER SYSTEM ***/ - /*********************************************************/ - - void UpdateSpeakTime(); - bool CanSpeak() const; - void ChangeSpeakTime(int utime); - - /*********************************************************/ - /*** VARIOUS SYSTEMS ***/ - /*********************************************************/ - MovementInfo m_movementInfo; - bool isMoving() const { return HasUnitMovementFlag(movementFlagsMask); } - bool isMovingOrTurning() const { return HasUnitMovementFlag(movementOrTurningFlagsMask); } - - bool CanFly() const { return HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY); } - bool IsFlying() const { return HasUnitMovementFlag(MOVEMENTFLAG_FLYING); } - - void HandleDrowning(); - - void SetClientControl(Unit* target, uint8 allowMove); - - // Transports - Transport * GetTransport() const { return m_transport; } - void SetTransport(Transport * t) { m_transport = t; } - - float GetTransOffsetX() const { return m_movementInfo.t_x; } - float GetTransOffsetY() const { return m_movementInfo.t_y; } - float GetTransOffsetZ() const { return m_movementInfo.t_z; } - float GetTransOffsetO() const { return m_movementInfo.t_o; } - uint32 GetTransTime() const { return m_movementInfo.t_time; } - - uint32 GetSaveTimer() const { return m_nextSave; } - void SetSaveTimer(uint32 timer) { m_nextSave = timer; } - - // Recall position - uint32 m_recallMap; - float m_recallX; - float m_recallY; - float m_recallZ; - float m_recallO; - void SaveRecallPosition(); - - // Homebind coordinates - uint32 m_homebindMapId; - uint16 m_homebindZoneId; - float m_homebindX; - float m_homebindY; - float m_homebindZ; - - // currently visible objects at player client - typedef std::set ClientGUIDs; - ClientGUIDs m_clientGUIDs; - - bool HaveAtClient(WorldObject const* u) { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } - - bool IsVisibleInGridForPlayer(Player* pl) const; - bool IsVisibleGloballyFor(Player* pl) const; - - void UpdateVisibilityOf(WorldObject* target); - - template - void UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); - - // Stealth detection system - uint32 m_DetectInvTimer; - void HandleStealthedUnitsDetection(); - - uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; - - bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; } - void SetAtLoginFlag(AtLoginFlags f) { m_atLoginFlags |= f; } - - LookingForGroup m_lookingForGroup; - - // Temporarily removed pet cache - uint32 GetTemporaryUnsummonedPetNumber() const { return m_temporaryUnsummonedPetNumber; } - void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; } - uint32 GetOldPetSpell() const { return m_oldpetspell; } - void SetOldPetSpell(uint32 petspell) { m_oldpetspell = petspell; } - - /*********************************************************/ - /*** INSTANCE SYSTEM ***/ - /*********************************************************/ - - typedef HM_NAMESPACE::hash_map< uint32 /*mapId*/, InstancePlayerBind > BoundInstancesMap; - - void UpdateHomebindTime(uint32 time); - - uint32 m_HomebindTimer; - bool m_InstanceValid; - // permanent binds and solo binds by difficulty - BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES]; - InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty); - BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } - void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); - void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false); - InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); - void SendRaidInfo(); - void SendSavedInstances(); - static void ConvertInstancesToGroup(Player *player, Group *group = NULL, uint64 player_guid = 0); - - /*********************************************************/ - /*** GROUP SYSTEM ***/ - /*********************************************************/ - - Group * GetGroupInvite() { return m_groupInvite; } - void SetGroupInvite(Group *group) { m_groupInvite = group; } - Group * GetGroup() { return m_group.getTarget(); } - const Group * GetGroup() const { return (const Group*)m_group.getTarget(); } - GroupReference& GetGroupRef() { return m_group; } - void SetGroup(Group *group, int8 subgroup = -1); - uint8 GetSubGroup() const { return m_group.getSubGroup(); } - uint32 GetGroupUpdateFlag() { return m_groupUpdateMask; } - void SetGroupUpdateFlag(uint32 flag) { m_groupUpdateMask |= flag; } - uint64 GetAuraUpdateMask() { return m_auraUpdateMask; } - void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); } - Player* GetNextRandomRaidMember(float radius); - - GridReference &GetGridRef() { return m_gridRef; } - bool isAllowedToLoot(Creature* creature); - - WorldLocation& GetTeleportDest() { return m_teleport_dest; } - - DeclinedName const* GetDeclinedNames() const { return m_declinedname; } - - protected: - - /*********************************************************/ - /*** BATTLEGROUND SYSTEM ***/ - /*********************************************************/ - - /* this variable is set to bg->m_InstanceID, when player is teleported to BG - (it is battleground's GUID)*/ - uint32 m_bgBattleGroundID; - /* - this is an array of BG queues (BgTypeIDs) in which is player - */ - struct BgBattleGroundQueueID_Rec - { - uint32 bgType; - bool invited; - }; - BgBattleGroundQueueID_Rec m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES]; - uint32 m_bgEntryPointMap; - float m_bgEntryPointX; - float m_bgEntryPointY; - float m_bgEntryPointZ; - float m_bgEntryPointO; - - std::set m_bgAfkReporter; - uint8 m_bgAfkReportedCount; - time_t m_bgAfkReportedTimer; - uint32 m_contestedPvPTimer; - - uint32 m_bgTeam; // what side the player will be added to - - /*********************************************************/ - /*** QUEST SYSTEM ***/ - /*********************************************************/ - - std::set m_timedquests; - - uint64 m_divider; - uint32 m_ingametime; - - /*********************************************************/ - /*** LOAD SYSTEM ***/ - /*********************************************************/ - - void _LoadActions(QueryResult *result); - void _LoadAuras(QueryResult *result, uint32 timediff); - void _LoadBoundInstances(QueryResult *result); - void _LoadInventory(QueryResult *result, uint32 timediff); - void _LoadMailInit(QueryResult *resultUnread, QueryResult *resultDelivery); - void _LoadMail(); - void _LoadMailedItems(Mail *mail); - void _LoadQuestStatus(QueryResult *result); - void _LoadDailyQuestStatus(QueryResult *result); - void _LoadGroup(QueryResult *result); - void _LoadReputation(QueryResult *result); - void _LoadSpells(QueryResult *result); - void _LoadTutorials(QueryResult *result); - void _LoadFriendList(QueryResult *result); - bool _LoadHomeBind(QueryResult *result); - void _LoadDeclinedNames(QueryResult *result); - - /*********************************************************/ - /*** SAVE SYSTEM ***/ - /*********************************************************/ - - void _SaveActions(); - void _SaveAuras(); - void _SaveInventory(); - void _SaveMail(); - void _SaveQuestStatus(); - void _SaveDailyQuestStatus(); - void _SaveReputation(); - void _SaveSpells(); - void _SaveTutorials(); - - void _SetCreateBits(UpdateMask *updateMask, Player *target) const; - void _SetUpdateBits(UpdateMask *updateMask, Player *target) const; - - /*********************************************************/ - /*** ENVIRONMENTAL SYSTEM ***/ - /*********************************************************/ - void HandleLava(); - void HandleSobering(); - void StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue); - void ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen); - void StopMirrorTimer(MirrorTimerType Type); - uint8 m_isunderwater; - bool m_isInWater; - - /*********************************************************/ - /*** HONOR SYSTEM ***/ - /*********************************************************/ - time_t m_lastHonorUpdateTime; - - void outDebugValues() const; - bool _removeSpell(uint16 spell_id); - uint64 m_lootGuid; - - uint32 m_race; - uint32 m_class; - uint32 m_team; - uint32 m_nextSave; - time_t m_speakTime; - uint32 m_speakCount; - uint32 m_dungeonDifficulty; - - uint32 m_atLoginFlags; - - Item* m_items[PLAYER_SLOTS_COUNT]; - uint32 m_currentBuybackSlot; - - std::vector m_itemUpdateQueue; - bool m_itemUpdateQueueBlocked; - - uint32 m_ExtraFlags; - uint64 m_curSelection; - - uint64 m_comboTarget; - int8 m_comboPoints; - - QuestStatusMap mQuestStatus; - - uint32 m_GuildIdInvited; - uint32 m_ArenaTeamIdInvited; - - PlayerMails m_mail; - PlayerSpellMap m_spells; - SpellCooldowns m_spellCooldowns; - - ActionButtonList m_actionButtons; - - float m_auraBaseMod[BASEMOD_END][MOD_END]; - - SpellModList m_spellMods[MAX_SPELLMOD]; - int32 m_SpellModRemoveCount; - EnchantDurationList m_enchantDuration; - ItemDurationList m_itemDuration; - - uint64 m_resurrectGUID; - uint32 m_resurrectMap; - float m_resurrectX, m_resurrectY, m_resurrectZ; - uint32 m_resurrectHealth, m_resurrectMana; - - WorldSession *m_session; - - typedef std::list JoinedChannelsList; - JoinedChannelsList m_channels; - - bool m_dontMove; - - int m_cinematic; - - Player *pTrader; - bool acceptTrade; - uint16 tradeItems[TRADE_SLOT_COUNT]; - uint32 tradeGold; - - time_t m_nextThinkTime; - - uint32 m_Tutorials[8]; - bool m_TutorialsChanged; - - bool m_DailyQuestChanged; - time_t m_lastDailyQuestTime; - - uint32 m_regenTimer; - uint32 m_breathTimer; - uint32 m_drunkTimer; - uint16 m_drunk; - uint32 m_weaponChangeTimer; - - uint32 m_zoneUpdateId; - uint32 m_zoneUpdateTimer; - uint32 m_areaUpdateId; - - uint32 m_deathTimer; - time_t m_deathExpireTime; - - uint32 m_restTime; - - uint32 m_WeaponProficiency; - uint32 m_ArmorProficiency; - bool m_canParry; - bool m_canDualWield; - uint8 m_swingErrorMsg; - float m_ammoDPS; - ////////////////////Rest System///////////////////// - int time_inn_enter; - uint32 inn_pos_mapid; - float inn_pos_x; - float inn_pos_y; - float inn_pos_z; - float m_rest_bonus; - RestType rest_type; - ////////////////////Rest System///////////////////// - - // Transports - Transport * m_transport; - - uint32 m_resetTalentsCost; - time_t m_resetTalentsTime; - uint32 m_usedTalentCount; - - // Social - PlayerSocial *m_social; - - // Groups - GroupReference m_group; - Group *m_groupInvite; - uint32 m_groupUpdateMask; - uint64 m_auraUpdateMask; - - // Temporarily removed pet cache - uint32 m_temporaryUnsummonedPetNumber; - uint32 m_oldpetspell; - - uint64 m_miniPet; - GuardianPetList m_guardianPets; - - // Player summoning - time_t m_summon_expire; - uint32 m_summon_mapid; - float m_summon_x; - float m_summon_y; - float m_summon_z; - - // Far Teleport - WorldLocation m_teleport_dest; - - DeclinedName *m_declinedname; - private: - // internal common parts for CanStore/StoreItem functions - uint8 _CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem ) const; - uint8 _CanStoreItem_InBag( uint8 bag, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool merge, bool non_specialized, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot ) const; - uint8 _CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool merge, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot ) const; - Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update ); - - GridReference m_gridRef; -}; - -void AddItemsSetItem(Player*player,Item *item); -void RemoveItemsSetItem(Player*player,ItemPrototype const *proto); - -// "the bodies of template functions must be made available in a header file" -template T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) return 0; - int32 totalpct = 0; - int32 totalflat = 0; - for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr) - { - SpellModifier *mod = *itr; - - if(!IsAffectedBySpellmod(spellInfo,mod,spell)) - continue; - if (mod->type == SPELLMOD_FLAT) - totalflat += mod->value; - else if (mod->type == SPELLMOD_PCT) - { - // skip percent mods for null basevalue (most important for spell mods with charges ) - if(basevalue == T(0)) - continue; - - // special case (skip >10sec spell casts for instant cast setting) - if( mod->op==SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100) - continue; - - totalpct += mod->value; - } - - if (mod->charges > 0 ) - { - --mod->charges; - if (mod->charges == 0) - { - mod->charges = -1; - mod->lastAffected = spell; - if(!mod->lastAffected) - mod->lastAffected = FindCurrentSpellBySpellId(spellId); - ++m_SpellModRemoveCount; - } - } - } - - float diff = (float)basevalue*(float)totalpct/100.0f + (float)totalflat; - basevalue = T((float)basevalue + diff); - return T(diff); -} -#endif +/* + * Copyright (C) 2005-2008 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 _PLAYER_H +#define _PLAYER_H + +#include "Common.h" +#include "ItemPrototype.h" +#include "Unit.h" +#include "Item.h" + +#include "Database/DatabaseEnv.h" +#include "NPCHandler.h" +#include "QuestDef.h" +#include "Group.h" +#include "Bag.h" +#include "WorldSession.h" +#include "Pet.h" +#include "Util.h" // for Tokens typedef + +#include +#include + +struct Mail; +class Channel; +class DynamicObject; +class Creature; +class Pet; +class PlayerMenu; +class Transport; +class UpdateMask; +class PlayerSocial; + +typedef std::deque PlayerMails; + +#define PLAYER_MAX_SKILLS 127 +#define PLAYER_MAX_DAILY_QUESTS 25 + +// Note: SPELLMOD_* values is aura types in fact +enum SpellModType +{ + SPELLMOD_FLAT = 107, // SPELL_AURA_ADD_FLAT_MODIFIER + SPELLMOD_PCT = 108 // SPELL_AURA_ADD_PCT_MODIFIER +}; + +enum PlayerSpellState +{ + PLAYERSPELL_UNCHANGED = 0, + PLAYERSPELL_CHANGED = 1, + PLAYERSPELL_NEW = 2, + PLAYERSPELL_REMOVED = 3 +}; + +struct PlayerSpell +{ + uint16 slotId : 16; + PlayerSpellState state : 8; + bool active : 1; + bool disabled : 1; +}; + +#define SPELL_WITHOUT_SLOT_ID uint16(-1) + +struct SpellModifier +{ + SpellModOp op : 8; + SpellModType type : 8; + int16 charges : 16; + int32 value; + uint64 mask; + uint32 spellId; + uint32 effectId; + Spell const* lastAffected; +}; + +typedef HM_NAMESPACE::hash_map PlayerSpellMap; +typedef std::list SpellModList; + +struct SpellCooldown +{ + time_t end; + uint16 itemid; +}; + +typedef std::map SpellCooldowns; + +enum TrainerSpellState +{ + TRAINER_SPELL_GREEN = 0, + TRAINER_SPELL_RED = 1, + TRAINER_SPELL_GRAY = 2 +}; + +enum ActionButtonUpdateState +{ + ACTIONBUTTON_UNCHANGED = 0, + ACTIONBUTTON_CHANGED = 1, + ACTIONBUTTON_NEW = 2, + ACTIONBUTTON_DELETED = 3 +}; + +struct ActionButton +{ + ActionButton() : action(0), type(0), misc(0), uState( ACTIONBUTTON_NEW ) {} + ActionButton(uint16 _action, uint8 _type, uint8 _misc) : action(_action), type(_type), misc(_misc), uState( ACTIONBUTTON_NEW ) {} + + uint16 action; + uint8 type; + uint8 misc; + ActionButtonUpdateState uState; +}; + +enum ActionButtonType +{ + ACTION_BUTTON_SPELL = 0, + ACTION_BUTTON_MACRO = 64, + ACTION_BUTTON_CMACRO= 65, + ACTION_BUTTON_ITEM = 128 +}; + +#define MAX_ACTION_BUTTONS 132 //checked in 2.3.0 + +typedef std::map ActionButtonList; + +typedef std::pair CreateSpellPair; + +struct PlayerCreateInfoItem +{ + PlayerCreateInfoItem(uint32 id, uint32 amount) : item_id(id), item_amount(amount) {} + + uint32 item_id; + uint32 item_amount; +}; + +typedef std::list PlayerCreateInfoItems; + +struct PlayerClassLevelInfo +{ + PlayerClassLevelInfo() : basehealth(0), basemana(0) {} + uint16 basehealth; + uint16 basemana; +}; + +struct PlayerClassInfo +{ + PlayerClassInfo() : levelInfo(NULL) { } + + PlayerClassLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1 +}; + +struct PlayerLevelInfo +{ + PlayerLevelInfo() { for(int i=0; i < MAX_STATS; ++i ) stats[i] = 0; } + + uint8 stats[MAX_STATS]; +}; + +struct PlayerInfo +{ + // existence checked by displayId != 0 // existence checked by displayId != 0 + PlayerInfo() : displayId_m(0),displayId_f(0),levelInfo(NULL) + { + } + + uint32 mapId; + uint32 zoneId; + float positionX; + float positionY; + float positionZ; + uint16 displayId_m; + uint16 displayId_f; + PlayerCreateInfoItems item; + std::list spell; + std::list action[4]; + + PlayerLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1 +}; + +struct PvPInfo +{ + PvPInfo() : inHostileArea(false), endTimer(0) {} + + bool inHostileArea; + time_t endTimer; +}; + +struct DuelInfo +{ + DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0) {} + + Player *initiator; + Player *opponent; + time_t startTimer; + time_t startTime; + time_t outOfBound; +}; + +struct Areas +{ + uint32 areaID; + uint32 areaFlag; + float x1; + float x2; + float y1; + float y2; +}; + +enum FactionFlags +{ + FACTION_FLAG_VISIBLE = 0x01, // makes visible in client (set or can be set at interaction with target of this faction) + FACTION_FLAG_AT_WAR = 0x02, // enable AtWar-button in client. player controlled (except opposition team always war state), Flag only set on initial creation + FACTION_FLAG_HIDDEN = 0x04, // hidden faction from reputation pane in client (player can gain reputation, but this update not sent to client) + FACTION_FLAG_INVISIBLE_FORCED = 0x08, // always overwrite FACTION_FLAG_VISIBLE and hide faction in rep.list, used for hide opposite team factions + FACTION_FLAG_PEACE_FORCED = 0x10, // always overwrite FACTION_FLAG_AT_WAR, used for prevent war with own team factions + FACTION_FLAG_INACTIVE = 0x20, // player controlled, state stored in characters.data ( CMSG_SET_FACTION_INACTIVE ) + FACTION_FLAG_RIVAL = 0x40 // flag for the two competing outland factions +}; + +typedef uint32 RepListID; +struct FactionState +{ + uint32 ID; + RepListID ReputationListID; + uint32 Flags; + int32 Standing; + bool Changed; +}; + +typedef std::map FactionStateList; + +typedef std::map ForcedReactions; + +typedef std::set GuardianPetList; + +struct EnchantDuration +{ + EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) {}; + EnchantDuration(Item * _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot), leftduration(_leftduration) { assert(item); }; + + Item * item; + EnchantmentSlot slot; + uint32 leftduration; +}; + +typedef std::list EnchantDurationList; +typedef std::list ItemDurationList; + +struct LookingForGroupSlot +{ + LookingForGroupSlot() : entry(0), type(0) {} + bool Empty() const { return !entry && !type; } + void Clear() { entry = 0; type = 0; } + void Set(uint32 _entry, uint32 _type ) { entry = _entry; type = _type; } + bool Is(uint32 _entry, uint32 _type) const { return entry==_entry && type==_type; } + bool canAutoJoin() const { return entry && (type == 1 || type == 5); } + + uint32 entry; + uint32 type; +}; + +#define MAX_LOOKING_FOR_GROUP_SLOT 3 + +struct LookingForGroup +{ + LookingForGroup() {} + bool HaveInSlot(LookingForGroupSlot const& slot) const { return HaveInSlot(slot.entry,slot.type); } + bool HaveInSlot(uint32 _entry, uint32 _type) const + { + for(int i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) + if(slots[i].Is(_entry,_type)) + return true; + return false; + } + + bool canAutoJoin() const + { + for(int i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) + if(slots[i].canAutoJoin()) + return true; + return false; + } + + bool Empty() const + { + for(int i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) + if(!slots[i].Empty()) + return false; + return more.Empty(); + } + + LookingForGroupSlot slots[MAX_LOOKING_FOR_GROUP_SLOT]; + LookingForGroupSlot more; + std::string comment; +}; + +enum PlayerMovementType +{ + MOVE_ROOT = 1, + MOVE_UNROOT = 2, + MOVE_WATER_WALK = 3, + MOVE_LAND_WALK = 4 +}; + +enum DrunkenState +{ + DRUNKEN_SOBER = 0, + DRUNKEN_TIPSY = 1, + DRUNKEN_DRUNK = 2, + DRUNKEN_SMASHED = 3 +}; + +enum PlayerStateType +{ + /* + PLAYER_STATE_DANCE + PLAYER_STATE_SLEEP + PLAYER_STATE_SIT + PLAYER_STATE_STAND + PLAYER_STATE_READYUNARMED + PLAYER_STATE_WORK + PLAYER_STATE_POINT(DNR) + PLAYER_STATE_NONE // not used or just no state, just standing there? + PLAYER_STATE_STUN + PLAYER_STATE_DEAD + PLAYER_STATE_KNEEL + PLAYER_STATE_USESTANDING + PLAYER_STATE_STUN_NOSHEATHE + PLAYER_STATE_USESTANDING_NOSHEATHE + PLAYER_STATE_WORK_NOSHEATHE + PLAYER_STATE_SPELLPRECAST + PLAYER_STATE_READYRIFLE + PLAYER_STATE_WORK_NOSHEATHE_MINING + PLAYER_STATE_WORK_NOSHEATHE_CHOPWOOD + PLAYER_STATE_AT_EASE + PLAYER_STATE_READY1H + PLAYER_STATE_SPELLKNEELSTART + PLAYER_STATE_SUBMERGED + */ + + PLAYER_STATE_NONE = 0, + PLAYER_STATE_SIT = 1, + PLAYER_STATE_SIT_CHAIR = 2, + PLAYER_STATE_SLEEP = 3, + PLAYER_STATE_SIT_LOW_CHAIR = 4, + PLAYER_STATE_SIT_MEDIUM_CHAIR = 5, + PLAYER_STATE_SIT_HIGH_CHAIR = 6, + PLAYER_STATE_DEAD = 7, + PLAYER_STATE_KNEEL = 8, + + PLAYER_STATE_FORM_ALL = 0x00FF0000, + + PLAYER_STATE_FLAG_ALWAYS_STAND = 0x01, // byte 4 + PLAYER_STATE_FLAG_CREEP = 0x02000000, + PLAYER_STATE_FLAG_UNTRACKABLE = 0x04000000, + PLAYER_STATE_FLAG_ALL = 0xFF000000, +}; + +enum PlayerFlags +{ + PLAYER_FLAGS_GROUP_LEADER = 0x00000001, + PLAYER_FLAGS_AFK = 0x00000002, + PLAYER_FLAGS_DND = 0x00000004, + PLAYER_FLAGS_GM = 0x00000008, + PLAYER_FLAGS_GHOST = 0x00000010, + PLAYER_FLAGS_RESTING = 0x00000020, + PLAYER_FLAGS_FFA_PVP = 0x00000080, + PLAYER_FLAGS_CONTESTED_PVP = 0x00000100, // Player has been involved in a PvP combat and will be attacked by contested guards + PLAYER_FLAGS_IN_PVP = 0x00000200, + PLAYER_FLAGS_HIDE_HELM = 0x00000400, + PLAYER_FLAGS_HIDE_CLOAK = 0x00000800, + PLAYER_FLAGS_UNK1 = 0x00001000, // played long time + PLAYER_FLAGS_UNK2 = 0x00002000, // played too long time + PLAYER_FLAGS_UNK3 = 0x00008000, // strange visual effect (2.0.1), looks like PLAYER_FLAGS_GHOST flag + PLAYER_FLAGS_SANCTUARY = 0x00010000, // player entered sanctuary + PLAYER_FLAGS_UNK4 = 0x00020000, // taxi benchmark mode (on/off) (2.0.1) + PLAYER_UNK = 0x00040000, // 2.0.8... +}; + +// used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1< QuestStatusMap; + +enum QuestSlotOffsets +{ + QUEST_ID_OFFSET = 0, + QUEST_STATE_OFFSET = 1, + QUEST_COUNTS_OFFSET = 2, + QUEST_TIME_OFFSET = 3 +}; + +#define MAX_QUEST_OFFSET 4 + +enum QuestSlotStateMask +{ + QUEST_STATE_NONE = 0x0000, + QUEST_STATE_COMPLETE = 0x0001, + QUEST_STATE_FAIL = 0x0002 +}; + +class Quest; +class Spell; +class Item; +class WorldSession; + +enum PlayerSlots +{ + // first slot for item stored (in any way in player m_items data) + PLAYER_SLOT_START = 0, + // last+1 slot for item stored (in any way in player m_items data) + PLAYER_SLOT_END = 118, + PLAYER_SLOTS_COUNT = (PLAYER_SLOT_END - PLAYER_SLOT_START) +}; + +enum EquipmentSlots +{ + EQUIPMENT_SLOT_START = 0, + EQUIPMENT_SLOT_HEAD = 0, + EQUIPMENT_SLOT_NECK = 1, + EQUIPMENT_SLOT_SHOULDERS = 2, + EQUIPMENT_SLOT_BODY = 3, + EQUIPMENT_SLOT_CHEST = 4, + EQUIPMENT_SLOT_WAIST = 5, + EQUIPMENT_SLOT_LEGS = 6, + EQUIPMENT_SLOT_FEET = 7, + EQUIPMENT_SLOT_WRISTS = 8, + EQUIPMENT_SLOT_HANDS = 9, + EQUIPMENT_SLOT_FINGER1 = 10, + EQUIPMENT_SLOT_FINGER2 = 11, + EQUIPMENT_SLOT_TRINKET1 = 12, + EQUIPMENT_SLOT_TRINKET2 = 13, + EQUIPMENT_SLOT_BACK = 14, + EQUIPMENT_SLOT_MAINHAND = 15, + EQUIPMENT_SLOT_OFFHAND = 16, + EQUIPMENT_SLOT_RANGED = 17, + EQUIPMENT_SLOT_TABARD = 18, + EQUIPMENT_SLOT_END = 19 +}; + +enum InventorySlots +{ + INVENTORY_SLOT_BAG_0 = 255, + INVENTORY_SLOT_BAG_START = 19, + INVENTORY_SLOT_BAG_1 = 19, + INVENTORY_SLOT_BAG_2 = 20, + INVENTORY_SLOT_BAG_3 = 21, + INVENTORY_SLOT_BAG_4 = 22, + INVENTORY_SLOT_BAG_END = 23, + + INVENTORY_SLOT_ITEM_START = 23, + INVENTORY_SLOT_ITEM_1 = 23, + INVENTORY_SLOT_ITEM_2 = 24, + INVENTORY_SLOT_ITEM_3 = 25, + INVENTORY_SLOT_ITEM_4 = 26, + INVENTORY_SLOT_ITEM_5 = 27, + INVENTORY_SLOT_ITEM_6 = 28, + INVENTORY_SLOT_ITEM_7 = 29, + INVENTORY_SLOT_ITEM_8 = 30, + INVENTORY_SLOT_ITEM_9 = 31, + INVENTORY_SLOT_ITEM_10 = 32, + INVENTORY_SLOT_ITEM_11 = 33, + INVENTORY_SLOT_ITEM_12 = 34, + INVENTORY_SLOT_ITEM_13 = 35, + INVENTORY_SLOT_ITEM_14 = 36, + INVENTORY_SLOT_ITEM_15 = 37, + INVENTORY_SLOT_ITEM_16 = 38, + INVENTORY_SLOT_ITEM_END = 39 +}; + +enum BankSlots +{ + BANK_SLOT_ITEM_START = 39, + BANK_SLOT_ITEM_1 = 39, + BANK_SLOT_ITEM_2 = 40, + BANK_SLOT_ITEM_3 = 41, + BANK_SLOT_ITEM_4 = 42, + BANK_SLOT_ITEM_5 = 43, + BANK_SLOT_ITEM_6 = 44, + BANK_SLOT_ITEM_7 = 45, + BANK_SLOT_ITEM_8 = 46, + BANK_SLOT_ITEM_9 = 47, + BANK_SLOT_ITEM_10 = 48, + BANK_SLOT_ITEM_11 = 49, + BANK_SLOT_ITEM_12 = 50, + BANK_SLOT_ITEM_13 = 51, + BANK_SLOT_ITEM_14 = 52, + BANK_SLOT_ITEM_15 = 53, + BANK_SLOT_ITEM_16 = 54, + BANK_SLOT_ITEM_17 = 55, + BANK_SLOT_ITEM_18 = 56, + BANK_SLOT_ITEM_19 = 57, + BANK_SLOT_ITEM_20 = 58, + BANK_SLOT_ITEM_21 = 59, + BANK_SLOT_ITEM_22 = 60, + BANK_SLOT_ITEM_23 = 61, + BANK_SLOT_ITEM_24 = 62, + BANK_SLOT_ITEM_25 = 63, + BANK_SLOT_ITEM_26 = 64, + BANK_SLOT_ITEM_27 = 65, + BANK_SLOT_ITEM_28 = 66, + BANK_SLOT_ITEM_END = 67, + + BANK_SLOT_BAG_START = 67, + BANK_SLOT_BAG_1 = 67, + BANK_SLOT_BAG_2 = 68, + BANK_SLOT_BAG_3 = 69, + BANK_SLOT_BAG_4 = 70, + BANK_SLOT_BAG_5 = 71, + BANK_SLOT_BAG_6 = 72, + BANK_SLOT_BAG_7 = 73, + BANK_SLOT_BAG_END = 74 +}; + +enum BuyBackSlots +{ + // stored in m_buybackitems + BUYBACK_SLOT_START = 74, + BUYBACK_SLOT_1 = 74, + BUYBACK_SLOT_2 = 75, + BUYBACK_SLOT_3 = 76, + BUYBACK_SLOT_4 = 77, + BUYBACK_SLOT_5 = 78, + BUYBACK_SLOT_6 = 79, + BUYBACK_SLOT_7 = 80, + BUYBACK_SLOT_8 = 81, + BUYBACK_SLOT_9 = 82, + BUYBACK_SLOT_10 = 83, + BUYBACK_SLOT_11 = 84, + BUYBACK_SLOT_12 = 85, + BUYBACK_SLOT_END = 86 +}; + +enum KeyRingSlots +{ + KEYRING_SLOT_START = 86, + KEYRING_SLOT_END = 118 +}; + +struct ItemPosCount +{ + ItemPosCount(uint16 _pos, uint8 _count) : pos(_pos), count(_count) {} + bool isContainedIn(std::vector const& vec) const; + uint16 pos; + uint8 count; +}; +typedef std::vector ItemPosCountVec; + +enum SwitchWeapon +{ + DEFAULT_SWITCH_WEAPON = 1500, //cooldown in ms + ROGUE_SWITCH_WEAPON = 1000 +}; + +enum TradeSlots +{ + TRADE_SLOT_COUNT = 7, + TRADE_SLOT_TRADED_COUNT = 6, + TRADE_SLOT_NONTRADED = 6 +}; + +enum TransferAbortReason +{ + TRANSFER_ABORT_MAX_PLAYERS = 0x0001, // Transfer Aborted: instance is full + TRANSFER_ABORT_NOT_FOUND = 0x0002, // Transfer Aborted: instance not found + TRANSFER_ABORT_TOO_MANY_INSTANCES = 0x0003, // You have entered too many instances recently. + TRANSFER_ABORT_ZONE_IN_COMBAT = 0x0005, // Unable to zone in while an encounter is in progress. + TRANSFER_ABORT_INSUF_EXPAN_LVL1 = 0x0106, // You must have TBC expansion installed to access this area. + TRANSFER_ABORT_DIFFICULTY1 = 0x0007, // Normal difficulty mode is not available for %s. + TRANSFER_ABORT_DIFFICULTY2 = 0x0107, // Heroic difficulty mode is not available for %s. + TRANSFER_ABORT_DIFFICULTY3 = 0x0207 // Epic difficulty mode is not available for %s. +}; + +enum InstanceResetWarningType +{ + RAID_INSTANCE_WARNING_HOURS = 1, // WARNING! %s is scheduled to reset in %d hour(s). + RAID_INSTANCE_WARNING_MIN = 2, // WARNING! %s is scheduled to reset in %d minute(s)! + RAID_INSTANCE_WARNING_MIN_SOON = 3, // WARNING! %s is scheduled to reset in %d minute(s). Please exit the zone or you will be returned to your bind location! + RAID_INSTANCE_WELCOME = 4 // Welcome to %s. This raid instance is scheduled to reset in %s. +}; + +struct MovementInfo +{ + // common + //uint32 flags; + uint8 unk1; + uint32 time; + float x, y, z, o; + // transport + uint64 t_guid; + float t_x, t_y, t_z, t_o; + uint32 t_time; + // swimming and unk + float s_pitch; + // last fall time + uint32 fallTime; + // jumping + float j_unk, j_sinAngle, j_cosAngle, j_xyspeed; + // spline + float u_unk1; + + MovementInfo() + { + //flags = + time = t_time = fallTime = 0; + unk1 = 0; + x = y = z = o = t_x = t_y = t_z = t_o = s_pitch = j_unk = j_sinAngle = j_cosAngle = j_xyspeed = u_unk1 = 0.0f; + t_guid = 0; + } + + /*void SetMovementFlags(uint32 _flags) + { + flags = _flags; + }*/ +}; + +// flags that use in movement check for example at spell casting +MovementFlags const movementFlagsMask = MovementFlags( + MOVEMENTFLAG_FORWARD |MOVEMENTFLAG_BACKWARD |MOVEMENTFLAG_STRAFE_LEFT|MOVEMENTFLAG_STRAFE_RIGHT| + MOVEMENTFLAG_PITCH_UP|MOVEMENTFLAG_PITCH_DOWN|MOVEMENTFLAG_FLY_UNK1 | + MOVEMENTFLAG_JUMPING |MOVEMENTFLAG_FALLING |MOVEMENTFLAG_FLY_UP | + MOVEMENTFLAG_FLYING |MOVEMENTFLAG_SPLINE +); + +MovementFlags const movementOrTurningFlagsMask = MovementFlags( + movementFlagsMask | MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT +); +class InstanceSave; + +enum RestType +{ + REST_TYPE_NO = 0, + REST_TYPE_IN_TAVERN = 1, + REST_TYPE_IN_CITY = 2 +}; + +enum DuelCompleteType +{ + DUEL_INTERUPTED = 0, + DUEL_WON = 1, + DUEL_FLED = 2 +}; + +enum TeleportToOptions +{ + TELE_TO_GM_MODE = 0x01, + TELE_TO_NOT_LEAVE_TRANSPORT = 0x02, + TELE_TO_NOT_LEAVE_COMBAT = 0x04, + TELE_TO_NOT_UNSUMMON_PET = 0x08, + TELE_TO_SPELL = 0x10, +}; + +/// Type of environmental damages +enum EnviromentalDamage +{ + DAMAGE_EXHAUSTED = 0, + DAMAGE_DROWNING = 1, + DAMAGE_FALL = 2, + DAMAGE_LAVA = 3, + DAMAGE_SLIME = 4, + DAMAGE_FIRE = 5, + DAMAGE_FALL_TO_VOID = 6 // custom case for fall without durability loss +}; + +// used at player loading query list preparing, and later result selection +enum PlayerLoginQueryIndex +{ + PLAYER_LOGIN_QUERY_LOADFROM = 0, + PLAYER_LOGIN_QUERY_LOADGROUP = 1, + PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES = 2, + PLAYER_LOGIN_QUERY_LOADAURAS = 3, + PLAYER_LOGIN_QUERY_LOADSPELLS = 4, + PLAYER_LOGIN_QUERY_LOADQUESTSTATUS = 5, + PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS = 6, + PLAYER_LOGIN_QUERY_LOADTUTORIALS = 7, // common for all characters for some account at specific realm + PLAYER_LOGIN_QUERY_LOADREPUTATION = 8, + PLAYER_LOGIN_QUERY_LOADINVENTORY = 9, + PLAYER_LOGIN_QUERY_LOADACTIONS = 10, + PLAYER_LOGIN_QUERY_LOADMAILCOUNT = 11, + PLAYER_LOGIN_QUERY_LOADMAILDATE = 12, + PLAYER_LOGIN_QUERY_LOADSOCIALLIST = 13, + PLAYER_LOGIN_QUERY_LOADHOMEBIND = 14, + PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS = 15, + PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES = 16, + PLAYER_LOGIN_QUERY_LOADGUILD = 17, +}; + +#define MAX_PLAYER_LOGIN_QUERY 18 + +// Player summoning auto-decline time (in secs) +#define MAX_PLAYER_SUMMON_DELAY (2*MINUTE) +#define MAX_MONEY_AMOUNT (0x7FFFFFFF-1) + +struct InstancePlayerBind +{ + InstanceSave *save; + bool perm; + /* permanent PlayerInstanceBinds are created in Raid/Heroic instances for players + that aren't already permanently bound when they are inside when a boss is killed + or when they enter an instance that the group leader is permanently bound to. */ + InstancePlayerBind() : save(NULL), perm(false) {} +}; + +class MANGOS_DLL_SPEC PlayerTaxi +{ + public: + PlayerTaxi(); + ~PlayerTaxi() {} + // Nodes + void InitTaxiNodesForLevel(uint32 race, uint32 level); + void LoadTaxiMask(const char* data); + void SaveTaxiMask(const char* data); + + uint32 GetTaximask( uint8 index ) const { return m_taximask[index]; } + bool IsTaximaskNodeKnown(uint32 nodeidx) const + { + uint8 field = uint8((nodeidx - 1) / 32); + uint32 submask = 1<<((nodeidx-1)%32); + return (m_taximask[field] & submask) == submask; + } + bool SetTaximaskNode(uint32 nodeidx) + { + uint8 field = uint8((nodeidx - 1) / 32); + uint32 submask = 1<<((nodeidx-1)%32); + if ((m_taximask[field] & submask) != submask ) + { + m_taximask[field] |= submask; + return true; + } + else + return false; + } + void AppendTaximaskTo(ByteBuffer& data,bool all); + + // Destinations + bool LoadTaxiDestinationsFromString(std::string values); + std::string SaveTaxiDestinationsToString(); + + void ClearTaxiDestinations() { m_TaxiDestinations.clear(); } + void AddTaxiDestination(uint32 dest) { m_TaxiDestinations.push_back(dest); } + uint32 GetTaxiSource() const { return m_TaxiDestinations.empty() ? 0 : m_TaxiDestinations.front(); } + uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() < 2 ? 0 : m_TaxiDestinations[1]; } + uint32 GetCurrentTaxiPath() const; + uint32 NextTaxiDestination() + { + m_TaxiDestinations.pop_front(); + return GetTaxiDestination(); + } + bool empty() const { return m_TaxiDestinations.empty(); } + private: + TaxiMask m_taximask; + std::deque m_TaxiDestinations; +}; + +class MANGOS_DLL_SPEC Player : public Unit +{ + friend class WorldSession; + friend void Item::AddToUpdateQueueOf(Player *player); + friend void Item::RemoveFromUpdateQueueOf(Player *player); + public: + explicit Player (WorldSession *session); + ~Player ( ); + + void CleanupsBeforeDelete(); + + static UpdateMask updateVisualBits; + static void InitVisibleBits(); + + void AddToWorld(); + void RemoveFromWorld(); + + bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0); + + bool TeleportTo(WorldLocation const &loc, uint32 options = 0) + { + return TeleportTo(loc.mapid, loc.x, loc.y, loc.z, options); + } + + void SetSummonPoint(uint32 mapid, float x, float y, float z) + { + m_summon_expire = time(NULL) + MAX_PLAYER_SUMMON_DELAY; + m_summon_mapid = mapid; + m_summon_x = x; + m_summon_y = y; + m_summon_z = z; + } + void SummonIfPossible(bool agree); + + bool Create( uint32 guidlow, std::string name, uint8 race, uint8 class_, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair, uint8 outfitId ); + + void Update( uint32 time ); + + void BuildEnumData( QueryResult * result, WorldPacket * p_data ); + + void SetInWater(bool apply); + + bool IsInWater() const { return m_isInWater; } + bool IsUnderWater() const; + + void SendInitialPacketsBeforeAddToMap(); + void SendInitialPacketsAfterAddToMap(); + void SendTransferAborted(uint32 mapid, uint16 reason); + void SendInstanceResetWarning(uint32 mapid, uint32 time); + + bool CanInteractWithNPCs(bool alive = true) const; + + bool ToggleAFK(); + bool ToggleDND(); + bool isAFK() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK); }; + bool isDND() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND); }; + uint8 chatTag() const; + std::string afkMsg; + std::string dndMsg; + + PlayerSocial *GetSocial() { return m_social; } + + PlayerTaxi m_taxi; + void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(),getLevel()); } + bool ActivateTaxiPathTo(std::vector const& nodes, uint32 mount_id = 0 , Creature* npc = NULL); + // mount_id can be used in scripting calls + bool isAcceptTickets() const { return GetSession()->GetSecurity() >= SEC_GAMEMASTER && (m_ExtraFlags & PLAYER_EXTRA_GM_ACCEPT_TICKETS); } + void SetAcceptTicket(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_GM_ACCEPT_TICKETS; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_ACCEPT_TICKETS; } + bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; } + void SetAcceptWhispers(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; } + bool isGameMaster() const { return m_ExtraFlags & PLAYER_EXTRA_GM_ON; } + void SetGameMaster(bool on); + bool isTaxiCheater() const { return m_ExtraFlags & PLAYER_EXTRA_TAXICHEAT; } + void SetTaxiCheater(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_TAXICHEAT; else m_ExtraFlags &= ~PLAYER_EXTRA_TAXICHEAT; } + bool isGMVisible() const { return !(m_ExtraFlags & PLAYER_EXTRA_GM_INVISIBLE); } + void SetGMVisible(bool on); + void SetPvPDeath(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_PVP_DEATH; else m_ExtraFlags &= ~PLAYER_EXTRA_PVP_DEATH; } + + void GiveXP(uint32 xp, Unit* victim); + void GiveLevel(uint32 level); + void InitStatsForLevel(bool reapplyMods = false); + + // Played Time Stuff + time_t m_logintime; + time_t m_Last_tick; + uint32 m_Played_time[2]; + uint32 GetTotalPlayedTime() { return m_Played_time[0]; }; + uint32 GetLevelPlayedTime() { return m_Played_time[1]; }; + + void setDeathState(DeathState s); // overwrite Unit::setDeathState + + void InnEnter (int time,uint32 mapid, float x,float y,float z) + { + inn_pos_mapid = mapid; + inn_pos_x = x; + inn_pos_y = y; + inn_pos_z = z; + time_inn_enter = time; + }; + + float GetRestBonus() const { return m_rest_bonus; }; + void SetRestBonus(float rest_bonus_new); + + RestType GetRestType() const { return rest_type; }; + void SetRestType(RestType n_r_type) { rest_type = n_r_type; }; + + uint32 GetInnPosMapId() const { return inn_pos_mapid; }; + float GetInnPosX() const { return inn_pos_x; }; + float GetInnPosY() const { return inn_pos_y; }; + float GetInnPosZ() const { return inn_pos_z; }; + + int GetTimeInnEnter() const { return time_inn_enter; }; + void UpdateInnerTime (int time) { time_inn_enter = time; }; + + void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false); + void RemoveMiniPet(); + Pet* GetMiniPet(); + void SetMiniPet(Pet* pet) { m_miniPet = pet->GetGUID(); } + void RemoveGuardians(); + bool HasGuardianWithEntry(uint32 entry); + void AddGuardian(Pet* pet) { m_guardianPets.insert(pet->GetGUID()); } + GuardianPetList const& GetGuardians() const { return m_guardianPets; } + void Uncharm(); + + void Say(std::string text, const uint32 language); + void Yell(std::string text, const uint32 language); + void TextEmote(std::string text); + void Whisper(std::string text, const uint32 language,uint64 receiver); + void BuildPlayerChat(WorldPacket *data, uint8 msgtype, std::string text, uint32 language) const; + + /*********************************************************/ + /*** STORAGE SYSTEM ***/ + /*********************************************************/ + + void SetVirtualItemSlot( uint8 i, Item* item); + void SetSheath( uint32 sheathed ); + uint8 FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const; + uint32 GetItemCount( uint32 item, bool inBankAlso = false, Item* skipItem = NULL ) const; + Item* GetItemByGuid( uint64 guid ) const; + Item* GetItemByPos( uint16 pos ) const; + Item* GetItemByPos( uint8 bag, uint8 slot ) const; + Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const; + Item* GetShield(bool useable = false) const; + static uint32 GetAttackBySlot( uint8 slot ); // MAX_ATTACK if not weapon slot + std::vector &GetItemUpdateQueue() { return m_itemUpdateQueue; } + static bool IsInventoryPos( uint16 pos ) { return IsInventoryPos(pos >> 8,pos & 255); } + static bool IsInventoryPos( uint8 bag, uint8 slot ); + static bool IsEquipmentPos( uint16 pos ) { return IsEquipmentPos(pos >> 8,pos & 255); } + static bool IsEquipmentPos( uint8 bag, uint8 slot ); + static bool IsBagPos( uint16 pos ); + static bool IsBankPos( uint16 pos ) { return IsBankPos(pos >> 8,pos & 255); } + static bool IsBankPos( uint8 bag, uint8 slot ); + bool HasBankBagSlot( uint8 slot ) const; + bool HasItemCount( uint32 item, uint32 count, bool inBankAlso = false ) const; + bool HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item const* ignoreItem = NULL); + Item* GetItemOrItemWithGemEquipped( uint32 item ) const; + uint8 CanTakeMoreSimilarItems(Item* pItem) const { return _CanTakeMoreSimilarItems(pItem->GetEntry(),pItem->GetCount(),pItem); } + uint8 CanTakeMoreSimilarItems(uint32 entry, uint32 count) const { return _CanTakeMoreSimilarItems(entry,count,NULL); } + uint8 CanStoreNewItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = NULL ) const + { + return _CanStoreItem(bag, slot, dest, item, count, NULL, false, no_space_count ); + } + uint8 CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, Item *pItem, bool swap = false ) const + { + if(!pItem) + return EQUIP_ERR_ITEM_NOT_FOUND; + uint32 count = pItem->GetCount(); + return _CanStoreItem( bag, slot, dest, pItem->GetEntry(), count, pItem, swap, NULL ); + + } + uint8 CanStoreItems( Item **pItem,int count) const; + uint8 CanEquipNewItem( uint8 slot, uint16 &dest, uint32 item, uint32 count, bool swap ) const; + uint8 CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading = true ) const; + uint8 CanUnequipItems( uint32 item, uint32 count ) const; + uint8 CanUnequipItem( uint16 src, bool swap ) const; + uint8 CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, Item *pItem, bool swap, bool not_loading = true ) const; + uint8 CanUseItem( Item *pItem, bool not_loading = true ) const; + bool HasItemTotemCategory( uint32 TotemCategory ) const; + bool CanUseItem( ItemPrototype const *pItem ); + uint8 CanUseAmmo( uint32 item ) const; + Item* StoreNewItem( ItemPosCountVec const& pos, uint32 item, bool update,int32 randomPropertyId = 0 ); + Item* StoreItem( ItemPosCountVec const& pos, Item *pItem, bool update ); + Item* EquipNewItem( uint16 pos, uint32 item, uint32 count, bool update ); + Item* EquipItem( uint16 pos, Item *pItem, bool update ); + void AutoUnequipOffhandIfNeed(); + + uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const; + uint8 _CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL ) const; + + void ApplyEquipCooldown( Item * pItem ); + void SetAmmo( uint32 item ); + void RemoveAmmo(); + float GetAmmoDPS() const { return m_ammoDPS; } + bool CheckAmmoCompatibility(const ItemPrototype *ammo_proto) const; + void QuickEquipItem( uint16 pos, Item *pItem); + void VisualizeItem( uint8 slot, Item *pItem); + void SetVisibleItemSlot(uint8 slot, Item *pItem); + Item* BankItem( ItemPosCountVec const& dest, Item *pItem, bool update ) + { + return StoreItem( dest, pItem, update); + } + Item* BankItem( uint16 pos, Item *pItem, bool update ); + void RemoveItem( uint8 bag, uint8 slot, bool update ); + void MoveItemFromInventory(uint8 bag, uint8 slot, bool update); + // in trade, auction, guild bank, mail.... + void MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB = false); + // in trade, guild bank, mail.... + void RemoveItemDependentAurasAndCasts( Item * pItem ); + void DestroyItem( uint8 bag, uint8 slot, bool update ); + void DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check = false); + void DestroyItemCount( Item* item, uint32& count, bool update ); + void DestroyConjuredItems( bool update ); + void DestroyZoneLimitedItem( bool update, uint32 new_zone ); + void SplitItem( uint16 src, uint16 dst, uint32 count ); + void SwapItem( uint16 src, uint16 dst ); + void AddItemToBuyBackSlot( Item *pItem ); + Item* GetItemFromBuyBackSlot( uint32 slot ); + void RemoveItemFromBuyBackSlot( uint32 slot, bool del ); + uint32 GetMaxKeyringSize() const { return KEYRING_SLOT_END-KEYRING_SLOT_START; } + void SendEquipError( uint8 msg, Item* pItem, Item *pItem2 ); + void SendBuyError( uint8 msg, Creature* pCreature, uint32 item, uint32 param ); + void SendSellError( uint8 msg, Creature* pCreature, uint64 guid, uint32 param ); + void AddWeaponProficiency(uint32 newflag) { m_WeaponProficiency |= newflag; } + void AddArmorProficiency(uint32 newflag) { m_ArmorProficiency |= newflag; } + uint32 GetWeaponProficiency() const { return m_WeaponProficiency; } + uint32 GetArmorProficiency() const { return m_ArmorProficiency; } + bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; } + bool IsUseEquipedWeapon( bool mainhand ) const + { + // disarm applied only to mainhand weapon + return !IsInFeralForm() && (!mainhand || !HasFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISARMED) ); + } + void SendNewItem( Item *item, uint32 count, bool received, bool created, bool broadcast = false ); + bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot); + + float GetReputationPriceDiscount( Creature const* pCreature ) const; + Player* GetTrader() const { return pTrader; } + void ClearTrade(); + void TradeCancel(bool sendback); + uint16 GetItemPosByTradeSlot(uint32 slot) const { return tradeItems[slot]; } + + void UpdateEnchantTime(uint32 time); + void UpdateItemDuration(uint32 time, bool realtimeonly=false); + void AddEnchantmentDurations(Item *item); + void RemoveEnchantmentDurations(Item *item); + void RemoveAllEnchantments(EnchantmentSlot slot); + void AddEnchantmentDuration(Item *item,EnchantmentSlot slot,uint32 duration); + void ApplyEnchantment(Item *item,EnchantmentSlot slot,bool apply, bool apply_dur = true, bool ignore_condition = false); + void ApplyEnchantment(Item *item,bool apply); + void SendEnchantmentDurations(); + void AddItemDurations(Item *item); + void RemoveItemDurations(Item *item); + void SendItemDurations(); + void LoadCorpse(); + void LoadPet(); + + uint32 m_stableSlots; + + /*********************************************************/ + /*** QUEST SYSTEM ***/ + /*********************************************************/ + + void PrepareQuestMenu( uint64 guid ); + void SendPreparedQuest( uint64 guid ); + bool IsActiveQuest( uint32 quest_id ) const; + Quest const *GetNextQuest( uint64 guid, Quest const *pQuest ); + bool CanSeeStartQuest( Quest const *pQuest ); + bool CanTakeQuest( Quest const *pQuest, bool msg ); + bool CanAddQuest( Quest const *pQuest, bool msg ); + bool CanCompleteQuest( uint32 quest_id ); + bool CanCompleteRepeatableQuest(Quest const *pQuest); + bool CanRewardQuest( Quest const *pQuest, bool msg ); + bool CanRewardQuest( Quest const *pQuest, uint32 reward, bool msg ); + void AddQuest( Quest const *pQuest, Object *questGiver ); + void CompleteQuest( uint32 quest_id ); + void IncompleteQuest( uint32 quest_id ); + void RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce = true ); + void FailQuest( uint32 quest_id ); + void FailTimedQuest( uint32 quest_id ); + bool SatisfyQuestSkillOrClass( Quest const* qInfo, bool msg ); + bool SatisfyQuestLevel( Quest const* qInfo, bool msg ); + bool SatisfyQuestLog( bool msg ); + bool SatisfyQuestPreviousQuest( Quest const* qInfo, bool msg ); + bool SatisfyQuestRace( Quest const* qInfo, bool msg ); + bool SatisfyQuestReputation( Quest const* qInfo, bool msg ); + bool SatisfyQuestStatus( Quest const* qInfo, bool msg ); + bool SatisfyQuestTimed( Quest const* qInfo, bool msg ); + bool SatisfyQuestExclusiveGroup( Quest const* qInfo, bool msg ); + bool SatisfyQuestNextChain( Quest const* qInfo, bool msg ); + bool SatisfyQuestPrevChain( Quest const* qInfo, bool msg ); + bool SatisfyQuestDay( Quest const* qInfo, bool msg ); + bool GiveQuestSourceItem( Quest const *pQuest ); + bool TakeQuestSourceItem( uint32 quest_id, bool msg ); + bool GetQuestRewardStatus( uint32 quest_id ) const; + QuestStatus GetQuestStatus( uint32 quest_id ) const; + void SetQuestStatus( uint32 quest_id, QuestStatus status ); + + void SetDailyQuestStatus( uint32 quest_id ); + void ResetDailyQuestStatus(); + + uint16 FindQuestSlot( uint32 quest_id ) const; + uint32 GetQuestSlotQuestId(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_ID_OFFSET); } + uint32 GetQuestSlotState(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_STATE_OFFSET); } + uint32 GetQuestSlotCounters(uint16 slot)const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET); } + uint8 GetQuestSlotCounter(uint16 slot,uint8 counter) const { return GetByteValue(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET,counter); } + uint32 GetQuestSlotTime(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_TIME_OFFSET); } + void SetQuestSlot(uint16 slot,uint32 quest_id, uint32 timer = 0) + { + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_ID_OFFSET,quest_id); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_STATE_OFFSET,0); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET,0); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_TIME_OFFSET,timer); + } + void SetQuestSlotCounter(uint16 slot,uint8 counter,uint8 count) { SetByteValue(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET,counter,count); } + void SetQuestSlotState(uint16 slot,uint32 state) { SetFlag(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_STATE_OFFSET,state); } + void RemoveQuestSlotState(uint16 slot,uint32 state) { RemoveFlag(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_STATE_OFFSET,state); } + void SetQuestSlotTimer(uint16 slot,uint32 timer) { SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot*MAX_QUEST_OFFSET + QUEST_TIME_OFFSET,timer); } + void SwapQuestSlot(uint16 slot1,uint16 slot2) + { + for (int i = 0; i < MAX_QUEST_OFFSET ; ++i ) + { + uint32 temp1 = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET *slot1 + i); + uint32 temp2 = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET *slot2 + i); + + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET *slot1 + i, temp2); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET *slot2 + i, temp1); + } + } + uint32 GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry); + void AdjustQuestReqItemCount( Quest const* pQuest ); + void AreaExploredOrEventHappens( uint32 questId ); + void GroupEventHappens( uint32 questId, WorldObject const* pEventObject ); + void ItemAddedQuestCheck( uint32 entry, uint32 count ); + void ItemRemovedQuestCheck( uint32 entry, uint32 count ); + void KilledMonster( uint32 entry, uint64 guid ); + void CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id ); + void TalkedToCreature( uint32 entry, uint64 guid ); + void MoneyChanged( uint32 value ); + bool HasQuestForItem( uint32 itemid ) const; + bool HasQuestForGO(int32 GOId); + void UpdateForQuestsGO(); + bool CanShareQuest(uint32 quest_id) const; + + void SendQuestComplete( uint32 quest_id ); + void SendQuestReward( Quest const *pQuest, uint32 XP, Object* questGiver ); + void SendQuestFailed( uint32 quest_id ); + void SendQuestTimerFailed( uint32 quest_id ); + void SendCanTakeQuestResponse( uint32 msg ); + void SendPushToPartyResponse( Player *pPlayer, uint32 msg ); + void SendQuestUpdateAddItem( Quest const* pQuest, uint32 item_idx, uint32 count ); + void SendQuestUpdateAddCreatureOrGo( Quest const* pQuest, uint64 guid, uint32 creatureOrGO_idx, uint32 old_count, uint32 add_count ); + + uint64 GetDivider() { return m_divider; }; + void SetDivider( uint64 guid ) { m_divider = guid; }; + + uint32 GetInGameTime() { return m_ingametime; }; + + void SetInGameTime( uint32 time ) { m_ingametime = time; }; + + void AddTimedQuest( uint32 quest_id ) { m_timedquests.insert(quest_id); } + + /*********************************************************/ + /*** LOAD SYSTEM ***/ + /*********************************************************/ + + bool LoadFromDB(uint32 guid, SqlQueryHolder *holder); + bool MinimalLoadFromDB(QueryResult *result, uint32 guid); + static bool LoadValuesArrayFromDB(Tokens& data,uint64 guid); + static uint32 GetUInt32ValueFromArray(Tokens const& data, uint16 index); + static float GetFloatValueFromArray(Tokens const& data, uint16 index); + static uint32 GetUInt32ValueFromDB(uint16 index, uint64 guid); + static float GetFloatValueFromDB(uint16 index, uint64 guid); + static uint32 GetZoneIdFromDB(uint64 guid); + static bool LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid); + + /*********************************************************/ + /*** SAVE SYSTEM ***/ + /*********************************************************/ + + void SaveToDB(); + void SaveInventoryAndGoldToDB(); // fast save function for item/money cheating preventing + void SaveGoldToDB() { SetUInt32ValueInDB(PLAYER_FIELD_COINAGE,GetMoney(),GetGUID()); } + static bool SaveValuesArrayInDB(Tokens const& data,uint64 guid); + static void SetUInt32ValueInArray(Tokens& data,uint16 index, uint32 value); + static void SetFloatValueInArray(Tokens& data,uint16 index, float value); + static void SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid); + static void SetFloatValueInDB(uint16 index, float value, uint64 guid); + static void SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint32 zone,uint64 guid); + + bool m_mailsLoaded; + bool m_mailsUpdated; + + void SetBindPoint(uint64 guid); + void SendTalentWipeConfirm(uint64 guid); + void RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ); + void SendPetSkillWipeConfirm(); + void CalcRage( uint32 damage,bool attacker ); + void RegenerateAll(); + void Regenerate(Powers power); + void RegenerateHealth(); + void setRegenTimer(uint32 time) {m_regenTimer = time;} + void setWeaponChangeTimer(uint32 time) {m_weaponChangeTimer = time;} + + uint32 GetMoney() { return GetUInt32Value (PLAYER_FIELD_COINAGE); } + void ModifyMoney( int32 d ) + { + if(d < 0) + SetMoney (GetMoney() > uint32(-d) ? GetMoney() + d : 0); + else + SetMoney (GetMoney() < MAX_MONEY_AMOUNT - d ? GetMoney() + d : MAX_MONEY_AMOUNT); + + // "At Gold Limit" + if(GetMoney() >= MAX_MONEY_AMOUNT) + SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD,NULL,NULL); + } + void SetMoney( uint32 value ) + { + SetUInt32Value (PLAYER_FIELD_COINAGE, value); + MoneyChanged( value ); + } + + uint32 GetTutorialInt(uint32 intId ) + { + ASSERT( (intId < 8) ); + return m_Tutorials[intId]; + } + + void SetTutorialInt(uint32 intId, uint32 value) + { + ASSERT( (intId < 8) ); + if(m_Tutorials[intId]!=value) + { + m_Tutorials[intId] = value; + m_TutorialsChanged = true; + } + } + + QuestStatusMap& getQuestStatusMap() { return mQuestStatus; }; + + const uint64& GetSelection( ) const { return m_curSelection; } + void SetSelection(const uint64 &guid) { m_curSelection = guid; SetUInt64Value(UNIT_FIELD_TARGET, guid); } + + uint8 GetComboPoints() { return m_comboPoints; } + uint64 GetComboTarget() { return m_comboTarget; } + + void AddComboPoints(Unit* target, int8 count); + void ClearComboPoints(); + void SendComboPoints(); + + void SendMailResult(uint32 mailId, uint32 mailAction, uint32 mailError, uint32 equipError = 0, uint32 item_guid = 0, uint32 item_count = 0); + void SendNewMail(); + void UpdateNextMailTimeAndUnreads(); + void AddNewMailDeliverTime(time_t deliver_time); + bool IsMailsLoaded() const { return m_mailsLoaded; } + + //void SetMail(Mail *m); + void RemoveMail(uint32 id); + + void AddMail(Mail* mail) { m_mail.push_front(mail);}// for call from WorldSession::SendMailTo + uint32 GetMailSize() { return m_mail.size();}; + Mail* GetMail(uint32 id); + + PlayerMails::iterator GetmailBegin() { return m_mail.begin();}; + PlayerMails::iterator GetmailEnd() { return m_mail.end();}; + + /*********************************************************/ + /*** MAILED ITEMS SYSTEM ***/ + /*********************************************************/ + + uint8 unReadMails; + time_t m_nextMailDelivereTime; + + typedef HM_NAMESPACE::hash_map ItemMap; + + ItemMap mMitems; //template defined in objectmgr.cpp + + Item* GetMItem(uint32 id) + { + ItemMap::const_iterator itr = mMitems.find(id); + if (itr != mMitems.end()) + return itr->second; + + return NULL; + } + + void AddMItem(Item* it) + { + ASSERT( it ); + //assert deleted, because items can be added before loading + mMitems[it->GetGUIDLow()] = it; + } + + bool RemoveMItem(uint32 id) + { + ItemMap::iterator i = mMitems.find(id); + if (i == mMitems.end()) + return false; + + mMitems.erase(i); + return true; + } + + void PetSpellInitialize(); + void CharmSpellInitialize(); + void PossessSpellInitialize(); + bool HasSpell(uint32 spell) const; + TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const; + bool IsSpellFitByClassAndRace( uint32 spell_id ) const; + + void SendProficiency(uint8 pr1, uint32 pr2); + void SendInitialSpells(); + bool addSpell(uint32 spell_id, bool active, bool learning = true, bool loading = false, uint16 slot_id=SPELL_WITHOUT_SLOT_ID, bool disabled = false); + void learnSpell(uint32 spell_id); + void removeSpell(uint32 spell_id, bool disabled = false); + void resetSpells(); + void learnDefaultSpells(bool loading = false); + void learnQuestRewardedSpells(); + void learnQuestRewardedSpells(Quest const* quest); + + uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); } + void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS1,points); } + bool resetTalents(bool no_cost = false); + uint32 resetTalentsCost() const; + void InitTalentForLevel(); + + uint32 GetFreePrimaryProffesionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS2); } + void SetFreePrimaryProffesions(uint16 profs) { SetUInt32Value(PLAYER_CHARACTER_POINTS2,profs); } + void InitPrimaryProffesions(); + + PlayerSpellMap const& GetSpellMap() const { return m_spells; } + PlayerSpellMap & GetSpellMap() { return m_spells; } + + void AddSpellMod(SpellModifier* mod, bool apply); + int32 GetTotalFlatMods(uint32 spellId, SpellModOp op); + int32 GetTotalPctMods(uint32 spellId, SpellModOp op); + bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell = NULL); + template T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell = NULL); + void RemoveSpellMods(Spell const* spell); + + bool HasSpellCooldown(uint32 spell_id) const + { + SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); + return itr != m_spellCooldowns.end() && itr->second.end > time(NULL); + } + uint32 GetSpellCooldownDelay(uint32 spell_id) const + { + SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); + time_t t = time(NULL); + return itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0; + } + void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time); + void SendCooldownEvent(SpellEntry const *spellInfo); + void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ); + void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); } + void RemoveArenaSpellCooldowns(); + void RemoveAllSpellCooldown(); + void _LoadSpellCooldowns(QueryResult *result); + void _SaveSpellCooldowns(); + + void setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana) + { + m_resurrectGUID = guid; + m_resurrectMap = mapId; + m_resurrectX = X; + m_resurrectY = Y; + m_resurrectZ = Z; + m_resurrectHealth = health; + m_resurrectMana = mana; + }; + void clearResurrectRequestData() { setResurrectRequestData(0,0,0.0f,0.0f,0.0f,0,0); } + bool isRessurectRequestedBy(uint64 guid) const { return m_resurrectGUID == guid; } + bool isRessurectRequested() const { return m_resurrectGUID != 0; } + void ResurectUsingRequestData(); + + int getCinematic() + { + return m_cinematic; + } + void setCinematic(int cine) + { + m_cinematic = cine; + } + + void addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc); + void removeActionButton(uint8 button); + void SendInitialActionButtons(); + + PvPInfo pvpInfo; + void UpdatePvP(bool state, bool ovrride=false); + void UpdateZone(uint32 newZone); + void UpdateArea(uint32 newArea); + + void UpdateZoneDependentAuras( uint32 zone_id ); // zones + void UpdateAreaDependentAuras( uint32 area_id ); // subzones + + void UpdateAfkReport(time_t currTime); + void UpdatePvPFlag(time_t currTime); + void UpdateContestedPvP(uint32 currTime); + void SetContestedPvPTimer(uint32 newTime) {m_contestedPvPTimer = newTime;} + void ResetContestedPvP() + { + clearUnitState(UNIT_STAT_ATTACK_PLAYER); + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP); + m_contestedPvPTimer = 0; + } + + /** todo: -maybe move UpdateDuelFlag+DuelComplete to independent DuelHandler.. **/ + DuelInfo *duel; + void UpdateDuelFlag(time_t currTime); + void CheckDuelDistance(time_t currTime); + void DuelComplete(DuelCompleteType type); + + bool IsGroupVisibleFor(Player* p) const; + bool IsInSameGroupWith(Player const* p) const; + bool IsInSameRaidWith(Player const* p) const { return p==this || (GetGroup() != NULL && GetGroup() == p->GetGroup()); } + void UninviteFromGroup(); + static void RemoveFromGroup(Group* group, uint64 guid); + void RemoveFromGroup() { RemoveFromGroup(GetGroup(),GetGUID()); } + void SendUpdateToOutOfRangeGroupMembers(); + + void SetInGuild(uint32 GuildId) { SetUInt32Value(PLAYER_GUILDID, GuildId); Player::SetUInt32ValueInDB(PLAYER_GUILDID, GuildId, this->GetGUID()); } + void SetRank(uint32 rankId){ SetUInt32Value(PLAYER_GUILDRANK, rankId); Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, rankId, this->GetGUID()); } + void SetGuildIdInvited(uint32 GuildId) { m_GuildIdInvited = GuildId; } + uint32 GetGuildId() { return GetUInt32Value(PLAYER_GUILDID); } + static uint32 GetGuildIdFromDB(uint64 guid); + uint32 GetRank(){ return GetUInt32Value(PLAYER_GUILDRANK); } + static uint32 GetRankFromDB(uint64 guid); + int GetGuildIdInvited() { return m_GuildIdInvited; } + static void RemovePetitionsAndSigns(uint64 guid, uint32 type); + + // Arena Team + void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot) + { + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId); + SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId, this->GetGUID()); + } + uint32 GetArenaTeamId(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6)); } + static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot); + void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; } + uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; } + + void SetDifficulty(uint32 dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } + uint8 GetDifficulty() { return m_dungeonDifficulty; } + + bool UpdateSkill(uint32 skill_id, uint32 step); + bool UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step); + + bool UpdateCraftSkill(uint32 spellid); + bool UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator = 1); + bool UpdateFishingSkill(); + + uint32 GetBaseDefenseSkillValue() const { return GetBaseSkillValue(SKILL_DEFENSE); } + uint32 GetBaseWeaponSkillValue(WeaponAttackType attType) const; + + uint32 GetSpellByProto(ItemPrototype *proto); + + float GetHealthBonusFromStamina(); + float GetManaBonusFromIntellect(); + + bool UpdateStats(Stats stat); + bool UpdateAllStats(); + void UpdateResistances(uint32 school); + void UpdateArmor(); + void UpdateMaxHealth(); + void UpdateMaxPower(Powers power); + void UpdateAttackPowerAndDamage(bool ranged = false); + void UpdateShieldBlockValue(); + void UpdateDamagePhysical(WeaponAttackType attType); + void UpdateSpellDamageAndHealingBonus(); + + void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage); + + void UpdateDefenseBonusesMod(); + void ApplyRatingMod(CombatRating cr, int32 value, bool apply); + float GetMeleeCritFromAgility(); + float GetDodgeFromAgility(); + float GetSpellCritFromIntellect(); + float OCTRegenHPPerSpirit(); + float OCTRegenMPPerSpirit(); + float GetRatingCoefficient(CombatRating cr) const; + float GetRatingBonusValue(CombatRating cr) const; + uint32 GetMeleeCritDamageReduction(uint32 damage) const; + uint32 GetRangedCritDamageReduction(uint32 damage) const; + uint32 GetSpellCritDamageReduction(uint32 damage) const; + uint32 GetDotDamageReduction(uint32 damage) const; + + float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const; + void UpdateBlockPercentage(); + void UpdateCritPercentage(WeaponAttackType attType); + void UpdateAllCritPercentages(); + void UpdateParryPercentage(); + void UpdateDodgePercentage(); + void UpdateAllSpellCritChances(); + void UpdateSpellCritChance(uint32 school); + void UpdateExpertise(WeaponAttackType attType); + void UpdateManaRegen(); + + const uint64& GetLootGUID() const { return m_lootGuid; } + void SetLootGUID(const uint64 &guid) { m_lootGuid = guid; } + + void RemovedInsignia(Player* looterPlr); + + WorldSession* GetSession() const { return m_session; } + void SetSession(WorldSession *s) { m_session = s; } + + void BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const; + void DestroyForPlayer( Player *target ) const; + void SendDelayResponse(const uint32); + void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP); + + //Low Level Packets + void PlaySound(uint32 Sound, bool OnlySelf); + //notifiers + void SendAttackSwingCantAttack(); + void SendAttackSwingCancelAttack(); + void SendAttackSwingDeadTarget(); + void SendAttackSwingNotStanding(); + void SendAttackSwingNotInRange(); + void SendAttackSwingBadFacingAttack(); + void SendAutoRepeatCancel(); + void SendExplorationExperience(uint32 Area, uint32 Experience); + + void SendDungeonDifficulty(bool IsInGroup); + void ResetInstances(uint8 method); + void SendResetInstanceSuccess(uint32 MapId); + void SendResetInstanceFailed(uint32 reason, uint32 MapId); + void SendResetFailedNotify(uint32 mapid); + + bool SetPosition(float x, float y, float z, float orientation, bool teleport = false); + void UpdateUnderwaterState( Map * m, float x, float y, float z ); + + void SendMessageToSet(WorldPacket *data, bool self);// overwrite Object::SendMessageToSet + void SendMessageToSetInRange(WorldPacket *data, float fist, bool self); + // overwrite Object::SendMessageToSetInRange + void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only); + + static void DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars = true); + + Corpse *GetCorpse() const; + void SpawnCorpseBones(); + void CreateCorpse(); + void KillPlayer(); + uint32 GetResurrectionSpellId(); + void ResurrectPlayer(float restore_percent, bool updateToWorld = true, bool applySickness = false); + void BuildPlayerRepop(); + void RepopAtGraveyard(); + + void DurabilityLossAll(double percent, bool inventory); + void DurabilityLoss(Item* item, double percent); + void DurabilityPointsLossAll(int32 points, bool inventory); + void DurabilityPointsLoss(Item* item, int32 points); + void DurabilityPointLossForEquipSlot(EquipmentSlots slot); + uint32 DurabilityRepairAll(bool cost, float discountMod, bool guildBank); + uint32 DurabilityRepair(uint16 pos, bool cost, float discountMod, bool guildBank); + + void StopMirrorTimers() + { + StopMirrorTimer(FATIGUE_TIMER); + StopMirrorTimer(BREATH_TIMER); + StopMirrorTimer(FIRE_TIMER); + } + + void SetMovement(PlayerMovementType pType); + + void JoinedChannel(Channel *c); + void LeftChannel(Channel *c); + void CleanupChannels(); + void UpdateLocalChannels( uint32 newZone ); + void LeaveLFGChannel(); + + void UpdateDefense(); + void UpdateWeaponSkill (WeaponAttackType attType); + void UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence); + + void SetSkill(uint32 id, uint16 currVal, uint16 maxVal); + uint16 GetMaxSkillValue(uint32 skill) const; // max + perm. bonus + uint16 GetPureMaxSkillValue(uint32 skill) const; // max + uint16 GetSkillValue(uint32 skill) const; // skill value + perm. bonus + temp bonus + uint16 GetBaseSkillValue(uint32 skill) const; // skill value + perm. bonus + uint16 GetPureSkillValue(uint32 skill) const; // skill value + int16 GetSkillTempBonusValue(uint32 skill) const; + bool HasSkill(uint32 skill) const; + void learnSkillRewardedSpells( uint32 id ); + void learnSkillRewardedSpells(); + + void SetDontMove(bool dontMove); + bool GetDontMove() const { return m_dontMove; } + + void CheckExploreSystem(void); + + static uint32 TeamForRace(uint8 race); + uint32 GetTeam() const { return m_team; } + static uint32 getFactionForRace(uint8 race); + void setFactionForRace(uint8 race); + + bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const; + bool RewardPlayerAndGroupAtKill(Unit* pVictim); + + FactionStateList m_factions; + ForcedReactions m_forcedReactions; + uint32 GetDefaultReputationFlags(const FactionEntry *factionEntry) const; + int32 GetBaseReputation(const FactionEntry *factionEntry) const; + int32 GetReputation(uint32 faction_id) const; + int32 GetReputation(const FactionEntry *factionEntry) const; + ReputationRank GetReputationRank(uint32 faction) const; + ReputationRank GetReputationRank(const FactionEntry *factionEntry) const; + ReputationRank GetBaseReputationRank(const FactionEntry *factionEntry) const; + ReputationRank ReputationToRank(int32 standing) const; + const static int32 ReputationRank_Length[MAX_REPUTATION_RANK]; + const static int32 Reputation_Cap = 42999; + const static int32 Reputation_Bottom = -42000; + bool ModifyFactionReputation(uint32 FactionTemplateId, int32 DeltaReputation); + bool ModifyFactionReputation(FactionEntry const* factionEntry, int32 standing); + bool ModifyOneFactionReputation(FactionEntry const* factionEntry, int32 standing); + bool SetFactionReputation(uint32 FactionTemplateId, int32 standing); + bool SetFactionReputation(FactionEntry const* factionEntry, int32 standing); + bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing); + int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest); + void RewardReputation(Unit *pVictim, float rate); + void RewardReputation(Quest const *pQuest); + void SetInitialFactions(); + void UpdateReputation() const; + void SendFactionState(FactionState const* faction) const; + void SendInitialReputations(); + FactionState const* GetFactionState( FactionEntry const* factionEntry) const; + void SetFactionAtWar(FactionState* faction, bool atWar); + void SetFactionInactive(FactionState* faction, bool inactive); + void SetFactionVisible(FactionState* faction); + void SetFactionVisibleForFactionTemplateId(uint32 FactionTemplateId); + void SetFactionVisibleForFactionId(uint32 FactionId); + void UpdateMaxSkills(); + void UpdateSkillsToMaxSkillsForLevel(); // for .levelup + void ModifySkillBonus(uint32 skillid,int32 val, bool talent); + + /*********************************************************/ + /*** PVP SYSTEM ***/ + /*********************************************************/ + void UpdateArenaFields(); + void UpdateHonorFields(); + bool RewardHonor(Unit *pVictim, uint32 groupsize, float honor = -1); + uint32 GetHonorPoints() { return GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY); } + uint32 GetArenaPoints() { return GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY); } + void ModifyHonorPoints( int32 value ); + void ModifyArenaPoints( int32 value ); + uint32 GetMaxPersonalArenaRatingRequirement(); + + //End of PvP System + + void SetDrunkValue(uint16 newDrunkValue, uint32 itemid=0); + uint16 GetDrunkValue() const { return m_drunk; } + static DrunkenState GetDrunkenstateByValue(uint16 value); + + uint32 GetDeathTimer() const { return m_deathTimer; } + uint32 GetCorpseReclaimDelay(bool pvp) const; + void UpdateCorpseReclaimDelay(); + void SendCorpseReclaimDelay(bool load = false); + + uint32 GetShieldBlockValue() const; // overwrite Unit version (virtual) + bool CanParry() const { return m_canParry; } + void SetCanParry(bool value); + bool CanBlock() const { return m_canBlock; } + void SetCanBlock(bool value); + bool CanDualWield() const { return m_canDualWield; } + void SetCanDualWield(bool value) { m_canDualWield = value; } + + void SetRegularAttackTime(); + void SetBaseModValue(BaseModGroup modGroup, BaseModType modType, float value) { m_auraBaseMod[modGroup][modType] = value; } + void HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply, bool affectStats = true); + float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const; + float GetTotalBaseModValue(BaseModGroup modGroup) const; + float GetTotalPercentageModValue(BaseModGroup modGroup) const { return m_auraBaseMod[modGroup][FLAT_MOD] + m_auraBaseMod[modGroup][PCT_MOD]; } + void _ApplyAllStatBonuses(); + void _RemoveAllStatBonuses(); + + void _ApplyWeaponDependentAuraMods(Item *item,WeaponAttackType attackType,bool apply); + void _ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply); + void _ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply); + + void _ApplyItemMods(Item *item,uint8 slot,bool apply); + void _RemoveAllItemMods(); + void _ApplyAllItemMods(); + void _ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply); + void _ApplyAmmoBonuses(); + bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot); + void ToggleMetaGemsActive(uint8 exceptslot, bool apply); + void CorrectMetaGemEnchants(uint8 slot, bool apply); + void InitDataForForm(bool reapplyMods = false); + + void ApplyItemEquipSpell(Item *item, bool apply, bool form_change = false); + void ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply, bool form_change = false); + void UpdateEquipSpellsAtFormChange(); + void CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attType); + + void SendInitWorldStates(); + void SendUpdateWorldState(uint32 Field, uint32 Value); + void SendDirectMessage(WorldPacket *data); + + void SendAuraDurationsForTarget(Unit* target); + + PlayerMenu* PlayerTalkClass; + std::vector ItemSetEff; + + void SendLoot(uint64 guid, LootType loot_type); + void SendLootRelease( uint64 guid ); + void SendNotifyLootItemRemoved(uint8 lootSlot); + void SendNotifyLootMoneyRemoved(); + + /*********************************************************/ + /*** BATTLEGROUND SYSTEM ***/ + /*********************************************************/ + + bool InBattleGround() const { return m_bgBattleGroundID != 0; } + uint32 GetBattleGroundId() const { return m_bgBattleGroundID; } + BattleGround* GetBattleGround() const; + bool InArena() const; + + static uint32 GetMinLevelForBattleGroundQueueId(uint32 queue_id); + static uint32 GetMaxLevelForBattleGroundQueueId(uint32 queue_id); + uint32 GetBattleGroundQueueIdFromLevel() const; + + uint32 GetBattleGroundQueueId(uint32 index) const { return m_bgBattleGroundQueueID[index].bgType; } + uint32 GetBattleGroundQueueIndex(uint32 bgType) const + { + for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) + if (m_bgBattleGroundQueueID[i].bgType == bgType) + return i; + return PLAYER_MAX_BATTLEGROUND_QUEUES; + } + bool IsInvitedForBattleGroundType(uint32 bgType) const + { + for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) + if (m_bgBattleGroundQueueID[i].bgType == bgType) + return m_bgBattleGroundQueueID[i].invited; + return PLAYER_MAX_BATTLEGROUND_QUEUES; + } + bool InBattleGroundQueueForBattleGroundType(uint32 bgType) const + { + return GetBattleGroundQueueIndex(bgType) < PLAYER_MAX_BATTLEGROUND_QUEUES; + } + + void SetBattleGroundId(uint32 val) { m_bgBattleGroundID = val; } + uint32 AddBattleGroundQueueId(uint32 val) + { + for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) + { + if (m_bgBattleGroundQueueID[i].bgType == 0 || m_bgBattleGroundQueueID[i].bgType == val) + { + m_bgBattleGroundQueueID[i].bgType = val; + m_bgBattleGroundQueueID[i].invited = false; + return i; + } + } + return PLAYER_MAX_BATTLEGROUND_QUEUES; + } + void RemoveBattleGroundQueueId(uint32 val) + { + for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) + { + if (m_bgBattleGroundQueueID[i].bgType == val) + { + m_bgBattleGroundQueueID[i].bgType = 0; + m_bgBattleGroundQueueID[i].invited = false; + return; + } + } + } + void SetInviteForBattleGroundType(uint32 bgType) + { + for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) + if (m_bgBattleGroundQueueID[i].bgType == bgType) + m_bgBattleGroundQueueID[i].invited = true; + } + + uint32 GetBattleGroundEntryPointMap() const { return m_bgEntryPointMap; } + float GetBattleGroundEntryPointX() const { return m_bgEntryPointX; } + float GetBattleGroundEntryPointY() const { return m_bgEntryPointY; } + float GetBattleGroundEntryPointZ() const { return m_bgEntryPointZ; } + float GetBattleGroundEntryPointO() const { return m_bgEntryPointO; } + void SetBattleGroundEntryPoint(uint32 Map, float PosX, float PosY, float PosZ, float PosO ) + { + m_bgEntryPointMap = Map; + m_bgEntryPointX = PosX; + m_bgEntryPointY = PosY; + m_bgEntryPointZ = PosZ; + m_bgEntryPointO = PosO; + } + + void SetBGTeam(uint32 team) { m_bgTeam = team; } + uint32 GetBGTeam() const { return m_bgTeam ? m_bgTeam : GetTeam(); } + + void LeaveBattleground(bool teleportToEntryPoint = true); + bool CanJoinToBattleground() const; + bool CanReportAfkDueToLimit(); + void ReportedAfkBy(Player* reporter); + void ClearAfkReports() { m_bgAfkReporter.clear(); } + + bool GetBGAccessByLevel(uint32 bgTypeId) const; + + /*********************************************************/ + /*** REST SYSTEM ***/ + /*********************************************************/ + + bool isRested() const { return GetRestTime() >= 10000; } + uint32 GetXPRestBonus(uint32 xp); + uint32 GetRestTime() const { return m_restTime;}; + void SetRestTime(uint32 v) { m_restTime = v;}; + + /*********************************************************/ + /*** ENVIROMENTAL SYSTEM ***/ + /*********************************************************/ + + void EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 damage); + + /*********************************************************/ + /*** FLOOD FILTER SYSTEM ***/ + /*********************************************************/ + + void UpdateSpeakTime(); + bool CanSpeak() const; + void ChangeSpeakTime(int utime); + + /*********************************************************/ + /*** VARIOUS SYSTEMS ***/ + /*********************************************************/ + MovementInfo m_movementInfo; + bool isMoving() const { return HasUnitMovementFlag(movementFlagsMask); } + bool isMovingOrTurning() const { return HasUnitMovementFlag(movementOrTurningFlagsMask); } + + bool CanFly() const { return HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY); } + bool IsFlying() const { return HasUnitMovementFlag(MOVEMENTFLAG_FLYING); } + + void HandleDrowning(); + + void SetClientControl(Unit* target, uint8 allowMove); + + // Transports + Transport * GetTransport() const { return m_transport; } + void SetTransport(Transport * t) { m_transport = t; } + + float GetTransOffsetX() const { return m_movementInfo.t_x; } + float GetTransOffsetY() const { return m_movementInfo.t_y; } + float GetTransOffsetZ() const { return m_movementInfo.t_z; } + float GetTransOffsetO() const { return m_movementInfo.t_o; } + uint32 GetTransTime() const { return m_movementInfo.t_time; } + + uint32 GetSaveTimer() const { return m_nextSave; } + void SetSaveTimer(uint32 timer) { m_nextSave = timer; } + + // Recall position + uint32 m_recallMap; + float m_recallX; + float m_recallY; + float m_recallZ; + float m_recallO; + void SaveRecallPosition(); + + // Homebind coordinates + uint32 m_homebindMapId; + uint16 m_homebindZoneId; + float m_homebindX; + float m_homebindY; + float m_homebindZ; + + // currently visible objects at player client + typedef std::set ClientGUIDs; + ClientGUIDs m_clientGUIDs; + + bool HaveAtClient(WorldObject const* u) { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } + + bool IsVisibleInGridForPlayer(Player* pl) const; + bool IsVisibleGloballyFor(Player* pl) const; + + void UpdateVisibilityOf(WorldObject* target); + + template + void UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); + + // Stealth detection system + uint32 m_DetectInvTimer; + void HandleStealthedUnitsDetection(); + + uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; + + bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; } + void SetAtLoginFlag(AtLoginFlags f) { m_atLoginFlags |= f; } + + LookingForGroup m_lookingForGroup; + + // Temporarily removed pet cache + uint32 GetTemporaryUnsummonedPetNumber() const { return m_temporaryUnsummonedPetNumber; } + void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; } + uint32 GetOldPetSpell() const { return m_oldpetspell; } + void SetOldPetSpell(uint32 petspell) { m_oldpetspell = petspell; } + + /*********************************************************/ + /*** INSTANCE SYSTEM ***/ + /*********************************************************/ + + typedef HM_NAMESPACE::hash_map< uint32 /*mapId*/, InstancePlayerBind > BoundInstancesMap; + + void UpdateHomebindTime(uint32 time); + + uint32 m_HomebindTimer; + bool m_InstanceValid; + // permanent binds and solo binds by difficulty + BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES]; + InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty); + BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } + void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); + void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false); + InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); + void SendRaidInfo(); + void SendSavedInstances(); + static void ConvertInstancesToGroup(Player *player, Group *group = NULL, uint64 player_guid = 0); + + /*********************************************************/ + /*** GROUP SYSTEM ***/ + /*********************************************************/ + + Group * GetGroupInvite() { return m_groupInvite; } + void SetGroupInvite(Group *group) { m_groupInvite = group; } + Group * GetGroup() { return m_group.getTarget(); } + const Group * GetGroup() const { return (const Group*)m_group.getTarget(); } + GroupReference& GetGroupRef() { return m_group; } + void SetGroup(Group *group, int8 subgroup = -1); + uint8 GetSubGroup() const { return m_group.getSubGroup(); } + uint32 GetGroupUpdateFlag() { return m_groupUpdateMask; } + void SetGroupUpdateFlag(uint32 flag) { m_groupUpdateMask |= flag; } + uint64 GetAuraUpdateMask() { return m_auraUpdateMask; } + void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); } + Player* GetNextRandomRaidMember(float radius); + + GridReference &GetGridRef() { return m_gridRef; } + bool isAllowedToLoot(Creature* creature); + + WorldLocation& GetTeleportDest() { return m_teleport_dest; } + + DeclinedName const* GetDeclinedNames() const { return m_declinedname; } + + protected: + + /*********************************************************/ + /*** BATTLEGROUND SYSTEM ***/ + /*********************************************************/ + + /* this variable is set to bg->m_InstanceID, when player is teleported to BG - (it is battleground's GUID)*/ + uint32 m_bgBattleGroundID; + /* + this is an array of BG queues (BgTypeIDs) in which is player + */ + struct BgBattleGroundQueueID_Rec + { + uint32 bgType; + bool invited; + }; + BgBattleGroundQueueID_Rec m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES]; + uint32 m_bgEntryPointMap; + float m_bgEntryPointX; + float m_bgEntryPointY; + float m_bgEntryPointZ; + float m_bgEntryPointO; + + std::set m_bgAfkReporter; + uint8 m_bgAfkReportedCount; + time_t m_bgAfkReportedTimer; + uint32 m_contestedPvPTimer; + + uint32 m_bgTeam; // what side the player will be added to + + /*********************************************************/ + /*** QUEST SYSTEM ***/ + /*********************************************************/ + + std::set m_timedquests; + + uint64 m_divider; + uint32 m_ingametime; + + /*********************************************************/ + /*** LOAD SYSTEM ***/ + /*********************************************************/ + + void _LoadActions(QueryResult *result); + void _LoadAuras(QueryResult *result, uint32 timediff); + void _LoadBoundInstances(QueryResult *result); + void _LoadInventory(QueryResult *result, uint32 timediff); + void _LoadMailInit(QueryResult *resultUnread, QueryResult *resultDelivery); + void _LoadMail(); + void _LoadMailedItems(Mail *mail); + void _LoadQuestStatus(QueryResult *result); + void _LoadDailyQuestStatus(QueryResult *result); + void _LoadGroup(QueryResult *result); + void _LoadReputation(QueryResult *result); + void _LoadSpells(QueryResult *result); + void _LoadTutorials(QueryResult *result); + void _LoadFriendList(QueryResult *result); + bool _LoadHomeBind(QueryResult *result); + void _LoadDeclinedNames(QueryResult *result); + + /*********************************************************/ + /*** SAVE SYSTEM ***/ + /*********************************************************/ + + void _SaveActions(); + void _SaveAuras(); + void _SaveInventory(); + void _SaveMail(); + void _SaveQuestStatus(); + void _SaveDailyQuestStatus(); + void _SaveReputation(); + void _SaveSpells(); + void _SaveTutorials(); + + void _SetCreateBits(UpdateMask *updateMask, Player *target) const; + void _SetUpdateBits(UpdateMask *updateMask, Player *target) const; + + /*********************************************************/ + /*** ENVIRONMENTAL SYSTEM ***/ + /*********************************************************/ + void HandleLava(); + void HandleSobering(); + void StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue); + void ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen); + void StopMirrorTimer(MirrorTimerType Type); + uint8 m_isunderwater; + bool m_isInWater; + + /*********************************************************/ + /*** HONOR SYSTEM ***/ + /*********************************************************/ + time_t m_lastHonorUpdateTime; + + void outDebugValues() const; + bool _removeSpell(uint16 spell_id); + uint64 m_lootGuid; + + uint32 m_race; + uint32 m_class; + uint32 m_team; + uint32 m_nextSave; + time_t m_speakTime; + uint32 m_speakCount; + uint32 m_dungeonDifficulty; + + uint32 m_atLoginFlags; + + Item* m_items[PLAYER_SLOTS_COUNT]; + uint32 m_currentBuybackSlot; + + std::vector m_itemUpdateQueue; + bool m_itemUpdateQueueBlocked; + + uint32 m_ExtraFlags; + uint64 m_curSelection; + + uint64 m_comboTarget; + int8 m_comboPoints; + + QuestStatusMap mQuestStatus; + + uint32 m_GuildIdInvited; + uint32 m_ArenaTeamIdInvited; + + PlayerMails m_mail; + PlayerSpellMap m_spells; + SpellCooldowns m_spellCooldowns; + + ActionButtonList m_actionButtons; + + float m_auraBaseMod[BASEMOD_END][MOD_END]; + + SpellModList m_spellMods[MAX_SPELLMOD]; + int32 m_SpellModRemoveCount; + EnchantDurationList m_enchantDuration; + ItemDurationList m_itemDuration; + + uint64 m_resurrectGUID; + uint32 m_resurrectMap; + float m_resurrectX, m_resurrectY, m_resurrectZ; + uint32 m_resurrectHealth, m_resurrectMana; + + WorldSession *m_session; + + typedef std::list JoinedChannelsList; + JoinedChannelsList m_channels; + + bool m_dontMove; + + int m_cinematic; + + Player *pTrader; + bool acceptTrade; + uint16 tradeItems[TRADE_SLOT_COUNT]; + uint32 tradeGold; + + time_t m_nextThinkTime; + + uint32 m_Tutorials[8]; + bool m_TutorialsChanged; + + bool m_DailyQuestChanged; + time_t m_lastDailyQuestTime; + + uint32 m_regenTimer; + uint32 m_breathTimer; + uint32 m_drunkTimer; + uint16 m_drunk; + uint32 m_weaponChangeTimer; + + uint32 m_zoneUpdateId; + uint32 m_zoneUpdateTimer; + uint32 m_areaUpdateId; + + uint32 m_deathTimer; + time_t m_deathExpireTime; + + uint32 m_restTime; + + uint32 m_WeaponProficiency; + uint32 m_ArmorProficiency; + bool m_canParry; + bool m_canBlock; + bool m_canDualWield; + uint8 m_swingErrorMsg; + float m_ammoDPS; + ////////////////////Rest System///////////////////// + int time_inn_enter; + uint32 inn_pos_mapid; + float inn_pos_x; + float inn_pos_y; + float inn_pos_z; + float m_rest_bonus; + RestType rest_type; + ////////////////////Rest System///////////////////// + + // Transports + Transport * m_transport; + + uint32 m_resetTalentsCost; + time_t m_resetTalentsTime; + uint32 m_usedTalentCount; + + // Social + PlayerSocial *m_social; + + // Groups + GroupReference m_group; + Group *m_groupInvite; + uint32 m_groupUpdateMask; + uint64 m_auraUpdateMask; + + // Temporarily removed pet cache + uint32 m_temporaryUnsummonedPetNumber; + uint32 m_oldpetspell; + + uint64 m_miniPet; + GuardianPetList m_guardianPets; + + // Player summoning + time_t m_summon_expire; + uint32 m_summon_mapid; + float m_summon_x; + float m_summon_y; + float m_summon_z; + + // Far Teleport + WorldLocation m_teleport_dest; + + DeclinedName *m_declinedname; + private: + // internal common parts for CanStore/StoreItem functions + uint8 _CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem ) const; + uint8 _CanStoreItem_InBag( uint8 bag, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool merge, bool non_specialized, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot ) const; + uint8 _CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool merge, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot ) const; + Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update ); + + GridReference m_gridRef; +}; + +void AddItemsSetItem(Player*player,Item *item); +void RemoveItemsSetItem(Player*player,ItemPrototype const *proto); + +// "the bodies of template functions must be made available in a header file" +template T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo) return 0; + int32 totalpct = 0; + int32 totalflat = 0; + for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr) + { + SpellModifier *mod = *itr; + + if(!IsAffectedBySpellmod(spellInfo,mod,spell)) + continue; + if (mod->type == SPELLMOD_FLAT) + totalflat += mod->value; + else if (mod->type == SPELLMOD_PCT) + { + // skip percent mods for null basevalue (most important for spell mods with charges ) + if(basevalue == T(0)) + continue; + + // special case (skip >10sec spell casts for instant cast setting) + if( mod->op==SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100) + continue; + + totalpct += mod->value; + } + + if (mod->charges > 0 ) + { + --mod->charges; + if (mod->charges == 0) + { + mod->charges = -1; + mod->lastAffected = spell; + if(!mod->lastAffected) + mod->lastAffected = FindCurrentSpellBySpellId(spellId); + ++m_SpellModRemoveCount; + } + } + } + + float diff = (float)basevalue*(float)totalpct/100.0f + (float)totalflat; + basevalue = T((float)basevalue + diff); + return T(diff); +} +#endif diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 06c6daead2a..ab04389601b 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -1994,4 +1994,108 @@ enum SummonType SUMMON_TYPE_UNKNOWN2 = 427, SUMMON_TYPE_POSESSED2 = 428 }; + +enum ResponseCodes +{ + RESPONSE_SUCCESS = 0x00, + RESPONSE_FAILURE = 0x01, + RESPONSE_CANCELLED = 0x02, + RESPONSE_DISCONNECTED = 0x03, + RESPONSE_FAILED_TO_CONNECT = 0x04, + RESPONSE_CONNECTED = 0x05, + RESPONSE_VERSION_MISMATCH = 0x06, + + CSTATUS_CONNECTING = 0x07, + CSTATUS_NEGOTIATING_SECURITY = 0x08, + CSTATUS_NEGOTIATION_COMPLETE = 0x09, + CSTATUS_NEGOTIATION_FAILED = 0x0A, + CSTATUS_AUTHENTICATING = 0x0B, + + AUTH_OK = 0x0C, + AUTH_FAILED = 0x0D, + AUTH_REJECT = 0x0E, + AUTH_BAD_SERVER_PROOF = 0x0F, + AUTH_UNAVAILABLE = 0x10, + AUTH_SYSTEM_ERROR = 0x11, + AUTH_BILLING_ERROR = 0x12, + AUTH_BILLING_EXPIRED = 0x13, + AUTH_VERSION_MISMATCH = 0x14, + AUTH_UNKNOWN_ACCOUNT = 0x15, + AUTH_INCORRECT_PASSWORD = 0x16, + AUTH_SESSION_EXPIRED = 0x17, + AUTH_SERVER_SHUTTING_DOWN = 0x18, + AUTH_ALREADY_LOGGING_IN = 0x19, + AUTH_LOGIN_SERVER_NOT_FOUND = 0x1A, + AUTH_WAIT_QUEUE = 0x1B, + AUTH_BANNED = 0x1C, + AUTH_ALREADY_ONLINE = 0x1D, + AUTH_NO_TIME = 0x1E, + AUTH_DB_BUSY = 0x1F, + AUTH_SUSPENDED = 0x20, + AUTH_PARENTAL_CONTROL = 0x21, + AUTH_LOCKED_ENFORCED = 0x22, + + REALM_LIST_IN_PROGRESS = 0x23, + REALM_LIST_SUCCESS = 0x24, + REALM_LIST_FAILED = 0x25, + REALM_LIST_INVALID = 0x26, + REALM_LIST_REALM_NOT_FOUND = 0x27, + + ACCOUNT_CREATE_IN_PROGRESS = 0x28, + ACCOUNT_CREATE_SUCCESS = 0x29, + ACCOUNT_CREATE_FAILED = 0x2A, + + CHAR_LIST_RETRIEVING = 0x2B, + CHAR_LIST_RETRIEVED = 0x2C, + CHAR_LIST_FAILED = 0x2D, + + CHAR_CREATE_IN_PROGRESS = 0x2E, + CHAR_CREATE_SUCCESS = 0x2F, + CHAR_CREATE_ERROR = 0x30, + CHAR_CREATE_FAILED = 0x31, + CHAR_CREATE_NAME_IN_USE = 0x32, + CHAR_CREATE_DISABLED = 0x33, + CHAR_CREATE_PVP_TEAMS_VIOLATION = 0x34, + CHAR_CREATE_SERVER_LIMIT = 0x35, + CHAR_CREATE_ACCOUNT_LIMIT = 0x36, + CHAR_CREATE_SERVER_QUEUE = 0x37, + CHAR_CREATE_ONLY_EXISTING = 0x38, + CHAR_CREATE_EXPANSION = 0x39, + + CHAR_DELETE_IN_PROGRESS = 0x3A, + CHAR_DELETE_SUCCESS = 0x3B, + CHAR_DELETE_FAILED = 0x3C, + CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x3D, + CHAR_DELETE_FAILED_GUILD_LEADER = 0x3E, + CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x3F, + + CHAR_LOGIN_IN_PROGRESS = 0x40, + CHAR_LOGIN_SUCCESS = 0x41, + CHAR_LOGIN_NO_WORLD = 0x42, + CHAR_LOGIN_DUPLICATE_CHARACTER = 0x43, + CHAR_LOGIN_NO_INSTANCES = 0x44, + CHAR_LOGIN_FAILED = 0x45, + CHAR_LOGIN_DISABLED = 0x46, + CHAR_LOGIN_NO_CHARACTER = 0x47, + CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x48, + CHAR_LOGIN_LOCKED_BY_BILLING = 0x49, + + CHAR_NAME_SUCCESS = 0x4A, + CHAR_NAME_FAILURE = 0x4B, + CHAR_NAME_NO_NAME = 0x4C, + CHAR_NAME_TOO_SHORT = 0x4D, + CHAR_NAME_TOO_LONG = 0x4E, + CHAR_NAME_INVALID_CHARACTER = 0x4F, + CHAR_NAME_MIXED_LANGUAGES = 0x50, + CHAR_NAME_PROFANE = 0x51, + CHAR_NAME_RESERVED = 0x52, + CHAR_NAME_INVALID_APOSTROPHE = 0x53, + CHAR_NAME_MULTIPLE_APOSTROPHES = 0x54, + CHAR_NAME_THREE_CONSECUTIVE = 0x55, + CHAR_NAME_INVALID_SPACE = 0x56, + CHAR_NAME_CONSECUTIVE_SPACES = 0x57, + CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x58, + CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x59, + CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x5A, +}; #endif diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 95e9ac1b745..d97cc2c6f0d 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -1,5115 +1,5070 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "Opcodes.h" -#include "Log.h" -#include "UpdateMask.h" -#include "World.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Player.h" -#include "Pet.h" -#include "Unit.h" -#include "Spell.h" -#include "DynamicObject.h" -#include "SpellAuras.h" -#include "Group.h" -#include "UpdateData.h" -#include "MapManager.h" -#include "ObjectAccessor.h" -#include "CellImpl.h" -#include "Policies/SingletonImp.h" -#include "SharedDefines.h" -#include "Tools.h" -#include "LootMgr.h" -#include "VMapFactory.h" -#include "BattleGround.h" -#include "Util.h" - -#define SPELL_CHANNEL_UPDATE_INTERVAL 1000 - -extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; - -bool IsQuestTameSpell(uint32 spellId) -{ - SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId); - if (!spellproto) return false; - - return spellproto->Effect[0] == SPELL_EFFECT_THREAT - && spellproto->Effect[1] == SPELL_EFFECT_APPLY_AURA && spellproto->EffectApplyAuraName[1] == SPELL_AURA_DUMMY; -} - -SpellCastTargets::SpellCastTargets() -{ - m_unitTarget = NULL; - m_itemTarget = NULL; - m_GOTarget = NULL; - - m_unitTargetGUID = 0; - m_GOTargetGUID = 0; - m_CorpseTargetGUID = 0; - m_itemTargetGUID = 0; - m_itemTargetEntry = 0; - - m_srcX = m_srcY = m_srcZ = m_destX = m_destY = m_destZ = 0; - m_strTarget = ""; - m_targetMask = 0; -} - -SpellCastTargets::~SpellCastTargets() -{ -} - -void SpellCastTargets::setUnitTarget(Unit *target) -{ - if (!target) - return; - - m_destX = target->GetPositionX(); - m_destY = target->GetPositionY(); - m_destZ = target->GetPositionZ(); - m_unitTarget = target; - m_unitTargetGUID = target->GetGUID(); - m_targetMask |= TARGET_FLAG_UNIT; -} - -void SpellCastTargets::setDestination(float x, float y, float z) -{ - m_destX = x; - m_destY = y; - m_destZ = z; - m_targetMask |= TARGET_FLAG_DEST_LOCATION; -} - -void SpellCastTargets::setGOTarget(GameObject *target) -{ - m_GOTarget = target; - m_GOTargetGUID = target->GetGUID(); - // m_targetMask |= TARGET_FLAG_OBJECT; -} - -void SpellCastTargets::setItemTarget(Item* item) -{ - if(!item) - return; - - m_itemTarget = item; - m_itemTargetGUID = item->GetGUID(); - m_itemTargetEntry = item->GetEntry(); - m_targetMask |= TARGET_FLAG_ITEM; -} - -void SpellCastTargets::setCorpseTarget(Corpse* corpse) -{ - m_CorpseTargetGUID = corpse->GetGUID(); -} - -void SpellCastTargets::Update(Unit* caster) -{ - m_GOTarget = m_GOTargetGUID ? ObjectAccessor::GetGameObject(*caster,m_GOTargetGUID) : NULL; - m_unitTarget = m_unitTargetGUID ? - ( m_unitTargetGUID==caster->GetGUID() ? caster : ObjectAccessor::GetUnit(*caster, m_unitTargetGUID) ) : - NULL; - - m_itemTarget = NULL; - if(caster->GetTypeId()==TYPEID_PLAYER) - { - if(m_targetMask & TARGET_FLAG_ITEM) - m_itemTarget = ((Player*)caster)->GetItemByGuid(m_itemTargetGUID); - else - { - Player* pTrader = ((Player*)caster)->GetTrader(); - if(pTrader && m_itemTargetGUID < TRADE_SLOT_COUNT) - m_itemTarget = pTrader->GetItemByPos(pTrader->GetItemPosByTradeSlot(m_itemTargetGUID)); - } - if(m_itemTarget) - m_itemTargetEntry = m_itemTarget->GetEntry(); - } -} - -bool SpellCastTargets::read ( WorldPacket * data, Unit *caster ) -{ - if(data->rpos()+4 > data->size()) - return false; - - *data >> m_targetMask; - - if(m_targetMask == TARGET_FLAG_SELF) - { - m_destX = caster->GetPositionX(); - m_destY = caster->GetPositionY(); - m_destZ = caster->GetPositionZ(); - m_unitTarget = caster; - m_unitTargetGUID = caster->GetGUID(); - return true; - } - // TARGET_FLAG_UNK2 is used for non-combat pets, maybe other? - if( m_targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2) ) - if(!readGUID(*data, m_unitTargetGUID)) - return false; - - if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK )) - if(!readGUID(*data, m_GOTargetGUID)) - return false; - - if(( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM )) && caster->GetTypeId() == TYPEID_PLAYER) - if(!readGUID(*data, m_itemTargetGUID)) - return false; - - if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION ) - { - if(data->rpos()+4+4+4 > data->size()) - return false; - - *data >> m_srcX >> m_srcY >> m_srcZ; - if(!MaNGOS::IsValidMapCoord(m_srcX, m_srcY, m_srcZ)) - return false; - } - - if( m_targetMask & TARGET_FLAG_DEST_LOCATION ) - { - if(data->rpos()+4+4+4 > data->size()) - return false; - - *data >> m_destX >> m_destY >> m_destZ; - if(!MaNGOS::IsValidMapCoord(m_destX, m_destY, m_destZ)) - return false; - } - - if( m_targetMask & TARGET_FLAG_STRING ) - { - if(data->rpos()+1 > data->size()) - return false; - - *data >> m_strTarget; - } - - if( m_targetMask & (TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) ) - if(!readGUID(*data, m_CorpseTargetGUID)) - return false; - - // find real units/GOs - Update(caster); - return true; -} - -void SpellCastTargets::write ( WorldPacket * data ) -{ - *data << uint32(m_targetMask); - - if( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_PVP_CORPSE | TARGET_FLAG_OBJECT | TARGET_FLAG_CORPSE | TARGET_FLAG_UNK2 ) ) - { - if(m_targetMask & TARGET_FLAG_UNIT) - { - if(m_unitTarget) - data->append(m_unitTarget->GetPackGUID()); - else - *data << uint8(0); - } - else if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK ) ) - { - if(m_GOTarget) - data->append(m_GOTarget->GetPackGUID()); - else - *data << uint8(0); - } - else if( m_targetMask & ( TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) ) - data->appendPackGUID(m_CorpseTargetGUID); - else - *data << uint8(0); - } - - if( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM ) ) - { - if(m_itemTarget) - data->append(m_itemTarget->GetPackGUID()); - else - *data << uint8(0); - } - - if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION ) - *data << m_srcX << m_srcY << m_srcZ; - - if( m_targetMask & TARGET_FLAG_DEST_LOCATION ) - *data << m_destX << m_destY << m_destZ; - - if( m_targetMask & TARGET_FLAG_STRING ) - *data << m_strTarget; -} - -Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 originalCasterGUID, Spell** triggeringContainer ) -{ - ASSERT( Caster != NULL && info != NULL ); - ASSERT( info == sSpellStore.LookupEntry( info->Id ) && "`info` must be pointer to sSpellStore element"); - - m_spellInfo = info; - m_caster = Caster; - m_selfContainer = NULL; - m_triggeringContainer = triggeringContainer; - m_deletable = true; - m_delayAtDamageCount = 0; - - m_applyMultiplierMask = 0; - - // Get data for type of attack - switch (m_spellInfo->DmgClass) - { - case SPELL_DAMAGE_CLASS_MELEE: - if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND) - m_attackType = OFF_ATTACK; - else - m_attackType = BASE_ATTACK; - break; - case SPELL_DAMAGE_CLASS_RANGED: - m_attackType = RANGED_ATTACK; - break; - default: - // Wands - if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_WAND) - m_attackType = RANGED_ATTACK; - else - m_attackType = BASE_ATTACK; - break; - } - - m_spellSchoolMask = GetSpellSchoolMask(info); // Can be override for some spell (wand shoot for example) - - if(m_attackType == RANGED_ATTACK) - { - // wand case - if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER) - { - if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK)) - m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType); - } - } - - if(originalCasterGUID) - m_originalCasterGUID = originalCasterGUID; - else - m_originalCasterGUID = m_caster->GetGUID(); - - if(m_originalCasterGUID==m_caster->GetGUID()) - m_originalCaster = m_caster; - else - { - m_originalCaster = ObjectAccessor::GetUnit(*m_caster,m_originalCasterGUID); - if(m_originalCaster && !m_originalCaster->IsInWorld()) m_originalCaster = NULL; - } - - for(int i=0; i <3; ++i) - m_currentBasePoints[i] = m_spellInfo->EffectBasePoints[i]; - - m_spellState = SPELL_STATE_NULL; - - m_castPositionX = m_castPositionY = m_castPositionZ = 0; - m_TriggerSpells.clear(); - m_IsTriggeredSpell = triggered; - //m_AreaAura = false; - m_CastItem = NULL; - - unitTarget = NULL; - itemTarget = NULL; - gameObjTarget = NULL; - focusObject = NULL; - m_cast_count = 0; - m_triggeredByAuraSpell = NULL; - - //Auto Shot & Shoot - if( m_spellInfo->AttributesEx2 == 0x000020 && !triggered ) - m_autoRepeat = true; - else - m_autoRepeat = false; - - m_powerCost = 0; // setup to correct value in Spell::prepare, don't must be used before. - m_casttime = 0; // setup to correct value in Spell::prepare, don't must be used before. - m_timer = 0; // will set to castime in preper - - m_needAliveTargetMask = 0; - - // determine reflection - m_canReflect = false; - - if(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && (m_spellInfo->AttributesEx2 & 0x4)==0) - { - for(int j=0;j<3;j++) - { - if (m_spellInfo->Effect[j]==0) - continue; - - if(!IsPositiveTarget(m_spellInfo->EffectImplicitTargetA[j],m_spellInfo->EffectImplicitTargetB[j])) - m_canReflect = true; - else - m_canReflect = (m_spellInfo->AttributesEx & (1<<7)) ? true : false; - - if(m_canReflect) - continue; - else - break; - } - } - - CleanupTargetList(); -} - -Spell::~Spell() -{ -} - -void Spell::FillTargetMap() -{ - // TODO: ADD the correct target FILLS!!!!!! - - for(uint32 i=0;i<3;i++) - { - // not call for empty effect. - // Also some spells use not used effect targets for store targets for dummy effect in triggered spells - if(m_spellInfo->Effect[i]==0) - continue; - - // targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT filled in Spell::canCast call - if( m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT || - m_spellInfo->EffectImplicitTargetB[i] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[i] != TARGET_SELF ) - continue; - - // TODO: find a way so this is not needed? - // for area auras always add caster as target (needed for totems for example) - if(IsAreaAuraEffect(m_spellInfo->Effect[i])) - AddUnitTarget(m_caster, i); - - std::list tmpUnitMap; - - // TargetA/TargetB dependent from each other, we not switch to full support this dependences - // but need it support in some know cases - switch(m_spellInfo->EffectImplicitTargetA[i]) - { - case TARGET_ALL_AROUND_CASTER: - if( m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_PARTY || - m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER || - m_spellInfo->EffectImplicitTargetB[i]==TARGET_RANDOM_RAID_MEMBER ) - { - SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); - } - // Note: this hack with search required until GO casting not implemented - // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support - // currently each enemy selected explicitly and self cast damage - else if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA && m_spellInfo->Effect[i]==SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) - { - if(m_targets.getUnitTarget()) - tmpUnitMap.push_back(m_targets.getUnitTarget()); - } - else - { - SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); - SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); - } - break; - case TARGET_TABLE_X_Y_Z_COORDINATES: - // Only if target A, for target B (used in teleports) dest select in effect - SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); - break; - default: - switch(m_spellInfo->EffectImplicitTargetB[i]) - { - case TARGET_SCRIPT_COORDINATES: // B case filled in canCast but we need fill unit list base at A case - SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); - break; - default: - SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); - SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); - break; - } - break; - } - - if( (m_spellInfo->EffectImplicitTargetA[i]==0 || m_spellInfo->EffectImplicitTargetA[i]==TARGET_EFFECT_SELECT) && - (m_spellInfo->EffectImplicitTargetB[i]==0 || m_spellInfo->EffectImplicitTargetB[i]==TARGET_EFFECT_SELECT) ) - { - // add here custom effects that need default target. - // FOR EVERY TARGET TYPE THERE IS A DIFFERENT FILL!! - switch(m_spellInfo->Effect[i]) - { - case SPELL_EFFECT_DUMMY: - { - switch(m_spellInfo->Id) - { - case 20577: // Cannibalize - { - // non-standard target selection - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); - float max_range = GetSpellMaxRange(srange); - - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - WorldObject* result = NULL; - - MaNGOS::CannibalizeObjectCheck u_check(m_caster, max_range); - MaNGOS::WorldObjectSearcher searcher(result, u_check); - - TypeContainerVisitor, GridTypeMapContainer > grid_searcher(searcher); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - - if(!result) - { - TypeContainerVisitor, WorldTypeMapContainer > world_searcher(searcher); - cell_lock->Visit(cell_lock, world_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } - - if(result) - { - switch(result->GetTypeId()) - { - case TYPEID_UNIT: - case TYPEID_PLAYER: - tmpUnitMap.push_back((Unit*)result); - break; - case TYPEID_CORPSE: - m_targets.setCorpseTarget((Corpse*)result); - if(Player* owner = ObjectAccessor::FindPlayer(((Corpse*)result)->GetOwnerGUID())) - tmpUnitMap.push_back(owner); - break; - } - } - else - { - // clear cooldown at fail - if(m_caster->GetTypeId()==TYPEID_PLAYER) - { - ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(m_spellInfo->Id); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - - SendCastResult(SPELL_FAILED_NO_EDIBLE_CORPSES); - finish(false); - } - break; - } - default: - if(m_targets.getUnitTarget()) - tmpUnitMap.push_back(m_targets.getUnitTarget()); - break; - } - break; - } - case SPELL_EFFECT_RESURRECT: - case SPELL_EFFECT_PARRY: - case SPELL_EFFECT_CREATE_ITEM: - case SPELL_EFFECT_TRIGGER_SPELL: - case SPELL_EFFECT_TRIGGER_MISSILE: - case SPELL_EFFECT_LEARN_SPELL: - case SPELL_EFFECT_SKILL_STEP: - case SPELL_EFFECT_PROFICIENCY: - case SPELL_EFFECT_SUMMON_POSSESSED: - case SPELL_EFFECT_SUMMON_OBJECT_WILD: - case SPELL_EFFECT_SELF_RESURRECT: - case SPELL_EFFECT_REPUTATION: - if(m_targets.getUnitTarget()) - tmpUnitMap.push_back(m_targets.getUnitTarget()); - break; - case SPELL_EFFECT_SUMMON_PLAYER: - if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->GetSelection()) - { - Player* target = objmgr.GetPlayer(((Player*)m_caster)->GetSelection()); - if(target) - tmpUnitMap.push_back(target); - } - break; - case SPELL_EFFECT_RESURRECT_NEW: - if(m_targets.getUnitTarget()) - tmpUnitMap.push_back(m_targets.getUnitTarget()); - if(m_targets.getCorpseTargetGUID()) - { - Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID()); - if(corpse) - { - Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID()); - if(owner) - tmpUnitMap.push_back(owner); - } - } - break; - case SPELL_EFFECT_SUMMON: - if(m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED || m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED2) - { - if(m_targets.getUnitTarget()) - tmpUnitMap.push_back(m_targets.getUnitTarget()); - } - else - tmpUnitMap.push_back(m_caster); - break; - case SPELL_EFFECT_SUMMON_CHANGE_ITEM: - case SPELL_EFFECT_SUMMON_WILD: - case SPELL_EFFECT_SUMMON_GUARDIAN: - case SPELL_EFFECT_TRANS_DOOR: - case SPELL_EFFECT_ADD_FARSIGHT: - case SPELL_EFFECT_STUCK: - case SPELL_EFFECT_DESTROY_ALL_TOTEMS: - case SPELL_EFFECT_SUMMON_DEMON: - case SPELL_EFFECT_SKILL: - tmpUnitMap.push_back(m_caster); - break; - case SPELL_EFFECT_LEARN_PET_SPELL: - if(Pet* pet = m_caster->GetPet()) - tmpUnitMap.push_back(pet); - break; - case SPELL_EFFECT_ENCHANT_ITEM: - case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY: - case SPELL_EFFECT_DISENCHANT: - case SPELL_EFFECT_FEED_PET: - case SPELL_EFFECT_PROSPECTING: - if(m_targets.getItemTarget()) - AddItemTarget(m_targets.getItemTarget(), i); - break; - case SPELL_EFFECT_APPLY_AURA: - switch(m_spellInfo->EffectApplyAuraName[i]) - { - case SPELL_AURA_ADD_FLAT_MODIFIER: // some spell mods auras have 0 target modes instead expected TARGET_SELF(1) (and present for other ranks for same spell for example) - case SPELL_AURA_ADD_PCT_MODIFIER: - tmpUnitMap.push_back(m_caster); - break; - default: // apply to target in other case - if(m_targets.getUnitTarget()) - tmpUnitMap.push_back(m_targets.getUnitTarget()); - break; - } - break; - case SPELL_EFFECT_APPLY_AREA_AURA_PARTY: - // AreaAura - if(m_spellInfo->Attributes == 0x9050000 || m_spellInfo->Attributes == 0x10000) - SetTargetMap(i,TARGET_AREAEFFECT_PARTY,tmpUnitMap); - break; - case SPELL_EFFECT_SKIN_PLAYER_CORPSE: - if(m_targets.getUnitTarget()) - { - tmpUnitMap.push_back(m_targets.getUnitTarget()); - } - else if (m_targets.getCorpseTargetGUID()) - { - Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID()); - if(corpse) - { - Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID()); - if(owner) - tmpUnitMap.push_back(owner); - } - } - break; - default: - break; - } - } - if(IsChanneledSpell(m_spellInfo) && !tmpUnitMap.empty()) - m_needAliveTargetMask |= (1<GetTypeId() == TYPEID_PLAYER) - { - Player *me = (Player*)m_caster; - for (std::list::const_iterator itr = tmpUnitMap.begin(); itr != tmpUnitMap.end(); itr++) - { - Unit *owner = (*itr)->GetOwner(); - Unit *u = owner ? owner : (*itr); - if(u!=m_caster && u->IsPvP() && (!me->duel || me->duel->opponent != u)) - { - me->UpdatePvP(true); - me->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - break; - } - } - } - - for (std::list::iterator itr = tmpUnitMap.begin() ; itr != tmpUnitMap.end();) - { - if(!CheckTarget(*itr, i, false )) - { - itr = tmpUnitMap.erase(itr); - continue; - } - else - ++itr; - } - - for(std::list::iterator iunit= tmpUnitMap.begin();iunit != tmpUnitMap.end();++iunit) - AddUnitTarget((*iunit), i); - } -} - -void Spell::CleanupTargetList() -{ - m_UniqueTargetInfo.clear(); - m_UniqueGOTargetInfo.clear(); - m_UniqueItemInfo.clear(); - m_countOfHit = 0; - m_countOfMiss = 0; - m_delayMoment = 0; -} - -void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex) -{ - if( m_spellInfo->Effect[effIndex]==0 ) - return; - - uint64 targetGUID = pVictim->GetGUID(); - - // Lookup target in already in list - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - { - if (targetGUID == ihit->targetGUID) // Found in list - { - ihit->effectMask |= 1<SpellHitResult(pVictim, m_spellInfo, m_canReflect); - if (target.missCondition == SPELL_MISS_NONE) - ++m_countOfHit; - else - ++m_countOfMiss; - - // Spell have speed - need calculate incoming time - if (m_spellInfo->speed > 0.0f) - { - // calculate spell incoming interval - float dist = m_caster->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ()); - if (dist < 5.0f) dist = 5.0f; - target.timeDelay = (uint64) floor(dist / m_spellInfo->speed * 1000.0f); - - // Calculate minimum incoming time - if (m_delayMoment==0 || m_delayMoment>target.timeDelay) - m_delayMoment = target.timeDelay; - } - else - target.timeDelay = 0LL; - - // If target reflect spell back to caster - if (target.missCondition==SPELL_MISS_REFLECT) - { - // Calculate reflected spell result on caster - target.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect); - - if (target.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell - target.reflectResult = SPELL_MISS_PARRY; - - // Increase time interval for reflected spells by 1.5 - target.timeDelay+=target.timeDelay>>1; - } - else - target.reflectResult = SPELL_MISS_NONE; - - // Add target to list - m_UniqueTargetInfo.push_back(target); -} - -void Spell::AddUnitTarget(uint64 unitGUID, uint32 effIndex) -{ - Unit* unit = m_caster->GetGUID()==unitGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, unitGUID); - if (unit) - AddUnitTarget(unit, effIndex); -} - -void Spell::AddGOTarget(GameObject* pVictim, uint32 effIndex) -{ - if( m_spellInfo->Effect[effIndex]==0 ) - return; - - uint64 targetGUID = pVictim->GetGUID(); - - // Lookup target in already in list - for(std::list::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit) - { - if (targetGUID == ihit->targetGUID) // Found in list - { - ihit->effectMask |= 1<speed > 0.0f) - { - // calculate spell incoming interval - float dist = m_caster->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ()); - if (dist < 5.0f) dist = 5.0f; - target.timeDelay = (uint64) floor(dist / m_spellInfo->speed * 1000.0f); - if (m_delayMoment==0 || m_delayMoment>target.timeDelay) - m_delayMoment = target.timeDelay; - } - else - target.timeDelay = 0LL; - - ++m_countOfHit; - - // Add target to list - m_UniqueGOTargetInfo.push_back(target); -} - -void Spell::AddGOTarget(uint64 goGUID, uint32 effIndex) -{ - GameObject* go = ObjectAccessor::GetGameObject(*m_caster, goGUID); - if (go) - AddGOTarget(go, effIndex); -} - -void Spell::AddItemTarget(Item* pitem, uint32 effIndex) -{ - if( m_spellInfo->Effect[effIndex]==0 ) - return; - - // Lookup target in already in list - for(std::list::iterator ihit= m_UniqueItemInfo.begin();ihit != m_UniqueItemInfo.end();++ihit) - { - if (pitem == ihit->item) // Found in list - { - ihit->effectMask |= 1<GetTypeId()== TYPEID_PLAYER) - ((Player*)m_caster)->UpdateWeaponSkill(BASE_ATTACK); - - m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_MISS, m_spellInfo, m_IsTriggeredSpell); - break; - case SPELL_MISS_RESIST: - m_caster->ProcDamageAndSpell(unitTarget, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, damageSchoolMask, m_spellInfo, m_IsTriggeredSpell); - break; - case SPELL_MISS_DODGE: - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->UpdateDefense(); - - // Overpower - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARRIOR) - { - ((Player*) m_caster)->AddComboPoints(unitTarget, 1); - m_caster->StartReactiveTimer( REACTIVE_OVERPOWER ); - } - - // Riposte - if (unitTarget->getClass() != CLASS_ROGUE) - { - unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); - unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); - } - - m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_DODGE, m_spellInfo, m_IsTriggeredSpell); - break; - case SPELL_MISS_PARRY: - // Update victim defense ? - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->UpdateDefense(); - // Mongoose bite - set only Counterattack here - if (unitTarget->getClass() == CLASS_HUNTER) - { - unitTarget->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); - unitTarget->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); - } - else - { - unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); - unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); - } - m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_PARRY, m_spellInfo, m_IsTriggeredSpell); - break; - case SPELL_MISS_BLOCK: - unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); - unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); - - m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_BLOCK, m_spellInfo, m_IsTriggeredSpell); - break; - // Trigger from this events not supported - case SPELL_MISS_EVADE: - case SPELL_MISS_IMMUNE: - case SPELL_MISS_IMMUNE2: - case SPELL_MISS_DEFLECT: - case SPELL_MISS_ABSORB: - // Trigger from reflects need do after get reflect result - case SPELL_MISS_REFLECT: - break; - default: - break; - } - } -} - -void Spell::DoAllEffectOnTarget(TargetInfo *target) -{ - if (target->processed) // Check target - return; - target->processed = true; // Target checked in apply effects procedure - - // Get mask of effects for target - uint32 mask = target->effectMask; - if (mask == 0) // No effects - return; - - Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID); - if (!unit) - return; - - SpellMissInfo missInfo = target->missCondition; - // Need init unitTarget by default unit (can changed in code on reflect) - // Or on missInfo!=SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem) - unitTarget = unit; - - if (missInfo==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target - DoSpellHitOnUnit(unit, mask); - else if (missInfo == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit) - { - if (target->reflectResult == SPELL_MISS_NONE) // If reflected spell hit caster -> do all effect on him - DoSpellHitOnUnit(m_caster, mask); - } - - // Do triggers only on miss/resist/parry/dodge - if (missInfo!=SPELL_MISS_NONE) - doTriggers(missInfo); - - // Call scripted function for AI if this spell is casted upon a creature (except pets) - if(IS_CREATURE_GUID(target->targetGUID)) - { - // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished) - // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... ) - if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() ) - ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id); - - if(((Creature*)unit)->AI()) - ((Creature*)unit)->AI()->SpellHit(m_caster ,m_spellInfo); - } -} - -void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) -{ - if(!unit || !effectMask) - return; - - // Recheck immune (only for delayed spells) - if( m_spellInfo->speed && ( - unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo),true) || - unit->IsImmunedToSpell(m_spellInfo,true) )) - { - m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE); - return; - } - - if( m_caster != unit ) - { - if( !m_caster->IsFriendlyTo(unit) ) - { - // for delayed spells ignore not visible explicit target - if(m_spellInfo->speed > 0.0f && unit==m_targets.getUnitTarget() && !unit->isVisibleForOrDetect(m_caster,false)) - { - m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); - return; - } - - // exclude Arcane Missiles Dummy Aura aura for now (attack on hit) - // TODO: find way to not need this? - if(!(m_spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && - m_spellInfo->SpellFamilyFlags & 0x800LL)) - { - unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) - { - if(!unit->IsStandState() && !unit->hasUnitState(UNIT_STAT_STUNDED)) - unit->SetStandState(PLAYER_STATE_NONE); - - if(!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI()) - ((Creature*)unit)->AI()->AttackStart(m_caster); - - unit->SetInCombatWith(m_caster); - m_caster->SetInCombatWith(unit); - - if(Player *attackedPlayer = unit->GetCharmerOrOwnerPlayerOrPlayerItself()) - { - m_caster->SetContestedPvP(attackedPlayer); - } - unit->AddThreat(m_caster, 0.0f); - } - } - } - else - { - // for delayed spells ignore negative spells (after duel end) for friendly targets - if(m_spellInfo->speed > 0.0f && !IsPositiveSpell(m_spellInfo->Id)) - { - m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); - return; - } - - // assisting case, healing and resurrection - if(unit->hasUnitState(UNIT_STAT_ATTACK_PLAYER)) - m_caster->SetContestedPvP(); - if( unit->isInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) - { - m_caster->SetInCombatState(unit->GetCombatTimer() > 0); - unit->getHostilRefManager().threatAssist(m_caster, 0.0f); - } - } - } - - // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add - m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo,m_triggeredByAuraSpell); - m_diminishLevel = unit->GetDiminishing(m_diminishGroup); - // Increase Diminishing on unit, current informations for actually casts will use values above - if((GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_PLAYER && unit->GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_ALL) - unit->IncrDiminishing(m_diminishGroup); - - for(uint32 effectNumber=0;effectNumber<3;effectNumber++) - { - if (effectMask & (1<DmgMultiplier[effectNumber]; - // Apply multiplier mods - if(Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier,this); - m_damageMultipliers[effectNumber] *= multiplier; - } - } - } -} - -void Spell::DoAllEffectOnTarget(GOTargetInfo *target) -{ - if (target->processed) // Check target - return; - target->processed = true; // Target checked in apply effects procedure - - uint32 effectMask = target->effectMask; - if(!effectMask) - return; - - GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID); - if(!go) - return; - - for(uint32 effectNumber=0;effectNumber<3;effectNumber++) - if (effectMask & (1<GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() ) - ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); -} - -void Spell::DoAllEffectOnTarget(ItemTargetInfo *target) -{ - uint32 effectMask = target->effectMask; - if(!target->item || !effectMask) - return; - - for(uint32 effectNumber=0;effectNumber<3;effectNumber++) - if (effectMask & (1<item, NULL, effectNumber); -} - -bool Spell::IsAliveUnitPresentInTargetList() -{ - // Not need check return true - if (m_needAliveTargetMask == 0) - return true; - - uint8 needAliveTargetMask = m_needAliveTargetMask; - - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - { - if( ihit->missCondition == SPELL_MISS_NONE && (needAliveTargetMask & ihit->effectMask) ) - { - Unit *unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); - - if (unit && unit->isAlive()) - needAliveTargetMask &= ~ihit->effectMask; // remove from need alive mask effect that have alive target - } - } - - // is all effects from m_needAliveTargetMask have alive targets - return needAliveTargetMask==0; -} - -// Helper for Chain Healing -// Spell target first -// Raidmates then descending by injury suffered (MaxHealth - Health) -// Other players/mobs then descending by injury suffered (MaxHealth - Health) -struct ChainHealingOrder : public std::binary_function -{ - const Unit* MainTarget; - ChainHealingOrder(Unit const* Target) : MainTarget(Target) {}; - // functor for operator ">" - bool operator()(Unit const* _Left, Unit const* _Right) const - { - return (ChainHealingHash(_Left) < ChainHealingHash(_Right)); - } - int32 ChainHealingHash(Unit const* Target) const - { - if (Target == MainTarget) - return 0; - else if (Target->GetTypeId() == TYPEID_PLAYER && MainTarget->GetTypeId() == TYPEID_PLAYER && - ((Player const*)Target)->IsInSameRaidWith((Player const*)MainTarget)) - { - if (Target->GetHealth() == Target->GetMaxHealth()) - return 40000; - else - return 20000 - Target->GetMaxHealth() + Target->GetHealth(); - } - else - return 40000 - Target->GetMaxHealth() + Target->GetHealth(); - } -}; - -class ChainHealingFullHealth: std::unary_function -{ - public: - const Unit* MainTarget; - ChainHealingFullHealth(const Unit* Target) : MainTarget(Target) {}; - - bool operator()(const Unit* Target) - { - return (Target != MainTarget && Target->GetHealth() == Target->GetMaxHealth()); - } -}; - -// Helper for targets nearest to the spell target -// The spell target is always first unless there is a target at _completely_ the same position (unbelievable case) -struct TargetDistanceOrder : public std::binary_function -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator ">" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); - } -}; - -void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) -{ - float radius; - if (m_spellInfo->EffectRadiusIndex[i]) - radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - else - radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); - - if(m_originalCaster) - if(Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius,this); - - uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[i]; - if(m_originalCaster) - if(Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, EffectChainTarget, this); - - uint32 unMaxTargets = m_spellInfo->MaxAffectedTargets; - switch(cur) - { - case TARGET_TOTEM_EARTH: - case TARGET_TOTEM_WATER: - case TARGET_TOTEM_AIR: - case TARGET_TOTEM_FIRE: - case TARGET_SELF: - case TARGET_SELF2: - case TARGET_DYNAMIC_OBJECT: - case TARGET_AREAEFFECT_CUSTOM: - case TARGET_AREAEFFECT_CUSTOM_2: - case TARGET_SUMMON: - { - TagUnitMap.push_back(m_caster); - break; - } - case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA: - { - m_targets.m_targetMask = 0; - unMaxTargets = EffectChainTarget; - float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; - - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list tempUnitMap; - - { - MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(m_caster, m_caster, max_range); - MaNGOS::UnitListSearcher searcher(tempUnitMap, u_check); - - TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); - TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } - - if(tempUnitMap.empty()) - break; - - tempUnitMap.sort(TargetDistanceOrder(m_caster)); - - //Now to get us a random target that's in the initial range of the spell - uint32 t = 0; - std::list::iterator itr = tempUnitMap.begin(); - while(itr!= tempUnitMap.end() && (*itr)->GetDistance(m_caster) < radius) - ++t, ++itr; - - if(!t) - break; - - itr = tempUnitMap.begin(); - std::advance(itr, rand()%t); - Unit *pUnitTarget = *itr; - TagUnitMap.push_back(pUnitTarget); - - tempUnitMap.erase(itr); - - tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); - - t = unMaxTargets - 1; - Unit *prev = pUnitTarget; - std::list::iterator next = tempUnitMap.begin(); - - while(t && next != tempUnitMap.end() ) - { - if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) - break; - - if(!prev->IsWithinLOSInMap(*next)) - { - ++next; - continue; - } - - prev = *next; - TagUnitMap.push_back(prev); - tempUnitMap.erase(next); - tempUnitMap.sort(TargetDistanceOrder(prev)); - next = tempUnitMap.begin(); - - --t; - } - }break; - case TARGET_PET: - { - Pet* tmpUnit = m_caster->GetPet(); - if (!tmpUnit) break; - TagUnitMap.push_back(tmpUnit); - break; - } - case TARGET_CHAIN_DAMAGE: - { - if (EffectChainTarget <= 1) - { - Unit* pUnitTarget = SelectMagnetTarget(); - if(pUnitTarget) - TagUnitMap.push_back(pUnitTarget); - } - else - { - Unit* pUnitTarget = m_targets.getUnitTarget(); - if(!pUnitTarget) - break; - - unMaxTargets = EffectChainTarget; - - float max_range; - if(m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE) - max_range = radius; // - else - //FIXME: This very like horrible hack and wrong for most spells - max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; - - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Unit* originalCaster = GetOriginalCaster(); - if(originalCaster) - { - std::list tempUnitMap; - - { - MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(pUnitTarget, originalCaster, max_range); - MaNGOS::UnitListSearcher searcher(tempUnitMap, u_check); - - TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); - TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } - - tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); - - if(tempUnitMap.empty()) - break; - - if(*tempUnitMap.begin() == pUnitTarget) - tempUnitMap.erase(tempUnitMap.begin()); - - TagUnitMap.push_back(pUnitTarget); - uint32 t = unMaxTargets - 1; - Unit *prev = pUnitTarget; - std::list::iterator next = tempUnitMap.begin(); - - while(t && next != tempUnitMap.end() ) - { - if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) - break; - - if(!prev->IsWithinLOSInMap(*next)) - { - ++next; - continue; - } - - prev = *next; - TagUnitMap.push_back(prev); - tempUnitMap.erase(next); - tempUnitMap.sort(TargetDistanceOrder(prev)); - next = tempUnitMap.begin(); - - --t; - } - } - } - }break; - case TARGET_ALL_ENEMY_IN_AREA: - { - }break; - case TARGET_ALL_ENEMY_IN_AREA_INSTANT: - { - // targets the ground, not the units in the area - if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) - { - CellPair p(MaNGOS::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_AOE_DAMAGE); - - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - - // exclude caster (this can be important if this not original caster) - TagUnitMap.remove(m_caster); - } - }break; - case TARGET_DUELVSPLAYER_COORDINATES: - { - if(Unit* currentTarget = m_targets.getUnitTarget()) - { - m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ()); - TagUnitMap.push_back(currentTarget); - } - }break; - case TARGET_ALL_PARTY_AROUND_CASTER: - case TARGET_ALL_PARTY_AROUND_CASTER_2: - case TARGET_ALL_PARTY: - { - Player *pTarget = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself(); - Group *pGroup = pTarget ? pTarget->GetGroup() : NULL; - - if(pGroup) - { - uint8 subgroup = pTarget->GetSubGroup(); - - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* Target = itr->getSource(); - - // IsHostileTo check duel and controlled by enemy - if( Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target) ) - { - if( m_caster->IsWithinDistInMap(Target, radius) ) - TagUnitMap.push_back(Target); - - if(Pet* pet = Target->GetPet()) - if( m_caster->IsWithinDistInMap(pet, radius) ) - TagUnitMap.push_back(pet); - } - } - } - else - { - Unit* ownerOrSelf = pTarget ? pTarget : m_caster->GetCharmerOrOwnerOrSelf(); - if(ownerOrSelf==m_caster || m_caster->IsWithinDistInMap(ownerOrSelf, radius)) - TagUnitMap.push_back(ownerOrSelf); - if(Pet* pet = ownerOrSelf->GetPet()) - if( m_caster->IsWithinDistInMap(pet, radius) ) - TagUnitMap.push_back(pet); - } - }break; - case TARGET_RANDOM_RAID_MEMBER: - { - if (m_caster->GetTypeId() == TYPEID_PLAYER) - if(Player* target = ((Player*)m_caster)->GetNextRandomRaidMember(radius)) - TagUnitMap.push_back(target); - }break; - case TARGET_SINGLE_FRIEND: - case TARGET_SINGLE_FRIEND_2: - { - if(m_targets.getUnitTarget()) - TagUnitMap.push_back(m_targets.getUnitTarget()); - }break; - case TARGET_NONCOMBAT_PET: - { - if(Unit* target = m_targets.getUnitTarget()) - if( target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && ((Pet*)target)->getPetType() == MINI_PET) - TagUnitMap.push_back(target); - }break; - case TARGET_ALL_AROUND_CASTER: - { - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_AOE_DAMAGE); - - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - }break; - case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: - { - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_FRIENDLY); - - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - }break; - case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: - { - CellPair p(MaNGOS::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_FRIENDLY); - - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - }break; - // TARGET_SINGLE_PARTY means that the spells can only be casted on a party member and not on the caster (some sceals, fire shield from imp, etc..) - case TARGET_SINGLE_PARTY: - { - Unit *target = m_targets.getUnitTarget(); - // Thoses spells apparently can't be casted on the caster. - if( target && target != m_caster) - { - // Can only be casted on group's members or its pets - Group *pGroup = NULL; - - Unit* owner = m_caster->GetCharmerOrOwner(); - Unit *targetOwner = target->GetCharmerOrOwner(); - if(owner) - { - if(owner->GetTypeId() == TYPEID_PLAYER) - { - if( target == owner ) - { - TagUnitMap.push_back(target); - break; - } - pGroup = ((Player*)owner)->GetGroup(); - } - } - else if (m_caster->GetTypeId() == TYPEID_PLAYER) - { - if( targetOwner == m_caster && target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isPet()) - { - TagUnitMap.push_back(target); - break; - } - pGroup = ((Player*)m_caster)->GetGroup(); - } - - if(pGroup) - { - // Our target can also be a player's pet who's grouped with us or our pet. But can't be controlled player - if(targetOwner) - { - if( targetOwner->GetTypeId() == TYPEID_PLAYER && - target->GetTypeId()==TYPEID_UNIT && (((Creature*)target)->isPet()) && - target->GetOwnerGUID()==targetOwner->GetGUID() && - pGroup->IsMember(((Player*)targetOwner)->GetGUID())) - { - TagUnitMap.push_back(target); - } - } - // 1Our target can be a player who is on our group - else if (target->GetTypeId() == TYPEID_PLAYER && pGroup->IsMember(((Player*)target)->GetGUID())) - { - TagUnitMap.push_back(target); - } - } - } - }break; - case TARGET_GAMEOBJECT: - { - if(m_targets.getGOTarget()) - AddGOTarget(m_targets.getGOTarget(), i); - }break; - case TARGET_IN_FRONT_OF_CASTER: - { - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - bool inFront = m_spellInfo->SpellVisual != 3879; - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, inFront ? PUSH_IN_FRONT : PUSH_IN_BACK,SPELL_TARGETS_AOE_DAMAGE); - - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - }break; - case TARGET_DUELVSPLAYER: - { - Unit *target = m_targets.getUnitTarget(); - if(target) - { - if(m_caster->IsFriendlyTo(target)) - { - TagUnitMap.push_back(target); - } - else - { - Unit* pUnitTarget = SelectMagnetTarget(); - if(pUnitTarget) - TagUnitMap.push_back(pUnitTarget); - } - } - }break; - case TARGET_GAMEOBJECT_ITEM: - { - if(m_targets.getGOTargetGUID()) - AddGOTarget(m_targets.getGOTarget(), i); - else if(m_targets.getItemTarget()) - AddItemTarget(m_targets.getItemTarget(), i); - break; - } - case TARGET_MASTER: - { - if(Unit* owner = m_caster->GetCharmerOrOwner()) - TagUnitMap.push_back(owner); - break; - } - case TARGET_ALL_ENEMY_IN_AREA_CHANNELED: - { - // targets the ground, not the units in the area - if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) - { - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_AOE_DAMAGE); - - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } - }break; - case TARGET_MINION: - { - if(m_spellInfo->Effect[i] != SPELL_EFFECT_DUEL) - TagUnitMap.push_back(m_caster); - }break; - case TARGET_SINGLE_ENEMY: - { - Unit* pUnitTarget = SelectMagnetTarget(); - if(pUnitTarget) - TagUnitMap.push_back(pUnitTarget); - }break; - case TARGET_AREAEFFECT_PARTY: - { - Unit* owner = m_caster->GetCharmerOrOwner(); - Player *pTarget = NULL; - - if(owner) - { - TagUnitMap.push_back(m_caster); - if(owner->GetTypeId() == TYPEID_PLAYER) - pTarget = (Player*)owner; - } - else if (m_caster->GetTypeId() == TYPEID_PLAYER) - { - if(Unit* target = m_targets.getUnitTarget()) - { - if( target->GetTypeId() != TYPEID_PLAYER) - { - if(((Creature*)target)->isPet()) - { - Unit *targetOwner = target->GetOwner(); - if(targetOwner->GetTypeId() == TYPEID_PLAYER) - pTarget = (Player*)targetOwner; - } - } - else - pTarget = (Player*)target; - } - } - - Group* pGroup = pTarget ? pTarget->GetGroup() : NULL; - - if(pGroup) - { - uint8 subgroup = pTarget->GetSubGroup(); - - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* Target = itr->getSource(); - - // IsHostileTo check duel and controlled by enemy - if(Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target)) - { - if( pTarget->IsWithinDistInMap(Target, radius) ) - TagUnitMap.push_back(Target); - - if(Pet* pet = Target->GetPet()) - if( pTarget->IsWithinDistInMap(pet, radius) ) - TagUnitMap.push_back(pet); - } - } - } - else if (owner) - { - if(m_caster->IsWithinDistInMap(owner, radius)) - TagUnitMap.push_back(owner); - } - else if(pTarget) - { - TagUnitMap.push_back(pTarget); - - if(Pet* pet = pTarget->GetPet()) - if( m_caster->IsWithinDistInMap(pet, radius) ) - TagUnitMap.push_back(pet); - } - - }break; - case TARGET_SCRIPT: - { - if(m_targets.getUnitTarget()) - TagUnitMap.push_back(m_targets.getUnitTarget()); - if(m_targets.getItemTarget()) - AddItemTarget(m_targets.getItemTarget(), i); - }break; - case TARGET_SELF_FISHING: - { - TagUnitMap.push_back(m_caster); - }break; - case TARGET_CHAIN_HEAL: - { - Unit* pUnitTarget = m_targets.getUnitTarget(); - if(!pUnitTarget) - break; - - if (EffectChainTarget <= 1) - TagUnitMap.push_back(pUnitTarget); - else - { - unMaxTargets = EffectChainTarget; - float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; - - std::list tempUnitMap; - - { - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, tempUnitMap, max_range, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY); - - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - - } - - if(m_caster != pUnitTarget && std::find(tempUnitMap.begin(),tempUnitMap.end(),m_caster) == tempUnitMap.end() ) - tempUnitMap.push_front(m_caster); - - tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); - - if(tempUnitMap.empty()) - break; - - if(*tempUnitMap.begin() == pUnitTarget) - tempUnitMap.erase(tempUnitMap.begin()); - - TagUnitMap.push_back(pUnitTarget); - uint32 t = unMaxTargets - 1; - Unit *prev = pUnitTarget; - std::list::iterator next = tempUnitMap.begin(); - - while(t && next != tempUnitMap.end() ) - { - if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) - break; - - if(!prev->IsWithinLOSInMap(*next)) - { - ++next; - continue; - } - - if((*next)->GetHealth() == (*next)->GetMaxHealth()) - { - next = tempUnitMap.erase(next); - continue; - } - - prev = *next; - TagUnitMap.push_back(prev); - tempUnitMap.erase(next); - tempUnitMap.sort(TargetDistanceOrder(prev)); - next = tempUnitMap.begin(); - - --t; - } - } - }break; - case TARGET_CURRENT_ENEMY_COORDINATES: - { - Unit* currentTarget = m_targets.getUnitTarget(); - if(currentTarget) - { - TagUnitMap.push_back(currentTarget); - m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ()); - if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA_INSTANT) - { - CellPair p(MaNGOS::ComputeCellPair(currentTarget->GetPositionX(), currentTarget->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_TARGET_CENTER, SPELL_TARGETS_AOE_DAMAGE); - TypeContainerVisitor world_notifier(notifier); - TypeContainerVisitor grid_notifier(notifier); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } - } - }break; - case TARGET_AREAEFFECT_PARTY_AND_CLASS: - { - Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER - ? (Player*)m_targets.getUnitTarget() : NULL; - - Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL; - if(pGroup) - { - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* Target = itr->getSource(); - - // IsHostileTo check duel and controlled by enemy - if( Target && targetPlayer->IsWithinDistInMap(Target, radius) && - targetPlayer->getClass() == Target->getClass() && - !m_caster->IsHostileTo(Target) ) - { - TagUnitMap.push_back(Target); - } - } - } - else if(m_targets.getUnitTarget()) - TagUnitMap.push_back(m_targets.getUnitTarget()); - break; - } - case TARGET_TABLE_X_Y_Z_COORDINATES: - { - SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); - if(st) - { - if (st->target_mapId == m_caster->GetMapId()) - m_targets.setDestination(st->target_X, st->target_Y, st->target_Z); - - // if B==TARGET_TABLE_X_Y_Z_COORDINATES then A already fill all required targets - if (m_spellInfo->EffectImplicitTargetB[i] && m_spellInfo->EffectImplicitTargetB[i]!=TARGET_TABLE_X_Y_Z_COORDINATES) - { - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - SpellTargets targetB = SPELL_TARGETS_AOE_DAMAGE; - // Select friendly targets for positive effect - if (IsPositiveEffect(m_spellInfo->Id, i)) - targetB = SPELL_TARGETS_FRIENDLY; - - MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_DEST_CENTER, targetB); - - TypeContainerVisitor world_notifier(notifier); - TypeContainerVisitor grid_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } - } - else - sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); - }break; - case TARGET_BEHIND_VICTIM: - { - Unit *pTarget = m_caster->getVictim(); - if(!pTarget && m_caster->GetTypeId() == TYPEID_PLAYER) - pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); - - if(pTarget) - { - float _target_x, _target_y, _target_z; - pTarget->GetClosePoint(_target_x, _target_y, _target_z, m_caster->GetObjectSize(), CONTACT_DISTANCE, M_PI); - if(pTarget->IsWithinLOS(_target_x,_target_y,_target_z)) - m_targets.setDestination(_target_x, _target_y, _target_z); - } - }break; - default: - break; - } - - if (unMaxTargets && TagUnitMap.size() > unMaxTargets) - { - // make sure one unit is always removed per iteration - uint32 removed_utarget = 0; - for (std::list::iterator itr = TagUnitMap.begin(), next; itr != TagUnitMap.end(); itr = next) - { - next = itr; - ++next; - if (!*itr) continue; - if ((*itr) == m_targets.getUnitTarget()) - { - TagUnitMap.erase(itr); - removed_utarget = 1; - // break; - } - } - // remove random units from the map - while (TagUnitMap.size() > unMaxTargets - removed_utarget) - { - uint32 poz = urand(0, TagUnitMap.size()-1); - for (std::list::iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end(); ++itr, --poz) - { - if (!*itr) continue; - if (!poz) - { - TagUnitMap.erase(itr); - break; - } - } - } - // the player's target will always be added to the map - if (removed_utarget && m_targets.getUnitTarget()) - TagUnitMap.push_back(m_targets.getUnitTarget()); - } -} - -void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura) -{ - m_targets = *targets; - - m_spellState = SPELL_STATE_PREPARING; - - m_castPositionX = m_caster->GetPositionX(); - m_castPositionY = m_caster->GetPositionY(); - m_castPositionZ = m_caster->GetPositionZ(); - m_castOrientation = m_caster->GetOrientation(); - - if(triggeredByAura) - m_triggeredByAuraSpell = triggeredByAura->GetSpellProto(); - - // create and add update event for this spell - SpellEvent* Event = new SpellEvent(this); - m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1)); - - //Prevent casting at cast another spell (ServerSide check) - if(m_caster->IsNonMeleeSpellCasted(false, true) && m_cast_count) - { - SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS); - finish(false); - return; - } - - // Fill cost data - m_powerCost = CalculatePowerCost(); - - uint8 result = CanCast(true); - if(result != 0 && !IsAutoRepeat()) //always cast autorepeat dummy for triggering - { - if(triggeredByAura) - { - SendChannelUpdate(0); - triggeredByAura->SetAuraDuration(0); - } - SendCastResult(result); - finish(false); - return; - } - - // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail) - m_casttime = GetSpellCastTime(m_spellInfo, this); - - // set timer base at cast time - ReSetTimer(); - - // stealth must be removed at cast starting (at show channel bar) - // skip triggered spell (item equip spell casting and other not explicit character casts/item uses) - if ( !m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo) ) - { - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - m_caster->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - } - - if(m_IsTriggeredSpell) - cast(true); - else - { - m_caster->SetCurrentCastedSpell( this ); - m_selfContainer = &(m_caster->m_currentSpells[GetCurrentContainer()]); - SendSpellStart(); - } -} - -void Spell::cancel() -{ - if(m_spellState == SPELL_STATE_FINISHED) - return; - - m_autoRepeat = false; - switch (m_spellState) - { - case SPELL_STATE_PREPARING: - case SPELL_STATE_DELAYED: - { - SendInterrupted(0); - SendCastResult(SPELL_FAILED_INTERRUPTED); - } break; - - case SPELL_STATE_CASTING: - { - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - { - if( ihit->missCondition == SPELL_MISS_NONE ) - { - Unit* unit = m_caster->GetGUID()==(*ihit).targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); - if( unit && unit->isAlive() ) - unit->RemoveAurasDueToSpell(m_spellInfo->Id); - } - } - - m_caster->RemoveAurasDueToSpell(m_spellInfo->Id); - SendChannelUpdate(0); - SendInterrupted(0); - SendCastResult(SPELL_FAILED_INTERRUPTED); - } break; - - default: - { - } break; - } - - finish(false); - m_caster->RemoveDynObject(m_spellInfo->Id); - m_caster->RemoveGameObject(m_spellInfo->Id,true); -} - -void Spell::cast(bool skipCheck) -{ - uint8 castResult = 0; - - // update pointers base at GUIDs to prevent access to non-existed already object - UpdatePointers(); - - // cancel at lost main target unit - if(!m_targets.getUnitTarget() && m_targets.getUnitTargetGUID() && m_targets.getUnitTargetGUID() != m_caster->GetGUID()) - { - cancel(); - return; - } - - if(m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster) - m_caster->SetInFront(m_targets.getUnitTarget()); - - castResult = CheckPower(); - if(castResult != 0) - { - SendCastResult(castResult); - finish(false); - return; - } - - // triggered cast called from Spell::prepare where it was already checked - if(!skipCheck) - { - castResult = CanCast(false); - if(castResult != 0) - { - SendCastResult(castResult); - finish(false); - return; - } - } - - // Conflagrate - consumes immolate - if ((m_spellInfo->TargetAuraState == AURA_STATE_IMMOLATE) && m_targets.getUnitTarget()) - { - // for caster applied auras only - Unit::AuraList const &mPeriodic = m_targets.getUnitTarget()->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i) - { - if( (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && ((*i)->GetSpellProto()->SpellFamilyFlags & 4) && - (*i)->GetCasterGUID()==m_caster->GetGUID() ) - { - m_targets.getUnitTarget()->RemoveAura((*i)->GetId(), (*i)->GetEffIndex()); - break; - } - } - } - - // traded items have trade slot instead of guid in m_itemTargetGUID - // set to real guid to be sent later to the client - m_targets.updateTradeSlotItem(); - - // CAST SPELL - SendSpellCooldown(); - - TakePower(); - TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot - FillTargetMap(); - - if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in Take*/FillTargetMap - return; - - SendCastResult(castResult); - SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... - - // Pass cast spell event to handler (not send triggered by aura spells) - if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED && !m_triggeredByAuraSpell) - { - m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), PROC_FLAG_CAST_SPELL, PROC_FLAG_NONE, 0, SPELL_SCHOOL_MASK_NONE, m_spellInfo, m_IsTriggeredSpell); - - // update pointers base at GUIDs to prevent access to non-existed already object - UpdatePointers(); // pointers can be invalidate at triggered spell casting - } - - // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells - if (m_spellInfo->speed > 0.0f) - { - - // Remove used for cast item if need (it can be already NULL after TakeReagents call - // in case delayed spell remove item at cast delay start - TakeCastItem(); - - // Okay, maps created, now prepare flags - m_immediateHandled = false; - m_spellState = SPELL_STATE_DELAYED; - SetDelayStart(0); - } - else - { - // Immediate spell, no big deal - handle_immediate(); - } -} - -void Spell::handle_immediate() -{ - // start channeling if applicable - if(IsChanneledSpell(m_spellInfo)) - { - m_spellState = SPELL_STATE_CASTING; - SendChannelStart(GetSpellDuration(m_spellInfo)); - } - - // process immediate effects (items, ground, etc.) also initialize some variables - _handle_immediate_phase(); - - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - DoAllEffectOnTarget(&(*ihit)); - - for(std::list::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit) - DoAllEffectOnTarget(&(*ihit)); - - // spell is finished, perform some last features of the spell here - _handle_finish_phase(); - - // Remove used for cast item if need (it can be already NULL after TakeReagents call - TakeCastItem(); - - if(m_spellState != SPELL_STATE_CASTING) - finish(true); // successfully finish spell cast (not last in case autorepeat or channel spell) -} - -uint64 Spell::handle_delayed(uint64 t_offset) -{ - uint64 next_time = 0; - - if (!m_immediateHandled) - { - _handle_immediate_phase(); - m_immediateHandled = true; - } - - // now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases) - for(std::list::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end();++ihit) - { - if (ihit->processed == false) - { - if ( ihit->timeDelay <= t_offset ) - DoAllEffectOnTarget(&(*ihit)); - else if( next_time == 0 || ihit->timeDelay < next_time ) - next_time = ihit->timeDelay; - } - } - - // now recheck gameobject targeting correctness - for(std::list::iterator ighit= m_UniqueGOTargetInfo.begin(); ighit != m_UniqueGOTargetInfo.end();++ighit) - { - if (ighit->processed == false) - { - if ( ighit->timeDelay <= t_offset ) - DoAllEffectOnTarget(&(*ighit)); - else if( next_time == 0 || ighit->timeDelay < next_time ) - next_time = ighit->timeDelay; - } - } - // All targets passed - need finish phase - if (next_time == 0) - { - // spell is finished, perform some last features of the spell here - _handle_finish_phase(); - - finish(true); // successfully finish spell cast - - // return zero, spell is finished now - return 0; - } - else - { - // spell is unfinished, return next execution time - return next_time; - } -} - -void Spell::_handle_immediate_phase() -{ - // handle some immediate features of the spell here - HandleThreatSpells(m_spellInfo->Id); - - m_needSpellLog = IsNeedSendToClient(); - for(uint32 j = 0;j<3;j++) - { - if(m_spellInfo->Effect[j]==0) - continue; - - // apply Send Event effect to ground in case empty target lists - if( m_spellInfo->Effect[j] == SPELL_EFFECT_SEND_EVENT && !HaveTargetsForEffect(j) ) - { - HandleEffects(NULL,NULL,NULL, j); - continue; - } - - // Don't do spell log, if is school damage spell - if(m_spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || m_spellInfo->Effect[j] == 0) - m_needSpellLog = false; - - uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[j]; - if(m_originalCaster) - if(Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, EffectChainTarget, this); - - // initialize multipliers - m_damageMultipliers[j] = 1.0f; - if( (m_spellInfo->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || m_spellInfo->EffectImplicitTargetA[j] == TARGET_CHAIN_HEAL) && - (EffectChainTarget > 1) ) - m_applyMultiplierMask |= 1 << j; - } - - // initialize Diminishing Returns Data - m_diminishLevel = DIMINISHING_LEVEL_1; - m_diminishGroup = DIMINISHING_NONE; - - // process items - for(std::list::iterator ihit= m_UniqueItemInfo.begin();ihit != m_UniqueItemInfo.end();++ihit) - DoAllEffectOnTarget(&(*ihit)); - - // process ground - for(uint32 j = 0;j<3;j++) - { - // persistent area auras target only the ground - if(m_spellInfo->Effect[j] == SPELL_EFFECT_PERSISTENT_AREA_AURA) - HandleEffects(NULL,NULL,NULL, j); - } -} - -void Spell::_handle_finish_phase() -{ - // spell log - if(m_needSpellLog) - SendLogExecute(); -} - -void Spell::SendSpellCooldown() -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* _player = (Player*)m_caster; - // Add cooldown for max (disable spell) - // Cooldown started on SendCooldownEvent call - if (m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) - { - _player->AddSpellCooldown(m_spellInfo->Id, 0, time(NULL) - 1); - return; - } - - // init cooldown values - uint32 cat = 0; - int32 rec = -1; - int32 catrec = -1; - - // some special item spells without correct cooldown in SpellInfo - // cooldown information stored in item prototype - // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client. - - if(m_CastItem) - { - ItemPrototype const* proto = m_CastItem->GetProto(); - if(proto) - { - for(int idx = 0; idx < 5; ++idx) - { - if(proto->Spells[idx].SpellId == m_spellInfo->Id) - { - cat = proto->Spells[idx].SpellCategory; - rec = proto->Spells[idx].SpellCooldown; - catrec = proto->Spells[idx].SpellCategoryCooldown; - break; - } - } - } - } - - // if no cooldown found above then base at DBC data - if(rec < 0 && catrec < 0) - { - cat = m_spellInfo->Category; - rec = m_spellInfo->RecoveryTime; - catrec = m_spellInfo->CategoryRecoveryTime; - } - - // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK) - // prevent 0 cooldowns set by another way - if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351)) - rec = _player->GetAttackTime(RANGED_ATTACK); - - // Now we have cooldown data (if found any), time to apply mods - if(rec > 0) - _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, rec, this); - - if(catrec > 0) - _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, catrec, this); - - // replace negative cooldowns by 0 - if (rec < 0) rec = 0; - if (catrec < 0) catrec = 0; - - // no cooldown after applying spell mods - if( rec == 0 && catrec == 0) - return; - - time_t curTime = time(NULL); - - time_t catrecTime = catrec ? curTime+catrec/1000 : 0; // in secs - time_t recTime = rec ? curTime+rec/1000 : catrecTime;// in secs - - // self spell cooldown - if(recTime > 0) - _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, recTime); - - // category spells - if (catrec > 0) - { - SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat); - if(i_scstore != sSpellCategoryStore.end()) - { - for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset) - { - if(*i_scset == m_spellInfo->Id) // skip main spell, already handled above - continue; - - _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime); - } - } - } -} - -void Spell::update(uint32 difftime) -{ - // update pointers based at it's GUIDs - UpdatePointers(); - - if(m_targets.getUnitTargetGUID() && !m_targets.getUnitTarget()) - { - cancel(); - return; - } - - // check if the player caster has moved before the spell finished - if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) && - (m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) && - (m_spellInfo->Effect[0] != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING))) - { - // always cancel for channeled spells - if( m_spellState == SPELL_STATE_CASTING ) - cancel(); - // don't cancel for melee, autorepeat, triggered and instant spells - else if(!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) - cancel(); - } - - switch(m_spellState) - { - case SPELL_STATE_PREPARING: - { - if(m_timer) - { - if(difftime >= m_timer) - m_timer = 0; - else - m_timer -= difftime; - } - - if(m_timer == 0 && !IsNextMeleeSwingSpell() && !IsAutoRepeat()) - cast(); - } break; - case SPELL_STATE_CASTING: - { - if(m_timer > 0) - { - if( m_caster->GetTypeId() == TYPEID_PLAYER ) - { - // check if player has jumped before the channeling finished - if(m_caster->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING)) - cancel(); - - // check for incapacitating player states - if( m_caster->hasUnitState(UNIT_STAT_STUNDED | UNIT_STAT_CONFUSED)) - cancel(); - - // check if player has turned if flag is set - if( m_spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_TURNING && m_castOrientation != m_caster->GetOrientation() ) - cancel(); - } - - // check if there are alive targets left - if (!IsAliveUnitPresentInTargetList()) - { - SendChannelUpdate(0); - finish(); - } - - if(difftime >= m_timer) - m_timer = 0; - else - m_timer -= difftime; - } - - if(m_timer == 0) - { - SendChannelUpdate(0); - - // channeled spell processed independently for quest targeting - // cast at creature (or GO) quest objectives update at successful cast channel finished - // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... ) - if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() ) - { - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - { - TargetInfo* target = &*ihit; - if(!IS_CREATURE_GUID(target->targetGUID)) - continue; - - Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID); - if (unit==NULL) - continue; - - ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id); - } - - for(std::list::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit) - { - GOTargetInfo* target = &*ihit; - - GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID); - if(!go) - continue; - - ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); - } - } - - finish(); - } - } break; - default: - { - }break; - } -} - -void Spell::finish(bool ok) -{ - if(!m_caster) - return; - - if(m_spellState == SPELL_STATE_FINISHED) - return; - - m_spellState = SPELL_STATE_FINISHED; - - //remove spell mods - if (m_caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)m_caster)->RemoveSpellMods(this); - - // other code related only to successfully finished spells - if(!ok) - return; - - //handle SPELL_AURA_ADD_TARGET_TRIGGER auras - Unit::AuraList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER); - for(Unit::AuraList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i) - { - SpellEntry const *auraSpellInfo = (*i)->GetSpellProto(); - uint32 auraSpellIdx = (*i)->GetEffIndex(); - if (IsAffectedBy(auraSpellInfo, auraSpellIdx)) - { - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - if( ihit->effectMask & (1<GetGUID() let load auras at login and speedup most often case - Unit *unit = m_caster->GetGUID()== ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); - if (unit && unit->isAlive()) - { - // Calculate chance at that moment (can be depend for example from combo points) - int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(),unit); - - if(roll_chance_i(chance)) - m_caster->CastSpell(unit, auraSpellInfo->EffectTriggerSpell[auraSpellIdx], true, NULL, (*i)); - } - } - } - } - - if (IsMeleeAttackResetSpell()) - { - m_caster->resetAttackTimer(BASE_ATTACK); - if(m_caster->haveOffhandWeapon()) - m_caster->resetAttackTimer(OFF_ATTACK); - } - - /*if (IsRangedAttackResetSpell()) - m_caster->resetAttackTimer(RANGED_ATTACK);*/ - - // Clear combo at finish state - if(m_caster->GetTypeId() == TYPEID_PLAYER && NeedsComboPoints(m_spellInfo)) - ((Player*)m_caster)->ClearComboPoints(); - - // call triggered spell only at successful cast (after clear combo points -> for add some if need) - if(!m_TriggerSpells.empty()) - TriggerSpell(); - - // Stop Attack for some spells - if( m_spellInfo->Attributes & SPELL_ATTR_STOP_ATTACK_TARGET ) - m_caster->AttackStop(); -} - -void Spell::SendCastResult(uint8 result) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if(((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time - return; - - if(result != 0) - { - WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); - data << uint32(m_spellInfo->Id); - data << uint8(result); // problem - data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) - switch (result) - { - case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(m_spellInfo->RequiresSpellFocus); - break; - case SPELL_FAILED_REQUIRES_AREA: - // hardcode areas limitation case - if( m_spellInfo->Id==41618 || m_spellInfo->Id==41620 ) - data << uint32(3842); - else if( m_spellInfo->Id==41617 || m_spellInfo->Id==41619 ) - data << uint32(3905); - // normal case - else - data << uint32(m_spellInfo->AreaId); - break; - case SPELL_FAILED_TOTEMS: - if(m_spellInfo->Totem[0]) - data << uint32(m_spellInfo->Totem[0]); - if(m_spellInfo->Totem[1]) - data << uint32(m_spellInfo->Totem[1]); - break; - case SPELL_FAILED_TOTEM_CATEGORY: - if(m_spellInfo->TotemCategory[0]) - data << uint32(m_spellInfo->TotemCategory[0]); - if(m_spellInfo->TotemCategory[1]) - data << uint32(m_spellInfo->TotemCategory[1]); - break; - case SPELL_FAILED_EQUIPPED_ITEM_CLASS: - data << uint32(m_spellInfo->EquippedItemClass); - data << uint32(m_spellInfo->EquippedItemSubClassMask); - data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); - break; - } - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - else - { - WorldPacket data(SMSG_CLEAR_EXTRA_AURA_INFO, (8+4)); - data.append(m_caster->GetPackGUID()); - data << uint32(m_spellInfo->Id); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } -} - -void Spell::SendSpellStart() -{ - if(!IsNeedSendToClient()) - return; - - sLog.outDebug("Sending SMSG_SPELL_START id=%u",m_spellInfo->Id); - - uint16 castFlags = CAST_FLAG_UNKNOWN1; - if(IsRangedSpell()) - castFlags |= CAST_FLAG_AMMO; - - Unit * target; - if(!m_targets.getUnitTarget()) - target = m_caster; - else - target = m_targets.getUnitTarget(); - - WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); - if(m_CastItem) - data.append(m_CastItem->GetPackGUID()); - else - data.append(m_caster->GetPackGUID()); - - data.append(m_caster->GetPackGUID()); - data << uint32(m_spellInfo->Id); - data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) - data << uint16(castFlags); - data << uint32(m_timer); - - m_targets.write(&data); - - if( castFlags & CAST_FLAG_AMMO ) - WriteAmmoToPacket(&data); - - m_caster->SendMessageToSet(&data, true); -} - -void Spell::SendSpellGo() -{ - // not send invisible spell casting - if(!IsNeedSendToClient()) - return; - - sLog.outDebug("Sending SMSG_SPELL_GO id=%u",m_spellInfo->Id); - - Unit * target; - if(!m_targets.getUnitTarget()) - target = m_caster; - else - target = m_targets.getUnitTarget(); - - uint16 castFlags = CAST_FLAG_UNKNOWN3; - if(IsRangedSpell()) - castFlags |= CAST_FLAG_AMMO; - - WorldPacket data(SMSG_SPELL_GO, 50); // guess size - if(m_CastItem) - data.append(m_CastItem->GetPackGUID()); - else - data.append(m_caster->GetPackGUID()); - - data.append(m_caster->GetPackGUID()); - data << uint32(m_spellInfo->Id); - data << uint16(castFlags); - data << uint32(getMSTime()); // timestamp - - WriteSpellGoTargets(&data); - - m_targets.write(&data); - - if( castFlags & CAST_FLAG_AMMO ) - WriteAmmoToPacket(&data); - - m_caster->SendMessageToSet(&data, true); -} - -void Spell::WriteAmmoToPacket( WorldPacket * data ) -{ - uint32 ammoInventoryType = 0; - uint32 ammoDisplayID = 0; - - if (m_caster->GetTypeId() == TYPEID_PLAYER) - { - Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK ); - if(pItem) - { - ammoInventoryType = pItem->GetProto()->InventoryType; - if( ammoInventoryType == INVTYPE_THROWN ) - ammoDisplayID = pItem->GetProto()->DisplayInfoID; - else - { - uint32 ammoID = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID); - if(ammoID) - { - ItemPrototype const *pProto = objmgr.GetItemPrototype( ammoID ); - if(pProto) - { - ammoDisplayID = pProto->DisplayInfoID; - ammoInventoryType = pProto->InventoryType; - } - } - else if(m_caster->GetDummyAura(46699)) // Requires No Ammo - { - ammoDisplayID = 5996; // normal arrow - ammoInventoryType = INVTYPE_AMMO; - } - } - } - } - // TODO: implement selection ammo data based at ranged weapon stored in equipmodel/equipinfo/equipslot fields - - *data << uint32(ammoDisplayID); - *data << uint32(ammoInventoryType); -} - -void Spell::WriteSpellGoTargets( WorldPacket * data ) -{ - *data << (uint8)m_countOfHit; - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - if ((*ihit).missCondition == SPELL_MISS_NONE) // Add only hits - *data << uint64(ihit->targetGUID); - - for(std::list::iterator ighit= m_UniqueGOTargetInfo.begin();ighit != m_UniqueGOTargetInfo.end();++ighit) - *data << uint64(ighit->targetGUID); // Always hits - - *data << (uint8)m_countOfMiss; - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - { - if( ihit->missCondition != SPELL_MISS_NONE ) // Add only miss - { - *data << uint64(ihit->targetGUID); - *data << uint8(ihit->missCondition); - if( ihit->missCondition == SPELL_MISS_REFLECT ) - *data << uint8(ihit->reflectResult); - } - } -} - -void Spell::SendLogExecute() -{ - Unit *target = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster; - - WorldPacket data(SMSG_SPELLLOGEXECUTE, (8+4+4+4+4+8)); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - data.append(m_caster->GetPackGUID()); - else - data.append(target->GetPackGUID()); - - data << uint32(m_spellInfo->Id); - uint32 count1 = 1; - data << uint32(count1); // count1 (effect count?) - for(uint32 i = 0; i < count1; ++i) - { - data << uint32(m_spellInfo->Effect[0]); // spell effect? - uint32 count2 = 1; - data << uint32(count2); // count2 (target count?) - for(uint32 j = 0; j < count2; ++j) - { - switch(m_spellInfo->Effect[0]) - { - case SPELL_EFFECT_POWER_DRAIN: - if(Unit *unit = m_targets.getUnitTarget()) - data.append(unit->GetPackGUID()); - else - data << uint8(0); - data << uint32(0); - data << uint32(0); - data << float(0); - break; - case SPELL_EFFECT_ADD_EXTRA_ATTACKS: - if(Unit *unit = m_targets.getUnitTarget()) - data.append(unit->GetPackGUID()); - else - data << uint8(0); - data << uint32(0); // count? - break; - case SPELL_EFFECT_INTERRUPT_CAST: - if(Unit *unit = m_targets.getUnitTarget()) - data.append(unit->GetPackGUID()); - else - data << uint8(0); - data << uint32(0); // spellid - break; - case SPELL_EFFECT_DURABILITY_DAMAGE: - if(Unit *unit = m_targets.getUnitTarget()) - data.append(unit->GetPackGUID()); - else - data << uint8(0); - data << uint32(0); - data << uint32(0); - break; - case SPELL_EFFECT_OPEN_LOCK: - case SPELL_EFFECT_OPEN_LOCK_ITEM: - if(Item *item = m_targets.getItemTarget()) - data.append(item->GetPackGUID()); - else - data << uint8(0); - break; - case SPELL_EFFECT_CREATE_ITEM: - data << uint32(m_spellInfo->EffectItemType[0]); - break; - case SPELL_EFFECT_SUMMON: - case SPELL_EFFECT_SUMMON_WILD: - case SPELL_EFFECT_SUMMON_GUARDIAN: - case SPELL_EFFECT_TRANS_DOOR: - case SPELL_EFFECT_SUMMON_PET: - case SPELL_EFFECT_SUMMON_POSSESSED: - case SPELL_EFFECT_SUMMON_TOTEM: - case SPELL_EFFECT_SUMMON_OBJECT_WILD: - case SPELL_EFFECT_CREATE_HOUSE: - case SPELL_EFFECT_DUEL: - case SPELL_EFFECT_SUMMON_TOTEM_SLOT1: - case SPELL_EFFECT_SUMMON_TOTEM_SLOT2: - case SPELL_EFFECT_SUMMON_TOTEM_SLOT3: - case SPELL_EFFECT_SUMMON_TOTEM_SLOT4: - case SPELL_EFFECT_SUMMON_PHANTASM: - case SPELL_EFFECT_SUMMON_CRITTER: - case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: - case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: - case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: - case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: - case SPELL_EFFECT_SUMMON_DEMON: - case SPELL_EFFECT_150: - if(Unit *unit = m_targets.getUnitTarget()) - data.append(unit->GetPackGUID()); - else if(m_targets.getItemTargetGUID()) - data.appendPackGUID(m_targets.getItemTargetGUID()); - else if(GameObject *go = m_targets.getGOTarget()) - data.append(go->GetPackGUID()); - else - data << uint8(0); // guid - break; - case SPELL_EFFECT_FEED_PET: - data << uint32(m_targets.getItemTargetEntry()); - break; - case SPELL_EFFECT_DISMISS_PET: - if(Unit *unit = m_targets.getUnitTarget()) - data.append(unit->GetPackGUID()); - else - data << uint8(0); - break; - default: - return; - } - } - } - - m_caster->SendMessageToSet(&data, true); -} - -void Spell::SendInterrupted(uint8 result) -{ - WorldPacket data(SMSG_SPELL_FAILURE, (8+4+1)); - data.append(m_caster->GetPackGUID()); - data << m_spellInfo->Id; - data << result; - m_caster->SendMessageToSet(&data, true); - - data.Initialize(SMSG_SPELL_FAILED_OTHER, (8+4)); - data.append(m_caster->GetPackGUID()); - data << m_spellInfo->Id; - m_caster->SendMessageToSet(&data, true); -} - -void Spell::SendChannelUpdate(uint32 time) -{ - if(time == 0) - { - m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,0); - m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,0); - } - - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data( MSG_CHANNEL_UPDATE, 8+4 ); - data.append(m_caster->GetPackGUID()); - data << time; - - ((Player*)m_caster)->GetSession()->SendPacket( &data ); -} - -void Spell::SendChannelStart(uint32 duration) -{ - WorldObject* target = NULL; - - // select first not rsusted target from target list for _0_ effect - if(!m_UniqueTargetInfo.empty()) - { - for(std::list::iterator itr= m_UniqueTargetInfo.begin();itr != m_UniqueTargetInfo.end();++itr) - { - if( (itr->effectMask & (1<<0)) && itr->reflectResult==SPELL_MISS_NONE && itr->targetGUID != m_caster->GetGUID()) - { - target = ObjectAccessor::GetUnit(*m_caster, itr->targetGUID); - break; - } - } - } - else if(!m_UniqueGOTargetInfo.empty()) - { - for(std::list::iterator itr= m_UniqueGOTargetInfo.begin();itr != m_UniqueGOTargetInfo.end();++itr) - { - if(itr->effectMask & (1<<0) ) - { - target = ObjectAccessor::GetGameObject(*m_caster, itr->targetGUID); - break; - } - } - } - - if (m_caster->GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data( MSG_CHANNEL_START, (8+4+4) ); - data.append(m_caster->GetPackGUID()); - data << m_spellInfo->Id; - data << duration; - - ((Player*)m_caster)->GetSession()->SendPacket( &data ); - } - - m_timer = duration; - if(target) - m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, target->GetGUID()); - m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, m_spellInfo->Id); -} - -void Spell::SendResurrectRequest(Player* target) -{ - WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+2+4)); - data << m_caster->GetGUID(); - data << uint32(1) << uint16(0) << uint32(1); - - target->GetSession()->SendPacket(&data); -} - -void Spell::SendPlaySpellVisual(uint32 SpellID) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); - data << m_caster->GetGUID(); - data << SpellID; - ((Player*)m_caster)->GetSession()->SendPacket(&data); -} - -void Spell::TakeCastItem() -{ - if(!m_CastItem || m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // not remove cast item at triggered spell (equipping, weapon damage, etc) - if(m_IsTriggeredSpell) - return; - - ItemPrototype const *proto = m_CastItem->GetProto(); - - if(!proto) - { - // This code is to avoid a crash - // I'm not sure, if this is really an error, but I guess every item needs a prototype - sLog.outError("Cast item has no item prototype highId=%d, lowId=%d",m_CastItem->GetGUIDHigh(), m_CastItem->GetGUIDLow()); - return; - } - - bool expendable = false; - bool withoutCharges = false; - - for (int i = 0; i<5; i++) - { - if (proto->Spells[i].SpellId) - { - // item has limited charges - if (proto->Spells[i].SpellCharges) - { - if (proto->Spells[i].SpellCharges < 0) - expendable = true; - - int32 charges = m_CastItem->GetSpellCharges(i); - - // item has charges left - if (charges) - { - (charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use - if (proto->Stackable < 2) - m_CastItem->SetSpellCharges(i, charges); - m_CastItem->SetState(ITEM_CHANGED, (Player*)m_caster); - } - - // all charges used - withoutCharges = (charges == 0); - } - } - } - - if (expendable && withoutCharges) - { - uint32 count = 1; - ((Player*)m_caster)->DestroyItemCount(m_CastItem, count, true); - - // prevent crash at access to deleted m_targets.getItemTarget - if(m_CastItem==m_targets.getItemTarget()) - m_targets.setItemTarget(NULL); - - m_CastItem = NULL; - } -} - -void Spell::TakePower() -{ - if(m_CastItem || m_triggeredByAuraSpell) - return; - - // health as power used - if(m_spellInfo->powerType == POWER_HEALTH) - { - m_caster->ModifyHealth( -(int32)m_powerCost ); - return; - } - - if(m_spellInfo->powerType >= MAX_POWERS) - { - sLog.outError("Spell::TakePower: Unknown power type '%d'", m_spellInfo->powerType); - return; - } - - Powers powerType = Powers(m_spellInfo->powerType); - - m_caster->ModifyPower(powerType, -(int32)m_powerCost); - - // Set the five second timer - if (powerType == POWER_MANA && m_powerCost > 0) - m_caster->SetLastManaUse(getMSTime()); -} - -void Spell::TakeReagents() -{ - if(m_IsTriggeredSpell) // reagents used in triggered spell removed by original spell or don't must be removed. - return; - - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if (m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP && - m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION)) - return; - - Player* p_caster = (Player*)m_caster; - - for(uint32 x=0;x<8;x++) - { - if(m_spellInfo->Reagent[x] <= 0) - continue; - - uint32 itemid = m_spellInfo->Reagent[x]; - uint32 itemcount = m_spellInfo->ReagentCount[x]; - - // if CastItem is also spell reagent - if (m_CastItem) - { - ItemPrototype const *proto = m_CastItem->GetProto(); - if( proto && proto->ItemId == itemid ) - { - for(int s=0;s<5;s++) - { - // CastItem will be used up and does not count as reagent - int32 charges = m_CastItem->GetSpellCharges(s); - if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2) - { - ++itemcount; - break; - } - } - - m_CastItem = NULL; - } - } - - // if getItemTarget is also spell reagent - if (m_targets.getItemTargetEntry()==itemid) - m_targets.setItemTarget(NULL); - - p_caster->DestroyItemCount(itemid, itemcount, true); - } -} - -void Spell::HandleThreatSpells(uint32 spellId) -{ - if(!m_targets.getUnitTarget() || !spellId) - return; - - if(!m_targets.getUnitTarget()->CanHaveThreatList()) - return; - - SpellThreatEntry const *threatSpell = sSpellThreatStore.LookupEntry(spellId); - if(!threatSpell) - return; - - m_targets.getUnitTarget()->AddThreat(m_caster, float(threatSpell->threat)); - - DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat); -} - -void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float DamageMultiplier) -{ - unitTarget = pUnitTarget; - itemTarget = pItemTarget; - gameObjTarget = pGOTarget; - - uint8 eff = m_spellInfo->Effect[i]; - uint32 mechanic = m_spellInfo->EffectMechanic[i]; - - damage = int32(CalculateDamage((uint8)i,unitTarget)*DamageMultiplier); - - sLog.outDebug( "Spell: Effect : %u", eff); - - //Simply return. Do not display "immune" in red text on client - if(unitTarget && unitTarget->IsImmunedToSpellEffect(eff, mechanic)) - return; - - if(eff TOTAL_SPELL_EFFECTS ", eff); - if (m_CastItem) - EffectEnchantItemTmp(i); - else - { - sLog.outError("SPELL: unknown effect %u spell id %u\n", - eff, m_spellInfo->Id); - } - } - */ -} - -void Spell::TriggerSpell() -{ - for(TriggerSpells::iterator si=m_TriggerSpells.begin(); si!=m_TriggerSpells.end(); ++si) - { - Spell* spell = new Spell(m_caster, (*si), true, m_originalCasterGUID, this->m_selfContainer); - spell->prepare(&m_targets); // use original spell original targets - } -} - -uint8 Spell::CanCast(bool strict) -{ - // check cooldowns to prevent cheating - if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) - { - if(m_triggeredByAuraSpell) - return SPELL_FAILED_DONT_REPORT; - else - return SPELL_FAILED_NOT_READY; - } - - // only allow triggered spells if at an ended battleground - if( !m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER) - if(BattleGround * bg = ((Player*)m_caster)->GetBattleGround()) - if(bg->GetStatus() == STATUS_WAIT_LEAVE) - return SPELL_FAILED_DONT_REPORT; - - // only check at first call, Stealth auras are already removed at second call - // for now, ignore triggered spells - if( strict && !m_IsTriggeredSpell) - { - // Cannot be used in this stance/form - if(uint8 shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form)) - return shapeError; - - if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura())) - return SPELL_FAILED_ONLY_STEALTHED; - } - - // caster state requirements - if(m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState))) - return SPELL_FAILED_CASTER_AURASTATE; - if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot))) - return SPELL_FAILED_CASTER_AURASTATE; - - // cancel autorepeat spells if cast start when moving - // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code) - if( m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->isMoving() ) - { - // skip stuck spell to allow use it in falling case and apply spell limitations at movement - if( (!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) || m_spellInfo->Effect[0] != SPELL_EFFECT_STUCK) && - (IsAutoRepeat() || (m_spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0) ) - return SPELL_FAILED_MOVING; - } - - Unit *target = m_targets.getUnitTarget(); - - if(target) - { - // target state requirements (not allowed state), apply to self also - if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot))) - return SPELL_FAILED_TARGET_AURASTATE; - - - if(target != m_caster) - { - // target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds - if(m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState))) - return SPELL_FAILED_TARGET_AURASTATE; - - // Not allow casting on flying player - if (target->isInFlight()) - return SPELL_FAILED_BAD_TARGETS; - - if(VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target)) - return SPELL_FAILED_LINE_OF_SIGHT; - - // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode - // this case can be triggered if rank not found (too low-level target for first rank) - if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) - { - for(int i=0;i<3;i++) - { - if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) - if(target->getLevel() + 10 < m_spellInfo->spellLevel) - return SPELL_FAILED_LOWLEVEL; - } - } - } - - // check pet presents - for(int j=0;j<3;j++) - { - if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_PET) - { - target = m_caster->GetPet(); - if(!target) - { - if(m_triggeredByAuraSpell) // not report pet not existence for triggered spells - return SPELL_FAILED_DONT_REPORT; - else - return SPELL_FAILED_NO_PET; - } - break; - } - } - - //check creature type - //ignore self casts (including area casts when caster selected as target) - if(target != m_caster) - { - if(!CheckTargetCreatureType(target)) - { - if(target->GetTypeId()==TYPEID_PLAYER) - return SPELL_FAILED_TARGET_IS_PLAYER; - else - return SPELL_FAILED_BAD_TARGETS; - } - } - - // TODO: this check can be applied and for player to prevent cheating when IsPositiveSpell will return always correct result. - // check target for pet/charmed casts (not self targeted), self targeted cast used for area effects and etc - if(m_caster != target && m_caster->GetTypeId()==TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID()) - { - // check correctness positive/negative cast target (pet cast real check and cheating check) - if(IsPositiveSpell(m_spellInfo->Id)) - { - if(m_caster->IsHostileTo(target)) - return SPELL_FAILED_BAD_TARGETS; - } - else - { - if(m_caster->IsFriendlyTo(target)) - return SPELL_FAILED_BAD_TARGETS; - } - } - - if(IsPositiveSpell(m_spellInfo->Id)) - { - if(target->IsImmunedToSpell(m_spellInfo,false)) - return SPELL_FAILED_TARGET_AURASTATE; - } - - //Must be behind the target. - if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) ) - { - SendInterrupted(2); - return SPELL_FAILED_NOT_BEHIND; - } - - //Target must be facing you. - if((m_spellInfo->Attributes == 0x150010) && !target->HasInArc(M_PI, m_caster) ) - { - SendInterrupted(2); - return SPELL_FAILED_NOT_INFRONT; - } - - // check if target is in combat - if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) - { - return SPELL_FAILED_TARGET_AFFECTING_COMBAT; - } - } - // Spell casted only on battleground - if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) && m_caster->GetTypeId()==TYPEID_PLAYER) - if(!((Player*)m_caster)->InBattleGround()) - return SPELL_FAILED_ONLY_BATTLEGROUNDS; - - // do not allow spells to be cast in arenas - // - with greater than 15 min CD without SPELL_ATTR_EX4_USABLE_IN_ARENA flag - // - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag - if( (m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) || - GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * 1000 && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) ) - if(MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId())) - if(mapEntry->IsBattleArena()) - return SPELL_FAILED_NOT_IN_ARENA; - - // zone check - if(!IsSpellAllowedInLocation(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId())) - return SPELL_FAILED_REQUIRES_AREA; - - // not let players cast spells at mount (and let do it to creatures) - if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell && - !IsPassiveSpell(m_spellInfo->Id) && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_MOUNTED) ) - { - if(m_caster->isInFlight()) - return SPELL_FAILED_NOT_FLYING; - else - return SPELL_FAILED_NOT_MOUNTED; - } - - // always (except passive spells) check items (focus object can be required for any type casts) - if(!IsPassiveSpell(m_spellInfo->Id)) - if(uint8 castResult = CheckItems()) - return castResult; - - //ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38 - if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example) - { - for(uint8 j = 0; j < 3; j++) - { - if( m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[j] != TARGET_SELF || - m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) - { - bool okDoo = false; - - SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); - SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); - if(lower==upper) - sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id); - - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); - float range = GetSpellMaxRange(srange); - - Creature* creatureScriptTarget = NULL; - GameObject* goScriptTarget = NULL; - - for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST) - { - switch(i_spellST->second.type) - { - case SPELL_TARGET_TYPE_GAMEOBJECT: - { - GameObject* p_GameObject = NULL; - - if(i_spellST->second.targetEntry) - { - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - MaNGOS::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range); - MaNGOS::GameObjectLastSearcher checker(p_GameObject,go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - - if(p_GameObject) - { - // remember found target and range, next attempt will find more near target with another entry - creatureScriptTarget = NULL; - goScriptTarget = p_GameObject; - range = go_check.GetLastRange(); - } - } - else if( focusObject ) //Focus Object - { - float frange = m_caster->GetDistance(focusObject); - if(range >= frange) - { - creatureScriptTarget = NULL; - goScriptTarget = focusObject; - range = frange; - } - } - break; - } - case SPELL_TARGET_TYPE_CREATURE: - case SPELL_TARGET_TYPE_DEAD: - default: - { - Creature *p_Creature = NULL; - - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); // Really don't know what is that??? - - MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range); - MaNGOS::CreatureLastSearcher searcher(p_Creature, u_check); - - TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - - if(p_Creature ) - { - creatureScriptTarget = p_Creature; - goScriptTarget = NULL; - range = u_check.GetLastRange(); - } - break; - } - } - } - - if(creatureScriptTarget) - { - // store coordinates for TARGET_SCRIPT_COORDINATES - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) - { - m_targets.setDestination(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ()); - - if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) - AddUnitTarget(creatureScriptTarget, j); - } - // store explicit target for TARGET_SCRIPT - else - AddUnitTarget(creatureScriptTarget, j); - } - else if(goScriptTarget) - { - // store coordinates for TARGET_SCRIPT_COORDINATES - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) - { - m_targets.setDestination(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ()); - - if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) - AddGOTarget(goScriptTarget, j); - } - // store explicit target for TARGET_SCRIPT - else - AddGOTarget(goScriptTarget, j); - } - //Missing DB Entry or targets for this spellEffect. - else - { - // not report target not existence for triggered spells - if(m_triggeredByAuraSpell || m_IsTriggeredSpell) - return SPELL_FAILED_DONT_REPORT; - else - return SPELL_FAILED_BAD_TARGETS; - } - } - } - } - - if(uint8 castResult = CheckRange(strict)) - return castResult; - - { - if(uint8 castResult = CheckPower()) - return castResult; - } - - if(!m_triggeredByAuraSpell) // triggered spell not affected by stun/etc - if(uint8 castResult = CheckCasterAuras()) - return castResult; - - for (int i = 0; i < 3; i++) - { - // for effects of spells that have only one target - switch(m_spellInfo->Effect[i]) - { - case SPELL_EFFECT_DUMMY: - { - // Execute - if(m_spellInfo->SpellIconID == 1648) - { - if(!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) - return SPELL_FAILED_BAD_TARGETS; - } - else if (m_spellInfo->Id == 51582) - { - if(m_caster->IsInWater()) - return SPELL_FAILED_ONLY_ABOVEWATER; - } - break; - } - case SPELL_EFFECT_SCHOOL_DAMAGE: - { - // Hammer of Wrath - if(m_spellInfo->SpellVisual == 7250) - { - if (!m_targets.getUnitTarget()) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - - if(m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) - return SPELL_FAILED_BAD_TARGETS; - } - break; - } - case SPELL_EFFECT_TAMECREATURE: - { - if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - - if (m_targets.getUnitTarget()->getLevel() > m_caster->getLevel()) - return SPELL_FAILED_HIGHLEVEL; - - CreatureInfo const *cinfo = ((Creature*)m_targets.getUnitTarget())->GetCreatureInfo(); - if( cinfo->type != CREATURE_TYPE_BEAST ) - return SPELL_FAILED_BAD_TARGETS; - - // use SMSG_PET_TAME_FAILURE? - if( !(cinfo->flag1 & 1) || !(cinfo->family) ) - return SPELL_FAILED_BAD_TARGETS; - - if(m_caster->GetPetGUID()) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - - if(m_caster->GetCharmGUID()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; - - break; - } - case SPELL_EFFECT_LEARN_SPELL: - { - if(m_spellInfo->EffectImplicitTargetA[i] != TARGET_PET) - break; - - Pet* pet = m_caster->GetPet(); - - if(!pet) - return SPELL_FAILED_NO_PET; - - SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); - - if(!learn_spellproto) - return SPELL_FAILED_NOT_KNOWN; - - if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id)) - return SPELL_FAILED_TOO_MANY_SKILLS; - - if(m_spellInfo->spellLevel > pet->getLevel()) - return SPELL_FAILED_LOWLEVEL; - - if(!pet->HasTPForSpell(learn_spellproto->Id)) - return SPELL_FAILED_TRAINING_POINTS; - - break; - } - case SPELL_EFFECT_LEARN_PET_SPELL: - { - Pet* pet = m_caster->GetPet(); - - if(!pet) - return SPELL_FAILED_NO_PET; - - SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); - - if(!learn_spellproto) - return SPELL_FAILED_NOT_KNOWN; - - if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id)) - return SPELL_FAILED_TOO_MANY_SKILLS; - - if(m_spellInfo->spellLevel > pet->getLevel()) - return SPELL_FAILED_LOWLEVEL; - - if(!pet->HasTPForSpell(learn_spellproto->Id)) - return SPELL_FAILED_TRAINING_POINTS; - - break; - } - case SPELL_EFFECT_FEED_PET: - { - if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getItemTarget() ) - return SPELL_FAILED_BAD_TARGETS; - - Pet* pet = m_caster->GetPet(); - - if(!pet) - return SPELL_FAILED_NO_PET; - - if(!pet->HaveInDiet(m_targets.getItemTarget()->GetProto())) - return SPELL_FAILED_WRONG_PET_FOOD; - - if(!pet->GetCurrentFoodBenefitLevel(m_targets.getItemTarget()->GetProto()->ItemLevel)) - return SPELL_FAILED_FOOD_LOWLEVEL; - - if(m_caster->isInCombat() || pet->isInCombat()) - return SPELL_FAILED_AFFECTING_COMBAT; - - break; - } - case SPELL_EFFECT_POWER_BURN: - case SPELL_EFFECT_POWER_DRAIN: - { - // Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects) - if(m_caster->GetTypeId() == TYPEID_PLAYER) - if(Unit* target = m_targets.getUnitTarget()) - if(target!=m_caster && target->getPowerType()!=m_spellInfo->EffectMiscValue[i]) - return SPELL_FAILED_BAD_TARGETS; - break; - } - case SPELL_EFFECT_CHARGE: - { - if (m_caster->hasUnitState(UNIT_STAT_ROOT)) - return SPELL_FAILED_ROOTED; - - break; - } - case SPELL_EFFECT_SKINNING: - { - if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() != TYPEID_UNIT) - return SPELL_FAILED_BAD_TARGETS; - - if( !(m_targets.getUnitTarget()->GetUInt32Value(UNIT_FIELD_FLAGS) & UNIT_FLAG_SKINNABLE) ) - return SPELL_FAILED_TARGET_UNSKINNABLE; - - Creature* creature = (Creature*)m_targets.getUnitTarget(); - if ( creature->GetCreatureType() != CREATURE_TYPE_CRITTER && ( !creature->lootForBody || !creature->loot.empty() ) ) - { - return SPELL_FAILED_TARGET_NOT_LOOTED; - } - - uint32 skill; - if(creature->GetCreatureInfo()->flag1 & 256) - skill = SKILL_HERBALISM; // special case - else if(creature->GetCreatureInfo()->flag1 & 512) - skill = SKILL_MINING; // special case - else - skill = SKILL_SKINNING; // normal case - - int32 skillValue = ((Player*)m_caster)->GetSkillValue(skill); - int32 TargetLevel = m_targets.getUnitTarget()->getLevel(); - int32 ReqValue = (skillValue < 100 ? (TargetLevel-10)*10 : TargetLevel*5); - if (ReqValue > skillValue) - return SPELL_FAILED_LOW_CASTLEVEL; - - // chance for fail at orange skinning attempt - if( (m_selfContainer && (*m_selfContainer) == this) && - skillValue < sWorld.GetConfigMaxSkillValue() && - (ReqValue < 0 ? 0 : ReqValue) > irand(skillValue-25, skillValue+37) ) - return SPELL_FAILED_TRY_AGAIN; - - break; - } - case SPELL_EFFECT_OPEN_LOCK_ITEM: - case SPELL_EFFECT_OPEN_LOCK: - { - if( m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT && - m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT_ITEM ) - break; - - if( m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc. - // we need a go target in case of TARGET_GAMEOBJECT - || m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT && !m_targets.getGOTarget() - // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM - || m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_ITEM && !m_targets.getGOTarget() && - (!m_targets.getItemTarget() || !m_targets.getItemTarget()->GetProto()->LockID || m_targets.getItemTarget()->GetOwner() != m_caster ) ) - return SPELL_FAILED_BAD_TARGETS; - - // get the lock entry - LockEntry const *lockInfo = NULL; - if (GameObject* go=m_targets.getGOTarget()) - lockInfo = sLockStore.LookupEntry(go->GetLockId()); - else if(Item* itm=m_targets.getItemTarget()) - lockInfo = sLockStore.LookupEntry(itm->GetProto()->LockID); - - // check lock compatibility - if (lockInfo) - { - // check for lock - key pair (checked by client also, just prevent cheating - bool ok_key = false; - for(int it = 0; it < 5; ++it) - { - switch(lockInfo->keytype[it]) - { - case LOCK_KEY_NONE: - break; - case LOCK_KEY_ITEM: - { - if(lockInfo->key[it]) - { - if(m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it]) - ok_key =true; - break; - } - } - case LOCK_KEY_SKILL: - { - if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->key[it]) - break; - - switch(lockInfo->key[it]) - { - case LOCKTYPE_HERBALISM: - if(((Player*)m_caster)->HasSkill(SKILL_HERBALISM)) - ok_key =true; - break; - case LOCKTYPE_MINING: - if(((Player*)m_caster)->HasSkill(SKILL_MINING)) - ok_key =true; - break; - default: - ok_key =true; - break; - } - } - } - if(ok_key) - break; - } - - if(!ok_key) - return SPELL_FAILED_BAD_TARGETS; - } - - // chance for fail at orange mining/herb/LockPicking gathering attempt - if (!m_selfContainer || ((*m_selfContainer) != this)) - break; - - // get the skill value of the player - int32 SkillValue = 0; - bool canFailAtMax = true; - if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_HERBALISM) - { - SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_HERBALISM); - canFailAtMax = false; - } - else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_MINING) - { - SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_MINING); - canFailAtMax = false; - } - else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) - SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_LOCKPICKING); - - // castitem check: rogue using skeleton keys. the skill values should not be added in this case. - if(m_CastItem) - SkillValue = 0; - - // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value) - SkillValue += m_currentBasePoints[i]+1; - - // get the required lock value - int32 ReqValue=0; - if (lockInfo) - { - // check for lock - key pair - bool ok = false; - for(int it = 0; it < 5; ++it) - { - if(lockInfo->keytype[it]==LOCK_KEY_ITEM && lockInfo->key[it] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it]) - { - // if so, we're good to go - ok = true; - break; - } - } - if(ok) - break; - - if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) - ReqValue = lockInfo->requiredlockskill; - else - ReqValue = lockInfo->requiredminingskill; - } - - // skill doesn't meet the required value - if (ReqValue > SkillValue) - return SPELL_FAILED_LOW_CASTLEVEL; - - // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill) - if((canFailAtMax || SkillValue < sWorld.GetConfigMaxSkillValue()) && ReqValue > irand(SkillValue-25, SkillValue+37)) - return SPELL_FAILED_TRY_AGAIN; - - break; - } - case SPELL_EFFECT_SUMMON_DEAD_PET: - { - Creature *pet = m_caster->GetPet(); - if(!pet) - return SPELL_FAILED_NO_PET; - - if(pet->isAlive()) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - - break; - } - // This is generic summon effect now and don't make this check for summon types similar - // SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN. - // These won't show up in m_caster->GetPetGUID() - case SPELL_EFFECT_SUMMON: - { - switch(m_spellInfo->EffectMiscValueB[i]) - { - case SUMMON_TYPE_POSESSED: - case SUMMON_TYPE_POSESSED2: - case SUMMON_TYPE_DEMON: - case SUMMON_TYPE_SUMMON: - { - if(m_caster->GetPetGUID()) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - - if(m_caster->GetCharmGUID()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; - break; - } - } - break; - } - // Don't make this check for SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN. - // These won't show up in m_caster->GetPetGUID() - case SPELL_EFFECT_SUMMON_POSSESSED: - case SPELL_EFFECT_SUMMON_PHANTASM: - case SPELL_EFFECT_SUMMON_DEMON: - { - if(m_caster->GetPetGUID()) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - - if(m_caster->GetCharmGUID()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; - - break; - } - case SPELL_EFFECT_SUMMON_PET: - { - if(m_caster->GetPetGUID()) //let warlock do a replacement summon - { - - Pet* pet = ((Player*)m_caster)->GetPet(); - - if (m_caster->GetTypeId()==TYPEID_PLAYER && m_caster->getClass()==CLASS_WARLOCK) - { - if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player) - pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetGUID()); - } - else - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - } - - if(m_caster->GetCharmGUID()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; - - break; - } - case SPELL_EFFECT_SUMMON_PLAYER: - { - if(m_caster->GetTypeId()!=TYPEID_PLAYER) - return SPELL_FAILED_BAD_TARGETS; - if(!((Player*)m_caster)->GetSelection()) - return SPELL_FAILED_BAD_TARGETS; - - Player* target = objmgr.GetPlayer(((Player*)m_caster)->GetSelection()); - if( !target || ((Player*)m_caster)==target || !target->IsInSameRaidWith((Player*)m_caster) ) - return SPELL_FAILED_BAD_TARGETS; - - // check if our map is dungeon - if( sMapStore.LookupEntry(m_caster->GetMapId())->IsDungeon() ) - { - InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(m_caster->GetMapId()); - if(!instance) - return SPELL_FAILED_TARGET_NOT_IN_INSTANCE; - if ( instance->levelMin > target->getLevel() ) - return SPELL_FAILED_LOWLEVEL; - if ( instance->levelMax && instance->levelMax < target->getLevel() ) - return SPELL_FAILED_HIGHLEVEL; - } - break; - } - case SPELL_EFFECT_LEAP: - case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER: - { - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation()); - float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation()); - // teleport a bit above terrain level to avoid falling below it - float fz = MapManager::Instance().GetBaseMap(m_caster->GetMapId())->GetHeight(fx,fy,m_caster->GetPositionZ(),true); - if(fz <= INVALID_HEIGHT) // note: this also will prevent use effect in instances without vmaps height enabled - return SPELL_FAILED_TRY_AGAIN; - - float caster_pos_z = m_caster->GetPositionZ(); - // Control the caster to not climb or drop when +-fz > 8 - if(!(fz<=caster_pos_z+8 && fz>=caster_pos_z-8)) - return SPELL_FAILED_TRY_AGAIN; - - // not allow use this effect at battleground until battleground start - if(m_caster->GetTypeId()==TYPEID_PLAYER) - if(BattleGround const *bg = ((Player*)m_caster)->GetBattleGround()) - if(bg->GetStatus() != STATUS_IN_PROGRESS) - return SPELL_FAILED_TRY_AGAIN; - break; - } - case SPELL_EFFECT_STEAL_BENEFICIAL_BUFF: - { - if (m_targets.getUnitTarget()==m_caster) - return SPELL_FAILED_BAD_TARGETS; - break; - } - default:break; - } - } - - for (int i = 0; i < 3; i++) - { - switch(m_spellInfo->EffectApplyAuraName[i]) - { - case SPELL_AURA_MOD_POSSESS: - case SPELL_AURA_MOD_CHARM: - { - if(m_caster->GetPetGUID()) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - - if(m_caster->GetCharmGUID()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; - - if(m_caster->GetCharmerGUID()) - return SPELL_FAILED_CHARMED; - - if(!m_targets.getUnitTarget()) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - - if(m_targets.getUnitTarget()->GetCharmerGUID()) - return SPELL_FAILED_CHARMED; - - if(int32(m_targets.getUnitTarget()->getLevel()) > CalculateDamage(i,m_targets.getUnitTarget())) - return SPELL_FAILED_HIGHLEVEL; - };break; - case SPELL_AURA_MOUNTED: - { - if (m_caster->IsInWater()) - return SPELL_FAILED_ONLY_ABOVEWATER; - - if (m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->GetTransport()) - return SPELL_FAILED_NO_MOUNTS_ALLOWED; - - // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells - if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaId) - return SPELL_FAILED_NO_MOUNTS_ALLOWED; - - if (m_caster->GetAreaId()==35) - return SPELL_FAILED_NO_MOUNTS_ALLOWED; - - ShapeshiftForm form = m_caster->m_form; - if( form == FORM_CAT || form == FORM_TREE || form == FORM_TRAVEL || - form == FORM_AQUA || form == FORM_BEAR || form == FORM_DIREBEAR || - form == FORM_CREATUREBEAR || form == FORM_GHOSTWOLF || form == FORM_FLIGHT || - form == FORM_FLIGHT_EPIC || form == FORM_MOONKIN ) - return SPELL_FAILED_NOT_SHAPESHIFT; - - break; - } - case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS: - { - if(!m_targets.getUnitTarget()) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - - // can be casted at non-friendly unit or own pet/charm - if(m_caster->IsFriendlyTo(m_targets.getUnitTarget())) - return SPELL_FAILED_TARGET_FRIENDLY; - };break; - case SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED: - case SPELL_AURA_FLY: - { - // not allow cast fly spells at old maps by players (all spells is self target) - if(m_caster->GetTypeId()==TYPEID_PLAYER) - { - if( !((Player*)m_caster)->isGameMaster() && - GetVirtualMapForMapAndZone(m_caster->GetMapId(),m_caster->GetZoneId()) != 530) - return SPELL_FAILED_NOT_HERE; - } - };break; - case SPELL_AURA_PERIODIC_MANA_LEECH: - { - if (!m_targets.getUnitTarget()) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - - if (m_caster->GetTypeId()!=TYPEID_PLAYER || m_CastItem) - break; - - if(m_targets.getUnitTarget()->getPowerType()!=POWER_MANA) - return SPELL_FAILED_BAD_TARGETS; - break; - } - default:break; - } - } - - // all ok - return 0; -} - -int16 Spell::PetCanCast(Unit* target) -{ - if(!m_caster->isAlive()) - return SPELL_FAILED_CASTER_DEAD; - - if(m_caster->IsNonMeleeSpellCasted(false)) //prevent spellcast interuption by another spellcast - return SPELL_FAILED_SPELL_IN_PROGRESS; - if(m_caster->isInCombat() && IsNonCombatSpell(m_spellInfo)) - return SPELL_FAILED_AFFECTING_COMBAT; - - if(m_caster->GetTypeId()==TYPEID_UNIT && (((Creature*)m_caster)->isPet() || m_caster->isCharmed())) - { - //dead owner (pets still alive when owners ressed?) - if(m_caster->GetCharmerOrOwner() && !m_caster->GetCharmerOrOwner()->isAlive()) - return SPELL_FAILED_CASTER_DEAD; - - if(!target && m_targets.getUnitTarget()) - target = m_targets.getUnitTarget(); - - bool need = false; - for(uint32 i = 0;i<3;i++) - { - if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_CHAIN_DAMAGE || m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND || m_spellInfo->EffectImplicitTargetA[i] == TARGET_DUELVSPLAYER || m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_PARTY || m_spellInfo->EffectImplicitTargetA[i] == TARGET_CURRENT_ENEMY_COORDINATES) - { - need = true; - if(!target) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - break; - } - } - if(need) - m_targets.setUnitTarget(target); - - Unit* _target = m_targets.getUnitTarget(); - - if(_target) //for target dead/target not valid - { - if(!_target->isAlive()) - return SPELL_FAILED_BAD_TARGETS; - - if(IsPositiveSpell(m_spellInfo->Id)) - { - if(m_caster->IsHostileTo(_target)) - return SPELL_FAILED_BAD_TARGETS; - } - else - { - bool duelvsplayertar = false; - for(int j=0;j<3;j++) - { - //TARGET_DUELVSPLAYER is positive AND negative - duelvsplayertar |= (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DUELVSPLAYER); - } - if(m_caster->IsFriendlyTo(target) && !duelvsplayertar) - { - return SPELL_FAILED_BAD_TARGETS; - } - } - } - //cooldown - if(((Creature*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) - return SPELL_FAILED_NOT_READY; - } - - uint16 result = CanCast(true); - if(result != 0) - return result; - else - return -1; //this allows to check spell fail 0, in combat -} - -uint8 Spell::CheckCasterAuras() const -{ - // Flag drop spells totally immuned to caster auras - // FIXME: find more nice check for all totally immuned spells - // AttributesEx3 & 0x10000000? - if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991) - return 0; - - uint8 school_immune = 0; - uint32 mechanic_immune = 0; - uint32 dispel_immune = 0; - - //Check if the spell grants school or mechanic immunity. - //We use bitmasks so the loop is done only once and not on every aura check below. - if ( m_spellInfo->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY ) - { - for(int i = 0;i < 3; i ++) - { - if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_SCHOOL_IMMUNITY) - school_immune |= uint32(m_spellInfo->EffectMiscValue[i]); - else if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MECHANIC_IMMUNITY) - mechanic_immune |= 1 << uint32(m_spellInfo->EffectMiscValue[i]); - else if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DISPEL_IMMUNITY) - dispel_immune |= GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i])); - } - //immune movement impairement and loss of control - if(m_spellInfo->Id==(uint32)42292) - mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; - } - - //Check whether the cast should be prevented by any state you might have. - uint8 prevented_reason = 0; - // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out - if(!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED) && m_caster->HasAuraType(SPELL_AURA_MOD_STUN)) - prevented_reason = SPELL_FAILED_STUNNED; - else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED)) - prevented_reason = SPELL_FAILED_CONFUSED; - else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED)) - prevented_reason = SPELL_FAILED_FLEEING; - else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE) - prevented_reason = SPELL_FAILED_SILENCED; - else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY) - prevented_reason = SPELL_FAILED_PACIFIED; - - // Attr must make flag drop spell totally immuned from all effects - if(prevented_reason) - { - if(school_immune || mechanic_immune || dispel_immune) - { - //Checking auras is needed now, because you are prevented by some state but the spell grants immunity. - Unit::AuraMap const& auras = m_caster->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) - { - if(itr->second) - { - if( GetSpellMechanicMask(itr->second->GetSpellProto(), itr->second->GetEffIndex()) & mechanic_immune ) - continue; - if( GetSpellSchoolMask(itr->second->GetSpellProto()) & school_immune ) - continue; - if( (1<<(itr->second->GetSpellProto()->Dispel)) & dispel_immune) - continue; - - //Make a second check for spell failed so the right SPELL_FAILED message is returned. - //That is needed when your casting is prevented by multiple states and you are only immune to some of them. - switch(itr->second->GetModifier()->m_auraname) - { - case SPELL_AURA_MOD_STUN: - if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED)) - return SPELL_FAILED_STUNNED; - break; - case SPELL_AURA_MOD_CONFUSE: - if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED)) - return SPELL_FAILED_CONFUSED; - break; - case SPELL_AURA_MOD_FEAR: - if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED)) - return SPELL_FAILED_FLEEING; - break; - case SPELL_AURA_MOD_SILENCE: - case SPELL_AURA_MOD_PACIFY: - case SPELL_AURA_MOD_PACIFY_SILENCE: - if( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY) - return SPELL_FAILED_PACIFIED; - else if ( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE) - return SPELL_FAILED_SILENCED; - break; - } - } - } - } - //You are prevented from casting and the spell casted does not grant immunity. Return a failed error. - else - return prevented_reason; - } - return 0; // all ok -} - -bool Spell::CanAutoCast(Unit* target) -{ - uint64 targetguid = target->GetGUID(); - - for(uint32 j = 0;j<3;j++) - { - if(m_spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA) - { - if( m_spellInfo->StackAmount <= 1) - { - if( target->HasAura(m_spellInfo->Id, j) ) - return false; - } - else - { - if( target->GetAuras().count(Unit::spellEffectPair(m_spellInfo->Id, j)) >= m_spellInfo->StackAmount) - return false; - } - } - else if ( IsAreaAuraEffect( m_spellInfo->Effect[j] )) - { - if( target->HasAura(m_spellInfo->Id, j) ) - return false; - } - } - - int16 result = PetCanCast(target); - - if(result == -1 || result == SPELL_FAILED_UNIT_NOT_INFRONT) - { - FillTargetMap(); - //check if among target units, our WANTED target is as well (->only self cast spells return false) - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - if( ihit->targetGUID == targetguid ) - return true; - } - return false; //target invalid -} - -uint8 Spell::CheckRange(bool strict) -{ - float range_mod; - - // self cast doesn't need range checking -- also for Starshards fix - if (m_spellInfo->rangeIndex == 1) return 0; - - if (strict) //add radius of caster - range_mod = 1.25; - else //add radius of caster and ~5 yds "give" - range_mod = 6.25; - - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); - float max_range = GetSpellMaxRange(srange) + range_mod; - float min_range = GetSpellMinRange(srange); - - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this); - - Unit *target = m_targets.getUnitTarget(); - - if(target && target != m_caster) - { - // distance from target center in checks - float dist = m_caster->GetDistance(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ()); - if(dist > max_range) - return SPELL_FAILED_OUT_OF_RANGE; //0x5A; - if(dist < min_range) - return SPELL_FAILED_TOO_CLOSE; - if( !m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER && - !IsPositiveSpell(m_spellInfo->Id) && !m_caster->HasInArc( M_PI, target ) ) - { - // Spell-Family Related Checks - switch (m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_PRIEST: - { - // Shadow Word: Death, castable without facing - if (m_spellInfo->SpellFamilyFlags & 0x200000000LL) - return 0; // this is not TARGET_FLAG_DEST_LOCATION so we can return safely - break; - } - case SPELLFAMILY_PALADIN: - { - // Holy Shock, require facing - if (m_spellInfo->SpellFamilyFlags & 0x200000LL) - return SPELL_FAILED_UNIT_NOT_INFRONT; - break; - } - case SPELLFAMILY_WARRIOR: - { - // Charge, require facing - if (m_spellInfo->SpellFamilyFlags & 1) - return SPELL_FAILED_UNIT_NOT_INFRONT; - break; - } - } - - // Ranged Weapon - if (IsRangedSpell()) - return SPELL_FAILED_UNIT_NOT_INFRONT; - - // Melee Combat - if (m_spellInfo->rangeIndex == 2) - return SPELL_FAILED_UNIT_NOT_INFRONT; - - // Missile Effect - if (m_spellInfo->speed > 0) - return SPELL_FAILED_UNIT_NOT_INFRONT; - - // Channeled Spells need facing - if (IsChanneledSpell(m_spellInfo)) - return SPELL_FAILED_UNIT_NOT_INFRONT; - - // Direct Damage and charge effects - for (uint8 i=0;i<3;++i) - { - if (m_spellInfo->Effect[i] == SPELL_EFFECT_SCHOOL_DAMAGE || - m_spellInfo->Effect[i] == SPELL_EFFECT_POWER_BURN || - m_spellInfo->Effect[i] == SPELL_EFFECT_HEALTH_LEECH || - m_spellInfo->Effect[i] == SPELL_EFFECT_CHARGE) - return SPELL_FAILED_UNIT_NOT_INFRONT; - } - } - } - - if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0) - { - float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); - if(dist > max_range) - return SPELL_FAILED_OUT_OF_RANGE; - if(dist < min_range) - return SPELL_FAILED_TOO_CLOSE; - } - - return 0; // ok -} - -int32 Spell::CalculatePowerCost() -{ - // item cast not used power - if(m_CastItem) - return 0; - - // Spell drain all exist power on cast (Only paladin lay of Hands) - if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER) - { - // If power type - health drain all - if (m_spellInfo->powerType == POWER_HEALTH) - return m_caster->GetHealth(); - // Else drain all power - if (m_spellInfo->powerType < MAX_POWERS) - return m_caster->GetPower(Powers(m_spellInfo->powerType)); - sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); - return 0; - } - - // Base powerCost - int32 powerCost = m_spellInfo->manaCost; - // PCT cost from total amount - if (m_spellInfo->ManaCostPercentage) - { - switch (m_spellInfo->powerType) - { - // health as power used - case POWER_HEALTH: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateHealth() / 100; - break; - case POWER_MANA: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100; - break; - case POWER_RAGE: - case POWER_FOCUS: - case POWER_ENERGY: - case POWER_HAPPINESS: - // case POWER_RUNES: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100; - break; - default: - sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); - return 0; - } - } - SpellSchools school = GetFirstSchoolInMask(m_spellSchoolMask); - // Flat mod from caster auras by spell school - powerCost += m_caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school); - // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) - if ( m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST ) - powerCost += m_caster->GetAttackTime(OFF_ATTACK)/100; - // Apply cost mod by spell - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, powerCost, this); - - if(m_spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION) - powerCost = int32(powerCost/ (1.117f* m_spellInfo->spellLevel / m_caster->getLevel() -0.1327f)); - - // PCT mod from user auras by school - powerCost = int32(powerCost * (1.0f+m_caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+school))); - if (powerCost < 0) - powerCost = 0; - return powerCost; -} - -uint8 Spell::CheckPower() -{ - // item cast not used power - if(m_CastItem) - return 0; - - // health as power used - need check health amount - if(m_spellInfo->powerType == POWER_HEALTH) - { - if(m_caster->GetHealth() <= m_powerCost) - return SPELL_FAILED_CASTER_AURASTATE; - return 0; - } - // Check valid power type - if( m_spellInfo->powerType >= MAX_POWERS ) - { - sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType); - return SPELL_FAILED_UNKNOWN; - } - // Check power amount - Powers powerType = Powers(m_spellInfo->powerType); - if(m_caster->GetPower(powerType) < m_powerCost) - return SPELL_FAILED_NO_POWER; - else - return 0; -} - -uint8 Spell::CheckItems() -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return 0; - - uint32 itemid, itemcount; - Player* p_caster = (Player*)m_caster; - - if(m_CastItem) - { - itemid = m_CastItem->GetEntry(); - if( !p_caster->HasItemCount(itemid,1) ) - return SPELL_FAILED_ITEM_NOT_READY; - else - { - ItemPrototype const *proto = m_CastItem->GetProto(); - if(!proto) - return SPELL_FAILED_ITEM_NOT_READY; - - for (int i = 0; i<5; i++) - { - if (proto->Spells[i].SpellCharges) - { - if(m_CastItem->GetSpellCharges(i)==0) - return SPELL_FAILED_NO_CHARGES_REMAIN; - } - } - - uint32 ItemClass = proto->Class; - if (ItemClass == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget()) - { - for (int i = 0; i < 3; i++) - { - // skip check, pet not required like checks, and for TARGET_PET m_targets.getUnitTarget() is not the real target but the caster - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_PET) - continue; - - if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) - if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth()) - return (uint8)SPELL_FAILED_ALREADY_AT_FULL_HEALTH; - - // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... - if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) - { - if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; - - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); - - if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) - return (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; - } - } - } - } - } - - if(m_targets.getItemTargetGUID()) - { - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return SPELL_FAILED_BAD_TARGETS; - - if(!m_targets.getItemTarget()) - return SPELL_FAILED_ITEM_GONE; - - if(!m_targets.getItemTarget()->IsFitToSpellRequirements(m_spellInfo)) - return SPELL_FAILED_EQUIPPED_ITEM_CLASS; - } - // if not item target then required item must be equipped - else - { - if(m_caster->GetTypeId() == TYPEID_PLAYER && !((Player*)m_caster)->HasItemFitToSpellReqirements(m_spellInfo)) - return SPELL_FAILED_EQUIPPED_ITEM_CLASS; - } - - if(m_spellInfo->RequiresSpellFocus) - { - CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - GameObject* ok = NULL; - MaNGOS::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus); - MaNGOS::GameObjectSearcher checker(ok,go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - - if(!ok) - return (uint8)SPELL_FAILED_REQUIRES_SPELL_FOCUS; - - focusObject = ok; // game object found in range - } - - if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP && - m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION))) - { - for(uint32 i=0;i<8;i++) - { - if(m_spellInfo->Reagent[i] <= 0) - continue; - - itemid = m_spellInfo->Reagent[i]; - itemcount = m_spellInfo->ReagentCount[i]; - - // if CastItem is also spell reagent - if( m_CastItem && m_CastItem->GetEntry() == itemid ) - { - ItemPrototype const *proto = m_CastItem->GetProto(); - if(!proto) - return SPELL_FAILED_ITEM_NOT_READY; - for(int s=0;s<5;s++) - { - // CastItem will be used up and does not count as reagent - int32 charges = m_CastItem->GetSpellCharges(s); - if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2) - { - ++itemcount; - break; - } - } - } - if( !p_caster->HasItemCount(itemid,itemcount) ) - return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54 - } - } - - uint32 totems = 2; - for(int i=0;i<2;++i) - { - if(m_spellInfo->Totem[i] != 0) - { - if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) ) - { - totems -= 1; - continue; - } - }else - totems -= 1; - } - if(totems != 0) - return (uint8)SPELL_FAILED_TOTEMS; //0x7C - - //Check items for TotemCategory - uint32 TotemCategory = 2; - for(int i=0;i<2;++i) - { - if(m_spellInfo->TotemCategory[i] != 0) - { - if( p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i]) ) - { - TotemCategory -= 1; - continue; - } - } - else - TotemCategory -= 1; - } - if(TotemCategory != 0) - return (uint8)SPELL_FAILED_TOTEM_CATEGORY; //0x7B - - for(int i = 0; i < 3; i++) - { - switch (m_spellInfo->Effect[i]) - { - case SPELL_EFFECT_CREATE_ITEM: - { - if (!m_IsTriggeredSpell && m_spellInfo->EffectItemType[i]) - { - ItemPosCountVec dest; - uint8 msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1 ); - if (msg != EQUIP_ERR_OK ) - { - p_caster->SendEquipError( msg, NULL, NULL ); - return SPELL_FAILED_DONT_REPORT; - } - } - break; - } - case SPELL_EFFECT_ENCHANT_ITEM: - { - Item* targetItem = m_targets.getItemTarget(); - if(!targetItem) - return SPELL_FAILED_ITEM_NOT_FOUND; - - if( targetItem->GetProto()->ItemLevel < m_spellInfo->baseLevel ) - return SPELL_FAILED_LOWLEVEL; - // Not allow enchant in trade slot for some enchant type - if( targetItem->GetOwner() != m_caster ) - { - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) - return SPELL_FAILED_ERROR; - if (pEnchant->slot & ENCHANTMENT_CAN_SOULBOUND) - return SPELL_FAILED_NOT_TRADEABLE; - } - break; - } - case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY: - { - Item *item = m_targets.getItemTarget(); - if(!item) - return SPELL_FAILED_ITEM_NOT_FOUND; - // Not allow enchant in trade slot for some enchant type - if( item->GetOwner() != m_caster ) - { - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) - return SPELL_FAILED_ERROR; - if (pEnchant->slot & ENCHANTMENT_CAN_SOULBOUND) - return SPELL_FAILED_NOT_TRADEABLE; - } - break; - } - case SPELL_EFFECT_ENCHANT_HELD_ITEM: - // check item existence in effect code (not output errors at offhand hold item effect to main hand for example - break; - case SPELL_EFFECT_DISENCHANT: - { - if(!m_targets.getItemTarget()) - return SPELL_FAILED_CANT_BE_DISENCHANTED; - - // prevent disenchanting in trade slot - if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() ) - return SPELL_FAILED_CANT_BE_DISENCHANTED; - - ItemPrototype const* itemProto = m_targets.getItemTarget()->GetProto(); - if(!itemProto) - return SPELL_FAILED_CANT_BE_DISENCHANTED; - - uint32 item_quality = itemProto->Quality; - // 2.0.x addon: Check player enchanting level agains the item desenchanting requirements - uint32 item_disenchantskilllevel = itemProto->RequiredDisenchantSkill; - if (item_disenchantskilllevel == uint32(-1)) - return SPELL_FAILED_CANT_BE_DISENCHANTED; - if (item_disenchantskilllevel > p_caster->GetSkillValue(SKILL_ENCHANTING)) - return SPELL_FAILED_LOW_CASTLEVEL; - if(item_quality > 4 || item_quality < 2) - return SPELL_FAILED_CANT_BE_DISENCHANTED; - if(itemProto->Class != ITEM_CLASS_WEAPON && itemProto->Class != ITEM_CLASS_ARMOR) - return SPELL_FAILED_CANT_BE_DISENCHANTED; - if (!itemProto->DisenchantID) - return SPELL_FAILED_CANT_BE_DISENCHANTED; - break; - } - case SPELL_EFFECT_PROSPECTING: - { - if(!m_targets.getItemTarget()) - return SPELL_FAILED_CANT_BE_PROSPECTED; - //ensure item is a prospectable ore - if(!(m_targets.getItemTarget()->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) || m_targets.getItemTarget()->GetProto()->Class != ITEM_CLASS_TRADE_GOODS) - return SPELL_FAILED_CANT_BE_PROSPECTED; - //prevent prospecting in trade slot - if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() ) - return SPELL_FAILED_CANT_BE_PROSPECTED; - //Check for enough skill in jewelcrafting - uint32 item_prospectingskilllevel = m_targets.getItemTarget()->GetProto()->RequiredSkillRank; - if(item_prospectingskilllevel >p_caster->GetSkillValue(SKILL_JEWELCRAFTING)) - return SPELL_FAILED_LOW_CASTLEVEL; - //make sure the player has the required ores in inventory - if(m_targets.getItemTarget()->GetCount() < 5) - return SPELL_FAILED_PROSPECT_NEED_MORE; - - if(!LootTemplates_Prospecting.HaveLootFor(m_targets.getItemTargetEntry())) - return SPELL_FAILED_CANT_BE_PROSPECTED; - - break; - } - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - { - if(m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_TARGET_NOT_PLAYER; - if( m_attackType != RANGED_ATTACK ) - break; - Item *pItem = ((Player*)m_caster)->GetWeaponForAttack(m_attackType); - if(!pItem || pItem->IsBroken()) - return SPELL_FAILED_EQUIPPED_ITEM; - - switch(pItem->GetProto()->SubClass) - { - case ITEM_SUBCLASS_WEAPON_THROWN: - { - uint32 ammo = pItem->GetEntry(); - if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) ) - return SPELL_FAILED_NO_AMMO; - }; break; - case ITEM_SUBCLASS_WEAPON_GUN: - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - { - uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID); - if(!ammo) - { - // Requires No Ammo - if(m_caster->GetDummyAura(46699)) - break; // skip other checks - - return SPELL_FAILED_NO_AMMO; - } - - ItemPrototype const *ammoProto = objmgr.GetItemPrototype( ammo ); - if(!ammoProto) - return SPELL_FAILED_NO_AMMO; - - if(ammoProto->Class != ITEM_CLASS_PROJECTILE) - return SPELL_FAILED_NO_AMMO; - - // check ammo ws. weapon compatibility - switch(pItem->GetProto()->SubClass) - { - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - if(ammoProto->SubClass!=ITEM_SUBCLASS_ARROW) - return SPELL_FAILED_NO_AMMO; - break; - case ITEM_SUBCLASS_WEAPON_GUN: - if(ammoProto->SubClass!=ITEM_SUBCLASS_BULLET) - return SPELL_FAILED_NO_AMMO; - break; - default: - return SPELL_FAILED_NO_AMMO; - } - - if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) ) - return SPELL_FAILED_NO_AMMO; - }; break; - case ITEM_SUBCLASS_WEAPON_WAND: - default: - break; - } - break; - } - default:break; - } - } - - return uint8(0); -} - -void Spell::Delayed() -{ - if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if (m_spellState == SPELL_STATE_DELAYED) - return; // spell is active and can't be time-backed - - // spells not loosing casting time ( slam, dynamites, bombs.. ) - if(!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE)) - return; - - //check resist chance - int32 resistChance = 100; //must be initialized to 100 for percent modifiers - ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this); - resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100; - if (roll_chance_i(resistChance)) - return; - - int32 delaytime = GetNextDelayAtDamageMsTime(); - - if(int32(m_timer) + delaytime > m_casttime) - { - delaytime = m_casttime - m_timer; - m_timer = m_casttime; - } - else - m_timer += delaytime; - - sLog.outDetail("Spell %u partially interrupted for (%d) ms at damage",m_spellInfo->Id,delaytime); - - WorldPacket data(SMSG_SPELL_DELAYED, 8+4); - data.append(m_caster->GetPackGUID()); - data << uint32(delaytime); - - m_caster->SendMessageToSet(&data,true); -} - -void Spell::DelayedChannel() -{ - if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING) - return; - - //check resist chance - int32 resistChance = 100; //must be initialized to 100 for percent modifiers - ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this); - resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100; - if (roll_chance_i(resistChance)) - return; - - int32 delaytime = GetNextDelayAtDamageMsTime(); - - if(int32(m_timer) < delaytime) - { - delaytime = m_timer; - m_timer = 0; - } - else - m_timer -= delaytime; - - sLog.outDebug("Spell %u partially interrupted for %i ms, new duration: %u ms", m_spellInfo->Id, delaytime, m_timer); - - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - { - if ((*ihit).missCondition == SPELL_MISS_NONE) - { - Unit* unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); - if (unit) - { - for (int j=0;j<3;j++) - if( ihit->effectMask & (1<DelayAura(m_spellInfo->Id, j, delaytime); - } - - } - } - - for(int j = 0; j < 3; j++) - { - // partially interrupt persistent area auras - DynamicObject* dynObj = m_caster->GetDynObject(m_spellInfo->Id, j); - if(dynObj) - dynObj->Delay(delaytime); - } - - SendChannelUpdate(m_timer); -} - -void Spell::UpdatePointers() -{ - if(m_originalCasterGUID==m_caster->GetGUID()) - m_originalCaster = m_caster; - else - { - m_originalCaster = ObjectAccessor::GetUnit(*m_caster,m_originalCasterGUID); - if(m_originalCaster && !m_originalCaster->IsInWorld()) m_originalCaster = NULL; - } - - m_targets.Update(m_caster); -} - -bool Spell::IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId) -{ - return spellmgr.IsAffectedBySpell(m_spellInfo,spellInfo->Id,effectId,spellInfo->EffectItemType[effectId]); -} - -bool Spell::CheckTargetCreatureType(Unit* target) const -{ - uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType; - - // Curse of Doom : not find another way to fix spell target check :/ - if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags == 0x0200000000LL) - { - // not allow cast at player - if(target->GetTypeId()==TYPEID_PLAYER) - return false; - - spellCreatureTargetMask = 0x7FF; - } - - // Dismiss Pet and Taming Lesson skipped - if(m_spellInfo->Id == 2641 || m_spellInfo->Id == 23356) - spellCreatureTargetMask = 0; - - if (spellCreatureTargetMask) - { - uint32 TargetCreatureType = target->GetCreatureTypeMask(); - - return !TargetCreatureType || (spellCreatureTargetMask & TargetCreatureType); - } - return true; -} - -CurrentSpellTypes Spell::GetCurrentContainer() -{ - if (IsNextMeleeSwingSpell()) - return(CURRENT_MELEE_SPELL); - else if (IsAutoRepeat()) - return(CURRENT_AUTOREPEAT_SPELL); - else if (IsChanneledSpell(m_spellInfo)) - return(CURRENT_CHANNELED_SPELL); - else - return(CURRENT_GENERIC_SPELL); -} - -bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase ) -{ - // Check targets for creature type mask and remove not appropriate (skip explicit self target case, maybe need other explicit targets) - if(m_spellInfo->EffectImplicitTargetA[eff]!=TARGET_SELF ) - { - if (!CheckTargetCreatureType(target)) - return false; - } - - // Check targets for not_selectable unit flag and remove - // A player can cast spells on his pet (or other controlled unit) though in any state - if (target != m_caster && target->GetCharmerOrOwnerGUID() != m_caster->GetGUID()) - { - // any unattackable target skipped - if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return false; - - // unselectable targets skipped in all cases except TARGET_SCRIPT targeting - // in case TARGET_SCRIPT target selected by server always and can't be cheated - if( target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_SCRIPT && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_SCRIPT ) - return false; - } - - //Check player targets and remove if in GM mode or GM invisibility (for not self casting case) - if( target != m_caster && target->GetTypeId()==TYPEID_PLAYER) - { - if(((Player*)target)->GetVisibility()==VISIBILITY_OFF) - return false; - - if(((Player*)target)->isGameMaster() && !IsPositiveSpell(m_spellInfo->Id)) - return false; - } - - //Check targets for LOS visibility (except spells without range limitations ) - switch(m_spellInfo->Effect[eff]) - { - case SPELL_EFFECT_SUMMON_PLAYER: // from anywhere - break; - case SPELL_EFFECT_DUMMY: - if(m_spellInfo->Id!=20577) // Cannibalize - break; - //fall through - case SPELL_EFFECT_RESURRECT_NEW: - // player far away, maybe his corpse near? - if(target!=m_caster && !target->IsWithinLOSInMap(m_caster)) - { - if(!m_targets.getCorpseTargetGUID()) - return false; - - Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID()); - if(!corpse) - return false; - - if(target->GetGUID()!=corpse->GetOwnerGUID()) - return false; - - if(!corpse->IsWithinLOSInMap(m_caster)) - return false; - } - - // all ok by some way or another, skip normal check - break; - default: // normal case - if(target!=m_caster && !target->IsWithinLOSInMap(m_caster)) - return false; - break; - } - - return true; -} - -Unit* Spell::SelectMagnetTarget() -{ - Unit* target = m_targets.getUnitTarget(); - - if(target && target->HasAuraType(SPELL_AURA_SPELL_MAGNET) && !(m_spellInfo->Attributes & 0x10)) - { - Unit::AuraList const& magnetAuras = target->GetAurasByType(SPELL_AURA_SPELL_MAGNET); - for(Unit::AuraList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr) - { - if(Unit* magnet = (*itr)->GetCaster()) - { - if(magnet->IsWithinLOSInMap(m_caster)) - { - target = magnet; - m_targets.setUnitTarget(target); - break; - } - } - } - } - - return target; -} - -bool Spell::IsNeedSendToClient() const -{ - return m_spellInfo->SpellVisual!=0 || IsChanneledSpell(m_spellInfo) || - m_spellInfo->speed > 0.0f || !m_triggeredByAuraSpell && !m_IsTriggeredSpell; -} - -bool Spell::HaveTargetsForEffect( uint8 effect ) const -{ - for(std::list::const_iterator itr= m_UniqueTargetInfo.begin();itr != m_UniqueTargetInfo.end();++itr) - if(itr->effectMask & (1<::const_iterator itr= m_UniqueGOTargetInfo.begin();itr != m_UniqueGOTargetInfo.end();++itr) - if(itr->effectMask & (1<::const_iterator itr= m_UniqueItemInfo.begin();itr != m_UniqueItemInfo.end();++itr) - if(itr->effectMask & (1<getState() != SPELL_STATE_FINISHED) - m_Spell->cancel(); - - if (m_Spell->IsDeletable()) - { - delete m_Spell; - } - else - { - sLog.outError("~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.", - (m_Spell->GetCaster()->GetTypeId()==TYPEID_PLAYER?"Player":"Creature"), m_Spell->GetCaster()->GetGUIDLow(),m_Spell->m_spellInfo->Id); - } -} - -bool SpellEvent::Execute(uint64 e_time, uint32 p_time) -{ - // update spell if it is not finished - if (m_Spell->getState() != SPELL_STATE_FINISHED) - m_Spell->update(p_time); - - // check spell state to process - switch (m_Spell->getState()) - { - case SPELL_STATE_FINISHED: - { - // spell was finished, check deletable state - if (m_Spell->IsDeletable()) - { - // check, if we do have unfinished triggered spells - - return(true); // spell is deletable, finish event - } - // event will be re-added automatically at the end of routine) - } break; - - case SPELL_STATE_CASTING: - { - // this spell is in channeled state, process it on the next update - // event will be re-added automatically at the end of routine) - } break; - - case SPELL_STATE_DELAYED: - { - // first, check, if we have just started - if (m_Spell->GetDelayStart() != 0) - { - // no, we aren't, do the typical update - // check, if we have channeled spell on our hands - if (IsChanneledSpell(m_Spell->m_spellInfo)) - { - // evented channeled spell is processed separately, casted once after delay, and not destroyed till finish - // check, if we have casting anything else except this channeled spell and autorepeat - if (m_Spell->GetCaster()->IsNonMeleeSpellCasted(false, true, true)) - { - // another non-melee non-delayed spell is casted now, abort - m_Spell->cancel(); - } - else - { - // do the action (pass spell to channeling state) - m_Spell->handle_immediate(); - } - // event will be re-added automatically at the end of routine) - } - else - { - // run the spell handler and think about what we can do next - uint64 t_offset = e_time - m_Spell->GetDelayStart(); - uint64 n_offset = m_Spell->handle_delayed(t_offset); - if (n_offset) - { - // re-add us to the queue - m_Spell->GetCaster()->m_Events.AddEvent(this, m_Spell->GetDelayStart() + n_offset, false); - return(false); // event not complete - } - // event complete - // finish update event will be re-added automatically at the end of routine) - } - } - else - { - // delaying had just started, record the moment - m_Spell->SetDelayStart(e_time); - // re-plan the event for the delay moment - m_Spell->GetCaster()->m_Events.AddEvent(this, e_time + m_Spell->GetDelayMoment(), false); - return(false); // event not complete - } - } break; - - default: - { - // all other states - // event will be re-added automatically at the end of routine) - } break; - } - - // spell processing not complete, plan event on the next update interval - m_Spell->GetCaster()->m_Events.AddEvent(this, e_time + 1, false); - return(false); // event not complete -} - -void SpellEvent::Abort(uint64 /*e_time*/) -{ - // oops, the spell we try to do is aborted - if (m_Spell->getState() != SPELL_STATE_FINISHED) - m_Spell->cancel(); -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "Opcodes.h" +#include "Log.h" +#include "UpdateMask.h" +#include "World.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Player.h" +#include "Pet.h" +#include "Unit.h" +#include "Spell.h" +#include "DynamicObject.h" +#include "SpellAuras.h" +#include "Group.h" +#include "UpdateData.h" +#include "MapManager.h" +#include "ObjectAccessor.h" +#include "CellImpl.h" +#include "Policies/SingletonImp.h" +#include "SharedDefines.h" +#include "Tools.h" +#include "LootMgr.h" +#include "VMapFactory.h" +#include "BattleGround.h" +#include "Util.h" + +#define SPELL_CHANNEL_UPDATE_INTERVAL 1000 + +extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; + +bool IsQuestTameSpell(uint32 spellId) +{ + SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId); + if (!spellproto) return false; + + return spellproto->Effect[0] == SPELL_EFFECT_THREAT + && spellproto->Effect[1] == SPELL_EFFECT_APPLY_AURA && spellproto->EffectApplyAuraName[1] == SPELL_AURA_DUMMY; +} + +SpellCastTargets::SpellCastTargets() +{ + m_unitTarget = NULL; + m_itemTarget = NULL; + m_GOTarget = NULL; + + m_unitTargetGUID = 0; + m_GOTargetGUID = 0; + m_CorpseTargetGUID = 0; + m_itemTargetGUID = 0; + m_itemTargetEntry = 0; + + m_srcX = m_srcY = m_srcZ = m_destX = m_destY = m_destZ = 0; + m_strTarget = ""; + m_targetMask = 0; +} + +SpellCastTargets::~SpellCastTargets() +{ +} + +void SpellCastTargets::setUnitTarget(Unit *target) +{ + if (!target) + return; + + m_destX = target->GetPositionX(); + m_destY = target->GetPositionY(); + m_destZ = target->GetPositionZ(); + m_unitTarget = target; + m_unitTargetGUID = target->GetGUID(); + m_targetMask |= TARGET_FLAG_UNIT; +} + +void SpellCastTargets::setDestination(float x, float y, float z) +{ + m_destX = x; + m_destY = y; + m_destZ = z; + m_targetMask |= TARGET_FLAG_DEST_LOCATION; +} + +void SpellCastTargets::setGOTarget(GameObject *target) +{ + m_GOTarget = target; + m_GOTargetGUID = target->GetGUID(); + // m_targetMask |= TARGET_FLAG_OBJECT; +} + +void SpellCastTargets::setItemTarget(Item* item) +{ + if(!item) + return; + + m_itemTarget = item; + m_itemTargetGUID = item->GetGUID(); + m_itemTargetEntry = item->GetEntry(); + m_targetMask |= TARGET_FLAG_ITEM; +} + +void SpellCastTargets::setCorpseTarget(Corpse* corpse) +{ + m_CorpseTargetGUID = corpse->GetGUID(); +} + +void SpellCastTargets::Update(Unit* caster) +{ + m_GOTarget = m_GOTargetGUID ? ObjectAccessor::GetGameObject(*caster,m_GOTargetGUID) : NULL; + m_unitTarget = m_unitTargetGUID ? + ( m_unitTargetGUID==caster->GetGUID() ? caster : ObjectAccessor::GetUnit(*caster, m_unitTargetGUID) ) : + NULL; + + m_itemTarget = NULL; + if(caster->GetTypeId()==TYPEID_PLAYER) + { + if(m_targetMask & TARGET_FLAG_ITEM) + m_itemTarget = ((Player*)caster)->GetItemByGuid(m_itemTargetGUID); + else + { + Player* pTrader = ((Player*)caster)->GetTrader(); + if(pTrader && m_itemTargetGUID < TRADE_SLOT_COUNT) + m_itemTarget = pTrader->GetItemByPos(pTrader->GetItemPosByTradeSlot(m_itemTargetGUID)); + } + if(m_itemTarget) + m_itemTargetEntry = m_itemTarget->GetEntry(); + } +} + +bool SpellCastTargets::read ( WorldPacket * data, Unit *caster ) +{ + if(data->rpos()+4 > data->size()) + return false; + + *data >> m_targetMask; + + if(m_targetMask == TARGET_FLAG_SELF) + { + m_destX = caster->GetPositionX(); + m_destY = caster->GetPositionY(); + m_destZ = caster->GetPositionZ(); + m_unitTarget = caster; + m_unitTargetGUID = caster->GetGUID(); + return true; + } + // TARGET_FLAG_UNK2 is used for non-combat pets, maybe other? + if( m_targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2) ) + if(!readGUID(*data, m_unitTargetGUID)) + return false; + + if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK )) + if(!readGUID(*data, m_GOTargetGUID)) + return false; + + if(( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM )) && caster->GetTypeId() == TYPEID_PLAYER) + if(!readGUID(*data, m_itemTargetGUID)) + return false; + + if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION ) + { + if(data->rpos()+4+4+4 > data->size()) + return false; + + *data >> m_srcX >> m_srcY >> m_srcZ; + if(!MaNGOS::IsValidMapCoord(m_srcX, m_srcY, m_srcZ)) + return false; + } + + if( m_targetMask & TARGET_FLAG_DEST_LOCATION ) + { + if(data->rpos()+4+4+4 > data->size()) + return false; + + *data >> m_destX >> m_destY >> m_destZ; + if(!MaNGOS::IsValidMapCoord(m_destX, m_destY, m_destZ)) + return false; + } + + if( m_targetMask & TARGET_FLAG_STRING ) + { + if(data->rpos()+1 > data->size()) + return false; + + *data >> m_strTarget; + } + + if( m_targetMask & (TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) ) + if(!readGUID(*data, m_CorpseTargetGUID)) + return false; + + // find real units/GOs + Update(caster); + return true; +} + +void SpellCastTargets::write ( WorldPacket * data ) +{ + *data << uint32(m_targetMask); + + if( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_PVP_CORPSE | TARGET_FLAG_OBJECT | TARGET_FLAG_CORPSE | TARGET_FLAG_UNK2 ) ) + { + if(m_targetMask & TARGET_FLAG_UNIT) + { + if(m_unitTarget) + data->append(m_unitTarget->GetPackGUID()); + else + *data << uint8(0); + } + else if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK ) ) + { + if(m_GOTarget) + data->append(m_GOTarget->GetPackGUID()); + else + *data << uint8(0); + } + else if( m_targetMask & ( TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) ) + data->appendPackGUID(m_CorpseTargetGUID); + else + *data << uint8(0); + } + + if( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM ) ) + { + if(m_itemTarget) + data->append(m_itemTarget->GetPackGUID()); + else + *data << uint8(0); + } + + if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION ) + *data << m_srcX << m_srcY << m_srcZ; + + if( m_targetMask & TARGET_FLAG_DEST_LOCATION ) + *data << m_destX << m_destY << m_destZ; + + if( m_targetMask & TARGET_FLAG_STRING ) + *data << m_strTarget; +} + +Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 originalCasterGUID, Spell** triggeringContainer ) +{ + ASSERT( Caster != NULL && info != NULL ); + ASSERT( info == sSpellStore.LookupEntry( info->Id ) && "`info` must be pointer to sSpellStore element"); + + m_spellInfo = info; + m_caster = Caster; + m_selfContainer = NULL; + m_triggeringContainer = triggeringContainer; + m_deletable = true; + m_delayAtDamageCount = 0; + + m_applyMultiplierMask = 0; + + // Get data for type of attack + switch (m_spellInfo->DmgClass) + { + case SPELL_DAMAGE_CLASS_MELEE: + if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND) + m_attackType = OFF_ATTACK; + else + m_attackType = BASE_ATTACK; + break; + case SPELL_DAMAGE_CLASS_RANGED: + m_attackType = RANGED_ATTACK; + break; + default: + // Wands + if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_WAND) + m_attackType = RANGED_ATTACK; + else + m_attackType = BASE_ATTACK; + break; + } + + m_spellSchoolMask = GetSpellSchoolMask(info); // Can be override for some spell (wand shoot for example) + + if(m_attackType == RANGED_ATTACK) + { + // wand case + if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER) + { + if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK)) + m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType); + } + } + + if(originalCasterGUID) + m_originalCasterGUID = originalCasterGUID; + else + m_originalCasterGUID = m_caster->GetGUID(); + + if(m_originalCasterGUID==m_caster->GetGUID()) + m_originalCaster = m_caster; + else + { + m_originalCaster = ObjectAccessor::GetUnit(*m_caster,m_originalCasterGUID); + if(m_originalCaster && !m_originalCaster->IsInWorld()) m_originalCaster = NULL; + } + + for(int i=0; i <3; ++i) + m_currentBasePoints[i] = m_spellInfo->EffectBasePoints[i]; + + m_spellState = SPELL_STATE_NULL; + + m_castPositionX = m_castPositionY = m_castPositionZ = 0; + m_TriggerSpells.clear(); + m_IsTriggeredSpell = triggered; + //m_AreaAura = false; + m_CastItem = NULL; + + unitTarget = NULL; + itemTarget = NULL; + gameObjTarget = NULL; + focusObject = NULL; + m_cast_count = 0; + m_triggeredByAuraSpell = NULL; + + //Auto Shot & Shoot + if( m_spellInfo->AttributesEx2 == 0x000020 && !triggered ) + m_autoRepeat = true; + else + m_autoRepeat = false; + + m_powerCost = 0; // setup to correct value in Spell::prepare, don't must be used before. + m_casttime = 0; // setup to correct value in Spell::prepare, don't must be used before. + m_timer = 0; // will set to castime in preper + + m_needAliveTargetMask = 0; + + // determine reflection + m_canReflect = false; + + if(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && (m_spellInfo->AttributesEx2 & 0x4)==0) + { + for(int j=0;j<3;j++) + { + if (m_spellInfo->Effect[j]==0) + continue; + + if(!IsPositiveTarget(m_spellInfo->EffectImplicitTargetA[j],m_spellInfo->EffectImplicitTargetB[j])) + m_canReflect = true; + else + m_canReflect = (m_spellInfo->AttributesEx & (1<<7)) ? true : false; + + if(m_canReflect) + continue; + else + break; + } + } + + CleanupTargetList(); +} + +Spell::~Spell() +{ +} + +void Spell::FillTargetMap() +{ + // TODO: ADD the correct target FILLS!!!!!! + + for(uint32 i=0;i<3;i++) + { + // not call for empty effect. + // Also some spells use not used effect targets for store targets for dummy effect in triggered spells + if(m_spellInfo->Effect[i]==0) + continue; + + // targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT filled in Spell::canCast call + if( m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT_COORDINATES || + m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT || + m_spellInfo->EffectImplicitTargetB[i] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[i] != TARGET_SELF ) + continue; + + // TODO: find a way so this is not needed? + // for area auras always add caster as target (needed for totems for example) + if(IsAreaAuraEffect(m_spellInfo->Effect[i])) + AddUnitTarget(m_caster, i); + + std::list tmpUnitMap; + + // TargetA/TargetB dependent from each other, we not switch to full support this dependences + // but need it support in some know cases + switch(m_spellInfo->EffectImplicitTargetA[i]) + { + case TARGET_ALL_AROUND_CASTER: + if( m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_PARTY || + m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER || + m_spellInfo->EffectImplicitTargetB[i]==TARGET_RANDOM_RAID_MEMBER ) + { + SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); + } + // Note: this hack with search required until GO casting not implemented + // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support + // currently each enemy selected explicitly and self cast damage + else if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA && m_spellInfo->Effect[i]==SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) + { + if(m_targets.getUnitTarget()) + tmpUnitMap.push_back(m_targets.getUnitTarget()); + } + else + { + SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); + SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); + } + break; + case TARGET_TABLE_X_Y_Z_COORDINATES: + // Only if target A, for target B (used in teleports) dest select in effect + SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); + break; + default: + switch(m_spellInfo->EffectImplicitTargetB[i]) + { + case TARGET_SCRIPT_COORDINATES: // B case filled in canCast but we need fill unit list base at A case + SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); + break; + default: + SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); + SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); + break; + } + break; + } + + if( (m_spellInfo->EffectImplicitTargetA[i]==0 || m_spellInfo->EffectImplicitTargetA[i]==TARGET_EFFECT_SELECT) && + (m_spellInfo->EffectImplicitTargetB[i]==0 || m_spellInfo->EffectImplicitTargetB[i]==TARGET_EFFECT_SELECT) ) + { + // add here custom effects that need default target. + // FOR EVERY TARGET TYPE THERE IS A DIFFERENT FILL!! + switch(m_spellInfo->Effect[i]) + { + case SPELL_EFFECT_DUMMY: + { + switch(m_spellInfo->Id) + { + case 20577: // Cannibalize + { + // non-standard target selection + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); + float max_range = GetSpellMaxRange(srange); + + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + WorldObject* result = NULL; + + MaNGOS::CannibalizeObjectCheck u_check(m_caster, max_range); + MaNGOS::WorldObjectSearcher searcher(result, u_check); + + TypeContainerVisitor, GridTypeMapContainer > grid_searcher(searcher); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + + if(!result) + { + TypeContainerVisitor, WorldTypeMapContainer > world_searcher(searcher); + cell_lock->Visit(cell_lock, world_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + } + + if(result) + { + switch(result->GetTypeId()) + { + case TYPEID_UNIT: + case TYPEID_PLAYER: + tmpUnitMap.push_back((Unit*)result); + break; + case TYPEID_CORPSE: + m_targets.setCorpseTarget((Corpse*)result); + if(Player* owner = ObjectAccessor::FindPlayer(((Corpse*)result)->GetOwnerGUID())) + tmpUnitMap.push_back(owner); + break; + } + } + else + { + // clear cooldown at fail + if(m_caster->GetTypeId()==TYPEID_PLAYER) + { + ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id); + + WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); + data << uint32(m_spellInfo->Id); + data << uint64(m_caster->GetGUID()); + ((Player*)m_caster)->GetSession()->SendPacket(&data); + } + + SendCastResult(SPELL_FAILED_NO_EDIBLE_CORPSES); + finish(false); + } + break; + } + default: + if(m_targets.getUnitTarget()) + tmpUnitMap.push_back(m_targets.getUnitTarget()); + break; + } + break; + } + case SPELL_EFFECT_RESURRECT: + case SPELL_EFFECT_PARRY: + case SPELL_EFFECT_BLOCK: + case SPELL_EFFECT_CREATE_ITEM: + case SPELL_EFFECT_TRIGGER_SPELL: + case SPELL_EFFECT_TRIGGER_MISSILE: + case SPELL_EFFECT_LEARN_SPELL: + case SPELL_EFFECT_SKILL_STEP: + case SPELL_EFFECT_PROFICIENCY: + case SPELL_EFFECT_SUMMON_POSSESSED: + case SPELL_EFFECT_SUMMON_OBJECT_WILD: + case SPELL_EFFECT_SELF_RESURRECT: + case SPELL_EFFECT_REPUTATION: + if(m_targets.getUnitTarget()) + tmpUnitMap.push_back(m_targets.getUnitTarget()); + break; + case SPELL_EFFECT_SUMMON_PLAYER: + if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->GetSelection()) + { + Player* target = objmgr.GetPlayer(((Player*)m_caster)->GetSelection()); + if(target) + tmpUnitMap.push_back(target); + } + break; + case SPELL_EFFECT_RESURRECT_NEW: + if(m_targets.getUnitTarget()) + tmpUnitMap.push_back(m_targets.getUnitTarget()); + if(m_targets.getCorpseTargetGUID()) + { + Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID()); + if(corpse) + { + Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID()); + if(owner) + tmpUnitMap.push_back(owner); + } + } + break; + case SPELL_EFFECT_SUMMON: + if(m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED || m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED2) + { + if(m_targets.getUnitTarget()) + tmpUnitMap.push_back(m_targets.getUnitTarget()); + } + else + tmpUnitMap.push_back(m_caster); + break; + case SPELL_EFFECT_SUMMON_CHANGE_ITEM: + case SPELL_EFFECT_SUMMON_WILD: + case SPELL_EFFECT_SUMMON_GUARDIAN: + case SPELL_EFFECT_TRANS_DOOR: + case SPELL_EFFECT_ADD_FARSIGHT: + case SPELL_EFFECT_STUCK: + case SPELL_EFFECT_DESTROY_ALL_TOTEMS: + case SPELL_EFFECT_SUMMON_DEMON: + case SPELL_EFFECT_SKILL: + tmpUnitMap.push_back(m_caster); + break; + case SPELL_EFFECT_LEARN_PET_SPELL: + if(Pet* pet = m_caster->GetPet()) + tmpUnitMap.push_back(pet); + break; + case SPELL_EFFECT_ENCHANT_ITEM: + case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY: + case SPELL_EFFECT_DISENCHANT: + case SPELL_EFFECT_FEED_PET: + case SPELL_EFFECT_PROSPECTING: + if(m_targets.getItemTarget()) + AddItemTarget(m_targets.getItemTarget(), i); + break; + case SPELL_EFFECT_APPLY_AURA: + switch(m_spellInfo->EffectApplyAuraName[i]) + { + case SPELL_AURA_ADD_FLAT_MODIFIER: // some spell mods auras have 0 target modes instead expected TARGET_SELF(1) (and present for other ranks for same spell for example) + case SPELL_AURA_ADD_PCT_MODIFIER: + tmpUnitMap.push_back(m_caster); + break; + default: // apply to target in other case + if(m_targets.getUnitTarget()) + tmpUnitMap.push_back(m_targets.getUnitTarget()); + break; + } + break; + case SPELL_EFFECT_APPLY_AREA_AURA_PARTY: + // AreaAura + if(m_spellInfo->Attributes == 0x9050000 || m_spellInfo->Attributes == 0x10000) + SetTargetMap(i,TARGET_AREAEFFECT_PARTY,tmpUnitMap); + break; + case SPELL_EFFECT_SKIN_PLAYER_CORPSE: + if(m_targets.getUnitTarget()) + { + tmpUnitMap.push_back(m_targets.getUnitTarget()); + } + else if (m_targets.getCorpseTargetGUID()) + { + Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID()); + if(corpse) + { + Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID()); + if(owner) + tmpUnitMap.push_back(owner); + } + } + break; + default: + break; + } + } + if(IsChanneledSpell(m_spellInfo) && !tmpUnitMap.empty()) + m_needAliveTargetMask |= (1<GetTypeId() == TYPEID_PLAYER) + { + Player *me = (Player*)m_caster; + for (std::list::const_iterator itr = tmpUnitMap.begin(); itr != tmpUnitMap.end(); itr++) + { + Unit *owner = (*itr)->GetOwner(); + Unit *u = owner ? owner : (*itr); + if(u!=m_caster && u->IsPvP() && (!me->duel || me->duel->opponent != u)) + { + me->UpdatePvP(true); + me->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + break; + } + } + } + + for (std::list::iterator itr = tmpUnitMap.begin() ; itr != tmpUnitMap.end();) + { + if(!CheckTarget(*itr, i, false )) + { + itr = tmpUnitMap.erase(itr); + continue; + } + else + ++itr; + } + + for(std::list::iterator iunit= tmpUnitMap.begin();iunit != tmpUnitMap.end();++iunit) + AddUnitTarget((*iunit), i); + } +} + +void Spell::CleanupTargetList() +{ + m_UniqueTargetInfo.clear(); + m_UniqueGOTargetInfo.clear(); + m_UniqueItemInfo.clear(); + m_countOfHit = 0; + m_countOfMiss = 0; + m_delayMoment = 0; +} + +void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex) +{ + if( m_spellInfo->Effect[effIndex]==0 ) + return; + + uint64 targetGUID = pVictim->GetGUID(); + + // Lookup target in already in list + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + { + if (targetGUID == ihit->targetGUID) // Found in list + { + ihit->effectMask |= 1<SpellHitResult(pVictim, m_spellInfo, m_canReflect); + if (target.missCondition == SPELL_MISS_NONE) + ++m_countOfHit; + else + ++m_countOfMiss; + + // Spell have speed - need calculate incoming time + if (m_spellInfo->speed > 0.0f) + { + // calculate spell incoming interval + float dist = m_caster->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ()); + if (dist < 5.0f) dist = 5.0f; + target.timeDelay = (uint64) floor(dist / m_spellInfo->speed * 1000.0f); + + // Calculate minimum incoming time + if (m_delayMoment==0 || m_delayMoment>target.timeDelay) + m_delayMoment = target.timeDelay; + } + else + target.timeDelay = 0LL; + + // If target reflect spell back to caster + if (target.missCondition==SPELL_MISS_REFLECT) + { + // Calculate reflected spell result on caster + target.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect); + + if (target.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell + target.reflectResult = SPELL_MISS_PARRY; + + // Increase time interval for reflected spells by 1.5 + target.timeDelay+=target.timeDelay>>1; + } + else + target.reflectResult = SPELL_MISS_NONE; + + // Add target to list + m_UniqueTargetInfo.push_back(target); +} + +void Spell::AddUnitTarget(uint64 unitGUID, uint32 effIndex) +{ + Unit* unit = m_caster->GetGUID()==unitGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, unitGUID); + if (unit) + AddUnitTarget(unit, effIndex); +} + +void Spell::AddGOTarget(GameObject* pVictim, uint32 effIndex) +{ + if( m_spellInfo->Effect[effIndex]==0 ) + return; + + uint64 targetGUID = pVictim->GetGUID(); + + // Lookup target in already in list + for(std::list::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit) + { + if (targetGUID == ihit->targetGUID) // Found in list + { + ihit->effectMask |= 1<speed > 0.0f) + { + // calculate spell incoming interval + float dist = m_caster->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ()); + if (dist < 5.0f) dist = 5.0f; + target.timeDelay = (uint64) floor(dist / m_spellInfo->speed * 1000.0f); + if (m_delayMoment==0 || m_delayMoment>target.timeDelay) + m_delayMoment = target.timeDelay; + } + else + target.timeDelay = 0LL; + + ++m_countOfHit; + + // Add target to list + m_UniqueGOTargetInfo.push_back(target); +} + +void Spell::AddGOTarget(uint64 goGUID, uint32 effIndex) +{ + GameObject* go = ObjectAccessor::GetGameObject(*m_caster, goGUID); + if (go) + AddGOTarget(go, effIndex); +} + +void Spell::AddItemTarget(Item* pitem, uint32 effIndex) +{ + if( m_spellInfo->Effect[effIndex]==0 ) + return; + + // Lookup target in already in list + for(std::list::iterator ihit= m_UniqueItemInfo.begin();ihit != m_UniqueItemInfo.end();++ihit) + { + if (pitem == ihit->item) // Found in list + { + ihit->effectMask |= 1<GetTypeId()== TYPEID_PLAYER) + ((Player*)m_caster)->UpdateWeaponSkill(BASE_ATTACK); + + m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_MISS, m_spellInfo, m_IsTriggeredSpell); + break; + case SPELL_MISS_RESIST: + m_caster->ProcDamageAndSpell(unitTarget, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, damageSchoolMask, m_spellInfo, m_IsTriggeredSpell); + break; + case SPELL_MISS_DODGE: + if(unitTarget->GetTypeId() == TYPEID_PLAYER) + ((Player*)unitTarget)->UpdateDefense(); + + // Overpower + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARRIOR) + { + ((Player*) m_caster)->AddComboPoints(unitTarget, 1); + m_caster->StartReactiveTimer( REACTIVE_OVERPOWER ); + } + + // Riposte + if (unitTarget->getClass() != CLASS_ROGUE) + { + unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); + unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); + } + + m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_DODGE, m_spellInfo, m_IsTriggeredSpell); + break; + case SPELL_MISS_PARRY: + // Update victim defense ? + if(unitTarget->GetTypeId() == TYPEID_PLAYER) + ((Player*)unitTarget)->UpdateDefense(); + // Mongoose bite - set only Counterattack here + if (unitTarget->getClass() == CLASS_HUNTER) + { + unitTarget->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); + unitTarget->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); + } + else + { + unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); + unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); + } + m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_PARRY, m_spellInfo, m_IsTriggeredSpell); + break; + case SPELL_MISS_BLOCK: + unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); + unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); + + m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_BLOCK, m_spellInfo, m_IsTriggeredSpell); + break; + // Trigger from this events not supported + case SPELL_MISS_EVADE: + case SPELL_MISS_IMMUNE: + case SPELL_MISS_IMMUNE2: + case SPELL_MISS_DEFLECT: + case SPELL_MISS_ABSORB: + // Trigger from reflects need do after get reflect result + case SPELL_MISS_REFLECT: + break; + default: + break; + } + } +} + +void Spell::DoAllEffectOnTarget(TargetInfo *target) +{ + if (target->processed) // Check target + return; + target->processed = true; // Target checked in apply effects procedure + + // Get mask of effects for target + uint32 mask = target->effectMask; + if (mask == 0) // No effects + return; + + Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID); + if (!unit) + return; + + SpellMissInfo missInfo = target->missCondition; + // Need init unitTarget by default unit (can changed in code on reflect) + // Or on missInfo!=SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem) + unitTarget = unit; + + if (missInfo==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target + DoSpellHitOnUnit(unit, mask); + else if (missInfo == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit) + { + if (target->reflectResult == SPELL_MISS_NONE) // If reflected spell hit caster -> do all effect on him + DoSpellHitOnUnit(m_caster, mask); + } + + // Do triggers only on miss/resist/parry/dodge + if (missInfo!=SPELL_MISS_NONE) + doTriggers(missInfo); + + // Call scripted function for AI if this spell is casted upon a creature (except pets) + if(IS_CREATURE_GUID(target->targetGUID)) + { + // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished) + // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... ) + if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() ) + ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id); + + if(((Creature*)unit)->AI()) + ((Creature*)unit)->AI()->SpellHit(m_caster ,m_spellInfo); + } +} + +void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) +{ + if(!unit || !effectMask) + return; + + // Recheck immune (only for delayed spells) + if( m_spellInfo->speed && ( + unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo),true) || + unit->IsImmunedToSpell(m_spellInfo,true) )) + { + m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE); + return; + } + + if( m_caster != unit ) + { + if( !m_caster->IsFriendlyTo(unit) ) + { + // for delayed spells ignore not visible explicit target + if(m_spellInfo->speed > 0.0f && unit==m_targets.getUnitTarget() && !unit->isVisibleForOrDetect(m_caster,false)) + { + m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); + return; + } + + // exclude Arcane Missiles Dummy Aura aura for now (attack on hit) + // TODO: find way to not need this? + if(!(m_spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && + m_spellInfo->SpellFamilyFlags & 0x800LL)) + { + unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) + { + if(!unit->IsStandState() && !unit->hasUnitState(UNIT_STAT_STUNDED)) + unit->SetStandState(PLAYER_STATE_NONE); + + if(!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI()) + ((Creature*)unit)->AI()->AttackStart(m_caster); + + unit->SetInCombatWith(m_caster); + m_caster->SetInCombatWith(unit); + + if(Player *attackedPlayer = unit->GetCharmerOrOwnerPlayerOrPlayerItself()) + { + m_caster->SetContestedPvP(attackedPlayer); + } + unit->AddThreat(m_caster, 0.0f); + } + } + } + else + { + // for delayed spells ignore negative spells (after duel end) for friendly targets + if(m_spellInfo->speed > 0.0f && !IsPositiveSpell(m_spellInfo->Id)) + { + m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); + return; + } + + // assisting case, healing and resurrection + if(unit->hasUnitState(UNIT_STAT_ATTACK_PLAYER)) + m_caster->SetContestedPvP(); + if( unit->isInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) + { + m_caster->SetInCombatState(unit->GetCombatTimer() > 0); + unit->getHostilRefManager().threatAssist(m_caster, 0.0f); + } + } + } + + // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add + m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo,m_triggeredByAuraSpell); + m_diminishLevel = unit->GetDiminishing(m_diminishGroup); + // Increase Diminishing on unit, current informations for actually casts will use values above + if((GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_PLAYER && unit->GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_ALL) + unit->IncrDiminishing(m_diminishGroup); + + for(uint32 effectNumber=0;effectNumber<3;effectNumber++) + { + if (effectMask & (1<DmgMultiplier[effectNumber]; + // Apply multiplier mods + if(Player* modOwner = m_originalCaster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier,this); + m_damageMultipliers[effectNumber] *= multiplier; + } + } + } +} + +void Spell::DoAllEffectOnTarget(GOTargetInfo *target) +{ + if (target->processed) // Check target + return; + target->processed = true; // Target checked in apply effects procedure + + uint32 effectMask = target->effectMask; + if(!effectMask) + return; + + GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID); + if(!go) + return; + + for(uint32 effectNumber=0;effectNumber<3;effectNumber++) + if (effectMask & (1<GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() ) + ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); +} + +void Spell::DoAllEffectOnTarget(ItemTargetInfo *target) +{ + uint32 effectMask = target->effectMask; + if(!target->item || !effectMask) + return; + + for(uint32 effectNumber=0;effectNumber<3;effectNumber++) + if (effectMask & (1<item, NULL, effectNumber); +} + +bool Spell::IsAliveUnitPresentInTargetList() +{ + // Not need check return true + if (m_needAliveTargetMask == 0) + return true; + + uint8 needAliveTargetMask = m_needAliveTargetMask; + + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + { + if( ihit->missCondition == SPELL_MISS_NONE && (needAliveTargetMask & ihit->effectMask) ) + { + Unit *unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); + + if (unit && unit->isAlive()) + needAliveTargetMask &= ~ihit->effectMask; // remove from need alive mask effect that have alive target + } + } + + // is all effects from m_needAliveTargetMask have alive targets + return needAliveTargetMask==0; +} + +// Helper for Chain Healing +// Spell target first +// Raidmates then descending by injury suffered (MaxHealth - Health) +// Other players/mobs then descending by injury suffered (MaxHealth - Health) +struct ChainHealingOrder : public std::binary_function +{ + const Unit* MainTarget; + ChainHealingOrder(Unit const* Target) : MainTarget(Target) {}; + // functor for operator ">" + bool operator()(Unit const* _Left, Unit const* _Right) const + { + return (ChainHealingHash(_Left) < ChainHealingHash(_Right)); + } + int32 ChainHealingHash(Unit const* Target) const + { + if (Target == MainTarget) + return 0; + else if (Target->GetTypeId() == TYPEID_PLAYER && MainTarget->GetTypeId() == TYPEID_PLAYER && + ((Player const*)Target)->IsInSameRaidWith((Player const*)MainTarget)) + { + if (Target->GetHealth() == Target->GetMaxHealth()) + return 40000; + else + return 20000 - Target->GetMaxHealth() + Target->GetHealth(); + } + else + return 40000 - Target->GetMaxHealth() + Target->GetHealth(); + } +}; + +class ChainHealingFullHealth: std::unary_function +{ + public: + const Unit* MainTarget; + ChainHealingFullHealth(const Unit* Target) : MainTarget(Target) {}; + + bool operator()(const Unit* Target) + { + return (Target != MainTarget && Target->GetHealth() == Target->GetMaxHealth()); + } +}; + +// Helper for targets nearest to the spell target +// The spell target is always first unless there is a target at _completely_ the same position (unbelievable case) +struct TargetDistanceOrder : public std::binary_function +{ + const Unit* MainTarget; + TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; + // functor for operator ">" + bool operator()(const Unit* _Left, const Unit* _Right) const + { + return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); + } +}; + +void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) +{ + float radius; + if (m_spellInfo->EffectRadiusIndex[i]) + radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + else + radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); + + if(m_originalCaster) + if(Player* modOwner = m_originalCaster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius,this); + + uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[i]; + if(m_originalCaster) + if(Player* modOwner = m_originalCaster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, EffectChainTarget, this); + + uint32 unMaxTargets = m_spellInfo->MaxAffectedTargets; + switch(cur) + { + case TARGET_TOTEM_EARTH: + case TARGET_TOTEM_WATER: + case TARGET_TOTEM_AIR: + case TARGET_TOTEM_FIRE: + case TARGET_SELF: + case TARGET_SELF2: + case TARGET_DYNAMIC_OBJECT: + case TARGET_AREAEFFECT_CUSTOM: + case TARGET_AREAEFFECT_CUSTOM_2: + case TARGET_SUMMON: + { + TagUnitMap.push_back(m_caster); + break; + } + case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA: + { + m_targets.m_targetMask = 0; + unMaxTargets = EffectChainTarget; + float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; + + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + std::list tempUnitMap; + + { + MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(m_caster, m_caster, max_range); + MaNGOS::UnitListSearcher searcher(tempUnitMap, u_check); + + TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); + TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + } + + if(tempUnitMap.empty()) + break; + + tempUnitMap.sort(TargetDistanceOrder(m_caster)); + + //Now to get us a random target that's in the initial range of the spell + uint32 t = 0; + std::list::iterator itr = tempUnitMap.begin(); + while(itr!= tempUnitMap.end() && (*itr)->GetDistance(m_caster) < radius) + ++t, ++itr; + + if(!t) + break; + + itr = tempUnitMap.begin(); + std::advance(itr, rand()%t); + Unit *pUnitTarget = *itr; + TagUnitMap.push_back(pUnitTarget); + + tempUnitMap.erase(itr); + + tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); + + t = unMaxTargets - 1; + Unit *prev = pUnitTarget; + std::list::iterator next = tempUnitMap.begin(); + + while(t && next != tempUnitMap.end() ) + { + if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) + break; + + if(!prev->IsWithinLOSInMap(*next)) + { + ++next; + continue; + } + + prev = *next; + TagUnitMap.push_back(prev); + tempUnitMap.erase(next); + tempUnitMap.sort(TargetDistanceOrder(prev)); + next = tempUnitMap.begin(); + + --t; + } + }break; + case TARGET_PET: + { + Pet* tmpUnit = m_caster->GetPet(); + if (!tmpUnit) break; + TagUnitMap.push_back(tmpUnit); + break; + } + case TARGET_CHAIN_DAMAGE: + { + if (EffectChainTarget <= 1) + { + Unit* pUnitTarget = SelectMagnetTarget(); + if(pUnitTarget) + TagUnitMap.push_back(pUnitTarget); + } + else + { + Unit* pUnitTarget = m_targets.getUnitTarget(); + if(!pUnitTarget) + break; + + unMaxTargets = EffectChainTarget; + + float max_range; + if(m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE) + max_range = radius; // + else + //FIXME: This very like horrible hack and wrong for most spells + max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; + + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Unit* originalCaster = GetOriginalCaster(); + if(originalCaster) + { + std::list tempUnitMap; + + { + MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(pUnitTarget, originalCaster, max_range); + MaNGOS::UnitListSearcher searcher(tempUnitMap, u_check); + + TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); + TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + } + + tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); + + if(tempUnitMap.empty()) + break; + + if(*tempUnitMap.begin() == pUnitTarget) + tempUnitMap.erase(tempUnitMap.begin()); + + TagUnitMap.push_back(pUnitTarget); + uint32 t = unMaxTargets - 1; + Unit *prev = pUnitTarget; + std::list::iterator next = tempUnitMap.begin(); + + while(t && next != tempUnitMap.end() ) + { + if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) + break; + + if(!prev->IsWithinLOSInMap(*next)) + { + ++next; + continue; + } + + prev = *next; + TagUnitMap.push_back(prev); + tempUnitMap.erase(next); + tempUnitMap.sort(TargetDistanceOrder(prev)); + next = tempUnitMap.begin(); + + --t; + } + } + } + }break; + case TARGET_ALL_ENEMY_IN_AREA: + { + }break; + case TARGET_ALL_ENEMY_IN_AREA_INSTANT: + { + // targets the ground, not the units in the area + if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) + { + CellPair p(MaNGOS::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_AOE_DAMAGE); + + TypeContainerVisitor world_object_notifier(notifier); + TypeContainerVisitor grid_object_notifier(notifier); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + + // exclude caster (this can be important if this not original caster) + TagUnitMap.remove(m_caster); + } + }break; + case TARGET_DUELVSPLAYER_COORDINATES: + { + if(Unit* currentTarget = m_targets.getUnitTarget()) + { + m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ()); + TagUnitMap.push_back(currentTarget); + } + }break; + case TARGET_ALL_PARTY_AROUND_CASTER: + case TARGET_ALL_PARTY_AROUND_CASTER_2: + case TARGET_ALL_PARTY: + { + Player *pTarget = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself(); + Group *pGroup = pTarget ? pTarget->GetGroup() : NULL; + + if(pGroup) + { + uint8 subgroup = pTarget->GetSubGroup(); + + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* Target = itr->getSource(); + + // IsHostileTo check duel and controlled by enemy + if( Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target) ) + { + if( m_caster->IsWithinDistInMap(Target, radius) ) + TagUnitMap.push_back(Target); + + if(Pet* pet = Target->GetPet()) + if( m_caster->IsWithinDistInMap(pet, radius) ) + TagUnitMap.push_back(pet); + } + } + } + else + { + Unit* ownerOrSelf = pTarget ? pTarget : m_caster->GetCharmerOrOwnerOrSelf(); + if(ownerOrSelf==m_caster || m_caster->IsWithinDistInMap(ownerOrSelf, radius)) + TagUnitMap.push_back(ownerOrSelf); + if(Pet* pet = ownerOrSelf->GetPet()) + if( m_caster->IsWithinDistInMap(pet, radius) ) + TagUnitMap.push_back(pet); + } + }break; + case TARGET_RANDOM_RAID_MEMBER: + { + if (m_caster->GetTypeId() == TYPEID_PLAYER) + if(Player* target = ((Player*)m_caster)->GetNextRandomRaidMember(radius)) + TagUnitMap.push_back(target); + }break; + case TARGET_SINGLE_FRIEND: + case TARGET_SINGLE_FRIEND_2: + { + if(m_targets.getUnitTarget()) + TagUnitMap.push_back(m_targets.getUnitTarget()); + }break; + case TARGET_NONCOMBAT_PET: + { + if(Unit* target = m_targets.getUnitTarget()) + if( target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && ((Pet*)target)->getPetType() == MINI_PET) + TagUnitMap.push_back(target); + }break; + case TARGET_ALL_AROUND_CASTER: + { + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_AOE_DAMAGE); + + TypeContainerVisitor world_object_notifier(notifier); + TypeContainerVisitor grid_object_notifier(notifier); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + }break; + case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: + { + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_FRIENDLY); + + TypeContainerVisitor world_object_notifier(notifier); + TypeContainerVisitor grid_object_notifier(notifier); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + }break; + case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: + { + CellPair p(MaNGOS::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_FRIENDLY); + + TypeContainerVisitor world_object_notifier(notifier); + TypeContainerVisitor grid_object_notifier(notifier); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + }break; + // TARGET_SINGLE_PARTY means that the spells can only be casted on a party member and not on the caster (some sceals, fire shield from imp, etc..) + case TARGET_SINGLE_PARTY: + { + Unit *target = m_targets.getUnitTarget(); + // Thoses spells apparently can't be casted on the caster. + if( target && target != m_caster) + { + // Can only be casted on group's members or its pets + Group *pGroup = NULL; + + Unit* owner = m_caster->GetCharmerOrOwner(); + Unit *targetOwner = target->GetCharmerOrOwner(); + if(owner) + { + if(owner->GetTypeId() == TYPEID_PLAYER) + { + if( target == owner ) + { + TagUnitMap.push_back(target); + break; + } + pGroup = ((Player*)owner)->GetGroup(); + } + } + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + if( targetOwner == m_caster && target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isPet()) + { + TagUnitMap.push_back(target); + break; + } + pGroup = ((Player*)m_caster)->GetGroup(); + } + + if(pGroup) + { + // Our target can also be a player's pet who's grouped with us or our pet. But can't be controlled player + if(targetOwner) + { + if( targetOwner->GetTypeId() == TYPEID_PLAYER && + target->GetTypeId()==TYPEID_UNIT && (((Creature*)target)->isPet()) && + target->GetOwnerGUID()==targetOwner->GetGUID() && + pGroup->IsMember(((Player*)targetOwner)->GetGUID())) + { + TagUnitMap.push_back(target); + } + } + // 1Our target can be a player who is on our group + else if (target->GetTypeId() == TYPEID_PLAYER && pGroup->IsMember(((Player*)target)->GetGUID())) + { + TagUnitMap.push_back(target); + } + } + } + }break; + case TARGET_GAMEOBJECT: + { + if(m_targets.getGOTarget()) + AddGOTarget(m_targets.getGOTarget(), i); + }break; + case TARGET_IN_FRONT_OF_CASTER: + { + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + bool inFront = m_spellInfo->SpellVisual != 3879; + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, inFront ? PUSH_IN_FRONT : PUSH_IN_BACK,SPELL_TARGETS_AOE_DAMAGE); + + TypeContainerVisitor world_object_notifier(notifier); + TypeContainerVisitor grid_object_notifier(notifier); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + }break; + case TARGET_DUELVSPLAYER: + { + Unit *target = m_targets.getUnitTarget(); + if(target) + { + if(m_caster->IsFriendlyTo(target)) + { + TagUnitMap.push_back(target); + } + else + { + Unit* pUnitTarget = SelectMagnetTarget(); + if(pUnitTarget) + TagUnitMap.push_back(pUnitTarget); + } + } + }break; + case TARGET_GAMEOBJECT_ITEM: + { + if(m_targets.getGOTargetGUID()) + AddGOTarget(m_targets.getGOTarget(), i); + else if(m_targets.getItemTarget()) + AddItemTarget(m_targets.getItemTarget(), i); + break; + } + case TARGET_MASTER: + { + if(Unit* owner = m_caster->GetCharmerOrOwner()) + TagUnitMap.push_back(owner); + break; + } + case TARGET_ALL_ENEMY_IN_AREA_CHANNELED: + { + // targets the ground, not the units in the area + if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) + { + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_AOE_DAMAGE); + + TypeContainerVisitor world_object_notifier(notifier); + TypeContainerVisitor grid_object_notifier(notifier); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + } + }break; + case TARGET_MINION: + { + if(m_spellInfo->Effect[i] != SPELL_EFFECT_DUEL) + TagUnitMap.push_back(m_caster); + }break; + case TARGET_SINGLE_ENEMY: + { + Unit* pUnitTarget = SelectMagnetTarget(); + if(pUnitTarget) + TagUnitMap.push_back(pUnitTarget); + }break; + case TARGET_AREAEFFECT_PARTY: + { + Unit* owner = m_caster->GetCharmerOrOwner(); + Player *pTarget = NULL; + + if(owner) + { + TagUnitMap.push_back(m_caster); + if(owner->GetTypeId() == TYPEID_PLAYER) + pTarget = (Player*)owner; + } + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + if(Unit* target = m_targets.getUnitTarget()) + { + if( target->GetTypeId() != TYPEID_PLAYER) + { + if(((Creature*)target)->isPet()) + { + Unit *targetOwner = target->GetOwner(); + if(targetOwner->GetTypeId() == TYPEID_PLAYER) + pTarget = (Player*)targetOwner; + } + } + else + pTarget = (Player*)target; + } + } + + Group* pGroup = pTarget ? pTarget->GetGroup() : NULL; + + if(pGroup) + { + uint8 subgroup = pTarget->GetSubGroup(); + + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* Target = itr->getSource(); + + // IsHostileTo check duel and controlled by enemy + if(Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target)) + { + if( pTarget->IsWithinDistInMap(Target, radius) ) + TagUnitMap.push_back(Target); + + if(Pet* pet = Target->GetPet()) + if( pTarget->IsWithinDistInMap(pet, radius) ) + TagUnitMap.push_back(pet); + } + } + } + else if (owner) + { + if(m_caster->IsWithinDistInMap(owner, radius)) + TagUnitMap.push_back(owner); + } + else if(pTarget) + { + TagUnitMap.push_back(pTarget); + + if(Pet* pet = pTarget->GetPet()) + if( m_caster->IsWithinDistInMap(pet, radius) ) + TagUnitMap.push_back(pet); + } + + }break; + case TARGET_SCRIPT: + { + if(m_targets.getUnitTarget()) + TagUnitMap.push_back(m_targets.getUnitTarget()); + if(m_targets.getItemTarget()) + AddItemTarget(m_targets.getItemTarget(), i); + }break; + case TARGET_SELF_FISHING: + { + TagUnitMap.push_back(m_caster); + }break; + case TARGET_CHAIN_HEAL: + { + Unit* pUnitTarget = m_targets.getUnitTarget(); + if(!pUnitTarget) + break; + + if (EffectChainTarget <= 1) + TagUnitMap.push_back(pUnitTarget); + else + { + unMaxTargets = EffectChainTarget; + float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; + + std::list tempUnitMap; + + { + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, tempUnitMap, max_range, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY); + + TypeContainerVisitor world_object_notifier(notifier); + TypeContainerVisitor grid_object_notifier(notifier); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + + } + + if(m_caster != pUnitTarget && std::find(tempUnitMap.begin(),tempUnitMap.end(),m_caster) == tempUnitMap.end() ) + tempUnitMap.push_front(m_caster); + + tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); + + if(tempUnitMap.empty()) + break; + + if(*tempUnitMap.begin() == pUnitTarget) + tempUnitMap.erase(tempUnitMap.begin()); + + TagUnitMap.push_back(pUnitTarget); + uint32 t = unMaxTargets - 1; + Unit *prev = pUnitTarget; + std::list::iterator next = tempUnitMap.begin(); + + while(t && next != tempUnitMap.end() ) + { + if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) + break; + + if(!prev->IsWithinLOSInMap(*next)) + { + ++next; + continue; + } + + if((*next)->GetHealth() == (*next)->GetMaxHealth()) + { + next = tempUnitMap.erase(next); + continue; + } + + prev = *next; + TagUnitMap.push_back(prev); + tempUnitMap.erase(next); + tempUnitMap.sort(TargetDistanceOrder(prev)); + next = tempUnitMap.begin(); + + --t; + } + } + }break; + case TARGET_CURRENT_ENEMY_COORDINATES: + { + Unit* currentTarget = m_targets.getUnitTarget(); + if(currentTarget) + { + TagUnitMap.push_back(currentTarget); + m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ()); + if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA_INSTANT) + { + CellPair p(MaNGOS::ComputeCellPair(currentTarget->GetPositionX(), currentTarget->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_TARGET_CENTER, SPELL_TARGETS_AOE_DAMAGE); + TypeContainerVisitor world_notifier(notifier); + TypeContainerVisitor grid_notifier(notifier); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + } + } + }break; + case TARGET_AREAEFFECT_PARTY_AND_CLASS: + { + Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER + ? (Player*)m_targets.getUnitTarget() : NULL; + + Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL; + if(pGroup) + { + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* Target = itr->getSource(); + + // IsHostileTo check duel and controlled by enemy + if( Target && targetPlayer->IsWithinDistInMap(Target, radius) && + targetPlayer->getClass() == Target->getClass() && + !m_caster->IsHostileTo(Target) ) + { + TagUnitMap.push_back(Target); + } + } + } + else if(m_targets.getUnitTarget()) + TagUnitMap.push_back(m_targets.getUnitTarget()); + break; + } + case TARGET_TABLE_X_Y_Z_COORDINATES: + { + SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); + if(st) + { + if (st->target_mapId == m_caster->GetMapId()) + m_targets.setDestination(st->target_X, st->target_Y, st->target_Z); + + // if B==TARGET_TABLE_X_Y_Z_COORDINATES then A already fill all required targets + if (m_spellInfo->EffectImplicitTargetB[i] && m_spellInfo->EffectImplicitTargetB[i]!=TARGET_TABLE_X_Y_Z_COORDINATES) + { + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + SpellTargets targetB = SPELL_TARGETS_AOE_DAMAGE; + // Select friendly targets for positive effect + if (IsPositiveEffect(m_spellInfo->Id, i)) + targetB = SPELL_TARGETS_FRIENDLY; + + MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_DEST_CENTER, targetB); + + TypeContainerVisitor world_notifier(notifier); + TypeContainerVisitor grid_notifier(notifier); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + } + } + else + sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); + }break; + case TARGET_BEHIND_VICTIM: + { + Unit *pTarget = m_caster->getVictim(); + if(!pTarget && m_caster->GetTypeId() == TYPEID_PLAYER) + pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); + + if(pTarget) + { + float _target_x, _target_y, _target_z; + pTarget->GetClosePoint(_target_x, _target_y, _target_z, m_caster->GetObjectSize(), CONTACT_DISTANCE, M_PI); + if(pTarget->IsWithinLOS(_target_x,_target_y,_target_z)) + m_targets.setDestination(_target_x, _target_y, _target_z); + } + }break; + default: + break; + } + + if (unMaxTargets && TagUnitMap.size() > unMaxTargets) + { + // make sure one unit is always removed per iteration + uint32 removed_utarget = 0; + for (std::list::iterator itr = TagUnitMap.begin(), next; itr != TagUnitMap.end(); itr = next) + { + next = itr; + ++next; + if (!*itr) continue; + if ((*itr) == m_targets.getUnitTarget()) + { + TagUnitMap.erase(itr); + removed_utarget = 1; + // break; + } + } + // remove random units from the map + while (TagUnitMap.size() > unMaxTargets - removed_utarget) + { + uint32 poz = urand(0, TagUnitMap.size()-1); + for (std::list::iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end(); ++itr, --poz) + { + if (!*itr) continue; + if (!poz) + { + TagUnitMap.erase(itr); + break; + } + } + } + // the player's target will always be added to the map + if (removed_utarget && m_targets.getUnitTarget()) + TagUnitMap.push_back(m_targets.getUnitTarget()); + } +} + +void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura) +{ + m_targets = *targets; + + m_spellState = SPELL_STATE_PREPARING; + + m_castPositionX = m_caster->GetPositionX(); + m_castPositionY = m_caster->GetPositionY(); + m_castPositionZ = m_caster->GetPositionZ(); + m_castOrientation = m_caster->GetOrientation(); + + if(triggeredByAura) + m_triggeredByAuraSpell = triggeredByAura->GetSpellProto(); + + // create and add update event for this spell + SpellEvent* Event = new SpellEvent(this); + m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1)); + + //Prevent casting at cast another spell (ServerSide check) + if(m_caster->IsNonMeleeSpellCasted(false, true) && m_cast_count) + { + SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS); + finish(false); + return; + } + + // Fill cost data + m_powerCost = CalculatePowerCost(); + + uint8 result = CanCast(true); + if(result != 0 && !IsAutoRepeat()) //always cast autorepeat dummy for triggering + { + if(triggeredByAura) + { + SendChannelUpdate(0); + triggeredByAura->SetAuraDuration(0); + } + SendCastResult(result); + finish(false); + return; + } + + // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail) + m_casttime = GetSpellCastTime(m_spellInfo, this); + + // set timer base at cast time + ReSetTimer(); + + // stealth must be removed at cast starting (at show channel bar) + // skip triggered spell (item equip spell casting and other not explicit character casts/item uses) + if ( !m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo) ) + { + m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + m_caster->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + } + + if(m_IsTriggeredSpell) + cast(true); + else + { + m_caster->SetCurrentCastedSpell( this ); + m_selfContainer = &(m_caster->m_currentSpells[GetCurrentContainer()]); + SendSpellStart(); + } +} + +void Spell::cancel() +{ + if(m_spellState == SPELL_STATE_FINISHED) + return; + + m_autoRepeat = false; + switch (m_spellState) + { + case SPELL_STATE_PREPARING: + case SPELL_STATE_DELAYED: + { + SendInterrupted(0); + SendCastResult(SPELL_FAILED_INTERRUPTED); + } break; + + case SPELL_STATE_CASTING: + { + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + { + if( ihit->missCondition == SPELL_MISS_NONE ) + { + Unit* unit = m_caster->GetGUID()==(*ihit).targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); + if( unit && unit->isAlive() ) + unit->RemoveAurasDueToSpell(m_spellInfo->Id); + } + } + + m_caster->RemoveAurasDueToSpell(m_spellInfo->Id); + SendChannelUpdate(0); + SendInterrupted(0); + SendCastResult(SPELL_FAILED_INTERRUPTED); + } break; + + default: + { + } break; + } + + finish(false); + m_caster->RemoveDynObject(m_spellInfo->Id); + m_caster->RemoveGameObject(m_spellInfo->Id,true); +} + +void Spell::cast(bool skipCheck) +{ + uint8 castResult = 0; + + // update pointers base at GUIDs to prevent access to non-existed already object + UpdatePointers(); + + // cancel at lost main target unit + if(!m_targets.getUnitTarget() && m_targets.getUnitTargetGUID() && m_targets.getUnitTargetGUID() != m_caster->GetGUID()) + { + cancel(); + return; + } + + if(m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster) + m_caster->SetInFront(m_targets.getUnitTarget()); + + castResult = CheckPower(); + if(castResult != 0) + { + SendCastResult(castResult); + finish(false); + return; + } + + // triggered cast called from Spell::prepare where it was already checked + if(!skipCheck) + { + castResult = CanCast(false); + if(castResult != 0) + { + SendCastResult(castResult); + finish(false); + return; + } + } + + // Conflagrate - consumes immolate + if ((m_spellInfo->TargetAuraState == AURA_STATE_IMMOLATE) && m_targets.getUnitTarget()) + { + // for caster applied auras only + Unit::AuraList const &mPeriodic = m_targets.getUnitTarget()->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); + for(Unit::AuraList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i) + { + if( (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && ((*i)->GetSpellProto()->SpellFamilyFlags & 4) && + (*i)->GetCasterGUID()==m_caster->GetGUID() ) + { + m_targets.getUnitTarget()->RemoveAura((*i)->GetId(), (*i)->GetEffIndex()); + break; + } + } + } + + // traded items have trade slot instead of guid in m_itemTargetGUID + // set to real guid to be sent later to the client + m_targets.updateTradeSlotItem(); + + // CAST SPELL + SendSpellCooldown(); + + TakePower(); + TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot + FillTargetMap(); + + if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in Take*/FillTargetMap + return; + + SendCastResult(castResult); + SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... + + // Pass cast spell event to handler (not send triggered by aura spells) + if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED && !m_triggeredByAuraSpell) + { + m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), PROC_FLAG_CAST_SPELL, PROC_FLAG_NONE, 0, SPELL_SCHOOL_MASK_NONE, m_spellInfo, m_IsTriggeredSpell); + + // update pointers base at GUIDs to prevent access to non-existed already object + UpdatePointers(); // pointers can be invalidate at triggered spell casting + } + + // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells + if (m_spellInfo->speed > 0.0f) + { + + // Remove used for cast item if need (it can be already NULL after TakeReagents call + // in case delayed spell remove item at cast delay start + TakeCastItem(); + + // Okay, maps created, now prepare flags + m_immediateHandled = false; + m_spellState = SPELL_STATE_DELAYED; + SetDelayStart(0); + } + else + { + // Immediate spell, no big deal + handle_immediate(); + } +} + +void Spell::handle_immediate() +{ + // start channeling if applicable + if(IsChanneledSpell(m_spellInfo)) + { + m_spellState = SPELL_STATE_CASTING; + SendChannelStart(GetSpellDuration(m_spellInfo)); + } + + // process immediate effects (items, ground, etc.) also initialize some variables + _handle_immediate_phase(); + + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + DoAllEffectOnTarget(&(*ihit)); + + for(std::list::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit) + DoAllEffectOnTarget(&(*ihit)); + + // spell is finished, perform some last features of the spell here + _handle_finish_phase(); + + // Remove used for cast item if need (it can be already NULL after TakeReagents call + TakeCastItem(); + + if(m_spellState != SPELL_STATE_CASTING) + finish(true); // successfully finish spell cast (not last in case autorepeat or channel spell) +} + +uint64 Spell::handle_delayed(uint64 t_offset) +{ + uint64 next_time = 0; + + if (!m_immediateHandled) + { + _handle_immediate_phase(); + m_immediateHandled = true; + } + + // now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases) + for(std::list::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end();++ihit) + { + if (ihit->processed == false) + { + if ( ihit->timeDelay <= t_offset ) + DoAllEffectOnTarget(&(*ihit)); + else if( next_time == 0 || ihit->timeDelay < next_time ) + next_time = ihit->timeDelay; + } + } + + // now recheck gameobject targeting correctness + for(std::list::iterator ighit= m_UniqueGOTargetInfo.begin(); ighit != m_UniqueGOTargetInfo.end();++ighit) + { + if (ighit->processed == false) + { + if ( ighit->timeDelay <= t_offset ) + DoAllEffectOnTarget(&(*ighit)); + else if( next_time == 0 || ighit->timeDelay < next_time ) + next_time = ighit->timeDelay; + } + } + // All targets passed - need finish phase + if (next_time == 0) + { + // spell is finished, perform some last features of the spell here + _handle_finish_phase(); + + finish(true); // successfully finish spell cast + + // return zero, spell is finished now + return 0; + } + else + { + // spell is unfinished, return next execution time + return next_time; + } +} + +void Spell::_handle_immediate_phase() +{ + // handle some immediate features of the spell here + HandleThreatSpells(m_spellInfo->Id); + + m_needSpellLog = IsNeedSendToClient(); + for(uint32 j = 0;j<3;j++) + { + if(m_spellInfo->Effect[j]==0) + continue; + + // apply Send Event effect to ground in case empty target lists + if( m_spellInfo->Effect[j] == SPELL_EFFECT_SEND_EVENT && !HaveTargetsForEffect(j) ) + { + HandleEffects(NULL,NULL,NULL, j); + continue; + } + + // Don't do spell log, if is school damage spell + if(m_spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || m_spellInfo->Effect[j] == 0) + m_needSpellLog = false; + + uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[j]; + if(m_originalCaster) + if(Player* modOwner = m_originalCaster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, EffectChainTarget, this); + + // initialize multipliers + m_damageMultipliers[j] = 1.0f; + if( (m_spellInfo->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || m_spellInfo->EffectImplicitTargetA[j] == TARGET_CHAIN_HEAL) && + (EffectChainTarget > 1) ) + m_applyMultiplierMask |= 1 << j; + } + + // initialize Diminishing Returns Data + m_diminishLevel = DIMINISHING_LEVEL_1; + m_diminishGroup = DIMINISHING_NONE; + + // process items + for(std::list::iterator ihit= m_UniqueItemInfo.begin();ihit != m_UniqueItemInfo.end();++ihit) + DoAllEffectOnTarget(&(*ihit)); + + // process ground + for(uint32 j = 0;j<3;j++) + { + // persistent area auras target only the ground + if(m_spellInfo->Effect[j] == SPELL_EFFECT_PERSISTENT_AREA_AURA) + HandleEffects(NULL,NULL,NULL, j); + } +} + +void Spell::_handle_finish_phase() +{ + // spell log + if(m_needSpellLog) + SendLogExecute(); +} + +void Spell::SendSpellCooldown() +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* _player = (Player*)m_caster; + // Add cooldown for max (disable spell) + // Cooldown started on SendCooldownEvent call + if (m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) + { + _player->AddSpellCooldown(m_spellInfo->Id, 0, time(NULL) - 1); + return; + } + + // init cooldown values + uint32 cat = 0; + int32 rec = -1; + int32 catrec = -1; + + // some special item spells without correct cooldown in SpellInfo + // cooldown information stored in item prototype + // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client. + + if(m_CastItem) + { + ItemPrototype const* proto = m_CastItem->GetProto(); + if(proto) + { + for(int idx = 0; idx < 5; ++idx) + { + if(proto->Spells[idx].SpellId == m_spellInfo->Id) + { + cat = proto->Spells[idx].SpellCategory; + rec = proto->Spells[idx].SpellCooldown; + catrec = proto->Spells[idx].SpellCategoryCooldown; + break; + } + } + } + } + + // if no cooldown found above then base at DBC data + if(rec < 0 && catrec < 0) + { + cat = m_spellInfo->Category; + rec = m_spellInfo->RecoveryTime; + catrec = m_spellInfo->CategoryRecoveryTime; + } + + // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK) + // prevent 0 cooldowns set by another way + if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351)) + rec = _player->GetAttackTime(RANGED_ATTACK); + + // Now we have cooldown data (if found any), time to apply mods + if(rec > 0) + _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, rec, this); + + if(catrec > 0) + _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, catrec, this); + + // replace negative cooldowns by 0 + if (rec < 0) rec = 0; + if (catrec < 0) catrec = 0; + + // no cooldown after applying spell mods + if( rec == 0 && catrec == 0) + return; + + time_t curTime = time(NULL); + + time_t catrecTime = catrec ? curTime+catrec/1000 : 0; // in secs + time_t recTime = rec ? curTime+rec/1000 : catrecTime;// in secs + + // self spell cooldown + if(recTime > 0) + _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, recTime); + + // category spells + if (catrec > 0) + { + SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat); + if(i_scstore != sSpellCategoryStore.end()) + { + for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset) + { + if(*i_scset == m_spellInfo->Id) // skip main spell, already handled above + continue; + + _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime); + } + } + } +} + +void Spell::update(uint32 difftime) +{ + // update pointers based at it's GUIDs + UpdatePointers(); + + if(m_targets.getUnitTargetGUID() && !m_targets.getUnitTarget()) + { + cancel(); + return; + } + + // check if the player caster has moved before the spell finished + if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) && + (m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) && + (m_spellInfo->Effect[0] != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING))) + { + // always cancel for channeled spells + if( m_spellState == SPELL_STATE_CASTING ) + cancel(); + // don't cancel for melee, autorepeat, triggered and instant spells + else if(!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) + cancel(); + } + + switch(m_spellState) + { + case SPELL_STATE_PREPARING: + { + if(m_timer) + { + if(difftime >= m_timer) + m_timer = 0; + else + m_timer -= difftime; + } + + if(m_timer == 0 && !IsNextMeleeSwingSpell() && !IsAutoRepeat()) + cast(); + } break; + case SPELL_STATE_CASTING: + { + if(m_timer > 0) + { + if( m_caster->GetTypeId() == TYPEID_PLAYER ) + { + // check if player has jumped before the channeling finished + if(m_caster->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING)) + cancel(); + + // check for incapacitating player states + if( m_caster->hasUnitState(UNIT_STAT_STUNDED | UNIT_STAT_CONFUSED)) + cancel(); + + // check if player has turned if flag is set + if( m_spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_TURNING && m_castOrientation != m_caster->GetOrientation() ) + cancel(); + } + + // check if there are alive targets left + if (!IsAliveUnitPresentInTargetList()) + { + SendChannelUpdate(0); + finish(); + } + + if(difftime >= m_timer) + m_timer = 0; + else + m_timer -= difftime; + } + + if(m_timer == 0) + { + SendChannelUpdate(0); + + // channeled spell processed independently for quest targeting + // cast at creature (or GO) quest objectives update at successful cast channel finished + // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... ) + if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() ) + { + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + { + TargetInfo* target = &*ihit; + if(!IS_CREATURE_GUID(target->targetGUID)) + continue; + + Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID); + if (unit==NULL) + continue; + + ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id); + } + + for(std::list::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit) + { + GOTargetInfo* target = &*ihit; + + GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID); + if(!go) + continue; + + ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); + } + } + + finish(); + } + } break; + default: + { + }break; + } +} + +void Spell::finish(bool ok) +{ + if(!m_caster) + return; + + if(m_spellState == SPELL_STATE_FINISHED) + return; + + m_spellState = SPELL_STATE_FINISHED; + + //remove spell mods + if (m_caster->GetTypeId() == TYPEID_PLAYER) + ((Player*)m_caster)->RemoveSpellMods(this); + + // other code related only to successfully finished spells + if(!ok) + return; + + //handle SPELL_AURA_ADD_TARGET_TRIGGER auras + Unit::AuraList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER); + for(Unit::AuraList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i) + { + SpellEntry const *auraSpellInfo = (*i)->GetSpellProto(); + uint32 auraSpellIdx = (*i)->GetEffIndex(); + if (IsAffectedBy(auraSpellInfo, auraSpellIdx)) + { + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + if( ihit->effectMask & (1<GetGUID() let load auras at login and speedup most often case + Unit *unit = m_caster->GetGUID()== ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); + if (unit && unit->isAlive()) + { + // Calculate chance at that moment (can be depend for example from combo points) + int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(),unit); + + if(roll_chance_i(chance)) + m_caster->CastSpell(unit, auraSpellInfo->EffectTriggerSpell[auraSpellIdx], true, NULL, (*i)); + } + } + } + } + + if (IsMeleeAttackResetSpell()) + { + m_caster->resetAttackTimer(BASE_ATTACK); + if(m_caster->haveOffhandWeapon()) + m_caster->resetAttackTimer(OFF_ATTACK); + } + + /*if (IsRangedAttackResetSpell()) + m_caster->resetAttackTimer(RANGED_ATTACK);*/ + + // Clear combo at finish state + if(m_caster->GetTypeId() == TYPEID_PLAYER && NeedsComboPoints(m_spellInfo)) + ((Player*)m_caster)->ClearComboPoints(); + + // call triggered spell only at successful cast (after clear combo points -> for add some if need) + if(!m_TriggerSpells.empty()) + TriggerSpell(); + + // Stop Attack for some spells + if( m_spellInfo->Attributes & SPELL_ATTR_STOP_ATTACK_TARGET ) + m_caster->AttackStop(); +} + +void Spell::SendCastResult(uint8 result) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if(((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time + return; + + if(result != 0) + { + WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); + data << uint32(m_spellInfo->Id); + data << uint8(result); // problem + data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) + switch (result) + { + case SPELL_FAILED_REQUIRES_SPELL_FOCUS: + data << uint32(m_spellInfo->RequiresSpellFocus); + break; + case SPELL_FAILED_REQUIRES_AREA: + // hardcode areas limitation case + if( m_spellInfo->Id==41618 || m_spellInfo->Id==41620 ) + data << uint32(3842); + else if( m_spellInfo->Id==41617 || m_spellInfo->Id==41619 ) + data << uint32(3905); + // normal case + else + data << uint32(m_spellInfo->AreaId); + break; + case SPELL_FAILED_TOTEMS: + if(m_spellInfo->Totem[0]) + data << uint32(m_spellInfo->Totem[0]); + if(m_spellInfo->Totem[1]) + data << uint32(m_spellInfo->Totem[1]); + break; + case SPELL_FAILED_TOTEM_CATEGORY: + if(m_spellInfo->TotemCategory[0]) + data << uint32(m_spellInfo->TotemCategory[0]); + if(m_spellInfo->TotemCategory[1]) + data << uint32(m_spellInfo->TotemCategory[1]); + break; + case SPELL_FAILED_EQUIPPED_ITEM_CLASS: + data << uint32(m_spellInfo->EquippedItemClass); + data << uint32(m_spellInfo->EquippedItemSubClassMask); + data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); + break; + } + ((Player*)m_caster)->GetSession()->SendPacket(&data); + } + else + { + WorldPacket data(SMSG_CLEAR_EXTRA_AURA_INFO, (8+4)); + data.append(m_caster->GetPackGUID()); + data << uint32(m_spellInfo->Id); + ((Player*)m_caster)->GetSession()->SendPacket(&data); + } +} + +void Spell::SendSpellStart() +{ + if(!IsNeedSendToClient()) + return; + + sLog.outDebug("Sending SMSG_SPELL_START id=%u",m_spellInfo->Id); + + uint16 castFlags = CAST_FLAG_UNKNOWN1; + if(IsRangedSpell()) + castFlags |= CAST_FLAG_AMMO; + + Unit * target; + if(!m_targets.getUnitTarget()) + target = m_caster; + else + target = m_targets.getUnitTarget(); + + WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); + if(m_CastItem) + data.append(m_CastItem->GetPackGUID()); + else + data.append(m_caster->GetPackGUID()); + + data.append(m_caster->GetPackGUID()); + data << uint32(m_spellInfo->Id); + data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) + data << uint16(castFlags); + data << uint32(m_timer); + + m_targets.write(&data); + + if( castFlags & CAST_FLAG_AMMO ) + WriteAmmoToPacket(&data); + + m_caster->SendMessageToSet(&data, true); +} + +void Spell::SendSpellGo() +{ + // not send invisible spell casting + if(!IsNeedSendToClient()) + return; + + sLog.outDebug("Sending SMSG_SPELL_GO id=%u",m_spellInfo->Id); + + Unit * target; + if(!m_targets.getUnitTarget()) + target = m_caster; + else + target = m_targets.getUnitTarget(); + + uint16 castFlags = CAST_FLAG_UNKNOWN3; + if(IsRangedSpell()) + castFlags |= CAST_FLAG_AMMO; + + WorldPacket data(SMSG_SPELL_GO, 50); // guess size + if(m_CastItem) + data.append(m_CastItem->GetPackGUID()); + else + data.append(m_caster->GetPackGUID()); + + data.append(m_caster->GetPackGUID()); + data << uint32(m_spellInfo->Id); + data << uint16(castFlags); + data << uint32(getMSTime()); // timestamp + + WriteSpellGoTargets(&data); + + m_targets.write(&data); + + if( castFlags & CAST_FLAG_AMMO ) + WriteAmmoToPacket(&data); + + m_caster->SendMessageToSet(&data, true); +} + +void Spell::WriteAmmoToPacket( WorldPacket * data ) +{ + uint32 ammoInventoryType = 0; + uint32 ammoDisplayID = 0; + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK ); + if(pItem) + { + ammoInventoryType = pItem->GetProto()->InventoryType; + if( ammoInventoryType == INVTYPE_THROWN ) + ammoDisplayID = pItem->GetProto()->DisplayInfoID; + else + { + uint32 ammoID = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID); + if(ammoID) + { + ItemPrototype const *pProto = objmgr.GetItemPrototype( ammoID ); + if(pProto) + { + ammoDisplayID = pProto->DisplayInfoID; + ammoInventoryType = pProto->InventoryType; + } + } + else if(m_caster->GetDummyAura(46699)) // Requires No Ammo + { + ammoDisplayID = 5996; // normal arrow + ammoInventoryType = INVTYPE_AMMO; + } + } + } + } + // TODO: implement selection ammo data based at ranged weapon stored in equipmodel/equipinfo/equipslot fields + + *data << uint32(ammoDisplayID); + *data << uint32(ammoInventoryType); +} + +void Spell::WriteSpellGoTargets( WorldPacket * data ) +{ + *data << (uint8)m_countOfHit; + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + if ((*ihit).missCondition == SPELL_MISS_NONE) // Add only hits + *data << uint64(ihit->targetGUID); + + for(std::list::iterator ighit= m_UniqueGOTargetInfo.begin();ighit != m_UniqueGOTargetInfo.end();++ighit) + *data << uint64(ighit->targetGUID); // Always hits + + *data << (uint8)m_countOfMiss; + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + { + if( ihit->missCondition != SPELL_MISS_NONE ) // Add only miss + { + *data << uint64(ihit->targetGUID); + *data << uint8(ihit->missCondition); + if( ihit->missCondition == SPELL_MISS_REFLECT ) + *data << uint8(ihit->reflectResult); + } + } +} + +void Spell::SendLogExecute() +{ + Unit *target = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster; + + WorldPacket data(SMSG_SPELLLOGEXECUTE, (8+4+4+4+4+8)); + + if(m_caster->GetTypeId() == TYPEID_PLAYER) + data.append(m_caster->GetPackGUID()); + else + data.append(target->GetPackGUID()); + + data << uint32(m_spellInfo->Id); + uint32 count1 = 1; + data << uint32(count1); // count1 (effect count?) + for(uint32 i = 0; i < count1; ++i) + { + data << uint32(m_spellInfo->Effect[0]); // spell effect? + uint32 count2 = 1; + data << uint32(count2); // count2 (target count?) + for(uint32 j = 0; j < count2; ++j) + { + switch(m_spellInfo->Effect[0]) + { + case SPELL_EFFECT_POWER_DRAIN: + if(Unit *unit = m_targets.getUnitTarget()) + data.append(unit->GetPackGUID()); + else + data << uint8(0); + data << uint32(0); + data << uint32(0); + data << float(0); + break; + case SPELL_EFFECT_ADD_EXTRA_ATTACKS: + if(Unit *unit = m_targets.getUnitTarget()) + data.append(unit->GetPackGUID()); + else + data << uint8(0); + data << uint32(0); // count? + break; + case SPELL_EFFECT_INTERRUPT_CAST: + if(Unit *unit = m_targets.getUnitTarget()) + data.append(unit->GetPackGUID()); + else + data << uint8(0); + data << uint32(0); // spellid + break; + case SPELL_EFFECT_DURABILITY_DAMAGE: + if(Unit *unit = m_targets.getUnitTarget()) + data.append(unit->GetPackGUID()); + else + data << uint8(0); + data << uint32(0); + data << uint32(0); + break; + case SPELL_EFFECT_OPEN_LOCK: + case SPELL_EFFECT_OPEN_LOCK_ITEM: + if(Item *item = m_targets.getItemTarget()) + data.append(item->GetPackGUID()); + else + data << uint8(0); + break; + case SPELL_EFFECT_CREATE_ITEM: + data << uint32(m_spellInfo->EffectItemType[0]); + break; + case SPELL_EFFECT_SUMMON: + case SPELL_EFFECT_SUMMON_WILD: + case SPELL_EFFECT_SUMMON_GUARDIAN: + case SPELL_EFFECT_TRANS_DOOR: + case SPELL_EFFECT_SUMMON_PET: + case SPELL_EFFECT_SUMMON_POSSESSED: + case SPELL_EFFECT_SUMMON_TOTEM: + case SPELL_EFFECT_SUMMON_OBJECT_WILD: + case SPELL_EFFECT_CREATE_HOUSE: + case SPELL_EFFECT_DUEL: + case SPELL_EFFECT_SUMMON_TOTEM_SLOT1: + case SPELL_EFFECT_SUMMON_TOTEM_SLOT2: + case SPELL_EFFECT_SUMMON_TOTEM_SLOT3: + case SPELL_EFFECT_SUMMON_TOTEM_SLOT4: + case SPELL_EFFECT_SUMMON_PHANTASM: + case SPELL_EFFECT_SUMMON_CRITTER: + case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: + case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: + case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: + case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: + case SPELL_EFFECT_SUMMON_DEMON: + case SPELL_EFFECT_150: + if(Unit *unit = m_targets.getUnitTarget()) + data.append(unit->GetPackGUID()); + else if(m_targets.getItemTargetGUID()) + data.appendPackGUID(m_targets.getItemTargetGUID()); + else if(GameObject *go = m_targets.getGOTarget()) + data.append(go->GetPackGUID()); + else + data << uint8(0); // guid + break; + case SPELL_EFFECT_FEED_PET: + data << uint32(m_targets.getItemTargetEntry()); + break; + case SPELL_EFFECT_DISMISS_PET: + if(Unit *unit = m_targets.getUnitTarget()) + data.append(unit->GetPackGUID()); + else + data << uint8(0); + break; + default: + return; + } + } + } + + m_caster->SendMessageToSet(&data, true); +} + +void Spell::SendInterrupted(uint8 result) +{ + WorldPacket data(SMSG_SPELL_FAILURE, (8+4+1)); + data.append(m_caster->GetPackGUID()); + data << m_spellInfo->Id; + data << result; + m_caster->SendMessageToSet(&data, true); + + data.Initialize(SMSG_SPELL_FAILED_OTHER, (8+4)); + data.append(m_caster->GetPackGUID()); + data << m_spellInfo->Id; + m_caster->SendMessageToSet(&data, true); +} + +void Spell::SendChannelUpdate(uint32 time) +{ + if(time == 0) + { + m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,0); + m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,0); + } + + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + WorldPacket data( MSG_CHANNEL_UPDATE, 8+4 ); + data.append(m_caster->GetPackGUID()); + data << time; + + ((Player*)m_caster)->GetSession()->SendPacket( &data ); +} + +void Spell::SendChannelStart(uint32 duration) +{ + WorldObject* target = NULL; + + // select first not rsusted target from target list for _0_ effect + if(!m_UniqueTargetInfo.empty()) + { + for(std::list::iterator itr= m_UniqueTargetInfo.begin();itr != m_UniqueTargetInfo.end();++itr) + { + if( (itr->effectMask & (1<<0)) && itr->reflectResult==SPELL_MISS_NONE && itr->targetGUID != m_caster->GetGUID()) + { + target = ObjectAccessor::GetUnit(*m_caster, itr->targetGUID); + break; + } + } + } + else if(!m_UniqueGOTargetInfo.empty()) + { + for(std::list::iterator itr= m_UniqueGOTargetInfo.begin();itr != m_UniqueGOTargetInfo.end();++itr) + { + if(itr->effectMask & (1<<0) ) + { + target = ObjectAccessor::GetGameObject(*m_caster, itr->targetGUID); + break; + } + } + } + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data( MSG_CHANNEL_START, (8+4+4) ); + data.append(m_caster->GetPackGUID()); + data << m_spellInfo->Id; + data << duration; + + ((Player*)m_caster)->GetSession()->SendPacket( &data ); + } + + m_timer = duration; + if(target) + m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, target->GetGUID()); + m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, m_spellInfo->Id); +} + +void Spell::SendResurrectRequest(Player* target) +{ + WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+2+4)); + data << m_caster->GetGUID(); + data << uint32(1) << uint16(0) << uint32(1); + + target->GetSession()->SendPacket(&data); +} + +void Spell::SendPlaySpellVisual(uint32 SpellID) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); + data << m_caster->GetGUID(); + data << SpellID; + ((Player*)m_caster)->GetSession()->SendPacket(&data); +} + +void Spell::TakeCastItem() +{ + if(!m_CastItem || m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // not remove cast item at triggered spell (equipping, weapon damage, etc) + if(m_IsTriggeredSpell) + return; + + ItemPrototype const *proto = m_CastItem->GetProto(); + + if(!proto) + { + // This code is to avoid a crash + // I'm not sure, if this is really an error, but I guess every item needs a prototype + sLog.outError("Cast item has no item prototype highId=%d, lowId=%d",m_CastItem->GetGUIDHigh(), m_CastItem->GetGUIDLow()); + return; + } + + bool expendable = false; + bool withoutCharges = false; + + for (int i = 0; i<5; i++) + { + if (proto->Spells[i].SpellId) + { + // item has limited charges + if (proto->Spells[i].SpellCharges) + { + if (proto->Spells[i].SpellCharges < 0) + expendable = true; + + int32 charges = m_CastItem->GetSpellCharges(i); + + // item has charges left + if (charges) + { + (charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use + if (proto->Stackable < 2) + m_CastItem->SetSpellCharges(i, charges); + m_CastItem->SetState(ITEM_CHANGED, (Player*)m_caster); + } + + // all charges used + withoutCharges = (charges == 0); + } + } + } + + if (expendable && withoutCharges) + { + uint32 count = 1; + ((Player*)m_caster)->DestroyItemCount(m_CastItem, count, true); + + // prevent crash at access to deleted m_targets.getItemTarget + if(m_CastItem==m_targets.getItemTarget()) + m_targets.setItemTarget(NULL); + + m_CastItem = NULL; + } +} + +void Spell::TakePower() +{ + if(m_CastItem || m_triggeredByAuraSpell) + return; + + // health as power used + if(m_spellInfo->powerType == POWER_HEALTH) + { + m_caster->ModifyHealth( -(int32)m_powerCost ); + return; + } + + if(m_spellInfo->powerType >= MAX_POWERS) + { + sLog.outError("Spell::TakePower: Unknown power type '%d'", m_spellInfo->powerType); + return; + } + + Powers powerType = Powers(m_spellInfo->powerType); + + m_caster->ModifyPower(powerType, -(int32)m_powerCost); + + // Set the five second timer + if (powerType == POWER_MANA && m_powerCost > 0) + m_caster->SetLastManaUse(getMSTime()); +} + +void Spell::TakeReagents() +{ + if(m_IsTriggeredSpell) // reagents used in triggered spell removed by original spell or don't must be removed. + return; + + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if (m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP && + m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION)) + return; + + Player* p_caster = (Player*)m_caster; + + for(uint32 x=0;x<8;x++) + { + if(m_spellInfo->Reagent[x] <= 0) + continue; + + uint32 itemid = m_spellInfo->Reagent[x]; + uint32 itemcount = m_spellInfo->ReagentCount[x]; + + // if CastItem is also spell reagent + if (m_CastItem) + { + ItemPrototype const *proto = m_CastItem->GetProto(); + if( proto && proto->ItemId == itemid ) + { + for(int s=0;s<5;s++) + { + // CastItem will be used up and does not count as reagent + int32 charges = m_CastItem->GetSpellCharges(s); + if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2) + { + ++itemcount; + break; + } + } + + m_CastItem = NULL; + } + } + + // if getItemTarget is also spell reagent + if (m_targets.getItemTargetEntry()==itemid) + m_targets.setItemTarget(NULL); + + p_caster->DestroyItemCount(itemid, itemcount, true); + } +} + +void Spell::HandleThreatSpells(uint32 spellId) +{ + if(!m_targets.getUnitTarget() || !spellId) + return; + + if(!m_targets.getUnitTarget()->CanHaveThreatList()) + return; + + SpellThreatEntry const *threatSpell = sSpellThreatStore.LookupEntry(spellId); + if(!threatSpell) + return; + + m_targets.getUnitTarget()->AddThreat(m_caster, float(threatSpell->threat)); + + DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat); +} + +void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float DamageMultiplier) +{ + unitTarget = pUnitTarget; + itemTarget = pItemTarget; + gameObjTarget = pGOTarget; + + uint8 eff = m_spellInfo->Effect[i]; + uint32 mechanic = m_spellInfo->EffectMechanic[i]; + + damage = int32(CalculateDamage((uint8)i,unitTarget)*DamageMultiplier); + + sLog.outDebug( "Spell: Effect : %u", eff); + + //Simply return. Do not display "immune" in red text on client + if(unitTarget && unitTarget->IsImmunedToSpellEffect(eff, mechanic)) + return; + + if(eff TOTAL_SPELL_EFFECTS ", eff); + if (m_CastItem) + EffectEnchantItemTmp(i); + else + { + sLog.outError("SPELL: unknown effect %u spell id %u\n", + eff, m_spellInfo->Id); + } + } + */ +} + +void Spell::TriggerSpell() +{ + for(TriggerSpells::iterator si=m_TriggerSpells.begin(); si!=m_TriggerSpells.end(); ++si) + { + Spell* spell = new Spell(m_caster, (*si), true, m_originalCasterGUID, this->m_selfContainer); + spell->prepare(&m_targets); // use original spell original targets + } +} + +uint8 Spell::CanCast(bool strict) +{ + // check cooldowns to prevent cheating + if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) + { + if(m_triggeredByAuraSpell) + return SPELL_FAILED_DONT_REPORT; + else + return SPELL_FAILED_NOT_READY; + } + + // only allow triggered spells if at an ended battleground + if( !m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER) + if(BattleGround * bg = ((Player*)m_caster)->GetBattleGround()) + if(bg->GetStatus() == STATUS_WAIT_LEAVE) + return SPELL_FAILED_DONT_REPORT; + + // only check at first call, Stealth auras are already removed at second call + // for now, ignore triggered spells + if( strict && !m_IsTriggeredSpell) + { + // Cannot be used in this stance/form + if(uint8 shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form)) + return shapeError; + + if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura())) + return SPELL_FAILED_ONLY_STEALTHED; + } + + // caster state requirements + if(m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState))) + return SPELL_FAILED_CASTER_AURASTATE; + if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot))) + return SPELL_FAILED_CASTER_AURASTATE; + + // cancel autorepeat spells if cast start when moving + // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code) + if( m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->isMoving() ) + { + // skip stuck spell to allow use it in falling case and apply spell limitations at movement + if( (!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) || m_spellInfo->Effect[0] != SPELL_EFFECT_STUCK) && + (IsAutoRepeat() || (m_spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0) ) + return SPELL_FAILED_MOVING; + } + + Unit *target = m_targets.getUnitTarget(); + + if(target) + { + // target state requirements (not allowed state), apply to self also + if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot))) + return SPELL_FAILED_TARGET_AURASTATE; + + + if(target != m_caster) + { + // target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds + if(m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState))) + return SPELL_FAILED_TARGET_AURASTATE; + + // Not allow casting on flying player + if (target->isInFlight()) + return SPELL_FAILED_BAD_TARGETS; + + if(VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target)) + return SPELL_FAILED_LINE_OF_SIGHT; + + // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode + // this case can be triggered if rank not found (too low-level target for first rank) + if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) + { + for(int i=0;i<3;i++) + { + if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) + if(target->getLevel() + 10 < m_spellInfo->spellLevel) + return SPELL_FAILED_LOWLEVEL; + } + } + } + + // check pet presents + for(int j=0;j<3;j++) + { + if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_PET) + { + target = m_caster->GetPet(); + if(!target) + { + if(m_triggeredByAuraSpell) // not report pet not existence for triggered spells + return SPELL_FAILED_DONT_REPORT; + else + return SPELL_FAILED_NO_PET; + } + break; + } + } + + //check creature type + //ignore self casts (including area casts when caster selected as target) + if(target != m_caster) + { + if(!CheckTargetCreatureType(target)) + { + if(target->GetTypeId()==TYPEID_PLAYER) + return SPELL_FAILED_TARGET_IS_PLAYER; + else + return SPELL_FAILED_BAD_TARGETS; + } + } + + // TODO: this check can be applied and for player to prevent cheating when IsPositiveSpell will return always correct result. + // check target for pet/charmed casts (not self targeted), self targeted cast used for area effects and etc + if(m_caster != target && m_caster->GetTypeId()==TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID()) + { + // check correctness positive/negative cast target (pet cast real check and cheating check) + if(IsPositiveSpell(m_spellInfo->Id)) + { + if(m_caster->IsHostileTo(target)) + return SPELL_FAILED_BAD_TARGETS; + } + else + { + if(m_caster->IsFriendlyTo(target)) + return SPELL_FAILED_BAD_TARGETS; + } + } + + if(IsPositiveSpell(m_spellInfo->Id)) + { + if(target->IsImmunedToSpell(m_spellInfo,false)) + return SPELL_FAILED_TARGET_AURASTATE; + } + + //Must be behind the target. + if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) ) + { + SendInterrupted(2); + return SPELL_FAILED_NOT_BEHIND; + } + + //Target must be facing you. + if((m_spellInfo->Attributes == 0x150010) && !target->HasInArc(M_PI, m_caster) ) + { + SendInterrupted(2); + return SPELL_FAILED_NOT_INFRONT; + } + + // check if target is in combat + if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) + { + return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + } + } + // Spell casted only on battleground + if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) && m_caster->GetTypeId()==TYPEID_PLAYER) + if(!((Player*)m_caster)->InBattleGround()) + return SPELL_FAILED_ONLY_BATTLEGROUNDS; + + // do not allow spells to be cast in arenas + // - with greater than 15 min CD without SPELL_ATTR_EX4_USABLE_IN_ARENA flag + // - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag + if( (m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) || + GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * 1000 && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) ) + if(MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId())) + if(mapEntry->IsBattleArena()) + return SPELL_FAILED_NOT_IN_ARENA; + + // zone check + if(!IsSpellAllowedInLocation(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId())) + return SPELL_FAILED_REQUIRES_AREA; + + // not let players cast spells at mount (and let do it to creatures) + if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell && + !IsPassiveSpell(m_spellInfo->Id) && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_MOUNTED) ) + { + if(m_caster->isInFlight()) + return SPELL_FAILED_NOT_FLYING; + else + return SPELL_FAILED_NOT_MOUNTED; + } + + // always (except passive spells) check items (focus object can be required for any type casts) + if(!IsPassiveSpell(m_spellInfo->Id)) + if(uint8 castResult = CheckItems()) + return castResult; + + //ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38 + if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example) + { + for(uint8 j = 0; j < 3; j++) + { + if( m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || + m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[j] != TARGET_SELF || + m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || + m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) + { + bool okDoo = false; + + SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); + SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); + if(lower==upper) + sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id); + + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); + float range = GetSpellMaxRange(srange); + + Creature* creatureScriptTarget = NULL; + GameObject* goScriptTarget = NULL; + + for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST) + { + switch(i_spellST->second.type) + { + case SPELL_TARGET_TYPE_GAMEOBJECT: + { + GameObject* p_GameObject = NULL; + + if(i_spellST->second.targetEntry) + { + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + MaNGOS::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range); + MaNGOS::GameObjectLastSearcher checker(p_GameObject,go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + + if(p_GameObject) + { + // remember found target and range, next attempt will find more near target with another entry + creatureScriptTarget = NULL; + goScriptTarget = p_GameObject; + range = go_check.GetLastRange(); + } + } + else if( focusObject ) //Focus Object + { + float frange = m_caster->GetDistance(focusObject); + if(range >= frange) + { + creatureScriptTarget = NULL; + goScriptTarget = focusObject; + range = frange; + } + } + break; + } + case SPELL_TARGET_TYPE_CREATURE: + case SPELL_TARGET_TYPE_DEAD: + default: + { + Creature *p_Creature = NULL; + + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); // Really don't know what is that??? + + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range); + MaNGOS::CreatureLastSearcher searcher(p_Creature, u_check); + + TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + + if(p_Creature ) + { + creatureScriptTarget = p_Creature; + goScriptTarget = NULL; + range = u_check.GetLastRange(); + } + break; + } + } + } + + if(creatureScriptTarget) + { + // store coordinates for TARGET_SCRIPT_COORDINATES + if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || + m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) + { + m_targets.setDestination(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ()); + + if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) + AddUnitTarget(creatureScriptTarget, j); + } + // store explicit target for TARGET_SCRIPT + else + AddUnitTarget(creatureScriptTarget, j); + } + else if(goScriptTarget) + { + // store coordinates for TARGET_SCRIPT_COORDINATES + if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || + m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) + { + m_targets.setDestination(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ()); + + if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) + AddGOTarget(goScriptTarget, j); + } + // store explicit target for TARGET_SCRIPT + else + AddGOTarget(goScriptTarget, j); + } + //Missing DB Entry or targets for this spellEffect. + else + { + // not report target not existence for triggered spells + if(m_triggeredByAuraSpell || m_IsTriggeredSpell) + return SPELL_FAILED_DONT_REPORT; + else + return SPELL_FAILED_BAD_TARGETS; + } + } + } + } + + if(uint8 castResult = CheckRange(strict)) + return castResult; + + { + if(uint8 castResult = CheckPower()) + return castResult; + } + + if(!m_triggeredByAuraSpell) // triggered spell not affected by stun/etc + if(uint8 castResult = CheckCasterAuras()) + return castResult; + + for (int i = 0; i < 3; i++) + { + // for effects of spells that have only one target + switch(m_spellInfo->Effect[i]) + { + case SPELL_EFFECT_DUMMY: + { + if(m_spellInfo->SpellIconID == 1648) // Execute + { + if(!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) + return SPELL_FAILED_BAD_TARGETS; + } + else if (m_spellInfo->Id == 51582) // Rocket Boots Engaged + { + if(m_caster->IsInWater()) + return SPELL_FAILED_ONLY_ABOVEWATER; + } + else if(m_spellInfo->SpellIconID==156) // Holy Shock + { + // spell different for friends and enemies + // hart version required facing + if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, target )) + return SPELL_FAILED_UNIT_NOT_INFRONT; + } + break; + } + case SPELL_EFFECT_SCHOOL_DAMAGE: + { + // Hammer of Wrath + if(m_spellInfo->SpellVisual == 7250) + { + if (!m_targets.getUnitTarget()) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + + if(m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) + return SPELL_FAILED_BAD_TARGETS; + } + break; + } + case SPELL_EFFECT_TAMECREATURE: + { + if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + + if (m_targets.getUnitTarget()->getLevel() > m_caster->getLevel()) + return SPELL_FAILED_HIGHLEVEL; + + CreatureInfo const *cinfo = ((Creature*)m_targets.getUnitTarget())->GetCreatureInfo(); + if( cinfo->type != CREATURE_TYPE_BEAST ) + return SPELL_FAILED_BAD_TARGETS; + + // use SMSG_PET_TAME_FAILURE? + if( !(cinfo->flag1 & 1) || !(cinfo->family) ) + return SPELL_FAILED_BAD_TARGETS; + + if(m_caster->GetPetGUID()) + return SPELL_FAILED_ALREADY_HAVE_SUMMON; + + if(m_caster->GetCharmGUID()) + return SPELL_FAILED_ALREADY_HAVE_CHARM; + + break; + } + case SPELL_EFFECT_LEARN_SPELL: + { + if(m_spellInfo->EffectImplicitTargetA[i] != TARGET_PET) + break; + + Pet* pet = m_caster->GetPet(); + + if(!pet) + return SPELL_FAILED_NO_PET; + + SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); + + if(!learn_spellproto) + return SPELL_FAILED_NOT_KNOWN; + + if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id)) + return SPELL_FAILED_TOO_MANY_SKILLS; + + if(m_spellInfo->spellLevel > pet->getLevel()) + return SPELL_FAILED_LOWLEVEL; + + if(!pet->HasTPForSpell(learn_spellproto->Id)) + return SPELL_FAILED_TRAINING_POINTS; + + break; + } + case SPELL_EFFECT_LEARN_PET_SPELL: + { + Pet* pet = m_caster->GetPet(); + + if(!pet) + return SPELL_FAILED_NO_PET; + + SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); + + if(!learn_spellproto) + return SPELL_FAILED_NOT_KNOWN; + + if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id)) + return SPELL_FAILED_TOO_MANY_SKILLS; + + if(m_spellInfo->spellLevel > pet->getLevel()) + return SPELL_FAILED_LOWLEVEL; + + if(!pet->HasTPForSpell(learn_spellproto->Id)) + return SPELL_FAILED_TRAINING_POINTS; + + break; + } + case SPELL_EFFECT_FEED_PET: + { + if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getItemTarget() ) + return SPELL_FAILED_BAD_TARGETS; + + Pet* pet = m_caster->GetPet(); + + if(!pet) + return SPELL_FAILED_NO_PET; + + if(!pet->HaveInDiet(m_targets.getItemTarget()->GetProto())) + return SPELL_FAILED_WRONG_PET_FOOD; + + if(!pet->GetCurrentFoodBenefitLevel(m_targets.getItemTarget()->GetProto()->ItemLevel)) + return SPELL_FAILED_FOOD_LOWLEVEL; + + if(m_caster->isInCombat() || pet->isInCombat()) + return SPELL_FAILED_AFFECTING_COMBAT; + + break; + } + case SPELL_EFFECT_POWER_BURN: + case SPELL_EFFECT_POWER_DRAIN: + { + // Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects) + if(m_caster->GetTypeId() == TYPEID_PLAYER) + if(Unit* target = m_targets.getUnitTarget()) + if(target!=m_caster && target->getPowerType()!=m_spellInfo->EffectMiscValue[i]) + return SPELL_FAILED_BAD_TARGETS; + break; + } + case SPELL_EFFECT_CHARGE: + { + if (m_caster->hasUnitState(UNIT_STAT_ROOT)) + return SPELL_FAILED_ROOTED; + + break; + } + case SPELL_EFFECT_SKINNING: + { + if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() != TYPEID_UNIT) + return SPELL_FAILED_BAD_TARGETS; + + if( !(m_targets.getUnitTarget()->GetUInt32Value(UNIT_FIELD_FLAGS) & UNIT_FLAG_SKINNABLE) ) + return SPELL_FAILED_TARGET_UNSKINNABLE; + + Creature* creature = (Creature*)m_targets.getUnitTarget(); + if ( creature->GetCreatureType() != CREATURE_TYPE_CRITTER && ( !creature->lootForBody || !creature->loot.empty() ) ) + { + return SPELL_FAILED_TARGET_NOT_LOOTED; + } + + uint32 skill; + if(creature->GetCreatureInfo()->flag1 & 256) + skill = SKILL_HERBALISM; // special case + else if(creature->GetCreatureInfo()->flag1 & 512) + skill = SKILL_MINING; // special case + else + skill = SKILL_SKINNING; // normal case + + int32 skillValue = ((Player*)m_caster)->GetSkillValue(skill); + int32 TargetLevel = m_targets.getUnitTarget()->getLevel(); + int32 ReqValue = (skillValue < 100 ? (TargetLevel-10)*10 : TargetLevel*5); + if (ReqValue > skillValue) + return SPELL_FAILED_LOW_CASTLEVEL; + + // chance for fail at orange skinning attempt + if( (m_selfContainer && (*m_selfContainer) == this) && + skillValue < sWorld.GetConfigMaxSkillValue() && + (ReqValue < 0 ? 0 : ReqValue) > irand(skillValue-25, skillValue+37) ) + return SPELL_FAILED_TRY_AGAIN; + + break; + } + case SPELL_EFFECT_OPEN_LOCK_ITEM: + case SPELL_EFFECT_OPEN_LOCK: + { + if( m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT && + m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT_ITEM ) + break; + + if( m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc. + // we need a go target in case of TARGET_GAMEOBJECT + || m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT && !m_targets.getGOTarget() + // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM + || m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_ITEM && !m_targets.getGOTarget() && + (!m_targets.getItemTarget() || !m_targets.getItemTarget()->GetProto()->LockID || m_targets.getItemTarget()->GetOwner() != m_caster ) ) + return SPELL_FAILED_BAD_TARGETS; + + // get the lock entry + LockEntry const *lockInfo = NULL; + if (GameObject* go=m_targets.getGOTarget()) + lockInfo = sLockStore.LookupEntry(go->GetLockId()); + else if(Item* itm=m_targets.getItemTarget()) + lockInfo = sLockStore.LookupEntry(itm->GetProto()->LockID); + + // check lock compatibility + if (lockInfo) + { + // check for lock - key pair (checked by client also, just prevent cheating + bool ok_key = false; + for(int it = 0; it < 5; ++it) + { + switch(lockInfo->keytype[it]) + { + case LOCK_KEY_NONE: + break; + case LOCK_KEY_ITEM: + { + if(lockInfo->key[it]) + { + if(m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it]) + ok_key =true; + break; + } + } + case LOCK_KEY_SKILL: + { + if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->key[it]) + break; + + switch(lockInfo->key[it]) + { + case LOCKTYPE_HERBALISM: + if(((Player*)m_caster)->HasSkill(SKILL_HERBALISM)) + ok_key =true; + break; + case LOCKTYPE_MINING: + if(((Player*)m_caster)->HasSkill(SKILL_MINING)) + ok_key =true; + break; + default: + ok_key =true; + break; + } + } + } + if(ok_key) + break; + } + + if(!ok_key) + return SPELL_FAILED_BAD_TARGETS; + } + + // chance for fail at orange mining/herb/LockPicking gathering attempt + if (!m_selfContainer || ((*m_selfContainer) != this)) + break; + + // get the skill value of the player + int32 SkillValue = 0; + bool canFailAtMax = true; + if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_HERBALISM) + { + SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_HERBALISM); + canFailAtMax = false; + } + else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_MINING) + { + SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_MINING); + canFailAtMax = false; + } + else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) + SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_LOCKPICKING); + + // castitem check: rogue using skeleton keys. the skill values should not be added in this case. + if(m_CastItem) + SkillValue = 0; + + // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value) + SkillValue += m_currentBasePoints[i]+1; + + // get the required lock value + int32 ReqValue=0; + if (lockInfo) + { + // check for lock - key pair + bool ok = false; + for(int it = 0; it < 5; ++it) + { + if(lockInfo->keytype[it]==LOCK_KEY_ITEM && lockInfo->key[it] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it]) + { + // if so, we're good to go + ok = true; + break; + } + } + if(ok) + break; + + if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) + ReqValue = lockInfo->requiredlockskill; + else + ReqValue = lockInfo->requiredminingskill; + } + + // skill doesn't meet the required value + if (ReqValue > SkillValue) + return SPELL_FAILED_LOW_CASTLEVEL; + + // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill) + if((canFailAtMax || SkillValue < sWorld.GetConfigMaxSkillValue()) && ReqValue > irand(SkillValue-25, SkillValue+37)) + return SPELL_FAILED_TRY_AGAIN; + + break; + } + case SPELL_EFFECT_SUMMON_DEAD_PET: + { + Creature *pet = m_caster->GetPet(); + if(!pet) + return SPELL_FAILED_NO_PET; + + if(pet->isAlive()) + return SPELL_FAILED_ALREADY_HAVE_SUMMON; + + break; + } + // This is generic summon effect now and don't make this check for summon types similar + // SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN. + // These won't show up in m_caster->GetPetGUID() + case SPELL_EFFECT_SUMMON: + { + switch(m_spellInfo->EffectMiscValueB[i]) + { + case SUMMON_TYPE_POSESSED: + case SUMMON_TYPE_POSESSED2: + case SUMMON_TYPE_DEMON: + case SUMMON_TYPE_SUMMON: + { + if(m_caster->GetPetGUID()) + return SPELL_FAILED_ALREADY_HAVE_SUMMON; + + if(m_caster->GetCharmGUID()) + return SPELL_FAILED_ALREADY_HAVE_CHARM; + break; + } + } + break; + } + // Don't make this check for SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN. + // These won't show up in m_caster->GetPetGUID() + case SPELL_EFFECT_SUMMON_POSSESSED: + case SPELL_EFFECT_SUMMON_PHANTASM: + case SPELL_EFFECT_SUMMON_DEMON: + { + if(m_caster->GetPetGUID()) + return SPELL_FAILED_ALREADY_HAVE_SUMMON; + + if(m_caster->GetCharmGUID()) + return SPELL_FAILED_ALREADY_HAVE_CHARM; + + break; + } + case SPELL_EFFECT_SUMMON_PET: + { + if(m_caster->GetPetGUID()) //let warlock do a replacement summon + { + + Pet* pet = ((Player*)m_caster)->GetPet(); + + if (m_caster->GetTypeId()==TYPEID_PLAYER && m_caster->getClass()==CLASS_WARLOCK) + { + if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player) + pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetGUID()); + } + else + return SPELL_FAILED_ALREADY_HAVE_SUMMON; + } + + if(m_caster->GetCharmGUID()) + return SPELL_FAILED_ALREADY_HAVE_CHARM; + + break; + } + case SPELL_EFFECT_SUMMON_PLAYER: + { + if(m_caster->GetTypeId()!=TYPEID_PLAYER) + return SPELL_FAILED_BAD_TARGETS; + if(!((Player*)m_caster)->GetSelection()) + return SPELL_FAILED_BAD_TARGETS; + + Player* target = objmgr.GetPlayer(((Player*)m_caster)->GetSelection()); + if( !target || ((Player*)m_caster)==target || !target->IsInSameRaidWith((Player*)m_caster) ) + return SPELL_FAILED_BAD_TARGETS; + + // check if our map is dungeon + if( sMapStore.LookupEntry(m_caster->GetMapId())->IsDungeon() ) + { + InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(m_caster->GetMapId()); + if(!instance) + return SPELL_FAILED_TARGET_NOT_IN_INSTANCE; + if ( instance->levelMin > target->getLevel() ) + return SPELL_FAILED_LOWLEVEL; + if ( instance->levelMax && instance->levelMax < target->getLevel() ) + return SPELL_FAILED_HIGHLEVEL; + } + break; + } + case SPELL_EFFECT_LEAP: + case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER: + { + float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation()); + float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation()); + // teleport a bit above terrain level to avoid falling below it + float fz = MapManager::Instance().GetBaseMap(m_caster->GetMapId())->GetHeight(fx,fy,m_caster->GetPositionZ(),true); + if(fz <= INVALID_HEIGHT) // note: this also will prevent use effect in instances without vmaps height enabled + return SPELL_FAILED_TRY_AGAIN; + + float caster_pos_z = m_caster->GetPositionZ(); + // Control the caster to not climb or drop when +-fz > 8 + if(!(fz<=caster_pos_z+8 && fz>=caster_pos_z-8)) + return SPELL_FAILED_TRY_AGAIN; + + // not allow use this effect at battleground until battleground start + if(m_caster->GetTypeId()==TYPEID_PLAYER) + if(BattleGround const *bg = ((Player*)m_caster)->GetBattleGround()) + if(bg->GetStatus() != STATUS_IN_PROGRESS) + return SPELL_FAILED_TRY_AGAIN; + break; + } + case SPELL_EFFECT_STEAL_BENEFICIAL_BUFF: + { + if (m_targets.getUnitTarget()==m_caster) + return SPELL_FAILED_BAD_TARGETS; + break; + } + default:break; + } + } + + for (int i = 0; i < 3; i++) + { + switch(m_spellInfo->EffectApplyAuraName[i]) + { + case SPELL_AURA_MOD_POSSESS: + case SPELL_AURA_MOD_CHARM: + { + if(m_caster->GetPetGUID()) + return SPELL_FAILED_ALREADY_HAVE_SUMMON; + + if(m_caster->GetCharmGUID()) + return SPELL_FAILED_ALREADY_HAVE_CHARM; + + if(m_caster->GetCharmerGUID()) + return SPELL_FAILED_CHARMED; + + if(!m_targets.getUnitTarget()) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + + if(m_targets.getUnitTarget()->GetCharmerGUID()) + return SPELL_FAILED_CHARMED; + + if(int32(m_targets.getUnitTarget()->getLevel()) > CalculateDamage(i,m_targets.getUnitTarget())) + return SPELL_FAILED_HIGHLEVEL; + };break; + case SPELL_AURA_MOUNTED: + { + if (m_caster->IsInWater()) + return SPELL_FAILED_ONLY_ABOVEWATER; + + if (m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->GetTransport()) + return SPELL_FAILED_NO_MOUNTS_ALLOWED; + + // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells + if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaId) + return SPELL_FAILED_NO_MOUNTS_ALLOWED; + + if (m_caster->GetAreaId()==35) + return SPELL_FAILED_NO_MOUNTS_ALLOWED; + + ShapeshiftForm form = m_caster->m_form; + if( form == FORM_CAT || form == FORM_TREE || form == FORM_TRAVEL || + form == FORM_AQUA || form == FORM_BEAR || form == FORM_DIREBEAR || + form == FORM_CREATUREBEAR || form == FORM_GHOSTWOLF || form == FORM_FLIGHT || + form == FORM_FLIGHT_EPIC || form == FORM_MOONKIN ) + return SPELL_FAILED_NOT_SHAPESHIFT; + + break; + } + case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS: + { + if(!m_targets.getUnitTarget()) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + + // can be casted at non-friendly unit or own pet/charm + if(m_caster->IsFriendlyTo(m_targets.getUnitTarget())) + return SPELL_FAILED_TARGET_FRIENDLY; + };break; + case SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED: + case SPELL_AURA_FLY: + { + // not allow cast fly spells at old maps by players (all spells is self target) + if(m_caster->GetTypeId()==TYPEID_PLAYER) + { + if( !((Player*)m_caster)->isGameMaster() && + GetVirtualMapForMapAndZone(m_caster->GetMapId(),m_caster->GetZoneId()) != 530) + return SPELL_FAILED_NOT_HERE; + } + };break; + case SPELL_AURA_PERIODIC_MANA_LEECH: + { + if (!m_targets.getUnitTarget()) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + + if (m_caster->GetTypeId()!=TYPEID_PLAYER || m_CastItem) + break; + + if(m_targets.getUnitTarget()->getPowerType()!=POWER_MANA) + return SPELL_FAILED_BAD_TARGETS; + break; + } + default:break; + } + } + + // all ok + return 0; +} + +int16 Spell::PetCanCast(Unit* target) +{ + if(!m_caster->isAlive()) + return SPELL_FAILED_CASTER_DEAD; + + if(m_caster->IsNonMeleeSpellCasted(false)) //prevent spellcast interuption by another spellcast + return SPELL_FAILED_SPELL_IN_PROGRESS; + if(m_caster->isInCombat() && IsNonCombatSpell(m_spellInfo)) + return SPELL_FAILED_AFFECTING_COMBAT; + + if(m_caster->GetTypeId()==TYPEID_UNIT && (((Creature*)m_caster)->isPet() || m_caster->isCharmed())) + { + //dead owner (pets still alive when owners ressed?) + if(m_caster->GetCharmerOrOwner() && !m_caster->GetCharmerOrOwner()->isAlive()) + return SPELL_FAILED_CASTER_DEAD; + + if(!target && m_targets.getUnitTarget()) + target = m_targets.getUnitTarget(); + + bool need = false; + for(uint32 i = 0;i<3;i++) + { + if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_CHAIN_DAMAGE || m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND || m_spellInfo->EffectImplicitTargetA[i] == TARGET_DUELVSPLAYER || m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_PARTY || m_spellInfo->EffectImplicitTargetA[i] == TARGET_CURRENT_ENEMY_COORDINATES) + { + need = true; + if(!target) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + break; + } + } + if(need) + m_targets.setUnitTarget(target); + + Unit* _target = m_targets.getUnitTarget(); + + if(_target) //for target dead/target not valid + { + if(!_target->isAlive()) + return SPELL_FAILED_BAD_TARGETS; + + if(IsPositiveSpell(m_spellInfo->Id)) + { + if(m_caster->IsHostileTo(_target)) + return SPELL_FAILED_BAD_TARGETS; + } + else + { + bool duelvsplayertar = false; + for(int j=0;j<3;j++) + { + //TARGET_DUELVSPLAYER is positive AND negative + duelvsplayertar |= (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DUELVSPLAYER); + } + if(m_caster->IsFriendlyTo(target) && !duelvsplayertar) + { + return SPELL_FAILED_BAD_TARGETS; + } + } + } + //cooldown + if(((Creature*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) + return SPELL_FAILED_NOT_READY; + } + + uint16 result = CanCast(true); + if(result != 0) + return result; + else + return -1; //this allows to check spell fail 0, in combat +} + +uint8 Spell::CheckCasterAuras() const +{ + // Flag drop spells totally immuned to caster auras + // FIXME: find more nice check for all totally immuned spells + // AttributesEx3 & 0x10000000? + if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991) + return 0; + + uint8 school_immune = 0; + uint32 mechanic_immune = 0; + uint32 dispel_immune = 0; + + //Check if the spell grants school or mechanic immunity. + //We use bitmasks so the loop is done only once and not on every aura check below. + if ( m_spellInfo->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY ) + { + for(int i = 0;i < 3; i ++) + { + if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_SCHOOL_IMMUNITY) + school_immune |= uint32(m_spellInfo->EffectMiscValue[i]); + else if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MECHANIC_IMMUNITY) + mechanic_immune |= 1 << uint32(m_spellInfo->EffectMiscValue[i]); + else if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DISPEL_IMMUNITY) + dispel_immune |= GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i])); + } + //immune movement impairement and loss of control + if(m_spellInfo->Id==(uint32)42292) + mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; + } + + //Check whether the cast should be prevented by any state you might have. + uint8 prevented_reason = 0; + // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out + if(!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED) && m_caster->HasAuraType(SPELL_AURA_MOD_STUN)) + prevented_reason = SPELL_FAILED_STUNNED; + else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED)) + prevented_reason = SPELL_FAILED_CONFUSED; + else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED)) + prevented_reason = SPELL_FAILED_FLEEING; + else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE) + prevented_reason = SPELL_FAILED_SILENCED; + else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY) + prevented_reason = SPELL_FAILED_PACIFIED; + + // Attr must make flag drop spell totally immuned from all effects + if(prevented_reason) + { + if(school_immune || mechanic_immune || dispel_immune) + { + //Checking auras is needed now, because you are prevented by some state but the spell grants immunity. + Unit::AuraMap const& auras = m_caster->GetAuras(); + for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) + { + if(itr->second) + { + if( GetSpellMechanicMask(itr->second->GetSpellProto(), itr->second->GetEffIndex()) & mechanic_immune ) + continue; + if( GetSpellSchoolMask(itr->second->GetSpellProto()) & school_immune ) + continue; + if( (1<<(itr->second->GetSpellProto()->Dispel)) & dispel_immune) + continue; + + //Make a second check for spell failed so the right SPELL_FAILED message is returned. + //That is needed when your casting is prevented by multiple states and you are only immune to some of them. + switch(itr->second->GetModifier()->m_auraname) + { + case SPELL_AURA_MOD_STUN: + if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED)) + return SPELL_FAILED_STUNNED; + break; + case SPELL_AURA_MOD_CONFUSE: + if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED)) + return SPELL_FAILED_CONFUSED; + break; + case SPELL_AURA_MOD_FEAR: + if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED)) + return SPELL_FAILED_FLEEING; + break; + case SPELL_AURA_MOD_SILENCE: + case SPELL_AURA_MOD_PACIFY: + case SPELL_AURA_MOD_PACIFY_SILENCE: + if( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY) + return SPELL_FAILED_PACIFIED; + else if ( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE) + return SPELL_FAILED_SILENCED; + break; + } + } + } + } + //You are prevented from casting and the spell casted does not grant immunity. Return a failed error. + else + return prevented_reason; + } + return 0; // all ok +} + +bool Spell::CanAutoCast(Unit* target) +{ + uint64 targetguid = target->GetGUID(); + + for(uint32 j = 0;j<3;j++) + { + if(m_spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA) + { + if( m_spellInfo->StackAmount <= 1) + { + if( target->HasAura(m_spellInfo->Id, j) ) + return false; + } + else + { + if( target->GetAuras().count(Unit::spellEffectPair(m_spellInfo->Id, j)) >= m_spellInfo->StackAmount) + return false; + } + } + else if ( IsAreaAuraEffect( m_spellInfo->Effect[j] )) + { + if( target->HasAura(m_spellInfo->Id, j) ) + return false; + } + } + + int16 result = PetCanCast(target); + + if(result == -1 || result == SPELL_FAILED_UNIT_NOT_INFRONT) + { + FillTargetMap(); + //check if among target units, our WANTED target is as well (->only self cast spells return false) + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + if( ihit->targetGUID == targetguid ) + return true; + } + return false; //target invalid +} + +uint8 Spell::CheckRange(bool strict) +{ + float range_mod; + + // self cast doesn't need range checking -- also for Starshards fix + if (m_spellInfo->rangeIndex == 1) return 0; + + if (strict) //add radius of caster + range_mod = 1.25; + else //add radius of caster and ~5 yds "give" + range_mod = 6.25; + + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); + float max_range = GetSpellMaxRange(srange) + range_mod; + float min_range = GetSpellMinRange(srange); + + if(Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this); + + Unit *target = m_targets.getUnitTarget(); + + if(target && target != m_caster) + { + // distance from target center in checks + float dist = m_caster->GetDistance(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ()); + if(dist > max_range) + return SPELL_FAILED_OUT_OF_RANGE; //0x5A; + if(dist < min_range) + return SPELL_FAILED_TOO_CLOSE; + if( m_caster->GetTypeId() == TYPEID_PLAYER && + (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc( M_PI, target ) ) + return SPELL_FAILED_UNIT_NOT_INFRONT; + } + + if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0) + { + float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); + if(dist > max_range) + return SPELL_FAILED_OUT_OF_RANGE; + if(dist < min_range) + return SPELL_FAILED_TOO_CLOSE; + } + + return 0; // ok +} + +int32 Spell::CalculatePowerCost() +{ + // item cast not used power + if(m_CastItem) + return 0; + + // Spell drain all exist power on cast (Only paladin lay of Hands) + if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER) + { + // If power type - health drain all + if (m_spellInfo->powerType == POWER_HEALTH) + return m_caster->GetHealth(); + // Else drain all power + if (m_spellInfo->powerType < MAX_POWERS) + return m_caster->GetPower(Powers(m_spellInfo->powerType)); + sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); + return 0; + } + + // Base powerCost + int32 powerCost = m_spellInfo->manaCost; + // PCT cost from total amount + if (m_spellInfo->ManaCostPercentage) + { + switch (m_spellInfo->powerType) + { + // health as power used + case POWER_HEALTH: + powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateHealth() / 100; + break; + case POWER_MANA: + powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100; + break; + case POWER_RAGE: + case POWER_FOCUS: + case POWER_ENERGY: + case POWER_HAPPINESS: + // case POWER_RUNES: + powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100; + break; + default: + sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); + return 0; + } + } + SpellSchools school = GetFirstSchoolInMask(m_spellSchoolMask); + // Flat mod from caster auras by spell school + powerCost += m_caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school); + // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) + if ( m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST ) + powerCost += m_caster->GetAttackTime(OFF_ATTACK)/100; + // Apply cost mod by spell + if(Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, powerCost, this); + + if(m_spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION) + powerCost = int32(powerCost/ (1.117f* m_spellInfo->spellLevel / m_caster->getLevel() -0.1327f)); + + // PCT mod from user auras by school + powerCost = int32(powerCost * (1.0f+m_caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+school))); + if (powerCost < 0) + powerCost = 0; + return powerCost; +} + +uint8 Spell::CheckPower() +{ + // item cast not used power + if(m_CastItem) + return 0; + + // health as power used - need check health amount + if(m_spellInfo->powerType == POWER_HEALTH) + { + if(m_caster->GetHealth() <= m_powerCost) + return SPELL_FAILED_CASTER_AURASTATE; + return 0; + } + // Check valid power type + if( m_spellInfo->powerType >= MAX_POWERS ) + { + sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType); + return SPELL_FAILED_UNKNOWN; + } + // Check power amount + Powers powerType = Powers(m_spellInfo->powerType); + if(m_caster->GetPower(powerType) < m_powerCost) + return SPELL_FAILED_NO_POWER; + else + return 0; +} + +uint8 Spell::CheckItems() +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return 0; + + uint32 itemid, itemcount; + Player* p_caster = (Player*)m_caster; + + if(m_CastItem) + { + itemid = m_CastItem->GetEntry(); + if( !p_caster->HasItemCount(itemid,1) ) + return SPELL_FAILED_ITEM_NOT_READY; + else + { + ItemPrototype const *proto = m_CastItem->GetProto(); + if(!proto) + return SPELL_FAILED_ITEM_NOT_READY; + + for (int i = 0; i<5; i++) + { + if (proto->Spells[i].SpellCharges) + { + if(m_CastItem->GetSpellCharges(i)==0) + return SPELL_FAILED_NO_CHARGES_REMAIN; + } + } + + uint32 ItemClass = proto->Class; + if (ItemClass == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget()) + { + for (int i = 0; i < 3; i++) + { + // skip check, pet not required like checks, and for TARGET_PET m_targets.getUnitTarget() is not the real target but the caster + if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_PET) + continue; + + if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) + if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth()) + return (uint8)SPELL_FAILED_ALREADY_AT_FULL_HEALTH; + + // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... + if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) + { + if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; + + Powers power = Powers(m_spellInfo->EffectMiscValue[i]); + + if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) + return (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; + } + } + } + } + } + + if(m_targets.getItemTargetGUID()) + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return SPELL_FAILED_BAD_TARGETS; + + if(!m_targets.getItemTarget()) + return SPELL_FAILED_ITEM_GONE; + + if(!m_targets.getItemTarget()->IsFitToSpellRequirements(m_spellInfo)) + return SPELL_FAILED_EQUIPPED_ITEM_CLASS; + } + // if not item target then required item must be equipped + else + { + if(m_caster->GetTypeId() == TYPEID_PLAYER && !((Player*)m_caster)->HasItemFitToSpellReqirements(m_spellInfo)) + return SPELL_FAILED_EQUIPPED_ITEM_CLASS; + } + + if(m_spellInfo->RequiresSpellFocus) + { + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + GameObject* ok = NULL; + MaNGOS::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus); + MaNGOS::GameObjectSearcher checker(ok,go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + + if(!ok) + return (uint8)SPELL_FAILED_REQUIRES_SPELL_FOCUS; + + focusObject = ok; // game object found in range + } + + if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP && + m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION))) + { + for(uint32 i=0;i<8;i++) + { + if(m_spellInfo->Reagent[i] <= 0) + continue; + + itemid = m_spellInfo->Reagent[i]; + itemcount = m_spellInfo->ReagentCount[i]; + + // if CastItem is also spell reagent + if( m_CastItem && m_CastItem->GetEntry() == itemid ) + { + ItemPrototype const *proto = m_CastItem->GetProto(); + if(!proto) + return SPELL_FAILED_ITEM_NOT_READY; + for(int s=0;s<5;s++) + { + // CastItem will be used up and does not count as reagent + int32 charges = m_CastItem->GetSpellCharges(s); + if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2) + { + ++itemcount; + break; + } + } + } + if( !p_caster->HasItemCount(itemid,itemcount) ) + return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54 + } + } + + uint32 totems = 2; + for(int i=0;i<2;++i) + { + if(m_spellInfo->Totem[i] != 0) + { + if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) ) + { + totems -= 1; + continue; + } + }else + totems -= 1; + } + if(totems != 0) + return (uint8)SPELL_FAILED_TOTEMS; //0x7C + + //Check items for TotemCategory + uint32 TotemCategory = 2; + for(int i=0;i<2;++i) + { + if(m_spellInfo->TotemCategory[i] != 0) + { + if( p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i]) ) + { + TotemCategory -= 1; + continue; + } + } + else + TotemCategory -= 1; + } + if(TotemCategory != 0) + return (uint8)SPELL_FAILED_TOTEM_CATEGORY; //0x7B + + for(int i = 0; i < 3; i++) + { + switch (m_spellInfo->Effect[i]) + { + case SPELL_EFFECT_CREATE_ITEM: + { + if (!m_IsTriggeredSpell && m_spellInfo->EffectItemType[i]) + { + ItemPosCountVec dest; + uint8 msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1 ); + if (msg != EQUIP_ERR_OK ) + { + p_caster->SendEquipError( msg, NULL, NULL ); + return SPELL_FAILED_DONT_REPORT; + } + } + break; + } + case SPELL_EFFECT_ENCHANT_ITEM: + { + Item* targetItem = m_targets.getItemTarget(); + if(!targetItem) + return SPELL_FAILED_ITEM_NOT_FOUND; + + if( targetItem->GetProto()->ItemLevel < m_spellInfo->baseLevel ) + return SPELL_FAILED_LOWLEVEL; + // Not allow enchant in trade slot for some enchant type + if( targetItem->GetOwner() != m_caster ) + { + uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) + return SPELL_FAILED_ERROR; + if (pEnchant->slot & ENCHANTMENT_CAN_SOULBOUND) + return SPELL_FAILED_NOT_TRADEABLE; + } + break; + } + case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY: + { + Item *item = m_targets.getItemTarget(); + if(!item) + return SPELL_FAILED_ITEM_NOT_FOUND; + // Not allow enchant in trade slot for some enchant type + if( item->GetOwner() != m_caster ) + { + uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) + return SPELL_FAILED_ERROR; + if (pEnchant->slot & ENCHANTMENT_CAN_SOULBOUND) + return SPELL_FAILED_NOT_TRADEABLE; + } + break; + } + case SPELL_EFFECT_ENCHANT_HELD_ITEM: + // check item existence in effect code (not output errors at offhand hold item effect to main hand for example + break; + case SPELL_EFFECT_DISENCHANT: + { + if(!m_targets.getItemTarget()) + return SPELL_FAILED_CANT_BE_DISENCHANTED; + + // prevent disenchanting in trade slot + if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() ) + return SPELL_FAILED_CANT_BE_DISENCHANTED; + + ItemPrototype const* itemProto = m_targets.getItemTarget()->GetProto(); + if(!itemProto) + return SPELL_FAILED_CANT_BE_DISENCHANTED; + + uint32 item_quality = itemProto->Quality; + // 2.0.x addon: Check player enchanting level agains the item desenchanting requirements + uint32 item_disenchantskilllevel = itemProto->RequiredDisenchantSkill; + if (item_disenchantskilllevel == uint32(-1)) + return SPELL_FAILED_CANT_BE_DISENCHANTED; + if (item_disenchantskilllevel > p_caster->GetSkillValue(SKILL_ENCHANTING)) + return SPELL_FAILED_LOW_CASTLEVEL; + if(item_quality > 4 || item_quality < 2) + return SPELL_FAILED_CANT_BE_DISENCHANTED; + if(itemProto->Class != ITEM_CLASS_WEAPON && itemProto->Class != ITEM_CLASS_ARMOR) + return SPELL_FAILED_CANT_BE_DISENCHANTED; + if (!itemProto->DisenchantID) + return SPELL_FAILED_CANT_BE_DISENCHANTED; + break; + } + case SPELL_EFFECT_PROSPECTING: + { + if(!m_targets.getItemTarget()) + return SPELL_FAILED_CANT_BE_PROSPECTED; + //ensure item is a prospectable ore + if(!(m_targets.getItemTarget()->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) || m_targets.getItemTarget()->GetProto()->Class != ITEM_CLASS_TRADE_GOODS) + return SPELL_FAILED_CANT_BE_PROSPECTED; + //prevent prospecting in trade slot + if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() ) + return SPELL_FAILED_CANT_BE_PROSPECTED; + //Check for enough skill in jewelcrafting + uint32 item_prospectingskilllevel = m_targets.getItemTarget()->GetProto()->RequiredSkillRank; + if(item_prospectingskilllevel >p_caster->GetSkillValue(SKILL_JEWELCRAFTING)) + return SPELL_FAILED_LOW_CASTLEVEL; + //make sure the player has the required ores in inventory + if(m_targets.getItemTarget()->GetCount() < 5) + return SPELL_FAILED_PROSPECT_NEED_MORE; + + if(!LootTemplates_Prospecting.HaveLootFor(m_targets.getItemTargetEntry())) + return SPELL_FAILED_CANT_BE_PROSPECTED; + + break; + } + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_TARGET_NOT_PLAYER; + if( m_attackType != RANGED_ATTACK ) + break; + Item *pItem = ((Player*)m_caster)->GetWeaponForAttack(m_attackType); + if(!pItem || pItem->IsBroken()) + return SPELL_FAILED_EQUIPPED_ITEM; + + switch(pItem->GetProto()->SubClass) + { + case ITEM_SUBCLASS_WEAPON_THROWN: + { + uint32 ammo = pItem->GetEntry(); + if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) ) + return SPELL_FAILED_NO_AMMO; + }; break; + case ITEM_SUBCLASS_WEAPON_GUN: + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + { + uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID); + if(!ammo) + { + // Requires No Ammo + if(m_caster->GetDummyAura(46699)) + break; // skip other checks + + return SPELL_FAILED_NO_AMMO; + } + + ItemPrototype const *ammoProto = objmgr.GetItemPrototype( ammo ); + if(!ammoProto) + return SPELL_FAILED_NO_AMMO; + + if(ammoProto->Class != ITEM_CLASS_PROJECTILE) + return SPELL_FAILED_NO_AMMO; + + // check ammo ws. weapon compatibility + switch(pItem->GetProto()->SubClass) + { + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + if(ammoProto->SubClass!=ITEM_SUBCLASS_ARROW) + return SPELL_FAILED_NO_AMMO; + break; + case ITEM_SUBCLASS_WEAPON_GUN: + if(ammoProto->SubClass!=ITEM_SUBCLASS_BULLET) + return SPELL_FAILED_NO_AMMO; + break; + default: + return SPELL_FAILED_NO_AMMO; + } + + if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) ) + return SPELL_FAILED_NO_AMMO; + }; break; + case ITEM_SUBCLASS_WEAPON_WAND: + default: + break; + } + break; + } + default:break; + } + } + + return uint8(0); +} + +void Spell::Delayed() +{ + if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if (m_spellState == SPELL_STATE_DELAYED) + return; // spell is active and can't be time-backed + + // spells not loosing casting time ( slam, dynamites, bombs.. ) + if(!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE)) + return; + + //check resist chance + int32 resistChance = 100; //must be initialized to 100 for percent modifiers + ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this); + resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100; + if (roll_chance_i(resistChance)) + return; + + int32 delaytime = GetNextDelayAtDamageMsTime(); + + if(int32(m_timer) + delaytime > m_casttime) + { + delaytime = m_casttime - m_timer; + m_timer = m_casttime; + } + else + m_timer += delaytime; + + sLog.outDetail("Spell %u partially interrupted for (%d) ms at damage",m_spellInfo->Id,delaytime); + + WorldPacket data(SMSG_SPELL_DELAYED, 8+4); + data.append(m_caster->GetPackGUID()); + data << uint32(delaytime); + + m_caster->SendMessageToSet(&data,true); +} + +void Spell::DelayedChannel() +{ + if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING) + return; + + //check resist chance + int32 resistChance = 100; //must be initialized to 100 for percent modifiers + ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this); + resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100; + if (roll_chance_i(resistChance)) + return; + + int32 delaytime = GetNextDelayAtDamageMsTime(); + + if(int32(m_timer) < delaytime) + { + delaytime = m_timer; + m_timer = 0; + } + else + m_timer -= delaytime; + + sLog.outDebug("Spell %u partially interrupted for %i ms, new duration: %u ms", m_spellInfo->Id, delaytime, m_timer); + + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + { + if ((*ihit).missCondition == SPELL_MISS_NONE) + { + Unit* unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); + if (unit) + { + for (int j=0;j<3;j++) + if( ihit->effectMask & (1<DelayAura(m_spellInfo->Id, j, delaytime); + } + + } + } + + for(int j = 0; j < 3; j++) + { + // partially interrupt persistent area auras + DynamicObject* dynObj = m_caster->GetDynObject(m_spellInfo->Id, j); + if(dynObj) + dynObj->Delay(delaytime); + } + + SendChannelUpdate(m_timer); +} + +void Spell::UpdatePointers() +{ + if(m_originalCasterGUID==m_caster->GetGUID()) + m_originalCaster = m_caster; + else + { + m_originalCaster = ObjectAccessor::GetUnit(*m_caster,m_originalCasterGUID); + if(m_originalCaster && !m_originalCaster->IsInWorld()) m_originalCaster = NULL; + } + + m_targets.Update(m_caster); +} + +bool Spell::IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId) +{ + return spellmgr.IsAffectedBySpell(m_spellInfo,spellInfo->Id,effectId,spellInfo->EffectItemType[effectId]); +} + +bool Spell::CheckTargetCreatureType(Unit* target) const +{ + uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType; + + // Curse of Doom : not find another way to fix spell target check :/ + if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags == 0x0200000000LL) + { + // not allow cast at player + if(target->GetTypeId()==TYPEID_PLAYER) + return false; + + spellCreatureTargetMask = 0x7FF; + } + + // Dismiss Pet and Taming Lesson skipped + if(m_spellInfo->Id == 2641 || m_spellInfo->Id == 23356) + spellCreatureTargetMask = 0; + + if (spellCreatureTargetMask) + { + uint32 TargetCreatureType = target->GetCreatureTypeMask(); + + return !TargetCreatureType || (spellCreatureTargetMask & TargetCreatureType); + } + return true; +} + +CurrentSpellTypes Spell::GetCurrentContainer() +{ + if (IsNextMeleeSwingSpell()) + return(CURRENT_MELEE_SPELL); + else if (IsAutoRepeat()) + return(CURRENT_AUTOREPEAT_SPELL); + else if (IsChanneledSpell(m_spellInfo)) + return(CURRENT_CHANNELED_SPELL); + else + return(CURRENT_GENERIC_SPELL); +} + +bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase ) +{ + // Check targets for creature type mask and remove not appropriate (skip explicit self target case, maybe need other explicit targets) + if(m_spellInfo->EffectImplicitTargetA[eff]!=TARGET_SELF ) + { + if (!CheckTargetCreatureType(target)) + return false; + } + + // Check targets for not_selectable unit flag and remove + // A player can cast spells on his pet (or other controlled unit) though in any state + if (target != m_caster && target->GetCharmerOrOwnerGUID() != m_caster->GetGUID()) + { + // any unattackable target skipped + if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return false; + + // unselectable targets skipped in all cases except TARGET_SCRIPT targeting + // in case TARGET_SCRIPT target selected by server always and can't be cheated + if( target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) && + m_spellInfo->EffectImplicitTargetA[eff] != TARGET_SCRIPT && + m_spellInfo->EffectImplicitTargetB[eff] != TARGET_SCRIPT ) + return false; + } + + //Check player targets and remove if in GM mode or GM invisibility (for not self casting case) + if( target != m_caster && target->GetTypeId()==TYPEID_PLAYER) + { + if(((Player*)target)->GetVisibility()==VISIBILITY_OFF) + return false; + + if(((Player*)target)->isGameMaster() && !IsPositiveSpell(m_spellInfo->Id)) + return false; + } + + //Check targets for LOS visibility (except spells without range limitations ) + switch(m_spellInfo->Effect[eff]) + { + case SPELL_EFFECT_SUMMON_PLAYER: // from anywhere + break; + case SPELL_EFFECT_DUMMY: + if(m_spellInfo->Id!=20577) // Cannibalize + break; + //fall through + case SPELL_EFFECT_RESURRECT_NEW: + // player far away, maybe his corpse near? + if(target!=m_caster && !target->IsWithinLOSInMap(m_caster)) + { + if(!m_targets.getCorpseTargetGUID()) + return false; + + Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID()); + if(!corpse) + return false; + + if(target->GetGUID()!=corpse->GetOwnerGUID()) + return false; + + if(!corpse->IsWithinLOSInMap(m_caster)) + return false; + } + + // all ok by some way or another, skip normal check + break; + default: // normal case + if(target!=m_caster && !target->IsWithinLOSInMap(m_caster)) + return false; + break; + } + + return true; +} + +Unit* Spell::SelectMagnetTarget() +{ + Unit* target = m_targets.getUnitTarget(); + + if(target && target->HasAuraType(SPELL_AURA_SPELL_MAGNET) && !(m_spellInfo->Attributes & 0x10)) + { + Unit::AuraList const& magnetAuras = target->GetAurasByType(SPELL_AURA_SPELL_MAGNET); + for(Unit::AuraList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr) + { + if(Unit* magnet = (*itr)->GetCaster()) + { + if(magnet->IsWithinLOSInMap(m_caster)) + { + target = magnet; + m_targets.setUnitTarget(target); + break; + } + } + } + } + + return target; +} + +bool Spell::IsNeedSendToClient() const +{ + return m_spellInfo->SpellVisual!=0 || IsChanneledSpell(m_spellInfo) || + m_spellInfo->speed > 0.0f || !m_triggeredByAuraSpell && !m_IsTriggeredSpell; +} + +bool Spell::HaveTargetsForEffect( uint8 effect ) const +{ + for(std::list::const_iterator itr= m_UniqueTargetInfo.begin();itr != m_UniqueTargetInfo.end();++itr) + if(itr->effectMask & (1<::const_iterator itr= m_UniqueGOTargetInfo.begin();itr != m_UniqueGOTargetInfo.end();++itr) + if(itr->effectMask & (1<::const_iterator itr= m_UniqueItemInfo.begin();itr != m_UniqueItemInfo.end();++itr) + if(itr->effectMask & (1<getState() != SPELL_STATE_FINISHED) + m_Spell->cancel(); + + if (m_Spell->IsDeletable()) + { + delete m_Spell; + } + else + { + sLog.outError("~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.", + (m_Spell->GetCaster()->GetTypeId()==TYPEID_PLAYER?"Player":"Creature"), m_Spell->GetCaster()->GetGUIDLow(),m_Spell->m_spellInfo->Id); + } +} + +bool SpellEvent::Execute(uint64 e_time, uint32 p_time) +{ + // update spell if it is not finished + if (m_Spell->getState() != SPELL_STATE_FINISHED) + m_Spell->update(p_time); + + // check spell state to process + switch (m_Spell->getState()) + { + case SPELL_STATE_FINISHED: + { + // spell was finished, check deletable state + if (m_Spell->IsDeletable()) + { + // check, if we do have unfinished triggered spells + + return(true); // spell is deletable, finish event + } + // event will be re-added automatically at the end of routine) + } break; + + case SPELL_STATE_CASTING: + { + // this spell is in channeled state, process it on the next update + // event will be re-added automatically at the end of routine) + } break; + + case SPELL_STATE_DELAYED: + { + // first, check, if we have just started + if (m_Spell->GetDelayStart() != 0) + { + // no, we aren't, do the typical update + // check, if we have channeled spell on our hands + if (IsChanneledSpell(m_Spell->m_spellInfo)) + { + // evented channeled spell is processed separately, casted once after delay, and not destroyed till finish + // check, if we have casting anything else except this channeled spell and autorepeat + if (m_Spell->GetCaster()->IsNonMeleeSpellCasted(false, true, true)) + { + // another non-melee non-delayed spell is casted now, abort + m_Spell->cancel(); + } + else + { + // do the action (pass spell to channeling state) + m_Spell->handle_immediate(); + } + // event will be re-added automatically at the end of routine) + } + else + { + // run the spell handler and think about what we can do next + uint64 t_offset = e_time - m_Spell->GetDelayStart(); + uint64 n_offset = m_Spell->handle_delayed(t_offset); + if (n_offset) + { + // re-add us to the queue + m_Spell->GetCaster()->m_Events.AddEvent(this, m_Spell->GetDelayStart() + n_offset, false); + return(false); // event not complete + } + // event complete + // finish update event will be re-added automatically at the end of routine) + } + } + else + { + // delaying had just started, record the moment + m_Spell->SetDelayStart(e_time); + // re-plan the event for the delay moment + m_Spell->GetCaster()->m_Events.AddEvent(this, e_time + m_Spell->GetDelayMoment(), false); + return(false); // event not complete + } + } break; + + default: + { + // all other states + // event will be re-added automatically at the end of routine) + } break; + } + + // spell processing not complete, plan event on the next update interval + m_Spell->GetCaster()->m_Events.AddEvent(this, e_time + 1, false); + return(false); // event not complete +} + +void SpellEvent::Abort(uint64 /*e_time*/) +{ + // oops, the spell we try to do is aborted + if (m_Spell->getState() != SPELL_STATE_FINISHED) + m_Spell->cancel(); +} diff --git a/src/game/Spell.h b/src/game/Spell.h index 898d74de0f2..d606fd71f34 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -1,694 +1,695 @@ -/* - * Copyright (C) 2005-2008 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 __SPELL_H -#define __SPELL_H - -#include "GridDefines.h" - -class WorldSession; -class Unit; -class DynamicObj; -class Player; -class GameObject; -class Group; -class Aura; - -enum SpellCastTargetFlags -{ - /*TARGET_FLAG_NONE = 0x0000, - TARGET_FLAG_SWIMMER = 0x0002, - TARGET_FLAG_ITEM = 0x0010, - TARGET_FLAG_SOURCE_AREA = 0x0020, - TARGET_FLAG_DEST_AREA = 0x0040, - TARGET_FLAG_UNKNOWN = 0x0080, - TARGET_FLAG_SELF = 0x0100, - TARGET_FLAG_PVP_CORPSE = 0x0200, - TARGET_FLAG_MASS_SPIRIT_HEAL = 0x0400, - TARGET_FLAG_BEAST_CORPSE = 0x0402, - TARGET_FLAG_OBJECT = 0x4000, - TARGET_FLAG_RESURRECTABLE = 0x8000*/ - - TARGET_FLAG_SELF = 0x00000000, - TARGET_FLAG_UNIT = 0x00000002, // pguid - TARGET_FLAG_ITEM = 0x00000010, // pguid - TARGET_FLAG_SOURCE_LOCATION = 0x00000020, // 3 float - TARGET_FLAG_DEST_LOCATION = 0x00000040, // 3 float - TARGET_FLAG_OBJECT_UNK = 0x00000080, // ? - TARGET_FLAG_PVP_CORPSE = 0x00000200, // pguid - TARGET_FLAG_OBJECT = 0x00000800, // pguid - TARGET_FLAG_TRADE_ITEM = 0x00001000, // pguid - TARGET_FLAG_STRING = 0x00002000, // string - TARGET_FLAG_UNK1 = 0x00004000, // ? - TARGET_FLAG_CORPSE = 0x00008000, // pguid - TARGET_FLAG_UNK2 = 0x00010000 // pguid -}; - -enum SpellCastFlags -{ - CAST_FLAG_UNKNOWN1 = 0x00000002, - CAST_FLAG_UNKNOWN2 = 0x00000010, - CAST_FLAG_AMMO = 0x00000020, - CAST_FLAG_UNKNOWN3 = 0x00000100 -}; - -enum SpellNotifyPushType -{ - PUSH_IN_FRONT, - PUSH_IN_BACK, - PUSH_SELF_CENTER, - PUSH_DEST_CENTER, - PUSH_TARGET_CENTER -}; - -bool IsQuestTameSpell(uint32 spellId); - -namespace MaNGOS -{ - struct SpellNotifierPlayer; - struct SpellNotifierCreatureAndPlayer; -} - -class SpellCastTargets -{ - public: - SpellCastTargets(); - ~SpellCastTargets(); - - bool read ( WorldPacket * data, Unit *caster ); - void write ( WorldPacket * data ); - - SpellCastTargets& operator=(const SpellCastTargets &target) - { - m_unitTarget = target.m_unitTarget; - m_itemTarget = target.m_itemTarget; - m_GOTarget = target.m_GOTarget; - - m_unitTargetGUID = target.m_unitTargetGUID; - m_GOTargetGUID = target.m_GOTargetGUID; - m_CorpseTargetGUID = target.m_CorpseTargetGUID; - m_itemTargetGUID = target.m_itemTargetGUID; - - m_itemTargetEntry = target.m_itemTargetEntry; - - m_srcX = target.m_srcX; - m_srcY = target.m_srcY; - m_srcZ = target.m_srcZ; - - m_destX = target.m_destX; - m_destY = target.m_destY; - m_destZ = target.m_destZ; - - m_strTarget = target.m_strTarget; - - m_targetMask = target.m_targetMask; - - return *this; - } - - uint64 getUnitTargetGUID() const { return m_unitTargetGUID; } - Unit *getUnitTarget() const { return m_unitTarget; } - void setUnitTarget(Unit *target); - void setDestination(float x, float y, float z); - - uint64 getGOTargetGUID() const { return m_GOTargetGUID; } - GameObject *getGOTarget() const { return m_GOTarget; } - void setGOTarget(GameObject *target); - - uint64 getCorpseTargetGUID() const { return m_CorpseTargetGUID; } - void setCorpseTarget(Corpse* corpse); - uint64 getItemTargetGUID() const { return m_itemTargetGUID; } - Item* getItemTarget() const { return m_itemTarget; } - uint32 getItemTargetEntry() const { return m_itemTargetEntry; } - void setItemTarget(Item* item); - void updateTradeSlotItem() - { - if(m_itemTarget && (m_targetMask & TARGET_FLAG_TRADE_ITEM)) - { - m_itemTargetGUID = m_itemTarget->GetGUID(); - m_itemTargetEntry = m_itemTarget->GetEntry(); - } - } - - bool IsEmpty() const { return m_GOTargetGUID==0 && m_unitTargetGUID==0 && m_itemTarget==0 && m_CorpseTargetGUID==0; } - - void Update(Unit* caster); - - float m_srcX, m_srcY, m_srcZ; - float m_destX, m_destY, m_destZ; - std::string m_strTarget; - - uint32 m_targetMask; - private: - // objects (can be used at spell creating and after Update at casting - Unit *m_unitTarget; - GameObject *m_GOTarget; - Item *m_itemTarget; - - // object GUID/etc, can be used always - uint64 m_unitTargetGUID; - uint64 m_GOTargetGUID; - uint64 m_CorpseTargetGUID; - uint64 m_itemTargetGUID; - uint32 m_itemTargetEntry; -}; - -enum SpellState -{ - SPELL_STATE_NULL = 0, - SPELL_STATE_PREPARING = 1, - SPELL_STATE_CASTING = 2, - SPELL_STATE_FINISHED = 3, - SPELL_STATE_IDLE = 4, - SPELL_STATE_DELAYED = 5 -}; - -#define SPELL_SPELL_CHANNEL_UPDATE_INTERVAL 1000 - -typedef std::multimap SpellTargetTimeMap; - -class Spell -{ - friend struct MaNGOS::SpellNotifierPlayer; - friend struct MaNGOS::SpellNotifierCreatureAndPlayer; - public: - - void EffectNULL(uint32 ); - void EffectUnused(uint32 ); - void EffectDistract(uint32 i); - void EffectPull(uint32 i); - void EffectSchoolDMG(uint32 i); - void EffectEnvirinmentalDMG(uint32 i); - void EffectInstaKill(uint32 i); - void EffectDummy(uint32 i); - void EffectTeleportUnits(uint32 i); - void EffectApplyAura(uint32 i); - void EffectSendEvent(uint32 i); - void EffectPowerBurn(uint32 i); - void EffectPowerDrain(uint32 i); - void EffectHeal(uint32 i); - void EffectHealthLeech(uint32 i); - void EffectQuestComplete(uint32 i); - void EffectCreateItem(uint32 i); - void EffectPersistentAA(uint32 i); - void EffectEnergize(uint32 i); - void EffectOpenLock(uint32 i); - void EffectSummonChangeItem(uint32 i); - void EffectOpenSecretSafe(uint32 i); - void EffectProficiency(uint32 i); - void EffectApplyAreaAura(uint32 i); - void EffectSummonType(uint32 i); - void EffectSummon(uint32 i); - void EffectLearnSpell(uint32 i); - void EffectDispel(uint32 i); - void EffectDualWield(uint32 i); - void EffectPickPocket(uint32 i); - void EffectAddFarsight(uint32 i); - void EffectSummonWild(uint32 i); - void EffectSummonGuardian(uint32 i); - void EffectHealMechanical(uint32 i); - void EffectTeleUnitsFaceCaster(uint32 i); - void EffectLearnSkill(uint32 i); - void EffectAddHonor(uint32 i); - void EffectTradeSkill(uint32 i); - void EffectEnchantItemPerm(uint32 i); - void EffectEnchantItemTmp(uint32 i); - void EffectTameCreature(uint32 i); - void EffectSummonPet(uint32 i); - void EffectLearnPetSpell(uint32 i); - void EffectWeaponDmg(uint32 i); - void EffectForceCast(uint32 i); - void EffectTriggerSpell(uint32 i); - void EffectTriggerMissileSpell(uint32 i); - void EffectThreat(uint32 i); - void EffectHealMaxHealth(uint32 i); - void EffectInterruptCast(uint32 i); - void EffectSummonObjectWild(uint32 i); - void EffectScriptEffect(uint32 i); - void EffectSanctuary(uint32 i); - void EffectAddComboPoints(uint32 i); - void EffectDuel(uint32 i); - void EffectStuck(uint32 i); - void EffectSummonPlayer(uint32 i); - void EffectActivateObject(uint32 i); - void EffectSummonTotem(uint32 i); - void EffectEnchantHeldItem(uint32 i); - void EffectSummonObject(uint32 i); - void EffectResurrect(uint32 i); - void EffectParry(uint32 i); - void EffectMomentMove(uint32 i); - void EffectTransmitted(uint32 i); - void EffectDisEnchant(uint32 i); - void EffectInebriate(uint32 i); - void EffectFeedPet(uint32 i); - void EffectDismissPet(uint32 i); - void EffectReputation(uint32 i); - void EffectSelfResurrect(uint32 i); - void EffectSkinning(uint32 i); - void EffectCharge(uint32 i); - void EffectProspecting(uint32 i); - void EffectSendTaxi(uint32 i); - void EffectSummonCritter(uint32 i); - void EffectKnockBack(uint32 i); - void EffectPlayerPull(uint32 i); - void EffectDispelMechanic(uint32 i); - void EffectSummonDeadPet(uint32 i); - void EffectDestroyAllTotems(uint32 i); - void EffectDurabilityDamage(uint32 i); - void EffectSkill(uint32 i); - void EffectTaunt(uint32 i); - void EffectDurabilityDamagePCT(uint32 i); - void EffectModifyThreatPercent(uint32 i); - void EffectResurrectNew(uint32 i); - void EffectAddExtraAttacks(uint32 i); - void EffectSpiritHeal(uint32 i); - void EffectSkinPlayerCorpse(uint32 i); - void EffectSummonDemon(uint32 i); - void EffectStealBeneficialBuff(uint32 i); - void EffectUnlearnSpecialization(uint32 i); - void EffectHealPct(uint32 i); - void EffectEnergisePct(uint32 i); - void EffectTriggerSpellWithValue(uint32 i); - void EffectTriggerRitualOfSummoning(uint32 i); - void EffectKillCredit(uint32 i); - void EffectQuestFail(uint32 i); - - Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 originalCasterGUID = 0, Spell** triggeringContainer = NULL ); - ~Spell(); - - void prepare(SpellCastTargets * targets, Aura* triggeredByAura = NULL); - void cancel(); - void update(uint32 difftime); - void cast(bool skipCheck = false); - void finish(bool ok = true); - void TakePower(); - void TakeReagents(); - void TakeCastItem(); - void TriggerSpell(); - uint8 CanCast(bool strict); - int16 PetCanCast(Unit* target); - bool CanAutoCast(Unit* target); - - // handlers - void handle_immediate(); - uint64 handle_delayed(uint64 t_offset); - // handler helpers - void _handle_immediate_phase(); - void _handle_finish_phase(); - - uint8 CheckItems(); - uint8 CheckRange(bool strict); - uint8 CheckPower(); - uint8 CheckCasterAuras() const; - - int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(m_spellInfo,i,m_currentBasePoints[i],target); } - int32 CalculatePowerCost(); - - bool HaveTargetsForEffect(uint8 effect) const; - void Delayed(); - void DelayedChannel(); - inline uint32 getState() const { return m_spellState; } - void setState(uint32 state) { m_spellState = state; } - - void DoCreateItem(uint32 i, uint32 itemtype); - - void WriteSpellGoTargets( WorldPacket * data ); - void WriteAmmoToPacket( WorldPacket * data ); - void FillTargetMap(); - - void SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap); - - Unit* SelectMagnetTarget(); - bool CheckTarget( Unit* target, uint32 eff, bool hitPhase ); - - void SendCastResult(uint8 result); - void SendSpellStart(); - void SendSpellGo(); - void SendSpellCooldown(); - void SendLogExecute(); - void SendInterrupted(uint8 result); - void SendChannelUpdate(uint32 time); - void SendChannelStart(uint32 duration); - void SendResurrectRequest(Player* target); - void SendPlaySpellVisual(uint32 SpellID); - - void HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float DamageMultiplier = 1.0); - void HandleThreatSpells(uint32 spellId); - //void HandleAddAura(Unit* Target); - - SpellEntry const* m_spellInfo; - int32 m_currentBasePoints[3]; // cache SpellEntry::EffectBasePoints and use for set custom base points - Item* m_CastItem; - uint8 m_cast_count; - SpellCastTargets m_targets; - - int32 GetCastTime() const { return m_casttime; } - bool IsAutoRepeat() const { return m_autoRepeat; } - void SetAutoRepeat(bool rep) { m_autoRepeat = rep; } - void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; } - bool IsNextMeleeSwingSpell() const - { - return m_spellInfo->Attributes & (SPELL_ATTR_ON_NEXT_SWING_1|SPELL_ATTR_ON_NEXT_SWING_2); - } - bool IsRangedSpell() const - { - return m_spellInfo->Attributes & SPELL_ATTR_RANGED; - } - bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; } - bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); } - bool IsRangedAttackResetSpell() const { return !m_IsTriggeredSpell && IsRangedSpell() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); } - - bool IsDeletable() const { return m_deletable; } - void SetDeletable(bool deletable) { m_deletable = deletable; } - uint64 GetDelayStart() const { return m_delayStart; } - void SetDelayStart(uint64 m_time) { m_delayStart = m_time; } - uint64 GetDelayMoment() const { return m_delayMoment; } - - bool IsNeedSendToClient() const; - - CurrentSpellTypes GetCurrentContainer(); - - Unit* GetCaster() const { return m_caster; } - Unit* GetOriginalCaster() const { return m_originalCaster; } - int32 GetPowerCost() const { return m_powerCost; } - - void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc) - - bool IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId); - - bool CheckTargetCreatureType(Unit* target) const; - - void AddTriggeredSpell(SpellEntry const* spell) { m_TriggerSpells.push_back(spell); } - - void CleanupTargetList(); - protected: - - void SendLoot(uint64 guid, LootType loottype); - - Unit* m_caster; - - uint64 m_originalCasterGUID; // real source of cast (aura caster/etc), used for spell targets selection - // e.g. damage around area spell trigered by victim aura and da,age emeies of aura caster - Unit* m_originalCaster; // cached pointer for m_originalCaster, updated at Spell::UpdatePointers() - - Spell** m_selfContainer; // pointer to our spell container (if applicable) - Spell** m_triggeringContainer; // pointer to container with spell that has triggered us - - //Spell data - SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example) - WeaponAttackType m_attackType; // For weapon based attack - int32 m_powerCost; // Calculated spell cost initialized only in Spell::prepare - int32 m_casttime; // Calculated spell cast time initialized only in Spell::prepare - bool m_canReflect; // can reflect this spell? - bool m_autoRepeat; - - uint8 m_delayAtDamageCount; - int32 GetNextDelayAtDamageMsTime() { return m_delayAtDamageCount < 5 ? 1000 - (m_delayAtDamageCount++)* 200 : 200; } - - // Delayed spells system - uint64 m_delayStart; // time of spell delay start, filled by event handler, zero = just started - uint64 m_delayMoment; // moment of next delay call, used internally - bool m_immediateHandled; // were immediate actions handled? (used by delayed spells only) - - // These vars are used in both delayed spell system and modified immediate spell system - bool m_deletable; // is the spell pending deletion or must be updated till permitted to delete? - bool m_needSpellLog; // need to send spell log? - uint8 m_applyMultiplierMask; // by effect: damage multiplier needed? - float m_damageMultipliers[3]; // by effect: damage multiplier - - // Current targets, to be used in SpellEffects (MUST BE USED ONLY IN SPELL EFFECTS) - Unit* unitTarget; - Item* itemTarget; - GameObject* gameObjTarget; - int32 damage; - - // this is set in Spell Hit, but used in Apply Aura handler - DiminishingLevels m_diminishLevel; - DiminishingGroup m_diminishGroup; - - // ------------------------------------------- - GameObject* focusObject; - - //****************************************** - // Spell trigger system - //****************************************** - void doTriggers(SpellMissInfo missInfo, uint32 damage=0, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NONE, uint32 block=0, uint32 absorb=0, bool crit=false); - - //***************************************** - // Spell target subsystem - //***************************************** - // Targets store structures and data - uint32 m_countOfHit; - uint32 m_countOfMiss; - struct TargetInfo - { - uint64 targetGUID; - uint64 timeDelay; - SpellMissInfo missCondition:8; - SpellMissInfo reflectResult:8; - uint8 effectMask:8; - bool processed:1; - }; - std::list m_UniqueTargetInfo; - uint8 m_needAliveTargetMask; // Mask req. alive targets - - struct GOTargetInfo - { - uint64 targetGUID; - uint64 timeDelay; - uint8 effectMask:8; - bool processed:1; - }; - std::list m_UniqueGOTargetInfo; - - struct ItemTargetInfo - { - Item *item; - uint8 effectMask; - }; - std::list m_UniqueItemInfo; - - void AddUnitTarget(Unit* target, uint32 effIndex); - void AddUnitTarget(uint64 unitGUID, uint32 effIndex); - void AddGOTarget(GameObject* target, uint32 effIndex); - void AddGOTarget(uint64 goGUID, uint32 effIndex); - void AddItemTarget(Item* target, uint32 effIndex); - void DoAllEffectOnTarget(TargetInfo *target); - void DoSpellHitOnUnit(Unit *unit, uint32 effectMask); - void DoAllEffectOnTarget(GOTargetInfo *target); - void DoAllEffectOnTarget(ItemTargetInfo *target); - bool IsAliveUnitPresentInTargetList(); - // ------------------------------------------- - - //List For Triggered Spells - typedef std::list TriggerSpells; - TriggerSpells m_TriggerSpells; - - uint32 m_spellState; - uint32 m_timer; - - float m_castPositionX; - float m_castPositionY; - float m_castPositionZ; - float m_castOrientation; - bool m_IsTriggeredSpell; - - // if need this can be replaced by Aura copy - // we can't store original aura link to prevent access to deleted auras - // and in same time need aura data and after aura deleting. - SpellEntry const* m_triggeredByAuraSpell; -}; - -enum ReplenishType -{ - REPLENISH_UNDEFINED = 0, - REPLENISH_HEALTH = 20, - REPLENISH_MANA = 21, - REPLENISH_RAGE = 22 -}; - -enum SpellTargets -{ - SPELL_TARGETS_HOSTILE, - SPELL_TARGETS_NOT_FRIENDLY, - SPELL_TARGETS_NOT_HOSTILE, - SPELL_TARGETS_FRIENDLY, - SPELL_TARGETS_AOE_DAMAGE -}; - -namespace MaNGOS -{ - struct MANGOS_DLL_DECL SpellNotifierPlayer - { - std::list &i_data; - Spell &i_spell; - const uint32& i_index; - float i_radius; - Unit* i_originalCaster; - - SpellNotifierPlayer(Spell &spell, std::list &data, const uint32 &i, float radius) - : i_data(data), i_spell(spell), i_index(i), i_radius(radius) - { - i_originalCaster = i_spell.GetOriginalCaster(); - } - - void Visit(PlayerMapType &m) - { - if(!i_originalCaster) - return; - - for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - Player * pPlayer = itr->getSource(); - if( !pPlayer->isAlive() || pPlayer->isInFlight()) - continue; - - if( i_originalCaster->IsFriendlyTo(pPlayer) ) - continue; - - if( pPlayer->GetDistance(i_spell.m_targets.m_destX, i_spell.m_targets.m_destY, i_spell.m_targets.m_destZ) < i_radius ) - i_data.push_back(pPlayer); - } - } - template void Visit(GridRefManager &) {} - }; - - struct MANGOS_DLL_DECL SpellNotifierCreatureAndPlayer - { - std::list *i_data; - Spell &i_spell; - const uint32& i_push_type; - float i_radius; - SpellTargets i_TargetType; - Unit* i_originalCaster; - - SpellNotifierCreatureAndPlayer(Spell &spell, std::list &data, float radius, const uint32 &type, - SpellTargets TargetType = SPELL_TARGETS_NOT_FRIENDLY) - : i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_TargetType(TargetType) - { - i_originalCaster = spell.GetOriginalCaster(); - } - - template inline void Visit(GridRefManager &m) - { - assert(i_data); - - if(!i_originalCaster) - return; - - for(typename GridRefManager::iterator itr = m.begin(); itr != m.end(); ++itr) - { - if( !itr->getSource()->isAlive() || (itr->getSource()->GetTypeId() == TYPEID_PLAYER && ((Player*)itr->getSource())->isInFlight())) - continue; - - switch (i_TargetType) - { - case SPELL_TARGETS_HOSTILE: - if (!itr->getSource()->isTargetableForAttack() || !i_originalCaster->IsHostileTo( itr->getSource() )) - continue; - break; - case SPELL_TARGETS_NOT_FRIENDLY: - if (!itr->getSource()->isTargetableForAttack() || i_originalCaster->IsFriendlyTo( itr->getSource() )) - continue; - break; - case SPELL_TARGETS_NOT_HOSTILE: - if (!itr->getSource()->isTargetableForAttack() || i_originalCaster->IsHostileTo( itr->getSource() )) - continue; - break; - case SPELL_TARGETS_FRIENDLY: - if (!itr->getSource()->isTargetableForAttack() || !i_originalCaster->IsFriendlyTo( itr->getSource() )) - continue; - break; - case SPELL_TARGETS_AOE_DAMAGE: - { - if(itr->getSource()->GetTypeId()==TYPEID_UNIT && ((Creature*)itr->getSource())->isTotem()) - continue; - if(!itr->getSource()->isTargetableForAttack()) - continue; - - Unit* check = i_originalCaster->GetCharmerOrOwnerOrSelf(); - - if( check->GetTypeId()==TYPEID_PLAYER ) - { - if (check->IsFriendlyTo( itr->getSource() )) - continue; - } - else - { - if (!check->IsHostileTo( itr->getSource() )) - continue; - } - } - break; - default: continue; - } - - switch(i_push_type) - { - case PUSH_IN_FRONT: - if(i_spell.GetCaster()->isInFront((Unit*)(itr->getSource()), i_radius, 2*M_PI/3 )) - i_data->push_back(itr->getSource()); - break; - case PUSH_IN_BACK: - if(i_spell.GetCaster()->isInBack((Unit*)(itr->getSource()), i_radius, 2*M_PI/3 )) - i_data->push_back(itr->getSource()); - break; - case PUSH_SELF_CENTER: - if(i_spell.GetCaster()->IsWithinDistInMap((Unit*)(itr->getSource()), i_radius)) - i_data->push_back(itr->getSource()); - break; - case PUSH_DEST_CENTER: - if((itr->getSource()->GetDistance(i_spell.m_targets.m_destX, i_spell.m_targets.m_destY, i_spell.m_targets.m_destZ) < i_radius )) - i_data->push_back(itr->getSource()); - break; - case PUSH_TARGET_CENTER: - if(i_spell.m_targets.getUnitTarget()->IsWithinDistInMap((Unit*)(itr->getSource()), i_radius)) - i_data->push_back(itr->getSource()); - break; - } - } - } - - #ifdef WIN32 - template<> inline void Visit(CorpseMapType & ) {} - template<> inline void Visit(GameObjectMapType & ) {} - template<> inline void Visit(DynamicObjectMapType & ) {} - #endif - }; - - #ifndef WIN32 - template<> inline void SpellNotifierCreatureAndPlayer::Visit(CorpseMapType& ) {} - template<> inline void SpellNotifierCreatureAndPlayer::Visit(GameObjectMapType& ) {} - template<> inline void SpellNotifierCreatureAndPlayer::Visit(DynamicObjectMapType& ) {} - #endif -} - -typedef void(Spell::*pEffect)(uint32 i); - -class SpellEvent : public BasicEvent -{ - public: - SpellEvent(Spell* spell); - virtual ~SpellEvent(); - - virtual bool Execute(uint64 e_time, uint32 p_time); - virtual void Abort(uint64 e_time); - protected: - Spell* m_Spell; -}; -#endif +/* + * Copyright (C) 2005-2008 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 __SPELL_H +#define __SPELL_H + +#include "GridDefines.h" + +class WorldSession; +class Unit; +class DynamicObj; +class Player; +class GameObject; +class Group; +class Aura; + +enum SpellCastTargetFlags +{ + /*TARGET_FLAG_NONE = 0x0000, + TARGET_FLAG_SWIMMER = 0x0002, + TARGET_FLAG_ITEM = 0x0010, + TARGET_FLAG_SOURCE_AREA = 0x0020, + TARGET_FLAG_DEST_AREA = 0x0040, + TARGET_FLAG_UNKNOWN = 0x0080, + TARGET_FLAG_SELF = 0x0100, + TARGET_FLAG_PVP_CORPSE = 0x0200, + TARGET_FLAG_MASS_SPIRIT_HEAL = 0x0400, + TARGET_FLAG_BEAST_CORPSE = 0x0402, + TARGET_FLAG_OBJECT = 0x4000, + TARGET_FLAG_RESURRECTABLE = 0x8000*/ + + TARGET_FLAG_SELF = 0x00000000, + TARGET_FLAG_UNIT = 0x00000002, // pguid + TARGET_FLAG_ITEM = 0x00000010, // pguid + TARGET_FLAG_SOURCE_LOCATION = 0x00000020, // 3 float + TARGET_FLAG_DEST_LOCATION = 0x00000040, // 3 float + TARGET_FLAG_OBJECT_UNK = 0x00000080, // ? + TARGET_FLAG_PVP_CORPSE = 0x00000200, // pguid + TARGET_FLAG_OBJECT = 0x00000800, // pguid + TARGET_FLAG_TRADE_ITEM = 0x00001000, // pguid + TARGET_FLAG_STRING = 0x00002000, // string + TARGET_FLAG_UNK1 = 0x00004000, // ? + TARGET_FLAG_CORPSE = 0x00008000, // pguid + TARGET_FLAG_UNK2 = 0x00010000 // pguid +}; + +enum SpellCastFlags +{ + CAST_FLAG_UNKNOWN1 = 0x00000002, + CAST_FLAG_UNKNOWN2 = 0x00000010, + CAST_FLAG_AMMO = 0x00000020, + CAST_FLAG_UNKNOWN3 = 0x00000100 +}; + +enum SpellNotifyPushType +{ + PUSH_IN_FRONT, + PUSH_IN_BACK, + PUSH_SELF_CENTER, + PUSH_DEST_CENTER, + PUSH_TARGET_CENTER +}; + +bool IsQuestTameSpell(uint32 spellId); + +namespace MaNGOS +{ + struct SpellNotifierPlayer; + struct SpellNotifierCreatureAndPlayer; +} + +class SpellCastTargets +{ + public: + SpellCastTargets(); + ~SpellCastTargets(); + + bool read ( WorldPacket * data, Unit *caster ); + void write ( WorldPacket * data ); + + SpellCastTargets& operator=(const SpellCastTargets &target) + { + m_unitTarget = target.m_unitTarget; + m_itemTarget = target.m_itemTarget; + m_GOTarget = target.m_GOTarget; + + m_unitTargetGUID = target.m_unitTargetGUID; + m_GOTargetGUID = target.m_GOTargetGUID; + m_CorpseTargetGUID = target.m_CorpseTargetGUID; + m_itemTargetGUID = target.m_itemTargetGUID; + + m_itemTargetEntry = target.m_itemTargetEntry; + + m_srcX = target.m_srcX; + m_srcY = target.m_srcY; + m_srcZ = target.m_srcZ; + + m_destX = target.m_destX; + m_destY = target.m_destY; + m_destZ = target.m_destZ; + + m_strTarget = target.m_strTarget; + + m_targetMask = target.m_targetMask; + + return *this; + } + + uint64 getUnitTargetGUID() const { return m_unitTargetGUID; } + Unit *getUnitTarget() const { return m_unitTarget; } + void setUnitTarget(Unit *target); + void setDestination(float x, float y, float z); + + uint64 getGOTargetGUID() const { return m_GOTargetGUID; } + GameObject *getGOTarget() const { return m_GOTarget; } + void setGOTarget(GameObject *target); + + uint64 getCorpseTargetGUID() const { return m_CorpseTargetGUID; } + void setCorpseTarget(Corpse* corpse); + uint64 getItemTargetGUID() const { return m_itemTargetGUID; } + Item* getItemTarget() const { return m_itemTarget; } + uint32 getItemTargetEntry() const { return m_itemTargetEntry; } + void setItemTarget(Item* item); + void updateTradeSlotItem() + { + if(m_itemTarget && (m_targetMask & TARGET_FLAG_TRADE_ITEM)) + { + m_itemTargetGUID = m_itemTarget->GetGUID(); + m_itemTargetEntry = m_itemTarget->GetEntry(); + } + } + + bool IsEmpty() const { return m_GOTargetGUID==0 && m_unitTargetGUID==0 && m_itemTarget==0 && m_CorpseTargetGUID==0; } + + void Update(Unit* caster); + + float m_srcX, m_srcY, m_srcZ; + float m_destX, m_destY, m_destZ; + std::string m_strTarget; + + uint32 m_targetMask; + private: + // objects (can be used at spell creating and after Update at casting + Unit *m_unitTarget; + GameObject *m_GOTarget; + Item *m_itemTarget; + + // object GUID/etc, can be used always + uint64 m_unitTargetGUID; + uint64 m_GOTargetGUID; + uint64 m_CorpseTargetGUID; + uint64 m_itemTargetGUID; + uint32 m_itemTargetEntry; +}; + +enum SpellState +{ + SPELL_STATE_NULL = 0, + SPELL_STATE_PREPARING = 1, + SPELL_STATE_CASTING = 2, + SPELL_STATE_FINISHED = 3, + SPELL_STATE_IDLE = 4, + SPELL_STATE_DELAYED = 5 +}; + +#define SPELL_SPELL_CHANNEL_UPDATE_INTERVAL 1000 + +typedef std::multimap SpellTargetTimeMap; + +class Spell +{ + friend struct MaNGOS::SpellNotifierPlayer; + friend struct MaNGOS::SpellNotifierCreatureAndPlayer; + public: + + void EffectNULL(uint32 ); + void EffectUnused(uint32 ); + void EffectDistract(uint32 i); + void EffectPull(uint32 i); + void EffectSchoolDMG(uint32 i); + void EffectEnvirinmentalDMG(uint32 i); + void EffectInstaKill(uint32 i); + void EffectDummy(uint32 i); + void EffectTeleportUnits(uint32 i); + void EffectApplyAura(uint32 i); + void EffectSendEvent(uint32 i); + void EffectPowerBurn(uint32 i); + void EffectPowerDrain(uint32 i); + void EffectHeal(uint32 i); + void EffectHealthLeech(uint32 i); + void EffectQuestComplete(uint32 i); + void EffectCreateItem(uint32 i); + void EffectPersistentAA(uint32 i); + void EffectEnergize(uint32 i); + void EffectOpenLock(uint32 i); + void EffectSummonChangeItem(uint32 i); + void EffectOpenSecretSafe(uint32 i); + void EffectProficiency(uint32 i); + void EffectApplyAreaAura(uint32 i); + void EffectSummonType(uint32 i); + void EffectSummon(uint32 i); + void EffectLearnSpell(uint32 i); + void EffectDispel(uint32 i); + void EffectDualWield(uint32 i); + void EffectPickPocket(uint32 i); + void EffectAddFarsight(uint32 i); + void EffectSummonWild(uint32 i); + void EffectSummonGuardian(uint32 i); + void EffectHealMechanical(uint32 i); + void EffectTeleUnitsFaceCaster(uint32 i); + void EffectLearnSkill(uint32 i); + void EffectAddHonor(uint32 i); + void EffectTradeSkill(uint32 i); + void EffectEnchantItemPerm(uint32 i); + void EffectEnchantItemTmp(uint32 i); + void EffectTameCreature(uint32 i); + void EffectSummonPet(uint32 i); + void EffectLearnPetSpell(uint32 i); + void EffectWeaponDmg(uint32 i); + void EffectForceCast(uint32 i); + void EffectTriggerSpell(uint32 i); + void EffectTriggerMissileSpell(uint32 i); + void EffectThreat(uint32 i); + void EffectHealMaxHealth(uint32 i); + void EffectInterruptCast(uint32 i); + void EffectSummonObjectWild(uint32 i); + void EffectScriptEffect(uint32 i); + void EffectSanctuary(uint32 i); + void EffectAddComboPoints(uint32 i); + void EffectDuel(uint32 i); + void EffectStuck(uint32 i); + void EffectSummonPlayer(uint32 i); + void EffectActivateObject(uint32 i); + void EffectSummonTotem(uint32 i); + void EffectEnchantHeldItem(uint32 i); + void EffectSummonObject(uint32 i); + void EffectResurrect(uint32 i); + void EffectParry(uint32 i); + void EffectBlock(uint32 i); + void EffectMomentMove(uint32 i); + void EffectTransmitted(uint32 i); + void EffectDisEnchant(uint32 i); + void EffectInebriate(uint32 i); + void EffectFeedPet(uint32 i); + void EffectDismissPet(uint32 i); + void EffectReputation(uint32 i); + void EffectSelfResurrect(uint32 i); + void EffectSkinning(uint32 i); + void EffectCharge(uint32 i); + void EffectProspecting(uint32 i); + void EffectSendTaxi(uint32 i); + void EffectSummonCritter(uint32 i); + void EffectKnockBack(uint32 i); + void EffectPlayerPull(uint32 i); + void EffectDispelMechanic(uint32 i); + void EffectSummonDeadPet(uint32 i); + void EffectDestroyAllTotems(uint32 i); + void EffectDurabilityDamage(uint32 i); + void EffectSkill(uint32 i); + void EffectTaunt(uint32 i); + void EffectDurabilityDamagePCT(uint32 i); + void EffectModifyThreatPercent(uint32 i); + void EffectResurrectNew(uint32 i); + void EffectAddExtraAttacks(uint32 i); + void EffectSpiritHeal(uint32 i); + void EffectSkinPlayerCorpse(uint32 i); + void EffectSummonDemon(uint32 i); + void EffectStealBeneficialBuff(uint32 i); + void EffectUnlearnSpecialization(uint32 i); + void EffectHealPct(uint32 i); + void EffectEnergisePct(uint32 i); + void EffectTriggerSpellWithValue(uint32 i); + void EffectTriggerRitualOfSummoning(uint32 i); + void EffectKillCredit(uint32 i); + void EffectQuestFail(uint32 i); + + Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 originalCasterGUID = 0, Spell** triggeringContainer = NULL ); + ~Spell(); + + void prepare(SpellCastTargets * targets, Aura* triggeredByAura = NULL); + void cancel(); + void update(uint32 difftime); + void cast(bool skipCheck = false); + void finish(bool ok = true); + void TakePower(); + void TakeReagents(); + void TakeCastItem(); + void TriggerSpell(); + uint8 CanCast(bool strict); + int16 PetCanCast(Unit* target); + bool CanAutoCast(Unit* target); + + // handlers + void handle_immediate(); + uint64 handle_delayed(uint64 t_offset); + // handler helpers + void _handle_immediate_phase(); + void _handle_finish_phase(); + + uint8 CheckItems(); + uint8 CheckRange(bool strict); + uint8 CheckPower(); + uint8 CheckCasterAuras() const; + + int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(m_spellInfo,i,m_currentBasePoints[i],target); } + int32 CalculatePowerCost(); + + bool HaveTargetsForEffect(uint8 effect) const; + void Delayed(); + void DelayedChannel(); + inline uint32 getState() const { return m_spellState; } + void setState(uint32 state) { m_spellState = state; } + + void DoCreateItem(uint32 i, uint32 itemtype); + + void WriteSpellGoTargets( WorldPacket * data ); + void WriteAmmoToPacket( WorldPacket * data ); + void FillTargetMap(); + + void SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap); + + Unit* SelectMagnetTarget(); + bool CheckTarget( Unit* target, uint32 eff, bool hitPhase ); + + void SendCastResult(uint8 result); + void SendSpellStart(); + void SendSpellGo(); + void SendSpellCooldown(); + void SendLogExecute(); + void SendInterrupted(uint8 result); + void SendChannelUpdate(uint32 time); + void SendChannelStart(uint32 duration); + void SendResurrectRequest(Player* target); + void SendPlaySpellVisual(uint32 SpellID); + + void HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float DamageMultiplier = 1.0); + void HandleThreatSpells(uint32 spellId); + //void HandleAddAura(Unit* Target); + + SpellEntry const* m_spellInfo; + int32 m_currentBasePoints[3]; // cache SpellEntry::EffectBasePoints and use for set custom base points + Item* m_CastItem; + uint8 m_cast_count; + SpellCastTargets m_targets; + + int32 GetCastTime() const { return m_casttime; } + bool IsAutoRepeat() const { return m_autoRepeat; } + void SetAutoRepeat(bool rep) { m_autoRepeat = rep; } + void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; } + bool IsNextMeleeSwingSpell() const + { + return m_spellInfo->Attributes & (SPELL_ATTR_ON_NEXT_SWING_1|SPELL_ATTR_ON_NEXT_SWING_2); + } + bool IsRangedSpell() const + { + return m_spellInfo->Attributes & SPELL_ATTR_RANGED; + } + bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; } + bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); } + bool IsRangedAttackResetSpell() const { return !m_IsTriggeredSpell && IsRangedSpell() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); } + + bool IsDeletable() const { return m_deletable; } + void SetDeletable(bool deletable) { m_deletable = deletable; } + uint64 GetDelayStart() const { return m_delayStart; } + void SetDelayStart(uint64 m_time) { m_delayStart = m_time; } + uint64 GetDelayMoment() const { return m_delayMoment; } + + bool IsNeedSendToClient() const; + + CurrentSpellTypes GetCurrentContainer(); + + Unit* GetCaster() const { return m_caster; } + Unit* GetOriginalCaster() const { return m_originalCaster; } + int32 GetPowerCost() const { return m_powerCost; } + + void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc) + + bool IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId); + + bool CheckTargetCreatureType(Unit* target) const; + + void AddTriggeredSpell(SpellEntry const* spell) { m_TriggerSpells.push_back(spell); } + + void CleanupTargetList(); + protected: + + void SendLoot(uint64 guid, LootType loottype); + + Unit* m_caster; + + uint64 m_originalCasterGUID; // real source of cast (aura caster/etc), used for spell targets selection + // e.g. damage around area spell trigered by victim aura and da,age emeies of aura caster + Unit* m_originalCaster; // cached pointer for m_originalCaster, updated at Spell::UpdatePointers() + + Spell** m_selfContainer; // pointer to our spell container (if applicable) + Spell** m_triggeringContainer; // pointer to container with spell that has triggered us + + //Spell data + SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example) + WeaponAttackType m_attackType; // For weapon based attack + int32 m_powerCost; // Calculated spell cost initialized only in Spell::prepare + int32 m_casttime; // Calculated spell cast time initialized only in Spell::prepare + bool m_canReflect; // can reflect this spell? + bool m_autoRepeat; + + uint8 m_delayAtDamageCount; + int32 GetNextDelayAtDamageMsTime() { return m_delayAtDamageCount < 5 ? 1000 - (m_delayAtDamageCount++)* 200 : 200; } + + // Delayed spells system + uint64 m_delayStart; // time of spell delay start, filled by event handler, zero = just started + uint64 m_delayMoment; // moment of next delay call, used internally + bool m_immediateHandled; // were immediate actions handled? (used by delayed spells only) + + // These vars are used in both delayed spell system and modified immediate spell system + bool m_deletable; // is the spell pending deletion or must be updated till permitted to delete? + bool m_needSpellLog; // need to send spell log? + uint8 m_applyMultiplierMask; // by effect: damage multiplier needed? + float m_damageMultipliers[3]; // by effect: damage multiplier + + // Current targets, to be used in SpellEffects (MUST BE USED ONLY IN SPELL EFFECTS) + Unit* unitTarget; + Item* itemTarget; + GameObject* gameObjTarget; + int32 damage; + + // this is set in Spell Hit, but used in Apply Aura handler + DiminishingLevels m_diminishLevel; + DiminishingGroup m_diminishGroup; + + // ------------------------------------------- + GameObject* focusObject; + + //****************************************** + // Spell trigger system + //****************************************** + void doTriggers(SpellMissInfo missInfo, uint32 damage=0, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NONE, uint32 block=0, uint32 absorb=0, bool crit=false); + + //***************************************** + // Spell target subsystem + //***************************************** + // Targets store structures and data + uint32 m_countOfHit; + uint32 m_countOfMiss; + struct TargetInfo + { + uint64 targetGUID; + uint64 timeDelay; + SpellMissInfo missCondition:8; + SpellMissInfo reflectResult:8; + uint8 effectMask:8; + bool processed:1; + }; + std::list m_UniqueTargetInfo; + uint8 m_needAliveTargetMask; // Mask req. alive targets + + struct GOTargetInfo + { + uint64 targetGUID; + uint64 timeDelay; + uint8 effectMask:8; + bool processed:1; + }; + std::list m_UniqueGOTargetInfo; + + struct ItemTargetInfo + { + Item *item; + uint8 effectMask; + }; + std::list m_UniqueItemInfo; + + void AddUnitTarget(Unit* target, uint32 effIndex); + void AddUnitTarget(uint64 unitGUID, uint32 effIndex); + void AddGOTarget(GameObject* target, uint32 effIndex); + void AddGOTarget(uint64 goGUID, uint32 effIndex); + void AddItemTarget(Item* target, uint32 effIndex); + void DoAllEffectOnTarget(TargetInfo *target); + void DoSpellHitOnUnit(Unit *unit, uint32 effectMask); + void DoAllEffectOnTarget(GOTargetInfo *target); + void DoAllEffectOnTarget(ItemTargetInfo *target); + bool IsAliveUnitPresentInTargetList(); + // ------------------------------------------- + + //List For Triggered Spells + typedef std::list TriggerSpells; + TriggerSpells m_TriggerSpells; + + uint32 m_spellState; + uint32 m_timer; + + float m_castPositionX; + float m_castPositionY; + float m_castPositionZ; + float m_castOrientation; + bool m_IsTriggeredSpell; + + // if need this can be replaced by Aura copy + // we can't store original aura link to prevent access to deleted auras + // and in same time need aura data and after aura deleting. + SpellEntry const* m_triggeredByAuraSpell; +}; + +enum ReplenishType +{ + REPLENISH_UNDEFINED = 0, + REPLENISH_HEALTH = 20, + REPLENISH_MANA = 21, + REPLENISH_RAGE = 22 +}; + +enum SpellTargets +{ + SPELL_TARGETS_HOSTILE, + SPELL_TARGETS_NOT_FRIENDLY, + SPELL_TARGETS_NOT_HOSTILE, + SPELL_TARGETS_FRIENDLY, + SPELL_TARGETS_AOE_DAMAGE +}; + +namespace MaNGOS +{ + struct MANGOS_DLL_DECL SpellNotifierPlayer + { + std::list &i_data; + Spell &i_spell; + const uint32& i_index; + float i_radius; + Unit* i_originalCaster; + + SpellNotifierPlayer(Spell &spell, std::list &data, const uint32 &i, float radius) + : i_data(data), i_spell(spell), i_index(i), i_radius(radius) + { + i_originalCaster = i_spell.GetOriginalCaster(); + } + + void Visit(PlayerMapType &m) + { + if(!i_originalCaster) + return; + + for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + Player * pPlayer = itr->getSource(); + if( !pPlayer->isAlive() || pPlayer->isInFlight()) + continue; + + if( i_originalCaster->IsFriendlyTo(pPlayer) ) + continue; + + if( pPlayer->GetDistance(i_spell.m_targets.m_destX, i_spell.m_targets.m_destY, i_spell.m_targets.m_destZ) < i_radius ) + i_data.push_back(pPlayer); + } + } + template void Visit(GridRefManager &) {} + }; + + struct MANGOS_DLL_DECL SpellNotifierCreatureAndPlayer + { + std::list *i_data; + Spell &i_spell; + const uint32& i_push_type; + float i_radius; + SpellTargets i_TargetType; + Unit* i_originalCaster; + + SpellNotifierCreatureAndPlayer(Spell &spell, std::list &data, float radius, const uint32 &type, + SpellTargets TargetType = SPELL_TARGETS_NOT_FRIENDLY) + : i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_TargetType(TargetType) + { + i_originalCaster = spell.GetOriginalCaster(); + } + + template inline void Visit(GridRefManager &m) + { + assert(i_data); + + if(!i_originalCaster) + return; + + for(typename GridRefManager::iterator itr = m.begin(); itr != m.end(); ++itr) + { + if( !itr->getSource()->isAlive() || (itr->getSource()->GetTypeId() == TYPEID_PLAYER && ((Player*)itr->getSource())->isInFlight())) + continue; + + switch (i_TargetType) + { + case SPELL_TARGETS_HOSTILE: + if (!itr->getSource()->isTargetableForAttack() || !i_originalCaster->IsHostileTo( itr->getSource() )) + continue; + break; + case SPELL_TARGETS_NOT_FRIENDLY: + if (!itr->getSource()->isTargetableForAttack() || i_originalCaster->IsFriendlyTo( itr->getSource() )) + continue; + break; + case SPELL_TARGETS_NOT_HOSTILE: + if (!itr->getSource()->isTargetableForAttack() || i_originalCaster->IsHostileTo( itr->getSource() )) + continue; + break; + case SPELL_TARGETS_FRIENDLY: + if (!itr->getSource()->isTargetableForAttack() || !i_originalCaster->IsFriendlyTo( itr->getSource() )) + continue; + break; + case SPELL_TARGETS_AOE_DAMAGE: + { + if(itr->getSource()->GetTypeId()==TYPEID_UNIT && ((Creature*)itr->getSource())->isTotem()) + continue; + if(!itr->getSource()->isTargetableForAttack()) + continue; + + Unit* check = i_originalCaster->GetCharmerOrOwnerOrSelf(); + + if( check->GetTypeId()==TYPEID_PLAYER ) + { + if (check->IsFriendlyTo( itr->getSource() )) + continue; + } + else + { + if (!check->IsHostileTo( itr->getSource() )) + continue; + } + } + break; + default: continue; + } + + switch(i_push_type) + { + case PUSH_IN_FRONT: + if(i_spell.GetCaster()->isInFront((Unit*)(itr->getSource()), i_radius, 2*M_PI/3 )) + i_data->push_back(itr->getSource()); + break; + case PUSH_IN_BACK: + if(i_spell.GetCaster()->isInBack((Unit*)(itr->getSource()), i_radius, 2*M_PI/3 )) + i_data->push_back(itr->getSource()); + break; + case PUSH_SELF_CENTER: + if(i_spell.GetCaster()->IsWithinDistInMap((Unit*)(itr->getSource()), i_radius)) + i_data->push_back(itr->getSource()); + break; + case PUSH_DEST_CENTER: + if((itr->getSource()->GetDistance(i_spell.m_targets.m_destX, i_spell.m_targets.m_destY, i_spell.m_targets.m_destZ) < i_radius )) + i_data->push_back(itr->getSource()); + break; + case PUSH_TARGET_CENTER: + if(i_spell.m_targets.getUnitTarget()->IsWithinDistInMap((Unit*)(itr->getSource()), i_radius)) + i_data->push_back(itr->getSource()); + break; + } + } + } + + #ifdef WIN32 + template<> inline void Visit(CorpseMapType & ) {} + template<> inline void Visit(GameObjectMapType & ) {} + template<> inline void Visit(DynamicObjectMapType & ) {} + #endif + }; + + #ifndef WIN32 + template<> inline void SpellNotifierCreatureAndPlayer::Visit(CorpseMapType& ) {} + template<> inline void SpellNotifierCreatureAndPlayer::Visit(GameObjectMapType& ) {} + template<> inline void SpellNotifierCreatureAndPlayer::Visit(DynamicObjectMapType& ) {} + #endif +} + +typedef void(Spell::*pEffect)(uint32 i); + +class SpellEvent : public BasicEvent +{ + public: + SpellEvent(Spell* spell); + virtual ~SpellEvent(); + + virtual bool Execute(uint64 e_time, uint32 p_time); + virtual void Abort(uint64 e_time); + protected: + Spell* m_Spell; +}; +#endif diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index fa037fcdb24..32be3d65065 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -1,6090 +1,6098 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "SharedDefines.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "UpdateMask.h" -#include "World.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Player.h" -#include "SkillExtraItems.h" -#include "Unit.h" -#include "CreatureAI.h" -#include "Spell.h" -#include "DynamicObject.h" -#include "SpellAuras.h" -#include "Group.h" -#include "UpdateData.h" -#include "MapManager.h" -#include "ObjectAccessor.h" -#include "SharedDefines.h" -#include "Pet.h" -#include "GameObject.h" -#include "GossipDef.h" -#include "Creature.h" -#include "Totem.h" -#include "CreatureAI.h" -#include "BattleGround.h" -#include "BattleGroundEY.h" -#include "BattleGroundWS.h" -#include "VMapFactory.h" -#include "Language.h" -#include "SocialMgr.h" -#include "Util.h" - -pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= -{ - &Spell::EffectNULL, // 0 - &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL - &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE - &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY - &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused - &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS - &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA - &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE - &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN - &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH - &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL - &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND - &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL - &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused - &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused - &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused - &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE - &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL - &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT - &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS - &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge - &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND) - &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY - &Spell::EffectUnused, // 23 SPELL_EFFECT_BLOCK one spell: Block - &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM - &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON - &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense - &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA - &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON - &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP - &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE - &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE - &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE - &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK - &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM - &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY - &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL - &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND) - &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL - &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE - &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD - &Spell::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD - &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN - &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER - &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP - &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related - &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there - &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL - &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth - &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect - &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR - &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused - &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot - &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM - &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY - &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE - &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET - &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL - &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE - &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM - &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY - &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT - &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN - &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT - &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL - &Spell::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused - &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused - &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH - &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST - &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT - &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move - &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET - &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT - &Spell::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED - &Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM - &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit - &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD - &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT - &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK - &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY - &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS - &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST) - &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT - &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL - &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK - &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER - &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT - &Spell::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1 - &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2 - &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3 - &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4 - &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash - &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM - &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM - &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT - &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING - &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE - &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER - &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK - &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT - &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE - &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET - &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET - &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION - &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 - &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 - &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 - &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 - &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC - &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET - &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS - &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE - &Spell::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON - &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW - &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME - &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT - &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags... - &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal - &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more - &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET - &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test - &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG - &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused - &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id) - &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster) - &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT - &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect? - &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell - &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND - &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY - &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT - &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells - &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value - &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization - &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry - &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET - &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT - &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT - &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap - &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused - &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST - &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed? - &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE - &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER - &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast - &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect - &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused - &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail - &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused - &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop - &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused - &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2 - &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend - &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry -}; - -void Spell::EffectNULL(uint32 /*i*/) -{ - sLog.outDebug("WORLD: Spell Effect DUMMY"); -} - -void Spell::EffectUnused(uint32 /*i*/) -{ - // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS -} - -void Spell::EffectResurrectNew(uint32 i) -{ - if(!unitTarget || unitTarget->isAlive()) - return; - - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if(!unitTarget->IsInWorld()) - return; - - Player* pTarget = ((Player*)unitTarget); - - if(pTarget->isRessurectRequested()) // already have one active request - return; - - uint32 health = damage; - uint32 mana = m_spellInfo->EffectMiscValue[i]; - pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); - SendResurrectRequest(pTarget); -} - -void Spell::EffectInstaKill(uint32 /*i*/) -{ - if( !unitTarget || !unitTarget->isAlive() ) - return; - - // Demonic Sacrifice - if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT) - { - uint32 entry = unitTarget->GetEntry(); - uint32 spellID; - switch(entry) - { - case 416: spellID=18789; break; //imp - case 417: spellID=18792; break; //fellhunter - case 1860: spellID=18790; break; //void - case 1863: spellID=18791; break; //succubus - case 17252: spellID=35701; break; //fellguard - default: - sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry); - return; - } - - m_caster->CastSpell(m_caster,spellID,true); - } - - if(m_caster==unitTarget) // prevent interrupt message - finish(); - - uint32 health = unitTarget->GetHealth(); - m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); -} - -void Spell::EffectEnvirinmentalDMG(uint32 i) -{ - uint32 absorb = 0; - uint32 resist = 0; - - // Note: this hack with damage replace required until GO casting not implemented - // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support - // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc - damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i]; - - m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - - m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false); - if(m_caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage); -} - -void Spell::EffectSchoolDMG(uint32 effect_idx) -{ - if( unitTarget && unitTarget->isAlive()) - { - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - //Gore - if(m_spellInfo->SpellIconID == 2269 ) - { - damage+= rand()%2 ? damage : 0; - } - - switch(m_spellInfo->Id) // better way to check unknown - { - // Meteor like spells (divided damage to targets) - case 24340: case 26558: case 28884: // Meteor - case 36837: case 38903: case 41276: // Meteor - case 26789: // Shard of the Fallen Star - case 31436: // Malevolent Cleave - case 35181: // Dive Bomb - case 40810: case 43267: case 43268: // Saber Lash - case 42384: // Brutal Swipe - case 45150: // Meteor Slash - { - uint32 count = 0; - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - if(ihit->effectMask & (1<GetHealth() / 2; - if(damage < 200) - damage = 200; - break; - } - } - break; - } - - case SPELLFAMILY_MAGE: - { - // Arcane Blast - if(m_spellInfo->SpellFamilyFlags & 0x20000000LL) - { - m_caster->CastSpell(m_caster,36032,true); - } - break; - } - case SPELLFAMILY_WARRIOR: - { - // Bloodthirst - if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL) - { - damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100); - } - // Shield Slam - else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) - damage += int32(m_caster->GetShieldBlockValue()); - // Victory Rush - else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL) - { - damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); - m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false); - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Incinerate Rank 1 & 2 - if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128) - { - // Incinerate does more dmg (dmg*0.25) if the target is Immolated. - if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE)) - damage += int32(damage*0.25); - } - break; - } - case SPELLFAMILY_DRUID: - { - // Ferocious Bite - if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587) - { - // converts each extra point of energy into ($f1+$AP/630) additional damage - float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx]; - damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple); - m_caster->SetPower(POWER_ENERGY,0); - } - // Rake - else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); - } - // Swipe - else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f); - } - // Starfire - else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL ) - { - Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i) - { - // Starfire Bonus (caster) - switch((*i)->GetModifier()->m_miscvalue) - { - case 5481: // Nordrassil Regalia - bonus - { - Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr) - { - // Moonfire or Insect Swarm (target debuff from any casters) - if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL ) - { - int32 mod = (*i)->GetModifier()->m_amount; - damage += damage*mod/100; - break; - } - } - break; - } - case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura - { - damage += (*i)->GetModifier()->m_amount; - break; - } - } - } - } - //Mangle Bonus for the initial damage of Lacerate and Rake - if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) || - (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246)) - { - Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID) - { - damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f); - break; - } - } - break; - } - case SPELLFAMILY_ROGUE: - { - // Envenom - if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL)) - { - // consume from stack dozes not more that have combo-points - if(uint32 combo = ((Player*)m_caster)->GetComboPoints()) - { - // count consumed deadly poison doses at target - uint32 doses = 0; - - // remove consumed poison doses - Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;) - { - // Deadly poison (only attacker applied) - if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) && - (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() ) - { - --combo; - ++doses; - - unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex()); - - itr = auras.begin(); - } - else - ++itr; - } - - damage *= doses; - damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses); - - // Eviscerate and Envenom Bonus Damage (item set effect) - if(m_caster->GetDummyAura(37169)) - damage += ((Player*)m_caster)->GetComboPoints()*40; - } - } - // Eviscerate - else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER) - { - if(uint32 combo = ((Player*)m_caster)->GetComboPoints()) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f); - - // Eviscerate and Envenom Bonus Damage (item set effect) - if(m_caster->GetDummyAura(37169)) - damage += combo*40; - } - } - break; - } - case SPELLFAMILY_HUNTER: - { - // Mongoose Bite - if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2); - } - // Arcane Shot - else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0) - { - damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15); - } - // Steady Shot - else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) - { - int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE)); - damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f); - } - //Explosive Trap Effect - else if(m_spellInfo->SpellFamilyFlags & 0x00000004) - { - damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1); - } - break; - } - case SPELLFAMILY_PALADIN: - { - //Judgement of Vengeance - if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292) - { - uint32 stacks = 0; - Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) - if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID()) - ++stacks; - if(!stacks) - //No damage if the target isn't affected by this - damage = -1; - else - damage *= stacks; - } - break; - } - } - - if(damage >= 0) - { - uint32 finalDamage; - if(m_originalCaster) // m_caster only passive source of cast - finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); - else - finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); - - // post effects - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_WARRIOR: - { - // Bloodthirst - if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL) - { - uint32 BTAura = 0; - switch(m_spellInfo->Id) - { - case 23881: BTAura = 23885; break; - case 23892: BTAura = 23886; break; - case 23893: BTAura = 23887; break; - case 23894: BTAura = 23888; break; - case 25251: BTAura = 25252; break; - case 30335: BTAura = 30339; break; - default: - sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id); - break; - } - - if (BTAura) - m_caster->CastSpell(m_caster,BTAura,true); - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Shadow Word: Death - if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive()) - // deals damage equal to damage done to caster if victim is not killed - m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false); - - break; - } - case SPELLFAMILY_PALADIN: - { - // Judgement of Blood - if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153) - { - int32 damagePoint = finalDamage * 33 / 100; - m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true); - } - break; - } - } - } - } -} - -void Spell::EffectDummy(uint32 i) -{ - if(!unitTarget && !gameObjTarget && !itemTarget) - return; - - // selection by spell family - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - // Gnomish Poultryizer trinket - switch(m_spellInfo->Id ) - { - case 8063: // Deviate Fish - { - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch(urand(1,5)) - { - case 1: spell_id = 8064; break; // Sleepy - case 2: spell_id = 8065; break; // Invigorate - case 3: spell_id = 8066; break; // Shrink - case 4: spell_id = 8067; break; // Party Time! - case 5: spell_id = 8068; break; // Healthy Spirit - } - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 8213: // Savory Deviate Delight - { - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch(urand(1,2)) - { - // Flip Out - ninja - case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break; - // Yaaarrrr - pirate - case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break; - } - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 8593: // Symbol of life (restore creature to life) - case 31225: // Shimmering Vessel (restore creature to life) - { - if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT) - return; - ((Creature*)unitTarget)->setDeathState(JUST_ALIVED); - return; - } - case 12162: // Deep wounds - case 12850: // (now good common check for this spells) - case 12868: - { - if(!unitTarget) - return; - - float damage; - // DW should benefit of attack power, damage percent mods etc. - // TODO: check if using offhand damage is correct and if it should be divided by 2 - if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK)) - damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2; - else - damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2; - - switch (m_spellInfo->Id) - { - case 12850: damage *= 0.2f; break; - case 12162: damage *= 0.4f; break; - case 12868: damage *= 0.6f; break; - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id); - return; - }; - - int32 deepWoundsDotBasePoints0 = int32(damage / 4); - m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL); - return; - } - case 12975: //Last Stand - { - int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3); - m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL); - return; - } - case 13120: // net-o-matic - { - if(!unitTarget) - return; - - uint32 spell_id = 0; - - uint32 roll = urand(0, 99); - - if(roll < 2) // 2% for 30 sec self root (off-like chance unknown) - spell_id = 16566; - else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown) - spell_id = 13119; - else // normal root - spell_id = 13099; - - m_caster->CastSpell(unitTarget,spell_id,true,NULL); - return; - } - case 13567: // Dummy Trigger - { - // can be used for different aura triggreing, so select by aura - if(!m_triggeredByAuraSpell || !unitTarget) - return; - - switch(m_triggeredByAuraSpell->Id) - { - case 26467: // Persistent Shield - m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true); - break; - default: - sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id); - break; - } - return; - } - case 14185: // Preparation Rogue - { - if(m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - //immediately finishes the cooldown on certain Rogue abilities - const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL)) - { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - } - return; - } - case 15998: // Capture Worg Pup - case 29435: // Capture Female Kaliri Hatchling - { - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - Creature* creatureTarget = (Creature*)unitTarget; - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - return; - } - case 16589: // Noggenfogger Elixir - { - if(m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch(urand(1,3)) - { - case 1: spell_id = 16595; break; - case 2: spell_id = 16593; break; - default:spell_id = 16591; break; - } - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 17251: // Spirit Healer Res - { - if(!unitTarget || !m_originalCaster) - return; - - if(m_originalCaster->GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8); - data << unitTarget->GetGUID(); - ((Player*)m_originalCaster)->GetSession()->SendPacket( &data ); - } - return; - } - case 17271: // Test Fetid Skull - { - if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - uint32 spell_id = roll_chance_i(50) ? 17269 : 17270; - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 20577: // Cannibalize - if (unitTarget) - m_caster->CastSpell(m_caster,20578,false,NULL); - return; - case 23019: // Crystal Prison Dummy DND - { - if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet()) - return; - - Creature* creatureTarget = (Creature*)unitTarget; - if(creatureTarget->isPet()) - return; - - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - - GameObject* pGameObj = new GameObject; - - Map *map = creatureTarget->GetMap(); - - if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, - creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), - creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) ) - { - delete pGameObj; - return; - } - - pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL)); - pGameObj->SetOwnerGUID(m_caster->GetGUID() ); - pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); - pGameObj->SetSpellId(m_spellInfo->Id); - - DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n"); - map->Add(pGameObj); - - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << uint64(pGameObj->GetGUID()); - m_caster->SendMessageToSet(&data,true); - - return; - } - case 23074: // Arc. Dragonling - if (!m_CastItem) return; - m_caster->CastSpell(m_caster,19804,true,m_CastItem); - return; - case 23075: // Mithril Mechanical Dragonling - if (!m_CastItem) return; - m_caster->CastSpell(m_caster,12749,true,m_CastItem); - return; - case 23076: // Mechanical Dragonling - if (!m_CastItem) return; - m_caster->CastSpell(m_caster,4073,true,m_CastItem); - return; - case 23133: // Gnomish Battle Chicken - if (!m_CastItem) return; - m_caster->CastSpell(m_caster,13166,true,m_CastItem); - return; - case 23448: // Ultrasafe Transporter: Gadgetzan - backfires - { - int32 r = irand(0, 119); - if ( r < 20 ) // 1/6 polymorph - m_caster->CastSpell(m_caster,23444,true); - else if ( r < 100 ) // 4/6 evil twin - m_caster->CastSpell(m_caster,23445,true); - else // 1/6 miss the target - m_caster->CastSpell(m_caster,36902,true); - return; - } - case 23453: // Ultrasafe Transporter: Gadgetzan - if ( roll_chance_i(50) ) // success - m_caster->CastSpell(m_caster,23441,true); - else // failure - m_caster->CastSpell(m_caster,23446,true); - return; - case 23645: // Hourglass Sand - m_caster->RemoveAurasDueToSpell(23170); - return; - case 23725: // Gift of Life (warrior bwl trinket) - m_caster->CastSpell(m_caster,23782,true); - m_caster->CastSpell(m_caster,23783,true); - return; - case 25860: // Reindeer Transformation - { - if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED)) - return; - - float flyspeed = m_caster->GetSpeedRate(MOVE_FLY); - float speed = m_caster->GetSpeedRate(MOVE_RUN); - - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); - - //5 different spells used depending on mounted speed and if mount can fly or not - if (flyspeed >= 4.1f) - m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer - else if (flyspeed >= 3.8f) - m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer - else if (flyspeed >= 1.6f) - m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer - else if (speed >= 2.0f) - m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer - else - m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer - - return; - } - //case 26074: // Holiday Cheer - // return; -- implemented at client side - case 28006: // Arcane Cloaking - { - if( unitTarget->GetTypeId() == TYPEID_PLAYER ) - m_caster->CastSpell(unitTarget,29294,true); - return; - } - case 28730: // Arcane Torrent (Mana) - { - int32 count = 0; - Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i) - if ((*i)->GetId() == 28734) - ++count; - if (count) - { - m_caster->RemoveAurasDueToSpell(28734); - int32 bp = damage * count; - m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true); - } - return; - } - case 29200: // Purify Helboar Meat - { - if( m_caster->GetTypeId() != TYPEID_PLAYER ) - return; - - uint32 spell_id = roll_chance_i(50) ? 29277 : 29278; - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 29858: // Soulshatter - if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster)) - m_caster->CastSpell(unitTarget,32835,true); - return; - case 30458: // Nigh Invulnerability - if (!m_CastItem) return; - if(roll_chance_i(86)) // success - m_caster->CastSpell(m_caster, 30456, true, m_CastItem); - else // backfire in 14% casts - m_caster->CastSpell(m_caster, 30457, true, m_CastItem); - return; - case 30507: // Poultryizer - if (!m_CastItem) return; - if(roll_chance_i(80)) // success - m_caster->CastSpell(unitTarget, 30501, true, m_CastItem); - else // backfire 20% - m_caster->CastSpell(unitTarget, 30504, true, m_CastItem); - return; - case 33060: // Make a Wish - { - if(m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - - switch(urand(1,5)) - { - case 1: spell_id = 33053; break; - case 2: spell_id = 33057; break; - case 3: spell_id = 33059; break; - case 4: spell_id = 33062; break; - case 5: spell_id = 33064; break; - } - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 35745: - { - uint32 spell_id; - switch(m_caster->GetAreaId()) - { - case 3900: spell_id = 35743; break; - case 3742: spell_id = 35744; break; - default: return; - } - - m_caster->CastSpell(m_caster,spell_id,true); - return; - } - case 37674: // Chaos Blast - if(unitTarget) - m_caster->CastSpell(unitTarget,37675,true); - return; - case 44875: // Complete Raptor Capture - { - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - Creature* creatureTarget = (Creature*)unitTarget; - - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - - //cast spell Raptor Capture Credit - m_caster->CastSpell(m_caster,42337,true,NULL); - return; - } - case 45030: // Impale Emissary - { - // Emissary of Hate Credit - m_caster->CastSpell(m_caster,45088,true); - return; - } - case 50243: // Teach Language - { - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // spell has a 1/3 chance to trigger one of the below - if(roll_chance_i(66)) - return; - if(((Player*)m_caster)->GetTeam() == ALLIANCE) - { - // 1000001 - gnomish binary - m_caster->CastSpell(m_caster, 50242, true); - } - else - { - // 01001000 - goblin binary - m_caster->CastSpell(m_caster, 50246, true); - } - - return; - } - case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite) - { - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround()) - bg->EventPlayerDroppedFlag((Player*)m_caster); - - m_caster->CastSpell(m_caster, 30452, true, NULL); - return; - } - } - - //All IconID Check in there - switch(m_spellInfo->SpellIconID) - { - // Berserking (troll racial traits) - case 1661: - { - uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100); - int32 melee_mod = 10; - if (healthPerc <= 40) - melee_mod = 30; - if (healthPerc < 100 && healthPerc > 40) - melee_mod = 10+(100-healthPerc)/3; - - int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1 - int32 hasteModBasePoints1 = (5-melee_mod); - int32 hasteModBasePoints2 = 5; - - // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway - m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true); - m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL); - return; - } - } - break; - case SPELLFAMILY_MAGE: - switch(m_spellInfo->Id ) - { - case 11958: // Cold Snap - { - if(m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - // immediately finishes the cooldown on Frost spells - const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED) - continue; - - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); - - if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && - (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) && - spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 ) - { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - } - return; - } - } - break; - case SPELLFAMILY_WARRIOR: - // Charge - if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867) - { - int32 chargeBasePoints0 = damage; - m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true); - return; - } - // Execute - if(m_spellInfo->SpellFamilyFlags & 0x20000000) - { - if(!unitTarget) - return; - - int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]); - m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0); - m_caster->SetPower(POWER_RAGE,0); - return; - } - if(m_spellInfo->Id==21977) //Warrior's Wrath - { - if(!unitTarget) - return; - - m_caster->CastSpell(unitTarget,21887,true); // spell mod - return; - } - break; - case SPELLFAMILY_WARLOCK: - //Life Tap (only it have this with dummy effect) - if (m_spellInfo->SpellFamilyFlags == 0x40000) - { - float cost = m_currentBasePoints[0]+1; - - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this); - - int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE); - - if(int32(m_caster->GetHealth()) > dmg) - { - // Shouldn't Appear in Combat Log - m_caster->ModifyHealth(-dmg); - - int32 mana = dmg; - - Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr) - { - // only Imp. Life Tap have this in combination with dummy aura - if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208) - mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100; - } - - m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL); - - // Mana Feed - int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster); - manaFeedVal = manaFeedVal * mana / 100; - if(manaFeedVal > 0) - m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL); - } - else - SendCastResult(SPELL_FAILED_FIZZLE); - return; - } - break; - case SPELLFAMILY_PRIEST: - switch(m_spellInfo->Id ) - { - case 28598: // Touch of Weakness triggered spell - { - if(!unitTarget || !m_triggeredByAuraSpell) - return; - - uint32 spellid = 0; - switch(m_triggeredByAuraSpell->Id) - { - case 2652: spellid = 2943; break; // Rank 1 - case 19261: spellid = 19249; break; // Rank 2 - case 19262: spellid = 19251; break; // Rank 3 - case 19264: spellid = 19252; break; // Rank 4 - case 19265: spellid = 19253; break; // Rank 5 - case 19266: spellid = 19254; break; // Rank 6 - case 25461: spellid = 25460; break; // Rank 7 - default: - sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id); - return; - } - m_caster->CastSpell(unitTarget, spellid, true, NULL); - return; - } - } - break; - case SPELLFAMILY_DRUID: - switch(m_spellInfo->Id ) - { - case 5420: // Tree of Life passive - { - // Tree of Life area effect - int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4); - m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL); - return; - } - } - break; - case SPELLFAMILY_ROGUE: - switch(m_spellInfo->Id ) - { - case 31231: // Cheat Death - { - m_caster->CastSpell(m_caster,45182,true); - return; - } - case 5938: // Shiv - { - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *pCaster = ((Player*)m_caster); - - Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK); - if(!item) - return; - - // all poison enchantments is temporary - uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT); - if(!enchant_id) - return; - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) - return; - - for (int s=0;s<3;s++) - { - if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) - continue; - - SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]); - if(!combatEntry || combatEntry->Dispel != DISPEL_POISON) - continue; - - m_caster->CastSpell(unitTarget, combatEntry, true, item); - } - - m_caster->CastSpell(unitTarget, 5940, true); - return; - } - } - break; - case SPELLFAMILY_HUNTER: - // Steady Shot - if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) - { - if( !unitTarget || !unitTarget->isAlive()) - return; - - bool found = false; - - // check dazed affect - Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); - for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter) - { - if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0) - { - found = true; - break; - } - } - - if(found) - m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); - return; - } - // Kill command - if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL) - { - if(m_caster->getClass()!=CLASS_HUNTER) - return; - - // clear hunter crit aura state - m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false); - - // additional damage from pet to pet target - Pet* pet = m_caster->GetPet(); - if(!pet || !pet->getVictim()) - return; - - uint32 spell_id = 0; - switch (m_spellInfo->Id) - { - case 34026: spell_id = 34027; break; // rank 1 - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id); - return; - } - - pet->CastSpell(pet->getVictim(), spell_id, true); - return; - } - - switch(m_spellInfo->Id) - { - case 23989: //Readiness talent - { - if(m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - //immediately finishes the cooldown for hunter abilities - const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 ) - { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - } - return; - } - case 37506: // Scatter Shot - { - if (m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - // break Auto Shot and autohit - m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - m_caster->AttackStop(); - ((Player*)m_caster)->SendAttackSwingCancelAttack(); - return; - } - } - break; - case SPELLFAMILY_PALADIN: - switch(m_spellInfo->SpellIconID) - { - case 156: // Holy Shock - { - if(!unitTarget) - return; - - int hurt = 0; - int heal = 0; - - switch(m_spellInfo->Id) - { - case 20473: hurt = 25912; heal = 25914; break; - case 20929: hurt = 25911; heal = 25913; break; - case 20930: hurt = 25902; heal = 25903; break; - case 27174: hurt = 27176; heal = 27175; break; - case 33072: hurt = 33073; heal = 33074; break; - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id); - return; - } - - if(m_caster->IsFriendlyTo(unitTarget)) - m_caster->CastSpell(unitTarget, heal, true, 0); - else - m_caster->CastSpell(unitTarget, hurt, true, 0); - - return; - } - case 561: // Judgement of command - { - if(!unitTarget) - return; - - uint32 spell_id = m_currentBasePoints[i]+1; - SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id); - if(!spell_proto) - return; - - if( !unitTarget->hasUnitState(UNIT_STAT_STUNDED) && m_caster->GetTypeId()==TYPEID_PLAYER) - { - // decreased damage (/2) for non-stunned target. - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_DAMAGE; - mod->value = -50; - mod->type = SPELLMOD_PCT; - mod->spellId = m_spellInfo->Id; - mod->effectId = i; - mod->lastAffected = NULL; - mod->mask = 0x0000020000000000LL; - mod->charges = 0; - - ((Player*)m_caster)->AddSpellMod(mod, true); - m_caster->CastSpell(unitTarget,spell_proto,true,NULL); - // mod deleted - ((Player*)m_caster)->AddSpellMod(mod, false); - } - else - m_caster->CastSpell(unitTarget,spell_proto,true,NULL); - - return; - } - } - - switch(m_spellInfo->Id) - { - case 31789: // Righteous Defense (step 1) - { - // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target) - - // non-standard cast requirement check - if (!unitTarget || unitTarget->getAttackers().empty()) - { - // clear cooldown at fail - if(m_caster->GetTypeId()==TYPEID_PLAYER) - { - ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(m_spellInfo->Id); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - - SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT); - return; - } - - // Righteous Defense (step 2) (in old version 31980 dummy effect) - // Clear targets for eff 1 - for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - ihit->effectMask &= ~(1<<1); - - // not empty (checked) - Unit::AttackerSet const& attackers = unitTarget->getAttackers(); - - // chance to be selected from list - float chance = 100.0f/attackers.size(); - uint32 count=0; - for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr) - { - if(!roll_chance_f(chance)) - continue; - ++count; - AddUnitTarget((*aItr), 1); - } - - // now let next effect cast spell at each target. - return; - } - case 37877: // Blessing of Faith - { - if(!unitTarget) - return; - - uint32 spell_id = 0; - switch(unitTarget->getClass()) - { - case CLASS_DRUID: spell_id = 37878; break; - case CLASS_PALADIN: spell_id = 37879; break; - case CLASS_PRIEST: spell_id = 37880; break; - case CLASS_SHAMAN: spell_id = 37881; break; - default: return; // ignore for not healing classes - } - - m_caster->CastSpell(m_caster,spell_id,true); - return; - } - } - break; - case SPELLFAMILY_SHAMAN: - //Shaman Rockbiter Weapon - if (m_spellInfo->SpellFamilyFlags == 0x400000) - { - uint32 spell_id = 0; - switch(m_spellInfo->Id) - { - case 8017: spell_id = 36494; break; // Rank 1 - case 8018: spell_id = 36750; break; // Rank 2 - case 8019: spell_id = 36755; break; // Rank 3 - case 10399: spell_id = 36759; break; // Rank 4 - case 16314: spell_id = 36763; break; // Rank 5 - case 16315: spell_id = 36766; break; // Rank 6 - case 16316: spell_id = 36771; break; // Rank 7 - case 25479: spell_id = 36775; break; // Rank 8 - case 25485: spell_id = 36499; break; // Rank 9 - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id); - return; - } - - SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id ); - - if(!spellInfo) - { - sLog.outError("WORLD: unknown spell id %i\n", spell_id); - return; - } - - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i) - { - if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i))) - { - if(item->IsFitToSpellRequirements(m_spellInfo)) - { - Spell *spell = new Spell(m_caster, spellInfo, true); - - // enchanting spell selected by calculated damage-per-sec in enchanting effect - // at calculation applied affect from Elemental Weapons talent - // real enchantment damage-1 - spell->m_currentBasePoints[1] = damage-1; - - SpellCastTargets targets; - targets.setItemTarget( item ); - spell->prepare(&targets); - } - } - } - return; - } - - if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect - { - if(!unitTarget || unitTarget->getPowerType() != POWER_MANA) - return; - - // Regenerate 6% of Total Mana Every 3 secs - int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100; - m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID); - return; - } - - break; - } - - // pet auras - if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id)) - { - m_caster->AddPetAura(petSpell); - return; - } -} - -void Spell::EffectTriggerSpellWithValue(uint32 i) -{ - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); - - if(!spellInfo) - { - sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id); - return; - } - - int32 bp = damage; - m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID); -} - -void Spell::EffectTriggerRitualOfSummoning(uint32 i) -{ - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); - - if(!spellInfo) - { - sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); - return; - } - - finish(); - Spell *spell = new Spell(m_caster, spellInfo, true); - - SpellCastTargets targets; - targets.setUnitTarget( unitTarget); - spell->prepare(&targets); - - m_caster->SetCurrentCastedSpell(spell); - spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]); - -} - -void Spell::EffectForceCast(uint32 i) -{ - if( !unitTarget ) - return; - - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); - - if(!spellInfo) - { - sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); - return; - } - - unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID); -} - -void Spell::EffectTriggerSpell(uint32 i) -{ - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - - // special cases - switch(triggered_spell_id) - { - // Vanish - case 18461: - { - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED); - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED); - - // if this spell is given to NPC it must handle rest by it's own AI - if ( m_caster->GetTypeId() != TYPEID_PLAYER ) - return; - - // get highest rank of the Stealth spell - uint32 spellId = 0; - const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - // only highest rank is shown in spell book, so simply check if shown in spell book - if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED) - continue; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (!spellInfo) - continue; - - if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH) - { - spellId = spellInfo->Id; - break; - } - } - - // no Stealth spell found - if (!spellId) - return; - - // reset cooldown on it if needed - if(((Player*)m_caster)->HasSpellCooldown(spellId)) - ((Player*)m_caster)->RemoveSpellCooldown(spellId); - - m_caster->CastSpell(m_caster, spellId, true); - return; - } - // just skip - case 23770: // Sayge's Dark Fortune of * - // not exist, common cooldown can be implemented in scripts if need. - return; - // Brittle Armor - (need add max stack of 24575 Brittle Armor) - case 29284: - { - const SpellEntry *spell = sSpellStore.LookupEntry(24575); - if (!spell) - return; - - for (int i=0; i < spell->StackAmount; ++i) - m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID); - return; - } - // Mercurial Shield - (need add max stack of 26464 Mercurial Shield) - case 29286: - { - const SpellEntry *spell = sSpellStore.LookupEntry(26464); - if (!spell) - return; - - for (int i=0; i < spell->StackAmount; ++i) - m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID); - return; - } - // Righteous Defense - case 31980: - { - m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID); - return; - } - // Cloak of Shadows - case 35729 : - { - Unit::AuraMap& Auras = m_caster->GetAuras(); - for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter) - { - // remove all harmful spells on you... - if( // ignore positive and passive auras - !iter->second->IsPositive() && !iter->second->IsPassive() && - // ignore physical auras - (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 && - // ignore immunity persistent spells - !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) ) - { - m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id); - iter = Auras.begin(); - } - } - return; - } - // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet - case 41967: - { - if (Unit *pet = m_caster->GetPet()) - pet->CastSpell(pet, 28305, true); - return; - } - } - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); - - if(!spellInfo) - { - sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); - return; - } - - // some triggered spells require specific equipment - if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER) - { - // main hand weapon required - if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND) - { - Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK); - - // skip spell if no weapon in slot or broken - if(!item || item->IsBroken() ) - return; - - // skip spell if weapon not fit to triggered spell - if(!item->IsFitToSpellRequirements(spellInfo)) - return; - } - - // offhand hand weapon required - if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND) - { - Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK); - - // skip spell if no weapon in slot or broken - if(!item || item->IsBroken() ) - return; - - // skip spell if weapon not fit to triggered spell - if(!item->IsFitToSpellRequirements(spellInfo)) - return; - } - } - - // some triggered spells must be casted instantly (for example, if next effect case instant kill caster) - bool instant = false; - for(uint32 j = i+1; j < 3; ++j) - { - if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF) - { - instant = true; - break; - } - } - - if(instant) - { - if (unitTarget) - m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID); - } - else - m_TriggerSpells.push_back(spellInfo); -} - -void Spell::EffectTriggerMissileSpell(uint32 effect_idx) -{ - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx]; - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); - - if(!spellInfo) - { - sLog.outError("EffectTriggerMissileSpell of spell %u: triggering unknown spell id %effect_idx", m_spellInfo->Id,triggered_spell_id); - return; - } - - if (m_CastItem) - DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); - - Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID ); - - SpellCastTargets targets; - targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ); - spell->m_CastItem = m_CastItem; - spell->prepare(&targets, NULL); -} - -void Spell::EffectTeleportUnits(uint32 i) -{ - if(!unitTarget || unitTarget->isInFlight()) - return; - - switch (m_spellInfo->EffectImplicitTargetB[i]) - { - case TARGET_INNKEEPER_COORDINATES: - { - // Only players can teleport to innkeeper - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - ((Player*)unitTarget)->TeleportTo(((Player*)unitTarget)->m_homebindMapId,((Player*)unitTarget)->m_homebindX,((Player*)unitTarget)->m_homebindY,((Player*)unitTarget)->m_homebindZ,unitTarget->GetOrientation(),unitTarget==m_caster ? TELE_TO_SPELL : 0); - return; - } - case TARGET_TABLE_X_Y_Z_COORDINATES: - { - // TODO: Only players can teleport? - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); - if(!st) - { - sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id ); - return; - } - ((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0); - break; - } - case TARGET_BEHIND_VICTIM: - { - // Get selected target for player (or victim for units) - Unit *pTarget = NULL; - if(m_caster->GetTypeId() == TYPEID_PLAYER) - pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); - else - pTarget = m_caster->getVictim(); - // No target present - return - if (!pTarget) - return; - // Init dest coordinates - uint32 mapid = m_caster->GetMapId(); - float x = m_targets.m_destX; - float y = m_targets.m_destY; - float z = m_targets.m_destZ; - float orientation = pTarget->GetOrientation(); - // Teleport - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - { - MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation); - WorldPacket data; - unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation); - unitTarget->SendMessageToSet(&data, false); - } - return; - } - default: - { - // If not exist data for dest location - return - if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) - { - sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id ); - return; - } - // Init dest coordinates - uint32 mapid = m_caster->GetMapId(); - float x = m_targets.m_destX; - float y = m_targets.m_destY; - float z = m_targets.m_destZ; - float orientation = unitTarget->GetOrientation(); - // Teleport - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - { - MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation); - WorldPacket data; - unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation); - unitTarget->SendMessageToSet(&data, false); - } - return; - } - } - - // post effects for TARGET_TABLE_X_Y_Z_COORDINATES - switch ( m_spellInfo->Id ) - { - // Dimensional Ripper - Everlook - case 23442: - { - int32 r = irand(0, 119); - if ( r >= 70 ) // 7/12 success - { - if ( r < 100 ) // 4/12 evil twin - m_caster->CastSpell(m_caster,23445,true); - else // 1/12 fire - m_caster->CastSpell(m_caster,23449,true); - } - return; - } - // Ultrasafe Transporter: Toshley's Station - case 36941: - { - if ( roll_chance_i(50) ) // 50% success - { - int32 rand_eff = urand(1,7); - switch ( rand_eff ) - { - case 1: - // soul split - evil - m_caster->CastSpell(m_caster,36900,true); - break; - case 2: - // soul split - good - m_caster->CastSpell(m_caster,36901,true); - break; - case 3: - // Increase the size - m_caster->CastSpell(m_caster,36895,true); - break; - case 4: - // Decrease the size - m_caster->CastSpell(m_caster,36893,true); - break; - case 5: - // Transform - { - if (((Player*)m_caster)->GetTeam() == ALLIANCE ) - m_caster->CastSpell(m_caster,36897,true); - else - m_caster->CastSpell(m_caster,36899,true); - break; - } - case 6: - // chicken - m_caster->CastSpell(m_caster,36940,true); - break; - case 7: - // evil twin - m_caster->CastSpell(m_caster,23445,true); - break; - } - } - return; - } - // Dimensional Ripper - Area 52 - case 36890: - { - if ( roll_chance_i(50) ) // 50% success - { - int32 rand_eff = urand(1,4); - switch ( rand_eff ) - { - case 1: - // soul split - evil - m_caster->CastSpell(m_caster,36900,true); - break; - case 2: - // soul split - good - m_caster->CastSpell(m_caster,36901,true); - break; - case 3: - // Increase the size - m_caster->CastSpell(m_caster,36895,true); - break; - case 4: - // Transform - { - if (((Player*)m_caster)->GetTeam() == ALLIANCE ) - m_caster->CastSpell(m_caster,36897,true); - else - m_caster->CastSpell(m_caster,36899,true); - break; - } - } - } - return; - } - } -} - -void Spell::EffectApplyAura(uint32 i) -{ - if(!unitTarget) - return; - - SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE]; - for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr) - if(itr->type == m_spellInfo->EffectApplyAuraName[i]) - return; - - // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load) - if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 && - (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) ) - return; - - Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster; - if(!caster) - return; - - sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]); - - Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem); - - // Now Reduce spell duration using data received at spell hit - int32 duration = Aur->GetAuraMaxDuration(); - unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel); - Aur->setDiminishGroup(m_diminishGroup); - - // if Aura removed and deleted, do not continue. - if(duration== 0 && !(Aur->IsPermanent())) - { - delete Aur; - return; - } - - if(duration != Aur->GetAuraMaxDuration()) - { - Aur->SetAuraMaxDuration(duration); - Aur->SetAuraDuration(duration); - } - - bool added = unitTarget->AddAura(Aur); - - // Aura not added and deleted in AddAura call; - if (!added) - return; - - // found crash at character loading, broken pointer to Aur... - // Aur was deleted in AddAura()... - if(!Aur) - return; - - // TODO Make a way so it works for every related spell! - if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players - { - uint32 spellId = 0; - if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL) - spellId = 6788; // Weakened Soul - else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE) - spellId = 25771; // Forbearance - else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA) - spellId = 41425; // Hypothermia - else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages - spellId = 11196; // Recently Bandaged - else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) ) - spellId = 23230; // Blood Fury - Healing Reduction - - SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId); - if (AdditionalSpellInfo) - { - // applied at target by target - Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0); - unitTarget->AddAura(AdditionalAura); - sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]); - } - } - - // Prayer of Mending (jump animation), we need formal caster instead original for correct animation - if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL)) - m_caster->CastSpell(unitTarget,41637,true,NULL,Aur); -} - -void Spell::EffectUnlearnSpecialization( uint32 i ) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)unitTarget; - uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i]; - - _player->removeSpell(spellToUnlearn); - - sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() ); -} - -void Spell::EffectPowerDrain(uint32 i) -{ - if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return; - - Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]); - - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - if(unitTarget->getPowerType() != drain_power) - return; - if(damage < 0) - return; - - uint32 curPower = unitTarget->GetPower(drain_power); - - //add spell damage bonus - damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE); - - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - uint32 power = damage; - if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER ) - power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power); - - int32 new_damage; - if(curPower < power) - new_damage = curPower; - else - new_damage = power; - - unitTarget->ModifyPower(drain_power,-new_damage); - - if(drain_power == POWER_MANA) - { - float manaMultiplier = m_spellInfo->EffectMultipleValue[i]; - if(manaMultiplier==0) - manaMultiplier = 1; - - if(Player *modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier); - - int32 gain = int32(new_damage*manaMultiplier); - - m_caster->ModifyPower(POWER_MANA,gain); - //send log - m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA,false); - } -} - -void Spell::EffectSendEvent(uint32 EffectIndex) -{ - if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround()) - { - BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); - if(bg && bg->GetStatus() == STATUS_IN_PROGRESS) - { - switch(m_spellInfo->Id) - { - case 23333: // Pickup Horde Flag - /*do not uncomment . - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - sLog.outDebug("Send Event Horde Flag Picked Up"); - break; - /* not used : - case 23334: // Drop Horde Flag - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerDroppedFlag((Player*)m_caster); - sLog.outDebug("Drop Horde Flag"); - break; - */ - case 23335: // Pickup Alliance Flag - /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - sLog.outDebug("Send Event Alliance Flag Picked Up"); - break; - /* not used : - case 23336: // Drop Alliance Flag - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerDroppedFlag((Player*)m_caster); - sLog.outDebug("Drop Alliance Flag"); - break; - case 23385: // Alliance Flag Returns - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - sLog.outDebug("Alliance Flag Returned"); - break; - case 23386: // Horde Flag Returns - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - sLog.outDebug("Horde Flag Returned"); - break;*/ - case 34976: - /* - if(bg->GetTypeID()==BATTLEGROUND_EY) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - */ - break; - default: - sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id); - break; - } - } - } - sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id); - sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject); -} - -void Spell::EffectPowerBurn(uint32 i) -{ - if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return; - - Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]); - - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - if(unitTarget->getPowerType()!=powertype) - return; - if(damage < 0) - return; - - int32 curPower = int32(unitTarget->GetPower(powertype)); - - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - uint32 power = damage; - if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER ) - power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power); - - int32 new_damage = (curPower < power) ? curPower : power; - - unitTarget->ModifyPower(powertype,-new_damage); - float multiplier = m_spellInfo->EffectMultipleValue[i]; - - if(Player *modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); - - new_damage = int32(new_damage*multiplier); - m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true); -} - -void Spell::EffectHeal( uint32 /*i*/ ) -{ - if( unitTarget && unitTarget->isAlive() && damage >= 0) - { - // Try to get original caster - Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; - - // Skip if m_originalCaster not available - if (!caster) - return; - - int32 addhealth = damage; - - // Vessel of the Naaru (Vial of the Sunwell trinket) - if (m_spellInfo->Id == 45064) - { - // Amount of heal - depends from stacked Holy Energy - int damageAmount = 0; - Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) - if((*i)->GetId() == 45062) - damageAmount+=(*i)->GetModifier()->m_amount; - if (damageAmount) - m_caster->RemoveAurasDueToSpell(45062); - - addhealth += damageAmount; - } - // Swiftmend - consumes Regrowth or Rejuvenation - else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND)) - { - Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); - // find most short by duration - Aura *targetAura = NULL; - for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) - { - if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID - && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) ) - { - if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration()) - targetAura = *i; - } - } - - if(!targetAura) - { - sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID()); - return; - } - int idx = 0; - while(idx < 3) - { - if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL) - break; - idx++; - } - - int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget); - int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx]; - unitTarget->RemoveAurasDueToSpell(targetAura->GetId()); - - addhealth += tickheal * tickcount; - } - else - addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget); - - bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType); - if (crit) - addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget); - caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit); - - int32 gain = unitTarget->ModifyHealth( int32(addhealth) ); - unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); - - if(caster->GetTypeId()==TYPEID_PLAYER) - if(BattleGround *bg = ((Player*)caster)->GetBattleGround()) - bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain); - - // ignore item heals - if(m_CastItem) - return; - - uint32 procHealer = PROC_FLAG_HEAL; - if (crit) - procHealer |= PROC_FLAG_CRIT_HEAL; - - m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell); - } -} - -void Spell::EffectHealPct( uint32 /*i*/ ) -{ - if( unitTarget && unitTarget->isAlive() && damage >= 0) - { - // Try to get original caster - Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; - - // Skip if m_originalCaster not available - if (!caster) - return; - - uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100; - caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false); - - int32 gain = unitTarget->ModifyHealth( int32(addhealth) ); - unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); - - if(caster->GetTypeId()==TYPEID_PLAYER) - if(BattleGround *bg = ((Player*)caster)->GetBattleGround()) - bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain); - } -} - -void Spell::EffectHealMechanical( uint32 /*i*/ ) -{ - // Mechanic creature type should be correctly checked by targetCreatureType field - if( unitTarget && unitTarget->isAlive() && damage >= 0) - { - // Try to get original caster - Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; - - // Skip if m_originalCaster not available - if (!caster) - return; - - uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget); - caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false); - unitTarget->ModifyHealth( int32(damage) ); - } -} - -void Spell::EffectHealthLeech(uint32 i) -{ - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - - if(damage < 0) - return; - - sLog.outDebug("HealthLeech :%i", damage); - - float multiplier = m_spellInfo->EffectMultipleValue[i]; - - if(Player *modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); - - int32 new_damage = int32(damage*multiplier); - uint32 curHealth = unitTarget->GetHealth(); - new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true); - if(curHealth < new_damage) - new_damage = curHealth; - - if(m_caster->isAlive()) - { - new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster); - - m_caster->ModifyHealth(new_damage); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage)); - } -} - -void Spell::DoCreateItem(uint32 i, uint32 itemtype) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player* player = (Player*)unitTarget; - - uint32 newitemid = itemtype; - ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid ); - if(!pProto) - { - player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); - return; - } - - uint32 num_to_add; - - // TODO: maybe all this can be replaced by using correct calculated `damage` value - if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE) - { - int32 basePoints = m_currentBasePoints[i]; - int32 randomPoints = m_spellInfo->EffectDieSides[i]; - if (randomPoints) - num_to_add = basePoints + irand(1, randomPoints); - else - num_to_add = basePoints + 1; - } - else if (pProto->MaxCount == 1) - num_to_add = 1; - else if(player->getLevel() >= m_spellInfo->spellLevel) - { - int32 basePoints = m_currentBasePoints[i]; - float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i]; - num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel); - } - else - num_to_add = 2; - - if (num_to_add < 1) - num_to_add = 1; - if (num_to_add > pProto->Stackable) - num_to_add = pProto->Stackable; - - // init items_count to 1, since 1 item will be created regardless of specialization - int items_count=1; - // the chance to create additional items - float additionalCreateChance=0.0f; - // the maximum number of created additional items - uint8 additionalMaxNum=0; - // get the chance and maximum number for creating extra items - if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) ) - { - // roll with this chance till we roll not to create or we create the max num - while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum ) - ++items_count; - } - - // really will be created more items - num_to_add *= items_count; - - // can the player store the new item? - ItemPosCountVec dest; - uint32 no_space = 0; - uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space ); - if( msg != EQUIP_ERR_OK ) - { - // convert to possible store amount - if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS ) - num_to_add -= no_space; - else - { - // if not created by another reason from full inventory or unique items amount limitation - player->SendEquipError( msg, NULL, NULL ); - return; - } - } - - if(num_to_add) - { - // create the new item and store it - Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid)); - - // was it successful? return error if not - if(!pItem) - { - player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); - return; - } - - // set the "Crafted by ..." property of the item - if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST) - pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow()); - - // send info to the client - if(pItem) - player->SendNewItem(pItem, num_to_add, true, true); - - // we succeeded in creating at least one item, so a levelup is possible - player->UpdateCraftSkill(m_spellInfo->Id); - } - - // for battleground marks send by mail if not add all expected - if(no_space > 0 ) - { - BattleGroundTypeId bgType; - switch(m_spellInfo->Id) - { - case SPELL_AV_MARK_WINNER: - case SPELL_AV_MARK_LOSER: - bgType = BATTLEGROUND_AV; - break; - case SPELL_WS_MARK_WINNER: - case SPELL_WS_MARK_LOSER: - bgType = BATTLEGROUND_WS; - break; - case SPELL_AB_MARK_WINNER: - case SPELL_AB_MARK_LOSER: - bgType = BATTLEGROUND_AB; - break; - default: - return; - } - - if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType)) - bg->SendRewardMarkByMail(player,newitemid,no_space); - } -} - -void Spell::EffectCreateItem(uint32 i) -{ - DoCreateItem(i,m_spellInfo->EffectItemType[i]); -} - -void Spell::EffectPersistentAA(uint32 i) -{ - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius); - - int32 duration = GetSpellDuration(m_spellInfo); - DynamicObject* dynObj = new DynamicObject; - if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius)) - { - delete dynObj; - return; - } - dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65); - dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003); - dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee); - m_caster->AddDynObject(dynObj); - MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj); -} - -void Spell::EffectEnergize(uint32 i) -{ - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - - if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return; - - // Some level depends spells - int multipler = 0; - int level_diff = 0; - switch (m_spellInfo->Id) - { - // Restore Energy - case 9512: - level_diff = m_caster->getLevel() - 40; - multipler = 2; - break; - // Blood Fury - case 24571: - level_diff = m_caster->getLevel() - 60; - multipler = 10; - break; - // Burst of Energy - case 24532: - level_diff = m_caster->getLevel() - 60; - multipler = 4; - break; - default: - break; - } - - if (level_diff > 0) - damage -= multipler * level_diff; - - if(damage < 0) - return; - - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); - - if(unitTarget->GetMaxPower(power) == 0) - return; - - unitTarget->ModifyPower(power,damage); - m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power); - - // Mad Alchemist's Potion - if (m_spellInfo->Id == 45051) - { - // find elixirs on target - uint32 elixir_mask = 0; - Unit::AuraMap& Auras = unitTarget->GetAuras(); - for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr) - { - uint32 spell_id = itr->second->GetId(); - if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id)) - elixir_mask |= mask; - } - - // get available elixir mask any not active type from battle/guardian (and flask if no any) - elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK; - - // get all available elixirs by mask and spell level - std::vector elixirs; - SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap(); - for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr) - { - if (itr->second & elixir_mask) - { - if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK)) - continue; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel())) - continue; - - elixirs.push_back(itr->first); - } - } - - if (!elixirs.empty()) - { - // cast random elixir on target - uint32 rand_spell = urand(0,elixirs.size()-1); - m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem); - } - } -} - -void Spell::EffectEnergisePct(uint32 i) -{ - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - - if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return; - - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); - - uint32 maxPower = unitTarget->GetMaxPower(power); - if(maxPower == 0) - return; - - uint32 gain = damage * maxPower / 100; - unitTarget->ModifyPower(power, gain); - m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power); -} - -void Spell::SendLoot(uint64 guid, LootType loottype) -{ - Player* player = (Player*)m_caster; - if (!player) - return; - - if (gameObjTarget) - { - switch (gameObjTarget->GetGoType()) - { - case GAMEOBJECT_TYPE_DOOR: - case GAMEOBJECT_TYPE_BUTTON: - gameObjTarget->UseDoorOrButton(); - sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); - return; - - case GAMEOBJECT_TYPE_QUESTGIVER: - // start or end quest - player->PrepareQuestMenu(guid); - player->SendPreparedQuest(guid); - return; - - case GAMEOBJECT_TYPE_SPELL_FOCUS: - // triggering linked GO - if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId) - gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); - return; - - case GAMEOBJECT_TYPE_GOOBER: - // goober_scripts can be triggered if the player don't have the quest - if (gameObjTarget->GetGOInfo()->goober.eventId) - { - sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow()); - sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget); - } - - // cast goober spell - if (gameObjTarget->GetGOInfo()->goober.questId) - ///Quest require to be active for GO using - if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE) - return; - - gameObjTarget->AddUniqueUse(player); - gameObjTarget->SetLootState(GO_JUST_DEACTIVATED); - - //TODO? Objective counting called without spell check but with quest objective check - // if send spell id then this line will duplicate to spell casting call (double counting) - // So we or have this line and not required in quest_template have reqSpellIdN - // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases. - player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0); - - // triggering linked GO - if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId) - gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); - - return; - - case GAMEOBJECT_TYPE_CHEST: - // TODO: possible must be moved to loot release (in different from linked triggering) - if (gameObjTarget->GetGOInfo()->chest.eventId) - { - sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow()); - sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget); - } - - // triggering linked GO - if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId) - gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); - - // Don't return, let loots been taken - } - } - - // Send loot - player->SendLoot(guid, loottype); -} - -void Spell::EffectOpenLock(uint32 /*i*/) -{ - if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) - { - sLog.outDebug( "WORLD: Open Lock - No Player Caster!"); - return; - } - - Player* player = (Player*)m_caster; - - LootType loottype = LOOT_CORPSE; - uint32 lockId = 0; - uint64 guid = 0; - - // Get lockId - if(gameObjTarget) - { - GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo(); - // Arathi Basin banner opening ! - if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune || - goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK ) - { - if(BattleGround *bg = player->GetBattleGround())// in battleground - { - if( !player->IsMounted() && // not mounted - !player->HasStealthAura() && // not stealthed - !player->HasInvisibilityAura() && // not invisible - player->isAlive() ) // live player - { - // check if it's correct bg - if(bg && bg->GetTypeID() == BATTLEGROUND_AB) - bg->EventPlayerClickedOnFlag(player, gameObjTarget); - - return; - } - } - } - else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND) - { - if(BattleGround *bg = player->GetBattleGround()) - if(bg->GetTypeID() == BATTLEGROUND_EY) - bg->EventPlayerClickedOnFlag(player, gameObjTarget); - return; - } - lockId = gameObjTarget->GetLockId(); - guid = gameObjTarget->GetGUID(); - } - else if(itemTarget) - { - lockId = itemTarget->GetProto()->LockID; - guid = itemTarget->GetGUID(); - } - else - { - sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!"); - return; - } - - if(!lockId) // possible case for GO and maybe for items. - { - SendLoot(guid, loottype); - return; - } - - // Get LockInfo - LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); - - if (!lockInfo) - { - sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!", - (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId); - SendCastResult(SPELL_FAILED_BAD_TARGETS); - return; - } - - // check key - for(int i = 0; i < 5; ++i) - { - // type==1 This means lockInfo->key[i] is an item - if(lockInfo->keytype[i]==LOCK_KEY_ITEM && lockInfo->key[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[i]) - { - SendLoot(guid, loottype); - return; - } - } - - uint32 SkillId = 0; - // Check and skill-up skill - if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL ) - SkillId = m_spellInfo->EffectMiscValue[1]; - // pickpocketing spells - else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK ) - SkillId = SKILL_LOCKPICKING; - - // skill bonus provided by casting spell (mostly item spells) - uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1); - - uint32 reqSkillValue = lockInfo->requiredminingskill; - - if(lockInfo->requiredlockskill) // required pick lock skill applying - { - if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?) - { - SendCastResult(SPELL_FAILED_FIZZLE); - return; - } - - reqSkillValue = lockInfo->requiredlockskill; - } - else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target - { - SendCastResult(SPELL_FAILED_BAD_TARGETS); - return; - } - - if ( SkillId ) - { - loottype = LOOT_SKINNING; - if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue ) - { - SendCastResult(SPELL_FAILED_LOW_CASTLEVEL); - return; - } - - // update skill if really known - uint32 SkillValue = player->GetPureSkillValue(SkillId); - if(SkillValue) // non only item base skill - { - if(gameObjTarget) - { - // Allow one skill-up until respawned - if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) && - player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) ) - gameObjTarget->AddToSkillupList( player->GetGUIDLow() ); - } - else if(itemTarget) - { - // Do one skill-up - uint32 SkillValue = player->GetPureSkillValue(SkillId); - player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue); - } - } - } - - SendLoot(guid, loottype); -} - -void Spell::EffectSummonChangeItem(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *player = (Player*)m_caster; - - // applied only to using item - if(!m_CastItem) - return; - - // ... only to item in own inventory/bank/equip_slot - if(m_CastItem->GetOwnerGUID()!=player->GetGUID()) - return; - - uint32 newitemid = m_spellInfo->EffectItemType[i]; - if(!newitemid) - return; - - uint16 pos = m_CastItem->GetPos(); - - Item *pNewItem = Item::CreateItem( newitemid, 1, player); - if( !pNewItem ) - return; - - for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i) - { - if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i))) - pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i))); - } - - if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)) - { - double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); - player->DurabilityLoss(pNewItem, loosePercent); - } - - if( player->IsInventoryPos( pos ) ) - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true ); - if( msg == EQUIP_ERR_OK ) - { - player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true); - - // prevent crash at access and unexpected charges counting with item update queue corrupt - if(m_CastItem==m_targets.getItemTarget()) - m_targets.setItemTarget(NULL); - - m_CastItem = NULL; - - player->StoreItem( dest, pNewItem, true); - return; - } - } - else if( player->IsBankPos ( pos ) ) - { - ItemPosCountVec dest; - uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true ); - if( msg == EQUIP_ERR_OK ) - { - player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true); - - // prevent crash at access and unexpected charges counting with item update queue corrupt - if(m_CastItem==m_targets.getItemTarget()) - m_targets.setItemTarget(NULL); - - m_CastItem = NULL; - - player->BankItem( dest, pNewItem, true); - return; - } - } - else if( player->IsEquipmentPos ( pos ) ) - { - uint16 dest; - uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true ); - if( msg == EQUIP_ERR_OK ) - { - player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true); - - // prevent crash at access and unexpected charges counting with item update queue corrupt - if(m_CastItem==m_targets.getItemTarget()) - m_targets.setItemTarget(NULL); - - m_CastItem = NULL; - - player->EquipItem( dest, pNewItem, true); - player->AutoUnequipOffhandIfNeed(); - return; - } - } - - // fail - delete pNewItem; -} - -void Spell::EffectOpenSecretSafe(uint32 i) -{ - EffectOpenLock(i); //no difference for now -} - -void Spell::EffectProficiency(uint32 /*i*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - Player *p_target = (Player*)unitTarget; - - uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask; - if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask)) - { - p_target->AddWeaponProficiency(subClassMask); - p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency()); - } - if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask)) - { - p_target->AddArmorProficiency(subClassMask); - p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency()); - } -} - -void Spell::EffectApplyAreaAura(uint32 i) -{ - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - - AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem); - unitTarget->AddAura(Aur); -} - -void Spell::EffectSummonType(uint32 i) -{ - switch(m_spellInfo->EffectMiscValueB[i]) - { - case SUMMON_TYPE_GUARDIAN: - case SUMMON_TYPE_POSESSED: - case SUMMON_TYPE_POSESSED2: - EffectSummonGuardian(i); - break; - case SUMMON_TYPE_WILD: - EffectSummonWild(i); - break; - case SUMMON_TYPE_DEMON: - EffectSummonDemon(i); - break; - case SUMMON_TYPE_SUMMON: - EffectSummon(i); - break; - case SUMMON_TYPE_CRITTER: - case SUMMON_TYPE_CRITTER2: - EffectSummonCritter(i); - break; - case SUMMON_TYPE_TOTEM_SLOT1: - case SUMMON_TYPE_TOTEM_SLOT2: - case SUMMON_TYPE_TOTEM_SLOT3: - case SUMMON_TYPE_TOTEM_SLOT4: - case SUMMON_TYPE_TOTEM: - EffectSummonTotem(i); - break; - case SUMMON_TYPE_UNKNOWN1: - case SUMMON_TYPE_UNKNOWN2: - case SUMMON_TYPE_UNKNOWN3: - case SUMMON_TYPE_UNKNOWN4: - case SUMMON_TYPE_UNKNOWN5: - case SUMMON_TYPE_UNKNOWN6: - break; - default: - sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]); - break; - } -} - -void Spell::EffectSummon(uint32 i) -{ - if(m_caster->GetPetGUID()) - return; - - if(!unitTarget) - return; - uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; - if(!pet_entry) - return; - uint32 level = m_caster->getLevel(); - Pet* spawnCreature = new Pet(SUMMON_PET); - - if(spawnCreature->LoadPetFromDB(m_caster,pet_entry)) - { - // set timer for unsummon - int32 duration = GetSpellDuration(m_spellInfo); - if(duration > 0) - spawnCreature->SetDuration(duration); - - return; - } - - Map *map = m_caster->GetMap(); - uint32 pet_number = objmgr.GeneratePetNumber(); - if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number)) - { - sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]); - delete spawnCreature; - return; - } - - // Summon in dest location - float x,y,z; - if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - } - else - m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize()); - - spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation()); - - if(!spawnCreature->IsPositionValid()) - { - sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY()); - delete spawnCreature; - return; - } - - // set timer for unsummon - int32 duration = GetSpellDuration(m_spellInfo); - if(duration > 0) - spawnCreature->SetDuration(duration); - - spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); - spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0); - spawnCreature->setPowerType(POWER_MANA); - spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); - spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0,2048); - spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000); - spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); - spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - spawnCreature->InitStatsForLevel(level); - - spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false); - - spawnCreature->AIM_Initialize(); - spawnCreature->InitPetCreateSpells(); - spawnCreature->SetHealth(spawnCreature->GetMaxHealth()); - spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA)); - - std::string name = m_caster->GetName(); - name.append(petTypeSuffix[spawnCreature->getPetType()]); - spawnCreature->SetName( name ); - - map->Add((Creature*)spawnCreature); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - m_caster->SetPet(spawnCreature); - spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE ); - spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT); - ((Player*)m_caster)->PetSpellInitialize(); - } -} - -void Spell::EffectLearnSpell(uint32 i) -{ - if(!unitTarget) - return; - - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - { - if(m_caster->GetTypeId() == TYPEID_PLAYER) - EffectLearnPetSpell(i); - - return; - } - - Player *player = (Player*)unitTarget; - - uint32 spellToLearn = (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) ? damage : m_spellInfo->EffectTriggerSpell[i]; - player->learnSpell(spellToLearn); - - sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() ); -} - -void Spell::EffectDispel(uint32 i) -{ - if(!unitTarget) - return; - - // Fill possible dispell list - std::vector dispel_list; - - // Create dispel mask by dispel type - uint32 dispel_type = m_spellInfo->EffectMiscValue[i]; - uint32 dispelMask = GetDispellMask( DispelType(dispel_type) ); - Unit::AuraMap const& auras = unitTarget->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - Aura *aur = (*itr).second; - if (aur && (1<GetSpellProto()->Dispel) & dispelMask) - { - if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC) - { - bool positive = true; - if (!aur->IsPositive()) - positive = false; - else - positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0; - - // do not remove positive auras if friendly target - // negative auras if non-friendly target - if(positive == unitTarget->IsFriendlyTo(m_caster)) - continue; - } - // Add aura to dispel list - dispel_list.push_back(aur); - } - } - // Ok if exist some buffs for dispel try dispel it - if (!dispel_list.empty()) - { - std::list < std::pair > success_list;// (spell_id,casterGuid) - std::list < uint32 > fail_list; // spell_id - int32 list_size = dispel_list.size(); - // Dispell N = damage buffs (or while exist buffs for dispel) - for (int32 count=0; count < damage && list_size > 0; ++count) - { - // Random select buff for dispel - Aura *aur = dispel_list[urand(0, list_size-1)]; - - SpellEntry const* spellInfo = aur->GetSpellProto(); - // Base dispel chance - // TODO: possible chance depend from spell level?? - int32 miss_chance = 0; - // Apply dispel mod from aura caster - if (Unit *caster = aur->GetCaster()) - { - if ( Player* modOwner = caster->GetSpellModOwner() ) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this); - } - // Try dispel - if (roll_chance_i(miss_chance)) - fail_list.push_back(aur->GetId()); - else - success_list.push_back(std::pair(aur->GetId(),aur->GetCasterGUID())); - // Remove buff from list for prevent doubles - for (std::vector::iterator j = dispel_list.begin(); j != dispel_list.end(); ) - { - Aura *dispeled = *j; - if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID()) - { - j = dispel_list.erase(j); - --list_size; - } - else - ++j; - } - } - // Send success log and really remove auras - if (!success_list.empty()) - { - int32 count = success_list.size(); - WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5); - data.append(unitTarget->GetPackGUID()); // Victim GUID - data.append(m_caster->GetPackGUID()); // Caster GUID - data << uint32(m_spellInfo->Id); // Dispell spell id - data << uint8(0); // not used - data << uint32(count); // count - for (std::list >::iterator j = success_list.begin(); j != success_list.end(); ++j) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first); - data << uint32(spellInfo->Id); // Spell Id - data << uint8(0); // 0 - dispeled !=0 cleansed - unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster); - } - m_caster->SendMessageToSet(&data, true); - - // On succes dispel - // Devour Magic - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12) - { - uint32 heal_spell = 0; - switch (m_spellInfo->Id) - { - case 19505: heal_spell = 19658; break; - case 19731: heal_spell = 19732; break; - case 19734: heal_spell = 19733; break; - case 19736: heal_spell = 19735; break; - case 27276: heal_spell = 27278; break; - case 27277: heal_spell = 27279; break; - default: - sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id); - break; - } - if (heal_spell) - m_caster->CastSpell(m_caster, heal_spell, true); - } - } - // Send fail log to client - if (!fail_list.empty()) - { - // Failed to dispell - WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size()); - data << uint64(m_caster->GetGUID()); // Caster GUID - data << uint64(unitTarget->GetGUID()); // Victim GUID - data << uint32(m_spellInfo->Id); // Dispell spell id - for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j) - data << uint32(*j); // Spell Id - m_caster->SendMessageToSet(&data, true); - } - } -} - -void Spell::EffectDualWield(uint32 /*i*/) -{ - if (unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->SetCanDualWield(true); -} - -void Spell::EffectPull(uint32 /*i*/) -{ - // TODO: create a proper pull towards distract spell center for distract - sLog.outDebug("WORLD: Spell Effect DUMMY"); -} - -void Spell::EffectDistract(uint32 /*i*/) -{ - // Check for possible target - if (!unitTarget || unitTarget->isInCombat()) - return; - - // target must be OK to do this - if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNDED | UNIT_STAT_FLEEING ) ) - return; - - float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY); - - if ( unitTarget->GetTypeId() == TYPEID_PLAYER ) - { - // For players just turn them - WorldPacket data; - ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle); - ((Player*)unitTarget)->GetSession()->SendPacket( &data ); - ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false); - } - else - { - // Set creature Distracted, Stop it, And turn it - unitTarget->SetOrientation(angle); - unitTarget->StopMoving(); - unitTarget->GetMotionMaster()->MoveDistract(damage*1000); - } -} - -void Spell::EffectPickPocket(uint32 /*i*/) -{ - if( m_caster->GetTypeId() != TYPEID_PLAYER ) - return; - - // victim must be creature and attackable - if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) ) - return; - - // victim have to be alive and humanoid or undead - if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0) - { - int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel()); - - if (chance > irand(0, 19)) - { - // Stealing successful - //sLog.outDebug("Sending loot from pickpocket"); - ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING); - } - else - { - // Reveal action + get attack - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - if (((Creature*)unitTarget)->AI()) - ((Creature*)unitTarget)->AI()->AttackStart(m_caster); - } - } -} - -void Spell::EffectAddFarsight(uint32 i) -{ - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - int32 duration = GetSpellDuration(m_spellInfo); - DynamicObject* dynObj = new DynamicObject; - if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius)) - { - delete dynObj; - return; - } - dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65); - dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); - m_caster->AddDynObject(dynObj); - MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj); - m_caster->SetUInt64Value(PLAYER_FARSIGHT, dynObj->GetGUID()); -} - -void Spell::EffectSummonWild(uint32 i) -{ - uint32 creature_entry = m_spellInfo->EffectMiscValue[i]; - if(!creature_entry) - return; - - uint32 level = m_caster->getLevel(); - - // level of creature summoned using engineering item based at engineering skill level - if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem) - { - ItemPrototype const *proto = m_CastItem->GetProto(); - if(proto && proto->RequiredSkill == SKILL_ENGINERING) - { - uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING); - if(skill202) - { - level = skill202/5; - } - } - } - - // select center of summon position - float center_x = m_targets.m_destX; - float center_y = m_targets.m_destY; - float center_z = m_targets.m_destZ; - - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - int32 amount = damage > 0 ? damage : 1; - - for(int32 count = 0; count < amount; ++count) - { - float px, py, pz; - // If dest location if present - if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - // Summon 1 unit in dest location - if (count == 0) - { - px = m_targets.m_destX; - py = m_targets.m_destY; - pz = m_targets.m_destZ; - } - // Summon in random point all other units if location present - else - m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz); - } - // Summon if dest location not present near caster - else - m_caster->GetClosePoint(px,py,pz,3.0f); - - int32 duration = GetSpellDuration(m_spellInfo); - - TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN; - - m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration); - } -} - -void Spell::EffectSummonGuardian(uint32 i) -{ - uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; - if(!pet_entry) - return; - - // Jewelery statue case (totem like) - if(m_spellInfo->SpellIconID==2056) - { - EffectSummonTotem(i); - return; - } - - // set timer for unsummon - int32 duration = GetSpellDuration(m_spellInfo); - - // Search old Guardian only for players (if casted spell not have duration or cooldown) - // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time - // so this code hack in fact - if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) ) - if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry)) - return; // find old guardian, ignore summon - - // in another case summon new - uint32 level = m_caster->getLevel(); - - // level of pet summoned using engineering item based at engineering skill level - if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem) - { - ItemPrototype const *proto = m_CastItem->GetProto(); - if(proto && proto->RequiredSkill == SKILL_ENGINERING) - { - uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING); - if(skill202) - { - level = skill202/5; - } - } - } - - // select center of summon position - float center_x = m_targets.m_destX; - float center_y = m_targets.m_destY; - float center_z = m_targets.m_destZ; - - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - int32 amount = damage > 0 ? damage : 1; - - for(int32 count = 0; count < amount; ++count) - { - Pet* spawnCreature = new Pet(GUARDIAN_PET); - - Map *map = m_caster->GetMap(); - uint32 pet_number = objmgr.GeneratePetNumber(); - if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number)) - { - sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]); - delete spawnCreature; - return; - } - - float px, py, pz; - // If dest location if present - if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - // Summon 1 unit in dest location - if (count == 0) - { - px = m_targets.m_destX; - py = m_targets.m_destY; - pz = m_targets.m_destZ; - } - // Summon in random point all other units if location present - else - m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz); - } - // Summon if dest location not present near caster - else - m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize()); - - spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation()); - - if(!spawnCreature->IsPositionValid()) - { - sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY()); - delete spawnCreature; - return; - } - - if(duration > 0) - spawnCreature->SetDuration(duration); - - spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); - spawnCreature->setPowerType(POWER_MANA); - spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0); - spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); - spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0); - spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); - spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - spawnCreature->InitStatsForLevel(level); - spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false); - - spawnCreature->AIM_Initialize(); - - if(m_caster->GetTypeId()==TYPEID_PLAYER) - ((Player*)m_caster)->AddGuardian(spawnCreature); - - map->Add((Creature*)spawnCreature); - } -} - -void Spell::EffectTeleUnitsFaceCaster(uint32 i) -{ - if(!unitTarget) - return; - - if(unitTarget->isInFlight()) - return; - - uint32 mapid = m_caster->GetMapId(); - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - float fx,fy,fz; - m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); - - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation()); -} - -void Spell::EffectLearnSkill(uint32 i) -{ - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if(damage < 0) - return; - - uint32 skillid = m_spellInfo->EffectMiscValue[i]; - uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid); - ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75); -} - -void Spell::EffectAddHonor(uint32 /*i*/) -{ - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, this->damage, ((Player*)unitTarget)->GetGUIDLow()); - - // TODO: find formula for honor reward based on player's level! - - // now fixed only for level 70 players: - if (((Player*)unitTarget)->getLevel() == 70) - ((Player*)unitTarget)->RewardHonor(NULL, 1, this->damage); -} - -void Spell::EffectTradeSkill(uint32 /*i*/) -{ - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - // uint32 skillid = m_spellInfo->EffectMiscValue[i]; - // uint16 skillmax = ((Player*)unitTarget)->(skillid); - // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75); -} - -void Spell::EffectEnchantItemPerm(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - if (!itemTarget) - return; - - Player* p_caster = (Player*)m_caster; - - p_caster->UpdateCraftSkill(m_spellInfo->Id); - - if (m_spellInfo->EffectMiscValue[i]) - { - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) - return; - - // item can be in trade slot and have owner diff. from caster - Player* item_owner = itemTarget->GetOwner(); - if(!item_owner) - return; - - if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) - sLog.outCommand("GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)", - p_caster->GetName(),p_caster->GetSession()->GetAccountId(), - itemTarget->GetProto()->Name1,itemTarget->GetEntry(), - item_owner->GetName(),item_owner->GetSession()->GetAccountId()); - - // remove old enchanting before applying new if equipped - item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false); - - itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0); - - // add new enchanting if equipped - item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true); - } -} - -void Spell::EffectEnchantItemTmp(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* p_caster = (Player*)m_caster; - - if(!itemTarget) - return; - - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - - // Shaman Rockbiter Weapon - if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY) - { - int32 enchnting_damage = m_currentBasePoints[1]+1; - - // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value - // with already applied percent bonus from Elemental Weapons talent - // Note: damage calculated (correctly) with rounding int32(float(v)) but - // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime - switch(enchnting_damage) - { - // Rank 1 - case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2] - // Rank 2 - case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4] - case 5: enchant_id = 3025; break; // 20% - // Rank 3 - case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6] - case 7: enchant_id = 3027; break; // 20% - // Rank 4 - case 9: enchant_id = 3032; break; // 0% [ 7% == 6] - case 10: enchant_id = 503; break; // 14% - case 11: enchant_id = 3031; break; // 20% - // Rank 5 - case 15: enchant_id = 3035; break; // 0% - case 16: enchant_id = 1663; break; // 7% - case 17: enchant_id = 3033; break; // 14% - case 18: enchant_id = 3034; break; // 20% - // Rank 6 - case 28: enchant_id = 3038; break; // 0% - case 29: enchant_id = 683; break; // 7% - case 31: enchant_id = 3036; break; // 14% - case 33: enchant_id = 3037; break; // 20% - // Rank 7 - case 40: enchant_id = 3041; break; // 0% - case 42: enchant_id = 1664; break; // 7% - case 45: enchant_id = 3039; break; // 14% - case 48: enchant_id = 3040; break; // 20% - // Rank 8 - case 49: enchant_id = 3044; break; // 0% - case 52: enchant_id = 2632; break; // 7% - case 55: enchant_id = 3042; break; // 14% - case 58: enchant_id = 3043; break; // 20% - // Rank 9 - case 62: enchant_id = 2633; break; // 0% - case 66: enchant_id = 3018; break; // 7% - case 70: enchant_id = 3019; break; // 14% - case 74: enchant_id = 3020; break; // 20% - default: - sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage); - return; - } - } - - if (!enchant_id) - { - sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i); - return; - } - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) - { - sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id); - return; - } - - // select enchantment duration - uint32 duration; - - // rogue family enchantments exception by duration - if(m_spellInfo->Id==38615) - duration = 1800; // 30 mins - // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints) - else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE) - duration = 3600; // 1 hour - // shaman family enchantments - else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN) - duration = 1800; // 30 mins - // other cases with this SpellVisual already selected - else if(m_spellInfo->SpellVisual==215) - duration = 1800; // 30 mins - // some fishing pole bonuses - else if(m_spellInfo->SpellVisual==563) - duration = 600; // 10 mins - // shaman rockbiter enchantments - else if(m_spellInfo->SpellVisual==0) - duration = 1800; // 30 mins - else if(m_spellInfo->Id==29702) - duration = 300; // 5 mins - else if(m_spellInfo->Id==37360) - duration = 300; // 5 mins - // default case - else - duration = 3600; // 1 hour - - // item can be in trade slot and have owner diff. from caster - Player* item_owner = itemTarget->GetOwner(); - if(!item_owner) - return; - - if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) - sLog.outCommand("GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)", - p_caster->GetName(),p_caster->GetSession()->GetAccountId(), - itemTarget->GetProto()->Name1,itemTarget->GetEntry(), - item_owner->GetName(),item_owner->GetSession()->GetAccountId()); - - // remove old enchanting before applying new if equipped - item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false); - - itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0); - - // add new enchanting if equipped - item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true); -} - -void Spell::EffectTameCreature(uint32 /*i*/) -{ - if(m_caster->GetPetGUID()) - return; - - if(!unitTarget) - return; - - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - return; - - Creature* creatureTarget = (Creature*)unitTarget; - - if(creatureTarget->isPet()) - return; - - if(m_caster->getClass() == CLASS_HUNTER) - { - // cast finish successfully - //SendChannelUpdate(0); - finish(); - - Pet* pet = new Pet(HUNTER_PET); - - if(!pet->CreateBaseAtCreature(creatureTarget)) - { - delete pet; - return; - } - - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - - pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID()); - pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); - pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); - pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - if(!pet->InitStatsForLevel(creatureTarget->getLevel())) - { - sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted."); - delete pet; - return; - } - - // prepare visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1); - - pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true); - // this enables pet details window (Shift+P) - pet->AIM_Initialize(); - pet->InitPetCreateSpells(); - pet->SetHealth(pet->GetMaxHealth()); - - MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet); - - // visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - m_caster->SetPet(pet); - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - ((Player*)m_caster)->PetSpellInitialize(); - } - } -} - -void Spell::EffectSummonPet(uint32 i) -{ - uint32 petentry = m_spellInfo->EffectMiscValue[i]; - - Pet *OldSummon = m_caster->GetPet(); - - // if pet requested type already exist - if( OldSummon ) - { - if(petentry == 0 || OldSummon->GetEntry() == petentry) - { - // pet in corpse state can't be summoned - if( OldSummon->isDead() ) - return; - - MapManager::Instance().GetMap(OldSummon->GetMapId(), OldSummon)->Remove((Creature*)OldSummon,false); - OldSummon->SetMapId(m_caster->GetMapId()); - - float px, py, pz; - m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize()); - - OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation()); - MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->Add((Creature*)OldSummon); - - if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() ) - { - ((Player*)m_caster)->PetSpellInitialize(); - } - return; - } - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false); - else - return; - } - - Pet* NewSummon = new Pet; - - // petentry==0 for hunter "call pet" (current pet summoned if any) - if(NewSummon->LoadPetFromDB(m_caster,petentry)) - { - if(NewSummon->getPetType()==SUMMON_PET) - { - // Remove Demonic Sacrifice auras (known pet) - Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();) - { - if((*itr)->GetModifier()->m_miscvalue==2228) - { - m_caster->RemoveAurasDueToSpell((*itr)->GetId()); - itr = auraClassScripts.begin(); - } - else - ++itr; - } - } - - return; - } - - // not error in case fail hunter call pet - if(!petentry) - { - delete NewSummon; - return; - } - - CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(petentry); - - if(!cInfo) - { - sLog.outError("EffectSummonPet: creature entry %u not found.",petentry); - delete NewSummon; - return; - } - - Map *map = m_caster->GetMap(); - uint32 pet_number = objmgr.GeneratePetNumber(); - if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number)) - { - delete NewSummon; - return; - } - - float px, py, pz; - m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize()); - - NewSummon->Relocate(px, py, pz, m_caster->GetOrientation()); - - if(!NewSummon->IsPositionValid()) - { - sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY()); - delete NewSummon; - return; - } - - uint32 petlevel = m_caster->getLevel(); - NewSummon->setPetType(SUMMON_PET); - - uint32 faction = m_caster->getFaction(); - if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isTotem()) - { - Unit* owner = ((Totem*)m_caster)->GetOwner(); - if(owner) - faction = owner->getFaction(); - NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE); - } - - NewSummon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID()); - NewSummon->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); - NewSummon->SetUInt32Value(UNIT_NPC_FLAGS , 0); - NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction); - NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0,2048); - NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,time(NULL)); - NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0); - NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000); - NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true); - // this enables pet details window (Shift+P) - - // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later - NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE); - - NewSummon->InitStatsForLevel( petlevel); - NewSummon->InitPetCreateSpells(); - - if(NewSummon->getPetType()==SUMMON_PET) - { - // Remove Demonic Sacrifice auras (new pet) - Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();) - { - if((*itr)->GetModifier()->m_miscvalue==2228) - { - m_caster->RemoveAurasDueToSpell((*itr)->GetId()); - itr = auraClassScripts.begin(); - } - else - ++itr; - } - - // generate new name for summon pet - std::string new_name=objmgr.GeneratePetName(petentry); - if(!new_name.empty()) - NewSummon->SetName(new_name); - } - else if(NewSummon->getPetType()==HUNTER_PET) - NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED); - - NewSummon->AIM_Initialize(); - NewSummon->SetHealth(NewSummon->GetMaxHealth()); - NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA)); - - map->Add((Creature*)NewSummon); - - m_caster->SetPet(NewSummon); - sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow()); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT); - ((Player*)m_caster)->PetSpellInitialize(); - } -} - -void Spell::EffectLearnPetSpell(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)m_caster; - - Pet *pet = _player->GetPet(); - if(!pet) - return; - if(!pet->isAlive()) - return; - - SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); - if(!learn_spellproto) - return; - - pet->SetTP(pet->m_TrainingPoints - pet->GetTPForSpell(learn_spellproto->Id)); - pet->learnSpell(learn_spellproto->Id); - - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - _player->PetSpellInitialize(); -} - -void Spell::EffectTaunt(uint32 /*i*/) -{ - // this effect use before aura Taunt apply for prevent taunt already attacking target - // for spell as marked "non effective at already attacking target" - if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER) - { - if(unitTarget->getVictim()==m_caster) - { - SendCastResult(SPELL_FAILED_DONT_REPORT); - return; - } - } - - // Also use this effect to set the taunter's threat to the taunted creature's highest value - if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim()) - unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat()); -} - -void Spell::EffectWeaponDmg(uint32 i) -{ - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - - // multiple weapon dmg effect workaround - // execute only the last weapon damage - // and handle all effects at once - for (int j = 0; j < 3; j++) - { - switch(m_spellInfo->Effect[j]) - { - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - if (j < i) // we must calculate only at last weapon effect - return; - break; - } - } - - // some spell specific modifiers - bool customBonusDamagePercentMod = false; - float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod - float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set - float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage - bool normalized = false; - - int32 spell_bonus = 0; // bonus specific for spell - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_WARRIOR: - { - // Whirlwind, single only spell with 2 weapon white damage apply if have - if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL)) - { - if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true)) - spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized); - } - // Devastate bonus and sunder armor refresh - else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508) - { - customBonusDamagePercentMod = true; - bonusDamagePercentMod = 0.0f; // only applied if auras found - - Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE); - for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr) - { - SpellEntry const *proto = (*itr)->GetSpellProto(); - if(proto->SpellVisual == 406 && proto->SpellIconID == 565) - { - int32 duration = GetSpellDuration(proto); - (*itr)->SetAuraDuration(duration); - (*itr)->UpdateAuraDuration(); - bonusDamagePercentMod += 1.0f; // +100% - } - } - } - break; - } - case SPELLFAMILY_ROGUE: - { - // Ambush - if(m_spellInfo->SpellFamilyFlags & 0x00000200LL) - { - customBonusDamagePercentMod = true; - bonusDamagePercentMod = 2.5f; // 250% - } - // Mutilate (for each hand) - else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL) - { - bool found = false; - // fast check - if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON)) - found = true; - // full aura scan - else - { - Unit::AuraMap const& auras = unitTarget->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) - { - if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON) - { - found = true; - break; - } - } - } - - if(found) - totalDamagePercentMod *= 1.5f; // 150% if poisoned - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Seal of Command - receive benefit from Spell Damage and Healing - if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL) - { - spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo))); - spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget)); - } - break; - } - case SPELLFAMILY_SHAMAN: - { - // Skyshatter Harness item set bonus - // Stormstrike - if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL) - { - Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i) - { - // Stormstrike AP Buff - if ( (*i)->GetModifier()->m_miscvalue == 5634 ) - { - m_caster->CastSpell(m_caster,38430,true,NULL,*i); - break; - } - } - } - } - } - - int32 fixed_bonus = 0; - for (int j = 0; j < 3; j++) - { - switch(m_spellInfo->Effect[j]) - { - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - fixed_bonus += CalculateDamage(j,unitTarget); - break; - case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - fixed_bonus += CalculateDamage(j,unitTarget); - normalized = true; - break; - case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f; - - // applied only to prev.effects fixed damage - if(customBonusDamagePercentMod) - fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod); - else - fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod); - break; - default: - break; // not weapon damage effect, just skip - } - } - - // non-weapon damage - int32 bonus = spell_bonus + fixed_bonus; - - // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage - if(bonus) - { - UnitMods unitMod; - switch(m_attackType) - { - default: - case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; - case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; - case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; - } - - float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); - bonus = int32(bonus*weapon_total_pct); - } - - // + weapon damage with applied weapon% dmg to base weapon damage in call - bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod); - - // total damage - bonus = int32(bonus*totalDamagePercentMod); - - // prevent negative damage - uint32 eff_damage = uint32(bonus > 0 ? bonus : 0); - - const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS; - - uint32 hitInfo = 0; - VictimState victimState = VICTIMSTATE_NORMAL; - uint32 blocked_dmg = 0; - uint32 absorbed_dmg = 0; - uint32 resisted_dmg = 0; - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); - - m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell); - - if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc - m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg); - - bool criticalhit = (hitInfo & HITINFO_CRITICALHIT); - m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit); - - if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg)) - { - eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg); - } - else - { - cleanDamage.damage += eff_damage; - eff_damage = 0; - } - - // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation - m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true); - - // Hemorrhage - if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000)) - { - if(m_caster->GetTypeId()==TYPEID_PLAYER) - ((Player*)m_caster)->AddComboPoints(unitTarget, 1); - } - // Mangle (Cat): CP - if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL)) - { - if(m_caster->GetTypeId()==TYPEID_PLAYER) - ((Player*)m_caster)->AddComboPoints(unitTarget,1); - } - - - // take ammo - if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER) - { - Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK ); - - // wands don't have ammo - if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND) - return; - - if( pItem->GetProto()->InventoryType == INVTYPE_THROWN ) - { - if(pItem->GetMaxStackCount()==1) - { - // decrease durability for non-stackable throw weapon - ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED); - } - else - { - // decrease items amount for stackable throw weapon - uint32 count = 1; - ((Player*)m_caster)->DestroyItemCount( pItem, count, true); - } - } - else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID)) - ((Player*)m_caster)->DestroyItemCount(ammo, 1, true); - } -} - -void Spell::EffectThreat(uint32 /*i*/) -{ - if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive()) - return; - - if(!unitTarget->CanHaveThreatList()) - return; - - unitTarget->AddThreat(m_caster, float(damage)); -} - -void Spell::EffectHealMaxHealth(uint32 /*i*/) -{ - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - - uint32 heal = m_caster->GetMaxHealth(); - - int32 gain = unitTarget->ModifyHealth(heal); - unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); - - m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal); -} - -void Spell::EffectInterruptCast(uint32 /*i*/) -{ - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - - // TODO: not all spells that used this effect apply cooldown at school spells - // also exist case: apply cooldown to interrupted cast only and to all spells - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) - { - if (unitTarget->m_currentSpells[i]) - { - // check if we can interrupt spell - if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE ) - { - unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo)); - unitTarget->InterruptSpell(i,false); - } - } - } -} - -void Spell::EffectSummonObjectWild(uint32 i) -{ - uint32 gameobject_id = m_spellInfo->EffectMiscValue[i]; - - GameObject* pGameObj = new GameObject; - - WorldObject* target = focusObject; - if( !target ) - target = m_caster; - - float x,y,z; - if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - } - else - m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE); - - Map *map = target->GetMap(); - - if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map, - x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1)) - { - delete pGameObj; - return; - } - - int32 duration = GetSpellDuration(m_spellInfo); - pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - - if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)... - m_caster->AddGameObject(pGameObj); - map->Add(pGameObj); - - if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS - { - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - Player *pl = (Player*)m_caster; - BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); - if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS) - { - uint32 team = ALLIANCE; - - if(pl->GetTeam() == team) - team = HORDE; - - ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team); - } - } - } - - if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY - { - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); - if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS) - { - ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID()); - } - } - } - - if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry()) - { - GameObject* linkedGO = new GameObject; - if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map, - x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1)) - { - linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0); - linkedGO->SetSpellId(m_spellInfo->Id); - - m_caster->AddGameObject(linkedGO); - map->Add(linkedGO); - } - else - { - delete linkedGO; - linkedGO = NULL; - return; - } - } -} - -void Spell::EffectScriptEffect(uint32 effIndex) -{ - // TODO: we must implement hunter pet summon at login there (spell 6962) - - // by spell id - switch(m_spellInfo->Id) - { - // Bending Shinbone - case 8856: - { - if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch(urand(1,5)) - { - case 1: spell_id = 8854; break; - default: spell_id = 8855; break; - } - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - - // Healthstone creating spells - case 6201: - case 6202: - case 5699: - case 11729: - case 11730: - case 27230: - { - uint32 itemtype; - uint32 rank = 0; - Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) - { - if((*i)->GetId() == 18692) - { - rank = 1; - break; - } - else if((*i)->GetId() == 18693) - { - rank = 2; - break; - } - } - - static uint32 const itypes[6][3] = { - { 5512,19004,19005}, // Minor Healthstone - { 5511,19006,19007}, // Lesser Healthstone - { 5509,19008,19009}, // Healthstone - { 5510,19010,19011}, // Greater Healthstone - { 9421,19012,19013}, // Major Healthstone - {22103,22104,22105} // Master Healthstone - }; - - switch(m_spellInfo->Id) - { - case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone - case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone - case 5699: itemtype=itypes[2][rank];break; // Healthstone - case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone - case 11730: itemtype=itypes[4][rank];break; // Major Healthstone - case 27230: itemtype=itypes[5][rank];break; // Master Healthstone - default: - return; - } - DoCreateItem( effIndex, itemtype ); - return; - } - // Brittle Armor - need remove one 24575 Brittle Armor aura - case 24590: - unitTarget->RemoveSingleAuraFromStack(24575, 0); - unitTarget->RemoveSingleAuraFromStack(24575, 1); - return; - // Mercurial Shield - need remove one 26464 Mercurial Shield aura - case 26465: - unitTarget->RemoveSingleAuraFromStack(26464, 0); - return; - // Orb teleport spells - case 25140: - case 25143: - case 25650: - case 25652: - case 29128: - case 29129: - case 35376: - case 35727: - { - if(!unitTarget) - return; - - uint32 spellid; - switch(m_spellInfo->Id) - { - case 25140: spellid = 32571; break; - case 25143: spellid = 32572; break; - case 25650: spellid = 30140; break; - case 25652: spellid = 30141; break; - case 29128: spellid = 32568; break; - case 29129: spellid = 32569; break; - case 35376: spellid = 25649; break; - case 35727: spellid = 35730; break; - default: - return; - } - - unitTarget->CastSpell(unitTarget,spellid,false); - return; - } - - // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell) - case 22539: - case 22972: - case 22975: - case 22976: - case 22977: - case 22978: - case 22979: - case 22980: - case 22981: - case 22982: - case 22983: - case 22984: - case 22985: - { - if(!unitTarget || !unitTarget->isAlive()) - return; - - // Onyxia Scale Cloak - if(unitTarget->GetDummyAura(22683)) - return; - - // Shadow Flame - m_caster->CastSpell(unitTarget, 22682, true); - return; - } - break; - - // Summon Black Qiraji Battle Tank - case 26656: - { - if(!unitTarget) - return; - - // Prevent stacking of mounts - unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); - - // Two separate mounts depending on area id (allows use both in and out of specific instance) - if (unitTarget->GetAreaId() == 3428) - unitTarget->CastSpell(unitTarget, 25863, false); - else - unitTarget->CastSpell(unitTarget, 26655, false); - break; - } - // Piccolo of the Flaming Fire - case 17512: - { - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE); - break; - } - - // Dreaming Glory - case 28698: - { - if(!unitTarget) - return; - unitTarget->CastSpell(unitTarget, 28694, true); - break; - } - - // Netherbloom - case 28702: - { - if(!unitTarget) - return; - // 25% chance of casting a random buff - if(roll_chance_i(75)) - return; - - // triggered spells are 28703 to 28707 - // Note: some sources say, that there was the possibility of - // receiving a debuff. However, this seems to be removed by a patch. - const uint32 spellid = 28703; - - // don't overwrite an existing aura - for(uint8 i=0; i<5; i++) - if(unitTarget->HasAura(spellid+i, 0)) - return; - unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true); - break; - } - - // Nightmare Vine - case 28720: - { - if(!unitTarget) - return; - // 25% chance of casting Nightmare Pollen - if(roll_chance_i(75)) - return; - unitTarget->CastSpell(unitTarget, 28721, true); - break; - } - - // Mirren's Drinking Hat - case 29830: - { - uint32 item = 0; - switch ( urand(1,6) ) - { - case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager - case 4: case 5: item = 23585; break;// Stouthammer Lite - case 6: item = 23586; break;// Aerie Peak Pale Ale - } - if (item) - DoCreateItem(effIndex,item); - break; - } - // Improved Sprint - case 30918: - { - // Removes snares and roots. - uint32 mechanic_mask = (1<GetAuras(); - for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next) - { - next = iter; - ++next; - Aura *aur = iter->second; - if (!aur->IsPositive()) //only remove negative spells - { - // check for mechanic mask - if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask) - { - unitTarget->RemoveAurasDueToSpell(aur->GetId()); - if(Auras.empty()) - break; - else - next = Auras.begin(); - } - } - } - break; - } - case 41126: // Flame Crash - { - if(!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 41131, true); - break; - } - case 44876: // Force Cast - Portal Effect: Sunwell Isle - { - if(!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 44870, true); - break; - } - - // Goblin Weather Machine - case 46203: - { - if(!unitTarget) - return; - - uint32 spellId; - switch(rand()%4) - { - case 0: - spellId=46740; - break; - case 1: - spellId=46739; - break; - case 2: - spellId=46738; - break; - case 3: - spellId=46736; - break; - } - unitTarget->CastSpell(unitTarget, spellId, true); - break; - } - } - - if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN ) - { - switch(m_spellInfo->SpellFamilyFlags) - { - // Judgement - case 0x800000: - { - if(!unitTarget || !unitTarget->isAlive()) - return; - uint32 spellId2 = 0; - - // all seals have aura dummy - Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr) - { - SpellEntry const *spellInfo = (*itr)->GetSpellProto(); - - // search seal (all seals have judgement's aura dummy spell id in 2 effect - if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 ) - continue; - - // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE - spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1; - - if(spellId2 <= 1) - continue; - - // found, remove seal - m_caster->RemoveAurasDueToSpell((*itr)->GetId()); - - // Sanctified Judgement - Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i) - { - if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL) - { - int32 chance = (*i)->GetModifier()->m_amount; - if ( roll_chance_i(chance) ) - { - int32 mana = spellInfo->manaCost; - if ( Player* modOwner = m_caster->GetSpellModOwner() ) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana); - mana = int32(mana* 0.8f); - m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i); - } - break; - } - } - - break; - } - - m_caster->CastSpell(unitTarget,spellId2,true); - return; - } - } - } - - // normal DB scripted effect - if(!unitTarget) - return; - - sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id); - sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget); -} - -void Spell::EffectSanctuary(uint32 /*i*/) -{ - if(!unitTarget) - return; - //unitTarget->CombatStop(); - - unitTarget->CombatStop(); - unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting - // Vanish allows to remove all threat and cast regular stealth so other spells can be used - if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH)) - { - ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); - } -} - -void Spell::EffectAddComboPoints(uint32 /*i*/) -{ - if(!unitTarget) - return; - - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if(damage <= 0) - return; - - ((Player*)m_caster)->AddComboPoints(unitTarget, damage); -} - -void Spell::EffectDuel(uint32 i) -{ - if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *caster = (Player*)m_caster; - Player *target = (Player*)unitTarget; - - // caster or target already have requested duel - if( caster->duel || target->duel || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) ) - return; - - // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities) - // Don't have to check the target's map since you cannot challenge someone across maps - if( caster->GetMapId() != 0 && caster->GetMapId() != 1 && caster->GetMapId() != 530) - { - SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here - return; - } - - AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId()); - if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) ) - { - SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here - return; - } - - AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId()); - if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) ) - { - SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here - return; - } - - //CREATE DUEL FLAG OBJECT - GameObject* pGameObj = new GameObject; - - uint32 gameobject_id = m_spellInfo->EffectMiscValue[i]; - - Map *map = m_caster->GetMap(); - if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map, - m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 , - m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 , - m_caster->GetPositionZ(), - m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1)) - { - delete pGameObj; - return; - } - - pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() ); - pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 ); - int32 duration = GetSpellDuration(m_spellInfo); - pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - - m_caster->AddGameObject(pGameObj); - map->Add(pGameObj); - //END - - // Send request - WorldPacket data(SMSG_DUEL_REQUESTED, 16); - data << pGameObj->GetGUID(); - data << caster->GetGUID(); - caster->GetSession()->SendPacket(&data); - target->GetSession()->SendPacket(&data); - - // create duel-info - DuelInfo *duel = new DuelInfo; - duel->initiator = caster; - duel->opponent = target; - duel->startTime = 0; - duel->startTimer = 0; - caster->duel = duel; - - DuelInfo *duel2 = new DuelInfo; - duel2->initiator = caster; - duel2->opponent = caster; - duel2->startTime = 0; - duel2->startTimer = 0; - target->duel = duel2; - - caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID()); - target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID()); -} - -void Spell::EffectStuck(uint32 /*i*/) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK)) - return; - - Player* pTarget = (Player*)unitTarget; - - sLog.outDebug("Spell Effect: Stuck"); - sLog.outDetail("Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", pTarget->GetName(), pTarget->GetGUIDLow(), m_caster->GetMapId(), m_caster->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); - - if(pTarget->isInFlight()) - return; - - // homebind location is loaded always - pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - - // Stuck spell trigger Hearthstone cooldown - SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690); - if(!spellInfo) - return; - Spell spell(pTarget,spellInfo,true,0); - spell.SendSpellCooldown(); -} - -void Spell::EffectSummonPlayer(uint32 /*i*/) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Evil Twin (ignore player summon, but hide this for summoner) - if(unitTarget->GetDummyAura(23445)) - return; - - float x,y,z; - m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize()); - - ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z); - - WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4); - data << uint64(m_caster->GetGUID()); // summoner guid - data << uint32(m_caster->GetZoneId()); // summoner zone - data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs - ((Player*)unitTarget)->GetSession()->SendPacket(&data); -} - -static ScriptInfo generateActivateCommand() -{ - ScriptInfo si; - si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT; - return si; -} - -void Spell::EffectActivateObject(uint32 effect_idx) -{ - if(!gameObjTarget) - return; - - static ScriptInfo activateCommand = generateActivateCommand(); - - int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx]; - - sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget); -} - -void Spell::EffectSummonTotem(uint32 i) -{ - uint8 slot = 0; - switch(m_spellInfo->EffectMiscValueB[i]) - { - case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break; - case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break; - case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break; - case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break; - // Battle standard case - case SUMMON_TYPE_TOTEM: slot = 254; break; - // jewelery statue case, like totem without slot - case SUMMON_TYPE_GUARDIAN: slot = 255; break; - default: return; - } - - if(slot < MAX_TOTEM) - { - uint64 guid = m_caster->m_TotemSlot[slot]; - if(guid != 0) - { - Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid); - if(OldTotem && OldTotem->isTotem()) - ((Totem*)OldTotem)->UnSummon(); - } - } - - uint32 team = 0; - if (m_caster->GetTypeId()==TYPEID_PLAYER) - team = ((Player*)m_caster)->GetTeam(); - - Totem* pTotem = new Totem; - - if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team )) - { - delete pTotem; - return; - } - - float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0; - - float x,y,z; - m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle); - - // totem must be at same Z in case swimming caster and etc. - if( fabs( z - m_caster->GetPositionZ() ) > 5 ) - z = m_caster->GetPositionZ(); - - pTotem->Relocate(x, y, z, m_caster->GetOrientation()); - - if(slot < MAX_TOTEM) - m_caster->m_TotemSlot[slot] = pTotem->GetGUID(); - - pTotem->SetOwner(m_caster->GetGUID()); - pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized - - int32 duration=GetSpellDuration(m_spellInfo); - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration); - pTotem->SetDuration(duration); - - if (damage) // if not spell info, DB values used - { - pTotem->SetMaxHealth(damage); - pTotem->SetHealth(damage); - } - - pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id); - pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE); - - pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true); - pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true); - - pTotem->Summon(m_caster); - - if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4); - data << uint8(slot); - data << uint64(pTotem->GetGUID()); - data << uint32(duration); - data << uint32(m_spellInfo->Id); - ((Player*)m_caster)->SendDirectMessage(&data); - } -} - -void Spell::EffectEnchantHeldItem(uint32 i) -{ - // this is only item spell effect applied to main-hand weapon of target player (players in area) - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player* item_owner = (Player*)unitTarget; - Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - - if(!item ) - return; - - // must be equipped - if(!item ->IsEquipped()) - return; - - if (m_spellInfo->EffectMiscValue[i]) - { - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first .. - if(!duration) - duration = m_currentBasePoints[i]+1; //Base points after .. - if(!duration) - duration = 10; //10 seconds for enchants which don't have listed duration - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) - return; - - // Always go to temp enchantment slot - EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT; - - // Enchantment will not be applied if a different one already exists - if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id) - return; - - // Apply the temporary enchantment - item->SetEnchantment(slot, enchant_id, duration*1000, 0); - item_owner->ApplyEnchantment(item,slot,true); - } -} - -void Spell::EffectDisEnchant(uint32 /*i*/) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* p_caster = (Player*)m_caster; - if(!itemTarget || !itemTarget->GetProto()->DisenchantID) - return; - - p_caster->UpdateCraftSkill(m_spellInfo->Id); - - ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING); - - // item will be removed at disenchanting end -} - -void Spell::EffectInebriate(uint32 /*i*/) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *player = (Player*)unitTarget; - uint16 currentDrunk = player->GetDrunkValue(); - uint16 drunkMod = damage * 256; - if (currentDrunk + drunkMod > 0xFFFF) - currentDrunk = 0xFFFF; - else - currentDrunk += drunkMod; - player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0); -} - -void Spell::EffectFeedPet(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)m_caster; - - if(!itemTarget) - return; - - Pet *pet = _player->GetPet(); - if(!pet) - return; - - if(!pet->isAlive()) - return; - - int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel); - if(benefit <= 0) - return; - - uint32 count = 1; - _player->DestroyItemCount(itemTarget,count,true); - // TODO: fix crash when a spell has two effects, both pointed at the same item target - - m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true); -} - -void Spell::EffectDismissPet(uint32 /*i*/) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Pet* pet = m_caster->GetPet(); - - // not let dismiss dead pet - if(!pet||!pet->isAlive()) - return; - - ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT); -} - -void Spell::EffectSummonObject(uint32 i) -{ - uint32 go_id = m_spellInfo->EffectMiscValue[i]; - - uint8 slot = 0; - switch(m_spellInfo->Effect[i]) - { - case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break; - case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break; - case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break; - case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break; - default: return; - } - - uint64 guid = m_caster->m_ObjectSlot[slot]; - if(guid != 0) - { - GameObject* obj = NULL; - if( m_caster ) - obj = ObjectAccessor::GetGameObject(*m_caster, guid); - - if(obj) obj->Delete(); - m_caster->m_ObjectSlot[slot] = 0; - } - - GameObject* pGameObj = new GameObject; - - float rot2 = sin(m_caster->GetOrientation()/2); - float rot3 = cos(m_caster->GetOrientation()/2); - - float x,y,z; - // If dest location if present - if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - } - // Summon in random point all other units if location present - else - m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE); - - Map *map = m_caster->GetMap(); - if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1)) - { - delete pGameObj; - return; - } - - pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel()); - int32 duration = GetSpellDuration(m_spellInfo); - pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - m_caster->AddGameObject(pGameObj); - - map->Add(pGameObj); - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << pGameObj->GetGUID(); - m_caster->SendMessageToSet(&data,true); - - m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID(); -} - -void Spell::EffectResurrect(uint32 i) -{ - if(!unitTarget) - return; - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if(unitTarget->isAlive()) - return; - if(!unitTarget->IsInWorld()) - return; - - switch (m_spellInfo->Id) - { - // Defibrillate (Goblin Jumper Cables) have 33% chance on success - case 8342: - if (roll_chance_i(67)) - { - m_caster->CastSpell(m_caster, 8338, true, m_CastItem); - return; - } - break; - // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success - case 22999: - if (roll_chance_i(50)) - { - m_caster->CastSpell(m_caster, 23055, true, m_CastItem); - return; - } - break; - default: - break; - } - - Player* pTarget = ((Player*)unitTarget); - - if(pTarget->isRessurectRequested()) // already have one active request - return; - - uint32 health = pTarget->GetMaxHealth() * damage / 100; - uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100; - - pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); - SendResurrectRequest(pTarget); -} - -void Spell::EffectAddExtraAttacks(uint32 /*i*/) -{ - if(!unitTarget || !unitTarget->isAlive()) - return; - - if( unitTarget->m_extraAttacks ) - return; - - unitTarget->m_extraAttacks = damage; -} - -void Spell::EffectParry(uint32 /*i*/) -{ - if (unitTarget->GetTypeId() == TYPEID_PLAYER) - { - ((Player*)unitTarget)->SetCanParry(true); - } -} - -void Spell::EffectMomentMove(uint32 i) -{ - if(unitTarget->isInFlight()) - return; - - if( m_spellInfo->rangeIndex== 1) //self range - { - uint32 mapid = m_caster->GetMapId(); - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - // before caster - float fx,fy,fz; - unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); - float ox,oy,oz; - unitTarget->GetPosition(ox,oy,oz); - - float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case - if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5)) - { - fx = fx2; - fy = fy2; - fz = fz2; - unitTarget->UpdateGroundPositionZ(fx,fy,fz); - } - - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation()); - } -} - -void Spell::EffectReputation(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)unitTarget; - - int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1 - - uint32 faction_id = m_spellInfo->EffectMiscValue[i]; - - FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id); - - if(!factionEntry) - return; - - _player->ModifyFactionReputation(factionEntry,rep_change); -} - -void Spell::EffectQuestComplete(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)m_caster; - - uint32 quest_id = m_spellInfo->EffectMiscValue[i]; - _player->AreaExploredOrEventHappens(quest_id); -} - -void Spell::EffectSelfResurrect(uint32 i) -{ - if(!unitTarget || unitTarget->isAlive()) - return; - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - if(!unitTarget->IsInWorld()) - return; - - uint32 health = 0; - uint32 mana = 0; - - // flat case - if(damage < 0) - { - health = uint32(-damage); - mana = m_spellInfo->EffectMiscValue[i]; - } - // percent case - else - { - health = uint32(damage/100.0f*unitTarget->GetMaxHealth()); - if(unitTarget->GetMaxPower(POWER_MANA) > 0) - mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA)); - } - - Player *plr = ((Player*)unitTarget); - plr->ResurrectPlayer(0.0f); - - plr->SetHealth( health ); - plr->SetPower(POWER_MANA, mana ); - plr->SetPower(POWER_RAGE, 0 ); - plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) ); - - plr->SpawnCorpseBones(); - - plr->SaveToDB(); -} - -void Spell::EffectSkinning(uint32 /*i*/) -{ - if(unitTarget->GetTypeId() != TYPEID_UNIT ) - return; - if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Creature* creature = (Creature*) unitTarget; - int32 targetLevel = creature->getLevel(); - - uint32 skill; - if(creature->GetCreatureInfo()->flag1 & 256) - skill = SKILL_HERBALISM; // special case - else if(creature->GetCreatureInfo()->flag1 & 512) - skill = SKILL_MINING; // special case - else - skill = SKILL_SKINNING; // normal case - - ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING); - creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - - int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5; - - int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill); - - // Double chances for elites - ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 ); -} - -void Spell::EffectCharge(uint32 /*i*/) -{ - if(!unitTarget || !m_caster) - return; - - float x, y, z; - unitTarget->GetContactPoint(m_caster, x, y, z); - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - ((Creature *)unitTarget)->StopMoving(); - - // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags - m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1); - - if(m_caster->GetTypeId() != TYPEID_PLAYER) - MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation()); - - // not all charge effects used in negative spells - if ( !IsPositiveSpell(m_spellInfo->Id)) - m_caster->Attack(unitTarget,true); -} - -void Spell::EffectSummonCritter(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - Player* player = (Player*)m_caster; - - uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; - if(!pet_entry) - return; - - Pet* old_critter = player->GetMiniPet(); - - // for same pet just despawn - if(old_critter && old_critter->GetEntry() == pet_entry) - { - player->RemoveMiniPet(); - return; - } - - // despawn old pet before summon new - if(old_critter) - player->RemoveMiniPet(); - - // summon new pet - Pet* critter = new Pet(MINI_PET); - - Map *map = m_caster->GetMap(); - uint32 pet_number = objmgr.GeneratePetNumber(); - if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), - map, pet_entry, pet_number)) - { - sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry); - delete critter; - return; - } - - float x,y,z; - // If dest location if present - if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - } - // Summon if dest location not present near caster - else - m_caster->GetClosePoint(x,y,z,critter->GetObjectSize()); - - critter->Relocate(x,y,z,m_caster->GetOrientation()); - - if(!critter->IsPositionValid()) - { - sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY()); - delete critter; - return; - } - - critter->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); - critter->SetUInt64Value(UNIT_FIELD_CREATEDBY,m_caster->GetGUID()); - critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); - critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - critter->AIM_Initialize(); - critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter... - critter->SetMaxHealth(1); - critter->SetHealth(1); - critter->SetLevel(1); - - // set timer for unsummon - int32 duration = GetSpellDuration(m_spellInfo); - if(duration > 0) - critter->SetDuration(duration); - - std::string name = player->GetName(); - name.append(petTypeSuffix[critter->getPetType()]); - critter->SetName( name ); - player->SetMiniPet(critter); - - map->Add((Creature*)critter); -} - -void Spell::EffectKnockBack(uint32 i) -{ - if(!unitTarget || !m_caster) - return; - - // Effect only works on players - if(unitTarget->GetTypeId()!=TYPEID_PLAYER) - return; - - float vsin = sin(m_caster->GetAngle(unitTarget)); - float vcos = cos(m_caster->GetAngle(unitTarget)); - - WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); - data.append(unitTarget->GetPackGUID()); - data << uint32(0); // Sequence - data << float(vcos); // x direction - data << float(vsin); // y direction - data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed - data << float(damage/-10); // Z Movement speed (vertical) - - ((Player*)unitTarget)->GetSession()->SendPacket(&data); -} - -void Spell::EffectSendTaxi(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]); - if(!entry) - return; - - std::vector nodes; - - nodes.resize(2); - nodes[0] = entry->from; - nodes[1] = entry->to; - - uint32 mountid = 0; - switch(m_spellInfo->Id) - { - case 31606: //Stormcrow Amulet - mountid = 17447; - break; - case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run - case 45113: //Quest - Sunwell Daily - Ship Bombing Run - case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return - mountid = 22840; - break; - case 34905: //Stealth Flight - mountid = 6851; - break; - } - - ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid); - -} - -void Spell::EffectPlayerPull(uint32 i) -{ - if(!unitTarget || !m_caster) - return; - - // Effect only works on players - if(unitTarget->GetTypeId()!=TYPEID_PLAYER) - return; - - float vsin = sin(unitTarget->GetAngle(m_caster)); - float vcos = cos(unitTarget->GetAngle(m_caster)); - - WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); - data.append(unitTarget->GetPackGUID()); - data << uint32(0); // Sequence - data << float(vcos); // x direction - data << float(vsin); // y direction - // Horizontal speed - data << float(damage ? damage : unitTarget->GetDistance2d(m_caster)); - data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed - - ((Player*)unitTarget)->GetSession()->SendPacket(&data); -} - -void Spell::EffectDispelMechanic(uint32 i) -{ - if(!unitTarget) - return; - - uint32 mechanic = m_spellInfo->EffectMiscValue[i]; - - Unit::AuraMap& Auras = unitTarget->GetAuras(); - for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next) - { - next = iter; - ++next; - SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id); - if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic) - { - unitTarget->RemoveAurasDueToSpell(spell->Id); - if(Auras.empty()) - break; - else - next = Auras.begin(); - } - } - return; -} - -void Spell::EffectSummonDeadPet(uint32 /*i*/) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - Player *_player = (Player*)m_caster; - Pet *pet = _player->GetPet(); - if(!pet) - return; - if(pet->isAlive()) - return; - if(damage < 0) - return; - pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - pet->setDeathState( ALIVE ); - pet->clearUnitState(UNIT_STAT_ALL_STATE); - pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100))); - - pet->AIM_Initialize(); - - _player->PetSpellInitialize(); - pet->SavePetToDB(PET_SAVE_AS_CURRENT); -} - -void Spell::EffectDestroyAllTotems(uint32 /*i*/) -{ - float mana = 0; - for(int slot = 0; slot < MAX_TOTEM; ++slot) - { - if(!m_caster->m_TotemSlot[slot]) - continue; - - Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]); - if(totem && totem->isTotem()) - { - uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id); - if(spellInfo) - mana += spellInfo->manaCost * damage / 100; - ((Totem*)totem)->UnSummon(); - } - } - - int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana)); - m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA); -} - -void Spell::EffectDurabilityDamage(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - int32 slot = m_spellInfo->EffectMiscValue[i]; - - // FIXME: some spells effects have value -1/-2 - // Possibly its mean -1 all player equipped items and -2 all items - if(slot < 0) - { - ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1)); - return; - } - - // invalid slot value - if(slot >= INVENTORY_SLOT_BAG_END) - return; - - if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot)) - ((Player*)unitTarget)->DurabilityPointsLoss(item,damage); -} - -void Spell::EffectDurabilityDamagePCT(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - int32 slot = m_spellInfo->EffectMiscValue[i]; - - // FIXME: some spells effects have value -1/-2 - // Possibly its mean -1 all player equipped items and -2 all items - if(slot < 0) - { - ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1)); - return; - } - - // invalid slot value - if(slot >= INVENTORY_SLOT_BAG_END) - return; - - if(damage <= 0) - return; - - if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot)) - ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f); -} - -void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/) -{ - if(!unitTarget) - return; - - unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage); -} - -void Spell::EffectTransmitted(uint32 effIndex) -{ - uint32 name_id = m_spellInfo->EffectMiscValue[effIndex]; - - GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id); - - if (!goinfo) - { - sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id); - return; - } - - float fx,fy,fz; - - if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - fx = m_targets.m_destX; - fy = m_targets.m_destY; - fz = m_targets.m_destZ; - } - //FIXME: this can be better check for most objects but still hack - else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0) - { - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex])); - m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis); - } - else - { - float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); - float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); - float dis = rand_norm() * (max_dis - min_dis) + min_dis; - - m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis); - } - - Map *cMap = m_caster->GetMap(); - - if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE) - { - if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole - { // but this is not proper, we really need to ignore not materialized objects - SendCastResult(SPELL_FAILED_NOT_HERE); - SendChannelUpdate(0); - return; - } - - // replace by water level in this case - fz = cMap->GetWaterLevel(fx,fy); - } - // if gameobject is summoning object, it should be spawned right on caster's position - else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL) - { - m_caster->GetPosition(fx,fy,fz); - } - - GameObject* pGameObj = new GameObject; - - if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap, - fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1)) - { - delete pGameObj; - return; - } - - int32 duration = GetSpellDuration(m_spellInfo); - - switch(goinfo->type) - { - case GAMEOBJECT_TYPE_FISHINGNODE: - { - m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID()); - // Orientation3 - pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 2, 0.88431775569915771 ); - // Orientation4 - pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 3, -0.4668855369091033 ); - m_caster->AddGameObject(pGameObj); // will removed at spell cancel - - // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo)) - // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME) - int32 lastSec; - switch(urand(0, 3)) - { - case 0: lastSec = 3; break; - case 1: lastSec = 7; break; - case 2: lastSec = 13; break; - case 3: lastSec = 17; break; - } - - duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000; - break; - } - case GAMEOBJECT_TYPE_SUMMONING_RITUAL: - { - if(m_caster->GetTypeId()==TYPEID_PLAYER) - { - pGameObj->AddUniqueUse((Player*)m_caster); - m_caster->AddGameObject(pGameObj); // will removed at spell cancel - } - break; - } - case GAMEOBJECT_TYPE_FISHINGHOLE: - case GAMEOBJECT_TYPE_CHEST: - default: - { - break; - } - } - - pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); - - pGameObj->SetOwnerGUID(m_caster->GetGUID() ); - - pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); - pGameObj->SetSpellId(m_spellInfo->Id); - - DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n"); - //m_caster->AddGameObject(pGameObj); - //m_ObjToDel.push_back(pGameObj); - - cMap->Add(pGameObj); - - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << uint64(pGameObj->GetGUID()); - m_caster->SendMessageToSet(&data,true); - - if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry()) - { - GameObject* linkedGO = new GameObject; - if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap, - fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1)) - { - linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0); - linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); - linkedGO->SetSpellId(m_spellInfo->Id); - linkedGO->SetOwnerGUID(m_caster->GetGUID() ); - - MapManager::Instance().GetMap(linkedGO->GetMapId(), linkedGO)->Add(linkedGO); - } - else - { - delete linkedGO; - linkedGO = NULL; - return; - } - } -} - -void Spell::EffectProspecting(uint32 /*i*/) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* p_caster = (Player*)m_caster; - if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)) - return; - - if(itemTarget->GetCount() < 5) - return; - - if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING)) - { - uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING); - uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank; - p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue); - } - - ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING); -} - -void Spell::EffectSkill(uint32 /*i*/) -{ - sLog.outDebug("WORLD: SkillEFFECT"); -} - -void Spell::EffectSummonDemon(uint32 i) -{ - float px = m_targets.m_destX; - float py = m_targets.m_destY; - float pz = m_targets.m_destZ; - - Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000); - if (!Charmed) - return; - - // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster? - Charmed->SetLevel(m_caster->getLevel()); - - // TODO: Add damage/mana/hp according to level - - if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon - { - // Enslave demon effect, without mana cost and cooldown - m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved - - // Inferno effect - Charmed->CastSpell(Charmed, 22703, true, 0); - } -} - -/* There is currently no need for this effect. We handle it in BattleGround.cpp - If we would handle the resurrection here, the spiritguide would instantly disappear as the - player revives, and so we wouldn't see the spirit heal visual effect on the npc. - This is why we use a half sec delay between the visual effect and the resurrection itself */ -void Spell::EffectSpiritHeal(uint32 /*i*/) -{ - /* - if(!unitTarget || unitTarget->isAlive()) - return; - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - if(!unitTarget->IsInWorld()) - return; - - //m_spellInfo->EffectBasePoints[i]; == 99 (percent?) - //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA)); - ((Player*)unitTarget)->ResurrectPlayer(1.0f); - ((Player*)unitTarget)->SpawnCorpseBones(); - */ -} - -// remove insignia spell effect -void Spell::EffectSkinPlayerCorpse(uint32 /*i*/) -{ - sLog.outDebug("Effect: SkinPlayerCorpse"); - if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) ) - return; - - ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster ); -} - -void Spell::EffectStealBeneficialBuff(uint32 i) -{ - sLog.outDebug("Effect: StealBeneficialBuff"); - - if(!unitTarget || unitTarget==m_caster) // can't steal from self - return; - - std::vector steal_list; - // Create dispel mask by dispel type - uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) ); - Unit::AuraMap const& auras = unitTarget->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - Aura *aur = (*itr).second; - if (aur && (1<GetSpellProto()->Dispel) & dispelMask) - { - // Need check for passive? this - if (aur->IsPositive() && !aur->IsPassive()) - steal_list.push_back(aur); - } - } - // Ok if exist some buffs for dispel try dispel it - if (!steal_list.empty()) - { - std::list < std::pair > success_list; - int32 list_size = steal_list.size(); - // Dispell N = damage buffs (or while exist buffs for dispel) - for (int32 count=0; count < damage && list_size > 0; ++count) - { - // Random select buff for dispel - Aura *aur = steal_list[urand(0, list_size-1)]; - // Not use chance for steal - // TODO possible need do it - success_list.push_back( std::pair(aur->GetId(),aur->GetCasterGUID())); - - // Remove buff from list for prevent doubles - for (std::vector::iterator j = steal_list.begin(); j != steal_list.end(); ) - { - Aura *stealed = *j; - if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID()) - { - j = steal_list.erase(j); - --list_size; - } - else - ++j; - } - } - // Really try steal and send log - if (!success_list.empty()) - { - int32 count = success_list.size(); - WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5); - data.append(unitTarget->GetPackGUID()); // Victim GUID - data.append(m_caster->GetPackGUID()); // Caster GUID - data << uint32(m_spellInfo->Id); // Dispell spell id - data << uint8(0); // not used - data << uint32(count); // count - for (std::list >::iterator j = success_list.begin(); j != success_list.end(); ++j) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first); - data << uint32(spellInfo->Id); // Spell Id - data << uint8(0); // 0 - steals !=0 transfers - unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster); - } - m_caster->SendMessageToSet(&data, true); - } - } -} - -void Spell::EffectKillCredit(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0); -} - -void Spell::EffectQuestFail(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]); -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "SharedDefines.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "UpdateMask.h" +#include "World.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Player.h" +#include "SkillExtraItems.h" +#include "Unit.h" +#include "CreatureAI.h" +#include "Spell.h" +#include "DynamicObject.h" +#include "SpellAuras.h" +#include "Group.h" +#include "UpdateData.h" +#include "MapManager.h" +#include "ObjectAccessor.h" +#include "SharedDefines.h" +#include "Pet.h" +#include "GameObject.h" +#include "GossipDef.h" +#include "Creature.h" +#include "Totem.h" +#include "CreatureAI.h" +#include "BattleGround.h" +#include "BattleGroundEY.h" +#include "BattleGroundWS.h" +#include "VMapFactory.h" +#include "Language.h" +#include "SocialMgr.h" +#include "Util.h" + +pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= +{ + &Spell::EffectNULL, // 0 + &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL + &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE + &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY + &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused + &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS + &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA + &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE + &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN + &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH + &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL + &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND + &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL + &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused + &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused + &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused + &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE + &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL + &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT + &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS + &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge + &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND) + &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY + &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block + &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM + &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON + &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense + &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA + &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON + &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP + &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE + &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE + &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE + &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK + &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM + &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY + &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL + &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND) + &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL + &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE + &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD + &Spell::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD + &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN + &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER + &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP + &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related + &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there + &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL + &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth + &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect + &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR + &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused + &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot + &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM + &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY + &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE + &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET + &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL + &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE + &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM + &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY + &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT + &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN + &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT + &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL + &Spell::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused + &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused + &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH + &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST + &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT + &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move + &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET + &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT + &Spell::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED + &Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM + &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit + &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD + &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT + &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK + &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY + &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS + &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST) + &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT + &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL + &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK + &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER + &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT + &Spell::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1 + &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2 + &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3 + &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4 + &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash + &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM + &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM + &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT + &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING + &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE + &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER + &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK + &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT + &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE + &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET + &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET + &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION + &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 + &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 + &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 + &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 + &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC + &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET + &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS + &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE + &Spell::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON + &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW + &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME + &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT + &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags... + &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal + &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more + &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET + &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test + &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG + &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused + &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id) + &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster) + &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT + &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect? + &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell + &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND + &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY + &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT + &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells + &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value + &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization + &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry + &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET + &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT + &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT + &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap + &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused + &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST + &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed? + &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE + &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER + &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast + &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect + &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused + &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail + &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused + &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop + &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused + &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2 + &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend + &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry +}; + +void Spell::EffectNULL(uint32 /*i*/) +{ + sLog.outDebug("WORLD: Spell Effect DUMMY"); +} + +void Spell::EffectUnused(uint32 /*i*/) +{ + // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS +} + +void Spell::EffectResurrectNew(uint32 i) +{ + if(!unitTarget || unitTarget->isAlive()) + return; + + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if(!unitTarget->IsInWorld()) + return; + + Player* pTarget = ((Player*)unitTarget); + + if(pTarget->isRessurectRequested()) // already have one active request + return; + + uint32 health = damage; + uint32 mana = m_spellInfo->EffectMiscValue[i]; + pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); + SendResurrectRequest(pTarget); +} + +void Spell::EffectInstaKill(uint32 /*i*/) +{ + if( !unitTarget || !unitTarget->isAlive() ) + return; + + // Demonic Sacrifice + if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT) + { + uint32 entry = unitTarget->GetEntry(); + uint32 spellID; + switch(entry) + { + case 416: spellID=18789; break; //imp + case 417: spellID=18792; break; //fellhunter + case 1860: spellID=18790; break; //void + case 1863: spellID=18791; break; //succubus + case 17252: spellID=35701; break; //fellguard + default: + sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry); + return; + } + + m_caster->CastSpell(m_caster,spellID,true); + } + + if(m_caster==unitTarget) // prevent interrupt message + finish(); + + uint32 health = unitTarget->GetHealth(); + m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); +} + +void Spell::EffectEnvirinmentalDMG(uint32 i) +{ + uint32 absorb = 0; + uint32 resist = 0; + + // Note: this hack with damage replace required until GO casting not implemented + // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support + // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc + damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i]; + + m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + + m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false); + if(m_caster->GetTypeId() == TYPEID_PLAYER) + ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage); +} + +void Spell::EffectSchoolDMG(uint32 effect_idx) +{ + if( unitTarget && unitTarget->isAlive()) + { + switch(m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + //Gore + if(m_spellInfo->SpellIconID == 2269 ) + { + damage+= rand()%2 ? damage : 0; + } + + switch(m_spellInfo->Id) // better way to check unknown + { + // Meteor like spells (divided damage to targets) + case 24340: case 26558: case 28884: // Meteor + case 36837: case 38903: case 41276: // Meteor + case 26789: // Shard of the Fallen Star + case 31436: // Malevolent Cleave + case 35181: // Dive Bomb + case 40810: case 43267: case 43268: // Saber Lash + case 42384: // Brutal Swipe + case 45150: // Meteor Slash + { + uint32 count = 0; + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + if(ihit->effectMask & (1<GetHealth() / 2; + if(damage < 200) + damage = 200; + break; + } + } + break; + } + + case SPELLFAMILY_MAGE: + { + // Arcane Blast + if(m_spellInfo->SpellFamilyFlags & 0x20000000LL) + { + m_caster->CastSpell(m_caster,36032,true); + } + break; + } + case SPELLFAMILY_WARRIOR: + { + // Bloodthirst + if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL) + { + damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100); + } + // Shield Slam + else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) + damage += int32(m_caster->GetShieldBlockValue()); + // Victory Rush + else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL) + { + damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); + m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false); + } + break; + } + case SPELLFAMILY_WARLOCK: + { + // Incinerate Rank 1 & 2 + if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128) + { + // Incinerate does more dmg (dmg*0.25) if the target is Immolated. + if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE)) + damage += int32(damage*0.25); + } + break; + } + case SPELLFAMILY_DRUID: + { + // Ferocious Bite + if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587) + { + // converts each extra point of energy into ($f1+$AP/630) additional damage + float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx]; + damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple); + m_caster->SetPower(POWER_ENERGY,0); + } + // Rake + else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL) + { + damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); + } + // Swipe + else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL) + { + damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f); + } + // Starfire + else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL ) + { + Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i) + { + // Starfire Bonus (caster) + switch((*i)->GetModifier()->m_miscvalue) + { + case 5481: // Nordrassil Regalia - bonus + { + Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); + for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr) + { + // Moonfire or Insect Swarm (target debuff from any casters) + if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL ) + { + int32 mod = (*i)->GetModifier()->m_amount; + damage += damage*mod/100; + break; + } + } + break; + } + case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura + { + damage += (*i)->GetModifier()->m_amount; + break; + } + } + } + } + //Mangle Bonus for the initial damage of Lacerate and Rake + if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) || + (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246)) + { + Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) + if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID) + { + damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f); + break; + } + } + break; + } + case SPELLFAMILY_ROGUE: + { + // Envenom + if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL)) + { + // consume from stack dozes not more that have combo-points + if(uint32 combo = ((Player*)m_caster)->GetComboPoints()) + { + // count consumed deadly poison doses at target + uint32 doses = 0; + + // remove consumed poison doses + Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); + for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;) + { + // Deadly poison (only attacker applied) + if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) && + (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() ) + { + --combo; + ++doses; + + unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex()); + + itr = auras.begin(); + } + else + ++itr; + } + + damage *= doses; + damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses); + + // Eviscerate and Envenom Bonus Damage (item set effect) + if(m_caster->GetDummyAura(37169)) + damage += ((Player*)m_caster)->GetComboPoints()*40; + } + } + // Eviscerate + else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER) + { + if(uint32 combo = ((Player*)m_caster)->GetComboPoints()) + { + damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f); + + // Eviscerate and Envenom Bonus Damage (item set effect) + if(m_caster->GetDummyAura(37169)) + damage += combo*40; + } + } + break; + } + case SPELLFAMILY_HUNTER: + { + // Mongoose Bite + if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342) + { + damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2); + } + // Arcane Shot + else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0) + { + damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15); + } + // Steady Shot + else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) + { + int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE)); + damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f); + } + //Explosive Trap Effect + else if(m_spellInfo->SpellFamilyFlags & 0x00000004) + { + damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1); + } + break; + } + case SPELLFAMILY_PALADIN: + { + //Judgement of Vengeance + if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292) + { + uint32 stacks = 0; + Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); + for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) + if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID()) + ++stacks; + if(!stacks) + //No damage if the target isn't affected by this + damage = -1; + else + damage *= stacks; + } + break; + } + } + + if(damage >= 0) + { + uint32 finalDamage; + if(m_originalCaster) // m_caster only passive source of cast + finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); + else + finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); + + // post effects + switch(m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_WARRIOR: + { + // Bloodthirst + if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL) + { + uint32 BTAura = 0; + switch(m_spellInfo->Id) + { + case 23881: BTAura = 23885; break; + case 23892: BTAura = 23886; break; + case 23893: BTAura = 23887; break; + case 23894: BTAura = 23888; break; + case 25251: BTAura = 25252; break; + case 30335: BTAura = 30339; break; + default: + sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id); + break; + } + + if (BTAura) + m_caster->CastSpell(m_caster,BTAura,true); + } + break; + } + case SPELLFAMILY_PRIEST: + { + // Shadow Word: Death + if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive()) + // deals damage equal to damage done to caster if victim is not killed + m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false); + + break; + } + case SPELLFAMILY_PALADIN: + { + // Judgement of Blood + if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153) + { + int32 damagePoint = finalDamage * 33 / 100; + m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true); + } + break; + } + } + } + } +} + +void Spell::EffectDummy(uint32 i) +{ + if(!unitTarget && !gameObjTarget && !itemTarget) + return; + + // selection by spell family + switch(m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + // Gnomish Poultryizer trinket + switch(m_spellInfo->Id ) + { + case 8063: // Deviate Fish + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1,5)) + { + case 1: spell_id = 8064; break; // Sleepy + case 2: spell_id = 8065; break; // Invigorate + case 3: spell_id = 8066; break; // Shrink + case 4: spell_id = 8067; break; // Party Time! + case 5: spell_id = 8068; break; // Healthy Spirit + } + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 8213: // Savory Deviate Delight + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1,2)) + { + // Flip Out - ninja + case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break; + // Yaaarrrr - pirate + case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break; + } + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 8593: // Symbol of life (restore creature to life) + case 31225: // Shimmering Vessel (restore creature to life) + { + if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT) + return; + ((Creature*)unitTarget)->setDeathState(JUST_ALIVED); + return; + } + case 12162: // Deep wounds + case 12850: // (now good common check for this spells) + case 12868: + { + if(!unitTarget) + return; + + float damage; + // DW should benefit of attack power, damage percent mods etc. + // TODO: check if using offhand damage is correct and if it should be divided by 2 + if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK)) + damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2; + else + damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2; + + switch (m_spellInfo->Id) + { + case 12850: damage *= 0.2f; break; + case 12162: damage *= 0.4f; break; + case 12868: damage *= 0.6f; break; + default: + sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id); + return; + }; + + int32 deepWoundsDotBasePoints0 = int32(damage / 4); + m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL); + return; + } + case 12975: //Last Stand + { + int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3); + m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL); + return; + } + case 13120: // net-o-matic + { + if(!unitTarget) + return; + + uint32 spell_id = 0; + + uint32 roll = urand(0, 99); + + if(roll < 2) // 2% for 30 sec self root (off-like chance unknown) + spell_id = 16566; + else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown) + spell_id = 13119; + else // normal root + spell_id = 13099; + + m_caster->CastSpell(unitTarget,spell_id,true,NULL); + return; + } + case 13567: // Dummy Trigger + { + // can be used for different aura triggreing, so select by aura + if(!m_triggeredByAuraSpell || !unitTarget) + return; + + switch(m_triggeredByAuraSpell->Id) + { + case 26467: // Persistent Shield + m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true); + break; + default: + sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id); + break; + } + return; + } + case 14185: // Preparation Rogue + { + if(m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + + //immediately finishes the cooldown on certain Rogue abilities + const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + uint32 classspell = itr->first; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); + + if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL)) + { + ((Player*)m_caster)->RemoveSpellCooldown(classspell); + + WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); + data << uint32(classspell); + data << uint64(m_caster->GetGUID()); + ((Player*)m_caster)->GetSession()->SendPacket(&data); + } + } + return; + } + case 15998: // Capture Worg Pup + case 29435: // Capture Female Kaliri Hatchling + { + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + Creature* creatureTarget = (Creature*)unitTarget; + creatureTarget->setDeathState(JUST_DIED); + creatureTarget->RemoveCorpse(); + creatureTarget->SetHealth(0); // just for nice GM-mode view + return; + } + case 16589: // Noggenfogger Elixir + { + if(m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1,3)) + { + case 1: spell_id = 16595; break; + case 2: spell_id = 16593; break; + default:spell_id = 16591; break; + } + + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 17251: // Spirit Healer Res + { + if(!unitTarget || !m_originalCaster) + return; + + if(m_originalCaster->GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8); + data << unitTarget->GetGUID(); + ((Player*)m_originalCaster)->GetSession()->SendPacket( &data ); + } + return; + } + case 17271: // Test Fetid Skull + { + if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + + uint32 spell_id = roll_chance_i(50) ? 17269 : 17270; + + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 20577: // Cannibalize + if (unitTarget) + m_caster->CastSpell(m_caster,20578,false,NULL); + return; + case 23019: // Crystal Prison Dummy DND + { + if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet()) + return; + + Creature* creatureTarget = (Creature*)unitTarget; + if(creatureTarget->isPet()) + return; + + creatureTarget->setDeathState(JUST_DIED); + creatureTarget->RemoveCorpse(); + creatureTarget->SetHealth(0); // just for nice GM-mode view + + GameObject* pGameObj = new GameObject; + + Map *map = creatureTarget->GetMap(); + + if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, + creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), + creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) ) + { + delete pGameObj; + return; + } + + pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL)); + pGameObj->SetOwnerGUID(m_caster->GetGUID() ); + pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); + pGameObj->SetSpellId(m_spellInfo->Id); + + DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n"); + map->Add(pGameObj); + + WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); + data << uint64(pGameObj->GetGUID()); + m_caster->SendMessageToSet(&data,true); + + return; + } + case 23074: // Arc. Dragonling + if (!m_CastItem) return; + m_caster->CastSpell(m_caster,19804,true,m_CastItem); + return; + case 23075: // Mithril Mechanical Dragonling + if (!m_CastItem) return; + m_caster->CastSpell(m_caster,12749,true,m_CastItem); + return; + case 23076: // Mechanical Dragonling + if (!m_CastItem) return; + m_caster->CastSpell(m_caster,4073,true,m_CastItem); + return; + case 23133: // Gnomish Battle Chicken + if (!m_CastItem) return; + m_caster->CastSpell(m_caster,13166,true,m_CastItem); + return; + case 23448: // Ultrasafe Transporter: Gadgetzan - backfires + { + int32 r = irand(0, 119); + if ( r < 20 ) // 1/6 polymorph + m_caster->CastSpell(m_caster,23444,true); + else if ( r < 100 ) // 4/6 evil twin + m_caster->CastSpell(m_caster,23445,true); + else // 1/6 miss the target + m_caster->CastSpell(m_caster,36902,true); + return; + } + case 23453: // Ultrasafe Transporter: Gadgetzan + if ( roll_chance_i(50) ) // success + m_caster->CastSpell(m_caster,23441,true); + else // failure + m_caster->CastSpell(m_caster,23446,true); + return; + case 23645: // Hourglass Sand + m_caster->RemoveAurasDueToSpell(23170); + return; + case 23725: // Gift of Life (warrior bwl trinket) + m_caster->CastSpell(m_caster,23782,true); + m_caster->CastSpell(m_caster,23783,true); + return; + case 25860: // Reindeer Transformation + { + if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED)) + return; + + float flyspeed = m_caster->GetSpeedRate(MOVE_FLY); + float speed = m_caster->GetSpeedRate(MOVE_RUN); + + m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); + + //5 different spells used depending on mounted speed and if mount can fly or not + if (flyspeed >= 4.1f) + m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer + else if (flyspeed >= 3.8f) + m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer + else if (flyspeed >= 1.6f) + m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer + else if (speed >= 2.0f) + m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer + else + m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer + + return; + } + //case 26074: // Holiday Cheer + // return; -- implemented at client side + case 28006: // Arcane Cloaking + { + if( unitTarget->GetTypeId() == TYPEID_PLAYER ) + m_caster->CastSpell(unitTarget,29294,true); + return; + } + case 28730: // Arcane Torrent (Mana) + { + int32 count = 0; + Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i) + if ((*i)->GetId() == 28734) + ++count; + if (count) + { + m_caster->RemoveAurasDueToSpell(28734); + int32 bp = damage * count; + m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true); + } + return; + } + case 29200: // Purify Helboar Meat + { + if( m_caster->GetTypeId() != TYPEID_PLAYER ) + return; + + uint32 spell_id = roll_chance_i(50) ? 29277 : 29278; + + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 29858: // Soulshatter + if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster)) + m_caster->CastSpell(unitTarget,32835,true); + return; + case 30458: // Nigh Invulnerability + if (!m_CastItem) return; + if(roll_chance_i(86)) // success + m_caster->CastSpell(m_caster, 30456, true, m_CastItem); + else // backfire in 14% casts + m_caster->CastSpell(m_caster, 30457, true, m_CastItem); + return; + case 30507: // Poultryizer + if (!m_CastItem) return; + if(roll_chance_i(80)) // success + m_caster->CastSpell(unitTarget, 30501, true, m_CastItem); + else // backfire 20% + m_caster->CastSpell(unitTarget, 30504, true, m_CastItem); + return; + case 33060: // Make a Wish + { + if(m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + + switch(urand(1,5)) + { + case 1: spell_id = 33053; break; + case 2: spell_id = 33057; break; + case 3: spell_id = 33059; break; + case 4: spell_id = 33062; break; + case 5: spell_id = 33064; break; + } + + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 35745: + { + uint32 spell_id; + switch(m_caster->GetAreaId()) + { + case 3900: spell_id = 35743; break; + case 3742: spell_id = 35744; break; + default: return; + } + + m_caster->CastSpell(m_caster,spell_id,true); + return; + } + case 37674: // Chaos Blast + if(unitTarget) + m_caster->CastSpell(unitTarget,37675,true); + return; + case 44875: // Complete Raptor Capture + { + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + Creature* creatureTarget = (Creature*)unitTarget; + + creatureTarget->setDeathState(JUST_DIED); + creatureTarget->RemoveCorpse(); + creatureTarget->SetHealth(0); // just for nice GM-mode view + + //cast spell Raptor Capture Credit + m_caster->CastSpell(m_caster,42337,true,NULL); + return; + } + case 45030: // Impale Emissary + { + // Emissary of Hate Credit + m_caster->CastSpell(m_caster,45088,true); + return; + } + case 50243: // Teach Language + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // spell has a 1/3 chance to trigger one of the below + if(roll_chance_i(66)) + return; + if(((Player*)m_caster)->GetTeam() == ALLIANCE) + { + // 1000001 - gnomish binary + m_caster->CastSpell(m_caster, 50242, true); + } + else + { + // 01001000 - goblin binary + m_caster->CastSpell(m_caster, 50246, true); + } + + return; + } + case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite) + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround()) + bg->EventPlayerDroppedFlag((Player*)m_caster); + + m_caster->CastSpell(m_caster, 30452, true, NULL); + return; + } + } + + //All IconID Check in there + switch(m_spellInfo->SpellIconID) + { + // Berserking (troll racial traits) + case 1661: + { + uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100); + int32 melee_mod = 10; + if (healthPerc <= 40) + melee_mod = 30; + if (healthPerc < 100 && healthPerc > 40) + melee_mod = 10+(100-healthPerc)/3; + + int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1 + int32 hasteModBasePoints1 = (5-melee_mod); + int32 hasteModBasePoints2 = 5; + + // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway + m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true); + m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL); + return; + } + } + break; + case SPELLFAMILY_MAGE: + switch(m_spellInfo->Id ) + { + case 11958: // Cold Snap + { + if(m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + + // immediately finishes the cooldown on Frost spells + const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + if (itr->second->state == PLAYERSPELL_REMOVED) + continue; + + uint32 classspell = itr->first; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); + + if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && + (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) && + spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 ) + { + ((Player*)m_caster)->RemoveSpellCooldown(classspell); + + WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); + data << uint32(classspell); + data << uint64(m_caster->GetGUID()); + ((Player*)m_caster)->GetSession()->SendPacket(&data); + } + } + return; + } + } + break; + case SPELLFAMILY_WARRIOR: + // Charge + if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867) + { + int32 chargeBasePoints0 = damage; + m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true); + return; + } + // Execute + if(m_spellInfo->SpellFamilyFlags & 0x20000000) + { + if(!unitTarget) + return; + + int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]); + m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0); + m_caster->SetPower(POWER_RAGE,0); + return; + } + if(m_spellInfo->Id==21977) //Warrior's Wrath + { + if(!unitTarget) + return; + + m_caster->CastSpell(unitTarget,21887,true); // spell mod + return; + } + break; + case SPELLFAMILY_WARLOCK: + //Life Tap (only it have this with dummy effect) + if (m_spellInfo->SpellFamilyFlags == 0x40000) + { + float cost = m_currentBasePoints[0]+1; + + if(Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this); + + int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE); + + if(int32(m_caster->GetHealth()) > dmg) + { + // Shouldn't Appear in Combat Log + m_caster->ModifyHealth(-dmg); + + int32 mana = dmg; + + Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr) + { + // only Imp. Life Tap have this in combination with dummy aura + if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208) + mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100; + } + + m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL); + + // Mana Feed + int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster); + manaFeedVal = manaFeedVal * mana / 100; + if(manaFeedVal > 0) + m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL); + } + else + SendCastResult(SPELL_FAILED_FIZZLE); + return; + } + break; + case SPELLFAMILY_PRIEST: + switch(m_spellInfo->Id ) + { + case 28598: // Touch of Weakness triggered spell + { + if(!unitTarget || !m_triggeredByAuraSpell) + return; + + uint32 spellid = 0; + switch(m_triggeredByAuraSpell->Id) + { + case 2652: spellid = 2943; break; // Rank 1 + case 19261: spellid = 19249; break; // Rank 2 + case 19262: spellid = 19251; break; // Rank 3 + case 19264: spellid = 19252; break; // Rank 4 + case 19265: spellid = 19253; break; // Rank 5 + case 19266: spellid = 19254; break; // Rank 6 + case 25461: spellid = 25460; break; // Rank 7 + default: + sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id); + return; + } + m_caster->CastSpell(unitTarget, spellid, true, NULL); + return; + } + } + break; + case SPELLFAMILY_DRUID: + switch(m_spellInfo->Id ) + { + case 5420: // Tree of Life passive + { + // Tree of Life area effect + int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4); + m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL); + return; + } + } + break; + case SPELLFAMILY_ROGUE: + switch(m_spellInfo->Id ) + { + case 31231: // Cheat Death + { + m_caster->CastSpell(m_caster,45182,true); + return; + } + case 5938: // Shiv + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *pCaster = ((Player*)m_caster); + + Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK); + if(!item) + return; + + // all poison enchantments is temporary + uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT); + if(!enchant_id) + return; + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) + return; + + for (int s=0;s<3;s++) + { + if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) + continue; + + SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]); + if(!combatEntry || combatEntry->Dispel != DISPEL_POISON) + continue; + + m_caster->CastSpell(unitTarget, combatEntry, true, item); + } + + m_caster->CastSpell(unitTarget, 5940, true); + return; + } + } + break; + case SPELLFAMILY_HUNTER: + // Steady Shot + if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) + { + if( !unitTarget || !unitTarget->isAlive()) + return; + + bool found = false; + + // check dazed affect + Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); + for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter) + { + if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0) + { + found = true; + break; + } + } + + if(found) + m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); + return; + } + // Kill command + if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL) + { + if(m_caster->getClass()!=CLASS_HUNTER) + return; + + // clear hunter crit aura state + m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false); + + // additional damage from pet to pet target + Pet* pet = m_caster->GetPet(); + if(!pet || !pet->getVictim()) + return; + + uint32 spell_id = 0; + switch (m_spellInfo->Id) + { + case 34026: spell_id = 34027; break; // rank 1 + default: + sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id); + return; + } + + pet->CastSpell(pet->getVictim(), spell_id, true); + return; + } + + switch(m_spellInfo->Id) + { + case 23989: //Readiness talent + { + if(m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + + //immediately finishes the cooldown for hunter abilities + const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + uint32 classspell = itr->first; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); + + if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 ) + { + ((Player*)m_caster)->RemoveSpellCooldown(classspell); + + WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); + data << uint32(classspell); + data << uint64(m_caster->GetGUID()); + ((Player*)m_caster)->GetSession()->SendPacket(&data); + } + } + return; + } + case 37506: // Scatter Shot + { + if (m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + + // break Auto Shot and autohit + m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + m_caster->AttackStop(); + ((Player*)m_caster)->SendAttackSwingCancelAttack(); + return; + } + } + break; + case SPELLFAMILY_PALADIN: + switch(m_spellInfo->SpellIconID) + { + case 156: // Holy Shock + { + if(!unitTarget) + return; + + int hurt = 0; + int heal = 0; + + switch(m_spellInfo->Id) + { + case 20473: hurt = 25912; heal = 25914; break; + case 20929: hurt = 25911; heal = 25913; break; + case 20930: hurt = 25902; heal = 25903; break; + case 27174: hurt = 27176; heal = 27175; break; + case 33072: hurt = 33073; heal = 33074; break; + default: + sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id); + return; + } + + if(m_caster->IsFriendlyTo(unitTarget)) + m_caster->CastSpell(unitTarget, heal, true, 0); + else + m_caster->CastSpell(unitTarget, hurt, true, 0); + + return; + } + case 561: // Judgement of command + { + if(!unitTarget) + return; + + uint32 spell_id = m_currentBasePoints[i]+1; + SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id); + if(!spell_proto) + return; + + if( !unitTarget->hasUnitState(UNIT_STAT_STUNDED) && m_caster->GetTypeId()==TYPEID_PLAYER) + { + // decreased damage (/2) for non-stunned target. + SpellModifier *mod = new SpellModifier; + mod->op = SPELLMOD_DAMAGE; + mod->value = -50; + mod->type = SPELLMOD_PCT; + mod->spellId = m_spellInfo->Id; + mod->effectId = i; + mod->lastAffected = NULL; + mod->mask = 0x0000020000000000LL; + mod->charges = 0; + + ((Player*)m_caster)->AddSpellMod(mod, true); + m_caster->CastSpell(unitTarget,spell_proto,true,NULL); + // mod deleted + ((Player*)m_caster)->AddSpellMod(mod, false); + } + else + m_caster->CastSpell(unitTarget,spell_proto,true,NULL); + + return; + } + } + + switch(m_spellInfo->Id) + { + case 31789: // Righteous Defense (step 1) + { + // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target) + + // non-standard cast requirement check + if (!unitTarget || unitTarget->getAttackers().empty()) + { + // clear cooldown at fail + if(m_caster->GetTypeId()==TYPEID_PLAYER) + { + ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id); + + WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); + data << uint32(m_spellInfo->Id); + data << uint64(m_caster->GetGUID()); + ((Player*)m_caster)->GetSession()->SendPacket(&data); + } + + SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT); + return; + } + + // Righteous Defense (step 2) (in old version 31980 dummy effect) + // Clear targets for eff 1 + for(std::list::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) + ihit->effectMask &= ~(1<<1); + + // not empty (checked) + Unit::AttackerSet const& attackers = unitTarget->getAttackers(); + + // chance to be selected from list + float chance = 100.0f/attackers.size(); + uint32 count=0; + for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr) + { + if(!roll_chance_f(chance)) + continue; + ++count; + AddUnitTarget((*aItr), 1); + } + + // now let next effect cast spell at each target. + return; + } + case 37877: // Blessing of Faith + { + if(!unitTarget) + return; + + uint32 spell_id = 0; + switch(unitTarget->getClass()) + { + case CLASS_DRUID: spell_id = 37878; break; + case CLASS_PALADIN: spell_id = 37879; break; + case CLASS_PRIEST: spell_id = 37880; break; + case CLASS_SHAMAN: spell_id = 37881; break; + default: return; // ignore for not healing classes + } + + m_caster->CastSpell(m_caster,spell_id,true); + return; + } + } + break; + case SPELLFAMILY_SHAMAN: + //Shaman Rockbiter Weapon + if (m_spellInfo->SpellFamilyFlags == 0x400000) + { + uint32 spell_id = 0; + switch(m_spellInfo->Id) + { + case 8017: spell_id = 36494; break; // Rank 1 + case 8018: spell_id = 36750; break; // Rank 2 + case 8019: spell_id = 36755; break; // Rank 3 + case 10399: spell_id = 36759; break; // Rank 4 + case 16314: spell_id = 36763; break; // Rank 5 + case 16315: spell_id = 36766; break; // Rank 6 + case 16316: spell_id = 36771; break; // Rank 7 + case 25479: spell_id = 36775; break; // Rank 8 + case 25485: spell_id = 36499; break; // Rank 9 + default: + sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id); + return; + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id ); + + if(!spellInfo) + { + sLog.outError("WORLD: unknown spell id %i\n", spell_id); + return; + } + + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i) + { + if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i))) + { + if(item->IsFitToSpellRequirements(m_spellInfo)) + { + Spell *spell = new Spell(m_caster, spellInfo, true); + + // enchanting spell selected by calculated damage-per-sec in enchanting effect + // at calculation applied affect from Elemental Weapons talent + // real enchantment damage-1 + spell->m_currentBasePoints[1] = damage-1; + + SpellCastTargets targets; + targets.setItemTarget( item ); + spell->prepare(&targets); + } + } + } + return; + } + + if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect + { + if(!unitTarget || unitTarget->getPowerType() != POWER_MANA) + return; + + // Regenerate 6% of Total Mana Every 3 secs + int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100; + m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID); + return; + } + + break; + } + + // pet auras + if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id)) + { + m_caster->AddPetAura(petSpell); + return; + } +} + +void Spell::EffectTriggerSpellWithValue(uint32 i) +{ + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); + + if(!spellInfo) + { + sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id); + return; + } + + int32 bp = damage; + m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID); +} + +void Spell::EffectTriggerRitualOfSummoning(uint32 i) +{ + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; + SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); + + if(!spellInfo) + { + sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); + return; + } + + finish(); + Spell *spell = new Spell(m_caster, spellInfo, true); + + SpellCastTargets targets; + targets.setUnitTarget( unitTarget); + spell->prepare(&targets); + + m_caster->SetCurrentCastedSpell(spell); + spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]); + +} + +void Spell::EffectForceCast(uint32 i) +{ + if( !unitTarget ) + return; + + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); + + if(!spellInfo) + { + sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); + return; + } + + unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID); +} + +void Spell::EffectTriggerSpell(uint32 i) +{ + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; + + // special cases + switch(triggered_spell_id) + { + // Vanish + case 18461: + { + m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); + m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED); + m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED); + + // if this spell is given to NPC it must handle rest by it's own AI + if ( m_caster->GetTypeId() != TYPEID_PLAYER ) + return; + + // get highest rank of the Stealth spell + uint32 spellId = 0; + const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + // only highest rank is shown in spell book, so simply check if shown in spell book + if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED) + continue; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + if (!spellInfo) + continue; + + if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH) + { + spellId = spellInfo->Id; + break; + } + } + + // no Stealth spell found + if (!spellId) + return; + + // reset cooldown on it if needed + if(((Player*)m_caster)->HasSpellCooldown(spellId)) + ((Player*)m_caster)->RemoveSpellCooldown(spellId); + + m_caster->CastSpell(m_caster, spellId, true); + return; + } + // just skip + case 23770: // Sayge's Dark Fortune of * + // not exist, common cooldown can be implemented in scripts if need. + return; + // Brittle Armor - (need add max stack of 24575 Brittle Armor) + case 29284: + { + const SpellEntry *spell = sSpellStore.LookupEntry(24575); + if (!spell) + return; + + for (int i=0; i < spell->StackAmount; ++i) + m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID); + return; + } + // Mercurial Shield - (need add max stack of 26464 Mercurial Shield) + case 29286: + { + const SpellEntry *spell = sSpellStore.LookupEntry(26464); + if (!spell) + return; + + for (int i=0; i < spell->StackAmount; ++i) + m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID); + return; + } + // Righteous Defense + case 31980: + { + m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID); + return; + } + // Cloak of Shadows + case 35729 : + { + Unit::AuraMap& Auras = m_caster->GetAuras(); + for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter) + { + // remove all harmful spells on you... + if( // ignore positive and passive auras + !iter->second->IsPositive() && !iter->second->IsPassive() && + // ignore physical auras + (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 && + // ignore immunity persistent spells + !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) ) + { + m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id); + iter = Auras.begin(); + } + } + return; + } + // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet + case 41967: + { + if (Unit *pet = m_caster->GetPet()) + pet->CastSpell(pet, 28305, true); + return; + } + } + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); + + if(!spellInfo) + { + sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); + return; + } + + // some triggered spells require specific equipment + if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER) + { + // main hand weapon required + if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND) + { + Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK); + + // skip spell if no weapon in slot or broken + if(!item || item->IsBroken() ) + return; + + // skip spell if weapon not fit to triggered spell + if(!item->IsFitToSpellRequirements(spellInfo)) + return; + } + + // offhand hand weapon required + if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND) + { + Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK); + + // skip spell if no weapon in slot or broken + if(!item || item->IsBroken() ) + return; + + // skip spell if weapon not fit to triggered spell + if(!item->IsFitToSpellRequirements(spellInfo)) + return; + } + } + + // some triggered spells must be casted instantly (for example, if next effect case instant kill caster) + bool instant = false; + for(uint32 j = i+1; j < 3; ++j) + { + if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF) + { + instant = true; + break; + } + } + + if(instant) + { + if (unitTarget) + m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID); + } + else + m_TriggerSpells.push_back(spellInfo); +} + +void Spell::EffectTriggerMissileSpell(uint32 effect_idx) +{ + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx]; + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); + + if(!spellInfo) + { + sLog.outError("EffectTriggerMissileSpell of spell %u: triggering unknown spell id %effect_idx", m_spellInfo->Id,triggered_spell_id); + return; + } + + if (m_CastItem) + DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); + + Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID ); + + SpellCastTargets targets; + targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ); + spell->m_CastItem = m_CastItem; + spell->prepare(&targets, NULL); +} + +void Spell::EffectTeleportUnits(uint32 i) +{ + if(!unitTarget || unitTarget->isInFlight()) + return; + + switch (m_spellInfo->EffectImplicitTargetB[i]) + { + case TARGET_INNKEEPER_COORDINATES: + { + // Only players can teleport to innkeeper + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + ((Player*)unitTarget)->TeleportTo(((Player*)unitTarget)->m_homebindMapId,((Player*)unitTarget)->m_homebindX,((Player*)unitTarget)->m_homebindY,((Player*)unitTarget)->m_homebindZ,unitTarget->GetOrientation(),unitTarget==m_caster ? TELE_TO_SPELL : 0); + return; + } + case TARGET_TABLE_X_Y_Z_COORDINATES: + { + // TODO: Only players can teleport? + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); + if(!st) + { + sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id ); + return; + } + ((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0); + break; + } + case TARGET_BEHIND_VICTIM: + { + // Get selected target for player (or victim for units) + Unit *pTarget = NULL; + if(m_caster->GetTypeId() == TYPEID_PLAYER) + pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); + else + pTarget = m_caster->getVictim(); + // No target present - return + if (!pTarget) + return; + // Init dest coordinates + uint32 mapid = m_caster->GetMapId(); + float x = m_targets.m_destX; + float y = m_targets.m_destY; + float z = m_targets.m_destZ; + float orientation = pTarget->GetOrientation(); + // Teleport + if(unitTarget->GetTypeId() == TYPEID_PLAYER) + ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); + else + { + MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation); + WorldPacket data; + unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation); + unitTarget->SendMessageToSet(&data, false); + } + return; + } + default: + { + // If not exist data for dest location - return + if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) + { + sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id ); + return; + } + // Init dest coordinates + uint32 mapid = m_caster->GetMapId(); + float x = m_targets.m_destX; + float y = m_targets.m_destY; + float z = m_targets.m_destZ; + float orientation = unitTarget->GetOrientation(); + // Teleport + if(unitTarget->GetTypeId() == TYPEID_PLAYER) + ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); + else + { + MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation); + WorldPacket data; + unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation); + unitTarget->SendMessageToSet(&data, false); + } + return; + } + } + + // post effects for TARGET_TABLE_X_Y_Z_COORDINATES + switch ( m_spellInfo->Id ) + { + // Dimensional Ripper - Everlook + case 23442: + { + int32 r = irand(0, 119); + if ( r >= 70 ) // 7/12 success + { + if ( r < 100 ) // 4/12 evil twin + m_caster->CastSpell(m_caster,23445,true); + else // 1/12 fire + m_caster->CastSpell(m_caster,23449,true); + } + return; + } + // Ultrasafe Transporter: Toshley's Station + case 36941: + { + if ( roll_chance_i(50) ) // 50% success + { + int32 rand_eff = urand(1,7); + switch ( rand_eff ) + { + case 1: + // soul split - evil + m_caster->CastSpell(m_caster,36900,true); + break; + case 2: + // soul split - good + m_caster->CastSpell(m_caster,36901,true); + break; + case 3: + // Increase the size + m_caster->CastSpell(m_caster,36895,true); + break; + case 4: + // Decrease the size + m_caster->CastSpell(m_caster,36893,true); + break; + case 5: + // Transform + { + if (((Player*)m_caster)->GetTeam() == ALLIANCE ) + m_caster->CastSpell(m_caster,36897,true); + else + m_caster->CastSpell(m_caster,36899,true); + break; + } + case 6: + // chicken + m_caster->CastSpell(m_caster,36940,true); + break; + case 7: + // evil twin + m_caster->CastSpell(m_caster,23445,true); + break; + } + } + return; + } + // Dimensional Ripper - Area 52 + case 36890: + { + if ( roll_chance_i(50) ) // 50% success + { + int32 rand_eff = urand(1,4); + switch ( rand_eff ) + { + case 1: + // soul split - evil + m_caster->CastSpell(m_caster,36900,true); + break; + case 2: + // soul split - good + m_caster->CastSpell(m_caster,36901,true); + break; + case 3: + // Increase the size + m_caster->CastSpell(m_caster,36895,true); + break; + case 4: + // Transform + { + if (((Player*)m_caster)->GetTeam() == ALLIANCE ) + m_caster->CastSpell(m_caster,36897,true); + else + m_caster->CastSpell(m_caster,36899,true); + break; + } + } + } + return; + } + } +} + +void Spell::EffectApplyAura(uint32 i) +{ + if(!unitTarget) + return; + + SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE]; + for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr) + if(itr->type == m_spellInfo->EffectApplyAuraName[i]) + return; + + // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load) + if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 && + (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) ) + return; + + Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster; + if(!caster) + return; + + sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]); + + Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem); + + // Now Reduce spell duration using data received at spell hit + int32 duration = Aur->GetAuraMaxDuration(); + unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel); + Aur->setDiminishGroup(m_diminishGroup); + + // if Aura removed and deleted, do not continue. + if(duration== 0 && !(Aur->IsPermanent())) + { + delete Aur; + return; + } + + if(duration != Aur->GetAuraMaxDuration()) + { + Aur->SetAuraMaxDuration(duration); + Aur->SetAuraDuration(duration); + } + + bool added = unitTarget->AddAura(Aur); + + // Aura not added and deleted in AddAura call; + if (!added) + return; + + // found crash at character loading, broken pointer to Aur... + // Aur was deleted in AddAura()... + if(!Aur) + return; + + // TODO Make a way so it works for every related spell! + if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players + { + uint32 spellId = 0; + if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL) + spellId = 6788; // Weakened Soul + else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE) + spellId = 25771; // Forbearance + else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA) + spellId = 41425; // Hypothermia + else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages + spellId = 11196; // Recently Bandaged + else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) ) + spellId = 23230; // Blood Fury - Healing Reduction + + SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId); + if (AdditionalSpellInfo) + { + // applied at target by target + Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0); + unitTarget->AddAura(AdditionalAura); + sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]); + } + } + + // Prayer of Mending (jump animation), we need formal caster instead original for correct animation + if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL)) + m_caster->CastSpell(unitTarget,41637,true,NULL,Aur); +} + +void Spell::EffectUnlearnSpecialization( uint32 i ) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)unitTarget; + uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i]; + + _player->removeSpell(spellToUnlearn); + + sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() ); +} + +void Spell::EffectPowerDrain(uint32 i) +{ + if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return; + + Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]); + + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + if(unitTarget->getPowerType() != drain_power) + return; + if(damage < 0) + return; + + uint32 curPower = unitTarget->GetPower(drain_power); + + //add spell damage bonus + damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE); + + // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) + uint32 power = damage; + if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER ) + power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power); + + int32 new_damage; + if(curPower < power) + new_damage = curPower; + else + new_damage = power; + + unitTarget->ModifyPower(drain_power,-new_damage); + + if(drain_power == POWER_MANA) + { + float manaMultiplier = m_spellInfo->EffectMultipleValue[i]; + if(manaMultiplier==0) + manaMultiplier = 1; + + if(Player *modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier); + + int32 gain = int32(new_damage*manaMultiplier); + + m_caster->ModifyPower(POWER_MANA,gain); + //send log + m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA,false); + } +} + +void Spell::EffectSendEvent(uint32 EffectIndex) +{ + if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround()) + { + BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); + if(bg && bg->GetStatus() == STATUS_IN_PROGRESS) + { + switch(m_spellInfo->Id) + { + case 23333: // Pickup Horde Flag + /*do not uncomment . + if(bg->GetTypeID()==BATTLEGROUND_WS) + bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); + sLog.outDebug("Send Event Horde Flag Picked Up"); + break; + /* not used : + case 23334: // Drop Horde Flag + if(bg->GetTypeID()==BATTLEGROUND_WS) + bg->EventPlayerDroppedFlag((Player*)m_caster); + sLog.outDebug("Drop Horde Flag"); + break; + */ + case 23335: // Pickup Alliance Flag + /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion + if(bg->GetTypeID()==BATTLEGROUND_WS) + bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); + sLog.outDebug("Send Event Alliance Flag Picked Up"); + break; + /* not used : + case 23336: // Drop Alliance Flag + if(bg->GetTypeID()==BATTLEGROUND_WS) + bg->EventPlayerDroppedFlag((Player*)m_caster); + sLog.outDebug("Drop Alliance Flag"); + break; + case 23385: // Alliance Flag Returns + if(bg->GetTypeID()==BATTLEGROUND_WS) + bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); + sLog.outDebug("Alliance Flag Returned"); + break; + case 23386: // Horde Flag Returns + if(bg->GetTypeID()==BATTLEGROUND_WS) + bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); + sLog.outDebug("Horde Flag Returned"); + break;*/ + case 34976: + /* + if(bg->GetTypeID()==BATTLEGROUND_EY) + bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); + */ + break; + default: + sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id); + break; + } + } + } + sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id); + sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject); +} + +void Spell::EffectPowerBurn(uint32 i) +{ + if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return; + + Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]); + + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + if(unitTarget->getPowerType()!=powertype) + return; + if(damage < 0) + return; + + int32 curPower = int32(unitTarget->GetPower(powertype)); + + // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) + uint32 power = damage; + if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER ) + power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power); + + int32 new_damage = (curPower < power) ? curPower : power; + + unitTarget->ModifyPower(powertype,-new_damage); + float multiplier = m_spellInfo->EffectMultipleValue[i]; + + if(Player *modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); + + new_damage = int32(new_damage*multiplier); + m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true); +} + +void Spell::EffectHeal( uint32 /*i*/ ) +{ + if( unitTarget && unitTarget->isAlive() && damage >= 0) + { + // Try to get original caster + Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; + + // Skip if m_originalCaster not available + if (!caster) + return; + + int32 addhealth = damage; + + // Vessel of the Naaru (Vial of the Sunwell trinket) + if (m_spellInfo->Id == 45064) + { + // Amount of heal - depends from stacked Holy Energy + int damageAmount = 0; + Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) + if((*i)->GetId() == 45062) + damageAmount+=(*i)->GetModifier()->m_amount; + if (damageAmount) + m_caster->RemoveAurasDueToSpell(45062); + + addhealth += damageAmount; + } + // Swiftmend - consumes Regrowth or Rejuvenation + else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND)) + { + Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); + // find most short by duration + Aura *targetAura = NULL; + for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) + { + if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID + && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) ) + { + if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration()) + targetAura = *i; + } + } + + if(!targetAura) + { + sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID()); + return; + } + int idx = 0; + while(idx < 3) + { + if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL) + break; + idx++; + } + + int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget); + int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx]; + unitTarget->RemoveAurasDueToSpell(targetAura->GetId()); + + addhealth += tickheal * tickcount; + } + else + addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget); + + bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType); + if (crit) + addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget); + caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit); + + int32 gain = unitTarget->ModifyHealth( int32(addhealth) ); + unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); + + if(caster->GetTypeId()==TYPEID_PLAYER) + if(BattleGround *bg = ((Player*)caster)->GetBattleGround()) + bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain); + + // ignore item heals + if(m_CastItem) + return; + + uint32 procHealer = PROC_FLAG_HEAL; + if (crit) + procHealer |= PROC_FLAG_CRIT_HEAL; + + m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell); + } +} + +void Spell::EffectHealPct( uint32 /*i*/ ) +{ + if( unitTarget && unitTarget->isAlive() && damage >= 0) + { + // Try to get original caster + Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; + + // Skip if m_originalCaster not available + if (!caster) + return; + + uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100; + caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false); + + int32 gain = unitTarget->ModifyHealth( int32(addhealth) ); + unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); + + if(caster->GetTypeId()==TYPEID_PLAYER) + if(BattleGround *bg = ((Player*)caster)->GetBattleGround()) + bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain); + } +} + +void Spell::EffectHealMechanical( uint32 /*i*/ ) +{ + // Mechanic creature type should be correctly checked by targetCreatureType field + if( unitTarget && unitTarget->isAlive() && damage >= 0) + { + // Try to get original caster + Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; + + // Skip if m_originalCaster not available + if (!caster) + return; + + uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget); + caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false); + unitTarget->ModifyHealth( int32(damage) ); + } +} + +void Spell::EffectHealthLeech(uint32 i) +{ + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + + if(damage < 0) + return; + + sLog.outDebug("HealthLeech :%i", damage); + + float multiplier = m_spellInfo->EffectMultipleValue[i]; + + if(Player *modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); + + int32 new_damage = int32(damage*multiplier); + uint32 curHealth = unitTarget->GetHealth(); + new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true); + if(curHealth < new_damage) + new_damage = curHealth; + + if(m_caster->isAlive()) + { + new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster); + + m_caster->ModifyHealth(new_damage); + + if(m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage)); + } +} + +void Spell::DoCreateItem(uint32 i, uint32 itemtype) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player* player = (Player*)unitTarget; + + uint32 newitemid = itemtype; + ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid ); + if(!pProto) + { + player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); + return; + } + + uint32 num_to_add; + + // TODO: maybe all this can be replaced by using correct calculated `damage` value + if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE) + { + int32 basePoints = m_currentBasePoints[i]; + int32 randomPoints = m_spellInfo->EffectDieSides[i]; + if (randomPoints) + num_to_add = basePoints + irand(1, randomPoints); + else + num_to_add = basePoints + 1; + } + else if (pProto->MaxCount == 1) + num_to_add = 1; + else if(player->getLevel() >= m_spellInfo->spellLevel) + { + int32 basePoints = m_currentBasePoints[i]; + float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i]; + num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel); + } + else + num_to_add = 2; + + if (num_to_add < 1) + num_to_add = 1; + if (num_to_add > pProto->Stackable) + num_to_add = pProto->Stackable; + + // init items_count to 1, since 1 item will be created regardless of specialization + int items_count=1; + // the chance to create additional items + float additionalCreateChance=0.0f; + // the maximum number of created additional items + uint8 additionalMaxNum=0; + // get the chance and maximum number for creating extra items + if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) ) + { + // roll with this chance till we roll not to create or we create the max num + while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum ) + ++items_count; + } + + // really will be created more items + num_to_add *= items_count; + + // can the player store the new item? + ItemPosCountVec dest; + uint32 no_space = 0; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space ); + if( msg != EQUIP_ERR_OK ) + { + // convert to possible store amount + if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS ) + num_to_add -= no_space; + else + { + // if not created by another reason from full inventory or unique items amount limitation + player->SendEquipError( msg, NULL, NULL ); + return; + } + } + + if(num_to_add) + { + // create the new item and store it + Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid)); + + // was it successful? return error if not + if(!pItem) + { + player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); + return; + } + + // set the "Crafted by ..." property of the item + if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST) + pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow()); + + // send info to the client + if(pItem) + player->SendNewItem(pItem, num_to_add, true, true); + + // we succeeded in creating at least one item, so a levelup is possible + player->UpdateCraftSkill(m_spellInfo->Id); + } + + // for battleground marks send by mail if not add all expected + if(no_space > 0 ) + { + BattleGroundTypeId bgType; + switch(m_spellInfo->Id) + { + case SPELL_AV_MARK_WINNER: + case SPELL_AV_MARK_LOSER: + bgType = BATTLEGROUND_AV; + break; + case SPELL_WS_MARK_WINNER: + case SPELL_WS_MARK_LOSER: + bgType = BATTLEGROUND_WS; + break; + case SPELL_AB_MARK_WINNER: + case SPELL_AB_MARK_LOSER: + bgType = BATTLEGROUND_AB; + break; + default: + return; + } + + if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType)) + bg->SendRewardMarkByMail(player,newitemid,no_space); + } +} + +void Spell::EffectCreateItem(uint32 i) +{ + DoCreateItem(i,m_spellInfo->EffectItemType[i]); +} + +void Spell::EffectPersistentAA(uint32 i) +{ + float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + + if(Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius); + + int32 duration = GetSpellDuration(m_spellInfo); + DynamicObject* dynObj = new DynamicObject; + if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius)) + { + delete dynObj; + return; + } + dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65); + dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003); + dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee); + m_caster->AddDynObject(dynObj); + MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj); +} + +void Spell::EffectEnergize(uint32 i) +{ + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + + if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return; + + // Some level depends spells + int multipler = 0; + int level_diff = 0; + switch (m_spellInfo->Id) + { + // Restore Energy + case 9512: + level_diff = m_caster->getLevel() - 40; + multipler = 2; + break; + // Blood Fury + case 24571: + level_diff = m_caster->getLevel() - 60; + multipler = 10; + break; + // Burst of Energy + case 24532: + level_diff = m_caster->getLevel() - 60; + multipler = 4; + break; + default: + break; + } + + if (level_diff > 0) + damage -= multipler * level_diff; + + if(damage < 0) + return; + + Powers power = Powers(m_spellInfo->EffectMiscValue[i]); + + if(unitTarget->GetMaxPower(power) == 0) + return; + + unitTarget->ModifyPower(power,damage); + m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power); + + // Mad Alchemist's Potion + if (m_spellInfo->Id == 45051) + { + // find elixirs on target + uint32 elixir_mask = 0; + Unit::AuraMap& Auras = unitTarget->GetAuras(); + for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr) + { + uint32 spell_id = itr->second->GetId(); + if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id)) + elixir_mask |= mask; + } + + // get available elixir mask any not active type from battle/guardian (and flask if no any) + elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK; + + // get all available elixirs by mask and spell level + std::vector elixirs; + SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap(); + for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr) + { + if (itr->second & elixir_mask) + { + if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK)) + continue; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel())) + continue; + + elixirs.push_back(itr->first); + } + } + + if (!elixirs.empty()) + { + // cast random elixir on target + uint32 rand_spell = urand(0,elixirs.size()-1); + m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem); + } + } +} + +void Spell::EffectEnergisePct(uint32 i) +{ + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + + if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return; + + Powers power = Powers(m_spellInfo->EffectMiscValue[i]); + + uint32 maxPower = unitTarget->GetMaxPower(power); + if(maxPower == 0) + return; + + uint32 gain = damage * maxPower / 100; + unitTarget->ModifyPower(power, gain); + m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power); +} + +void Spell::SendLoot(uint64 guid, LootType loottype) +{ + Player* player = (Player*)m_caster; + if (!player) + return; + + if (gameObjTarget) + { + switch (gameObjTarget->GetGoType()) + { + case GAMEOBJECT_TYPE_DOOR: + case GAMEOBJECT_TYPE_BUTTON: + gameObjTarget->UseDoorOrButton(); + sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); + return; + + case GAMEOBJECT_TYPE_QUESTGIVER: + // start or end quest + player->PrepareQuestMenu(guid); + player->SendPreparedQuest(guid); + return; + + case GAMEOBJECT_TYPE_SPELL_FOCUS: + // triggering linked GO + if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId) + gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); + return; + + case GAMEOBJECT_TYPE_GOOBER: + // goober_scripts can be triggered if the player don't have the quest + if (gameObjTarget->GetGOInfo()->goober.eventId) + { + sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow()); + sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget); + } + + // cast goober spell + if (gameObjTarget->GetGOInfo()->goober.questId) + ///Quest require to be active for GO using + if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE) + return; + + gameObjTarget->AddUniqueUse(player); + gameObjTarget->SetLootState(GO_JUST_DEACTIVATED); + + //TODO? Objective counting called without spell check but with quest objective check + // if send spell id then this line will duplicate to spell casting call (double counting) + // So we or have this line and not required in quest_template have reqSpellIdN + // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases. + player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0); + + // triggering linked GO + if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId) + gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); + + return; + + case GAMEOBJECT_TYPE_CHEST: + // TODO: possible must be moved to loot release (in different from linked triggering) + if (gameObjTarget->GetGOInfo()->chest.eventId) + { + sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow()); + sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget); + } + + // triggering linked GO + if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId) + gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); + + // Don't return, let loots been taken + } + } + + // Send loot + player->SendLoot(guid, loottype); +} + +void Spell::EffectOpenLock(uint32 /*i*/) +{ + if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) + { + sLog.outDebug( "WORLD: Open Lock - No Player Caster!"); + return; + } + + Player* player = (Player*)m_caster; + + LootType loottype = LOOT_CORPSE; + uint32 lockId = 0; + uint64 guid = 0; + + // Get lockId + if(gameObjTarget) + { + GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo(); + // Arathi Basin banner opening ! + if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune || + goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK ) + { + if(BattleGround *bg = player->GetBattleGround())// in battleground + { + if( !player->IsMounted() && // not mounted + !player->HasStealthAura() && // not stealthed + !player->HasInvisibilityAura() && // not invisible + player->isAlive() ) // live player + { + // check if it's correct bg + if(bg && bg->GetTypeID() == BATTLEGROUND_AB) + bg->EventPlayerClickedOnFlag(player, gameObjTarget); + + return; + } + } + } + else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND) + { + if(BattleGround *bg = player->GetBattleGround()) + if(bg->GetTypeID() == BATTLEGROUND_EY) + bg->EventPlayerClickedOnFlag(player, gameObjTarget); + return; + } + lockId = gameObjTarget->GetLockId(); + guid = gameObjTarget->GetGUID(); + } + else if(itemTarget) + { + lockId = itemTarget->GetProto()->LockID; + guid = itemTarget->GetGUID(); + } + else + { + sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!"); + return; + } + + if(!lockId) // possible case for GO and maybe for items. + { + SendLoot(guid, loottype); + return; + } + + // Get LockInfo + LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); + + if (!lockInfo) + { + sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!", + (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId); + SendCastResult(SPELL_FAILED_BAD_TARGETS); + return; + } + + // check key + for(int i = 0; i < 5; ++i) + { + // type==1 This means lockInfo->key[i] is an item + if(lockInfo->keytype[i]==LOCK_KEY_ITEM && lockInfo->key[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[i]) + { + SendLoot(guid, loottype); + return; + } + } + + uint32 SkillId = 0; + // Check and skill-up skill + if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL ) + SkillId = m_spellInfo->EffectMiscValue[1]; + // pickpocketing spells + else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK ) + SkillId = SKILL_LOCKPICKING; + + // skill bonus provided by casting spell (mostly item spells) + uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1); + + uint32 reqSkillValue = lockInfo->requiredminingskill; + + if(lockInfo->requiredlockskill) // required pick lock skill applying + { + if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?) + { + SendCastResult(SPELL_FAILED_FIZZLE); + return; + } + + reqSkillValue = lockInfo->requiredlockskill; + } + else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target + { + SendCastResult(SPELL_FAILED_BAD_TARGETS); + return; + } + + if ( SkillId ) + { + loottype = LOOT_SKINNING; + if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue ) + { + SendCastResult(SPELL_FAILED_LOW_CASTLEVEL); + return; + } + + // update skill if really known + uint32 SkillValue = player->GetPureSkillValue(SkillId); + if(SkillValue) // non only item base skill + { + if(gameObjTarget) + { + // Allow one skill-up until respawned + if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) && + player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) ) + gameObjTarget->AddToSkillupList( player->GetGUIDLow() ); + } + else if(itemTarget) + { + // Do one skill-up + uint32 SkillValue = player->GetPureSkillValue(SkillId); + player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue); + } + } + } + + SendLoot(guid, loottype); +} + +void Spell::EffectSummonChangeItem(uint32 i) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *player = (Player*)m_caster; + + // applied only to using item + if(!m_CastItem) + return; + + // ... only to item in own inventory/bank/equip_slot + if(m_CastItem->GetOwnerGUID()!=player->GetGUID()) + return; + + uint32 newitemid = m_spellInfo->EffectItemType[i]; + if(!newitemid) + return; + + uint16 pos = m_CastItem->GetPos(); + + Item *pNewItem = Item::CreateItem( newitemid, 1, player); + if( !pNewItem ) + return; + + for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i) + { + if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i))) + pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i))); + } + + if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)) + { + double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); + player->DurabilityLoss(pNewItem, loosePercent); + } + + if( player->IsInventoryPos( pos ) ) + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true ); + if( msg == EQUIP_ERR_OK ) + { + player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true); + + // prevent crash at access and unexpected charges counting with item update queue corrupt + if(m_CastItem==m_targets.getItemTarget()) + m_targets.setItemTarget(NULL); + + m_CastItem = NULL; + + player->StoreItem( dest, pNewItem, true); + return; + } + } + else if( player->IsBankPos ( pos ) ) + { + ItemPosCountVec dest; + uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true ); + if( msg == EQUIP_ERR_OK ) + { + player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true); + + // prevent crash at access and unexpected charges counting with item update queue corrupt + if(m_CastItem==m_targets.getItemTarget()) + m_targets.setItemTarget(NULL); + + m_CastItem = NULL; + + player->BankItem( dest, pNewItem, true); + return; + } + } + else if( player->IsEquipmentPos ( pos ) ) + { + uint16 dest; + uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true ); + if( msg == EQUIP_ERR_OK ) + { + player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true); + + // prevent crash at access and unexpected charges counting with item update queue corrupt + if(m_CastItem==m_targets.getItemTarget()) + m_targets.setItemTarget(NULL); + + m_CastItem = NULL; + + player->EquipItem( dest, pNewItem, true); + player->AutoUnequipOffhandIfNeed(); + return; + } + } + + // fail + delete pNewItem; +} + +void Spell::EffectOpenSecretSafe(uint32 i) +{ + EffectOpenLock(i); //no difference for now +} + +void Spell::EffectProficiency(uint32 /*i*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + Player *p_target = (Player*)unitTarget; + + uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask; + if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask)) + { + p_target->AddWeaponProficiency(subClassMask); + p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency()); + } + if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask)) + { + p_target->AddArmorProficiency(subClassMask); + p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency()); + } +} + +void Spell::EffectApplyAreaAura(uint32 i) +{ + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + + AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem); + unitTarget->AddAura(Aur); +} + +void Spell::EffectSummonType(uint32 i) +{ + switch(m_spellInfo->EffectMiscValueB[i]) + { + case SUMMON_TYPE_GUARDIAN: + case SUMMON_TYPE_POSESSED: + case SUMMON_TYPE_POSESSED2: + EffectSummonGuardian(i); + break; + case SUMMON_TYPE_WILD: + EffectSummonWild(i); + break; + case SUMMON_TYPE_DEMON: + EffectSummonDemon(i); + break; + case SUMMON_TYPE_SUMMON: + EffectSummon(i); + break; + case SUMMON_TYPE_CRITTER: + case SUMMON_TYPE_CRITTER2: + EffectSummonCritter(i); + break; + case SUMMON_TYPE_TOTEM_SLOT1: + case SUMMON_TYPE_TOTEM_SLOT2: + case SUMMON_TYPE_TOTEM_SLOT3: + case SUMMON_TYPE_TOTEM_SLOT4: + case SUMMON_TYPE_TOTEM: + EffectSummonTotem(i); + break; + case SUMMON_TYPE_UNKNOWN1: + case SUMMON_TYPE_UNKNOWN2: + case SUMMON_TYPE_UNKNOWN3: + case SUMMON_TYPE_UNKNOWN4: + case SUMMON_TYPE_UNKNOWN5: + case SUMMON_TYPE_UNKNOWN6: + break; + default: + sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]); + break; + } +} + +void Spell::EffectSummon(uint32 i) +{ + if(m_caster->GetPetGUID()) + return; + + if(!unitTarget) + return; + uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; + if(!pet_entry) + return; + uint32 level = m_caster->getLevel(); + Pet* spawnCreature = new Pet(SUMMON_PET); + + if(spawnCreature->LoadPetFromDB(m_caster,pet_entry)) + { + // set timer for unsummon + int32 duration = GetSpellDuration(m_spellInfo); + if(duration > 0) + spawnCreature->SetDuration(duration); + + return; + } + + Map *map = m_caster->GetMap(); + uint32 pet_number = objmgr.GeneratePetNumber(); + if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number)) + { + sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]); + delete spawnCreature; + return; + } + + // Summon in dest location + float x,y,z; + if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + x = m_targets.m_destX; + y = m_targets.m_destY; + z = m_targets.m_destZ; + } + else + m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize()); + + spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation()); + + if(!spawnCreature->IsPositionValid()) + { + sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY()); + delete spawnCreature; + return; + } + + // set timer for unsummon + int32 duration = GetSpellDuration(m_spellInfo); + if(duration > 0) + spawnCreature->SetDuration(duration); + + spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); + spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0); + spawnCreature->setPowerType(POWER_MANA); + spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); + spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0); + spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0,2048); + spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); + spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0); + spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0); + spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000); + spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); + spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + + spawnCreature->InitStatsForLevel(level); + + spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false); + + spawnCreature->AIM_Initialize(); + spawnCreature->InitPetCreateSpells(); + spawnCreature->SetHealth(spawnCreature->GetMaxHealth()); + spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA)); + + std::string name = m_caster->GetName(); + name.append(petTypeSuffix[spawnCreature->getPetType()]); + spawnCreature->SetName( name ); + + map->Add((Creature*)spawnCreature); + + if(m_caster->GetTypeId() == TYPEID_PLAYER) + { + m_caster->SetPet(spawnCreature); + spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE ); + spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT); + ((Player*)m_caster)->PetSpellInitialize(); + } +} + +void Spell::EffectLearnSpell(uint32 i) +{ + if(!unitTarget) + return; + + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + { + if(m_caster->GetTypeId() == TYPEID_PLAYER) + EffectLearnPetSpell(i); + + return; + } + + Player *player = (Player*)unitTarget; + + uint32 spellToLearn = (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) ? damage : m_spellInfo->EffectTriggerSpell[i]; + player->learnSpell(spellToLearn); + + sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() ); +} + +void Spell::EffectDispel(uint32 i) +{ + if(!unitTarget) + return; + + // Fill possible dispell list + std::vector dispel_list; + + // Create dispel mask by dispel type + uint32 dispel_type = m_spellInfo->EffectMiscValue[i]; + uint32 dispelMask = GetDispellMask( DispelType(dispel_type) ); + Unit::AuraMap const& auras = unitTarget->GetAuras(); + for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + Aura *aur = (*itr).second; + if (aur && (1<GetSpellProto()->Dispel) & dispelMask) + { + if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC) + { + bool positive = true; + if (!aur->IsPositive()) + positive = false; + else + positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0; + + // do not remove positive auras if friendly target + // negative auras if non-friendly target + if(positive == unitTarget->IsFriendlyTo(m_caster)) + continue; + } + // Add aura to dispel list + dispel_list.push_back(aur); + } + } + // Ok if exist some buffs for dispel try dispel it + if (!dispel_list.empty()) + { + std::list < std::pair > success_list;// (spell_id,casterGuid) + std::list < uint32 > fail_list; // spell_id + int32 list_size = dispel_list.size(); + // Dispell N = damage buffs (or while exist buffs for dispel) + for (int32 count=0; count < damage && list_size > 0; ++count) + { + // Random select buff for dispel + Aura *aur = dispel_list[urand(0, list_size-1)]; + + SpellEntry const* spellInfo = aur->GetSpellProto(); + // Base dispel chance + // TODO: possible chance depend from spell level?? + int32 miss_chance = 0; + // Apply dispel mod from aura caster + if (Unit *caster = aur->GetCaster()) + { + if ( Player* modOwner = caster->GetSpellModOwner() ) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this); + } + // Try dispel + if (roll_chance_i(miss_chance)) + fail_list.push_back(aur->GetId()); + else + success_list.push_back(std::pair(aur->GetId(),aur->GetCasterGUID())); + // Remove buff from list for prevent doubles + for (std::vector::iterator j = dispel_list.begin(); j != dispel_list.end(); ) + { + Aura *dispeled = *j; + if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID()) + { + j = dispel_list.erase(j); + --list_size; + } + else + ++j; + } + } + // Send success log and really remove auras + if (!success_list.empty()) + { + int32 count = success_list.size(); + WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5); + data.append(unitTarget->GetPackGUID()); // Victim GUID + data.append(m_caster->GetPackGUID()); // Caster GUID + data << uint32(m_spellInfo->Id); // Dispell spell id + data << uint8(0); // not used + data << uint32(count); // count + for (std::list >::iterator j = success_list.begin(); j != success_list.end(); ++j) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first); + data << uint32(spellInfo->Id); // Spell Id + data << uint8(0); // 0 - dispeled !=0 cleansed + unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster); + } + m_caster->SendMessageToSet(&data, true); + + // On succes dispel + // Devour Magic + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12) + { + uint32 heal_spell = 0; + switch (m_spellInfo->Id) + { + case 19505: heal_spell = 19658; break; + case 19731: heal_spell = 19732; break; + case 19734: heal_spell = 19733; break; + case 19736: heal_spell = 19735; break; + case 27276: heal_spell = 27278; break; + case 27277: heal_spell = 27279; break; + default: + sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id); + break; + } + if (heal_spell) + m_caster->CastSpell(m_caster, heal_spell, true); + } + } + // Send fail log to client + if (!fail_list.empty()) + { + // Failed to dispell + WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size()); + data << uint64(m_caster->GetGUID()); // Caster GUID + data << uint64(unitTarget->GetGUID()); // Victim GUID + data << uint32(m_spellInfo->Id); // Dispell spell id + for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j) + data << uint32(*j); // Spell Id + m_caster->SendMessageToSet(&data, true); + } + } +} + +void Spell::EffectDualWield(uint32 /*i*/) +{ + if (unitTarget->GetTypeId() == TYPEID_PLAYER) + ((Player*)unitTarget)->SetCanDualWield(true); +} + +void Spell::EffectPull(uint32 /*i*/) +{ + // TODO: create a proper pull towards distract spell center for distract + sLog.outDebug("WORLD: Spell Effect DUMMY"); +} + +void Spell::EffectDistract(uint32 /*i*/) +{ + // Check for possible target + if (!unitTarget || unitTarget->isInCombat()) + return; + + // target must be OK to do this + if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNDED | UNIT_STAT_FLEEING ) ) + return; + + float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY); + + if ( unitTarget->GetTypeId() == TYPEID_PLAYER ) + { + // For players just turn them + WorldPacket data; + ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle); + ((Player*)unitTarget)->GetSession()->SendPacket( &data ); + ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false); + } + else + { + // Set creature Distracted, Stop it, And turn it + unitTarget->SetOrientation(angle); + unitTarget->StopMoving(); + unitTarget->GetMotionMaster()->MoveDistract(damage*1000); + } +} + +void Spell::EffectPickPocket(uint32 /*i*/) +{ + if( m_caster->GetTypeId() != TYPEID_PLAYER ) + return; + + // victim must be creature and attackable + if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) ) + return; + + // victim have to be alive and humanoid or undead + if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0) + { + int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel()); + + if (chance > irand(0, 19)) + { + // Stealing successful + //sLog.outDebug("Sending loot from pickpocket"); + ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING); + } + else + { + // Reveal action + get attack + m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + if (((Creature*)unitTarget)->AI()) + ((Creature*)unitTarget)->AI()->AttackStart(m_caster); + } + } +} + +void Spell::EffectAddFarsight(uint32 i) +{ + float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + int32 duration = GetSpellDuration(m_spellInfo); + DynamicObject* dynObj = new DynamicObject; + if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius)) + { + delete dynObj; + return; + } + dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65); + dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); + m_caster->AddDynObject(dynObj); + MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj); + m_caster->SetUInt64Value(PLAYER_FARSIGHT, dynObj->GetGUID()); +} + +void Spell::EffectSummonWild(uint32 i) +{ + uint32 creature_entry = m_spellInfo->EffectMiscValue[i]; + if(!creature_entry) + return; + + uint32 level = m_caster->getLevel(); + + // level of creature summoned using engineering item based at engineering skill level + if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem) + { + ItemPrototype const *proto = m_CastItem->GetProto(); + if(proto && proto->RequiredSkill == SKILL_ENGINERING) + { + uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING); + if(skill202) + { + level = skill202/5; + } + } + } + + // select center of summon position + float center_x = m_targets.m_destX; + float center_y = m_targets.m_destY; + float center_z = m_targets.m_destZ; + + float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + + int32 amount = damage > 0 ? damage : 1; + + for(int32 count = 0; count < amount; ++count) + { + float px, py, pz; + // If dest location if present + if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + // Summon 1 unit in dest location + if (count == 0) + { + px = m_targets.m_destX; + py = m_targets.m_destY; + pz = m_targets.m_destZ; + } + // Summon in random point all other units if location present + else + m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz); + } + // Summon if dest location not present near caster + else + m_caster->GetClosePoint(px,py,pz,3.0f); + + int32 duration = GetSpellDuration(m_spellInfo); + + TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN; + + m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration); + } +} + +void Spell::EffectSummonGuardian(uint32 i) +{ + uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; + if(!pet_entry) + return; + + // Jewelery statue case (totem like) + if(m_spellInfo->SpellIconID==2056) + { + EffectSummonTotem(i); + return; + } + + // set timer for unsummon + int32 duration = GetSpellDuration(m_spellInfo); + + // Search old Guardian only for players (if casted spell not have duration or cooldown) + // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time + // so this code hack in fact + if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) ) + if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry)) + return; // find old guardian, ignore summon + + // in another case summon new + uint32 level = m_caster->getLevel(); + + // level of pet summoned using engineering item based at engineering skill level + if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem) + { + ItemPrototype const *proto = m_CastItem->GetProto(); + if(proto && proto->RequiredSkill == SKILL_ENGINERING) + { + uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING); + if(skill202) + { + level = skill202/5; + } + } + } + + // select center of summon position + float center_x = m_targets.m_destX; + float center_y = m_targets.m_destY; + float center_z = m_targets.m_destZ; + + float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + + int32 amount = damage > 0 ? damage : 1; + + for(int32 count = 0; count < amount; ++count) + { + Pet* spawnCreature = new Pet(GUARDIAN_PET); + + Map *map = m_caster->GetMap(); + uint32 pet_number = objmgr.GeneratePetNumber(); + if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number)) + { + sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]); + delete spawnCreature; + return; + } + + float px, py, pz; + // If dest location if present + if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + // Summon 1 unit in dest location + if (count == 0) + { + px = m_targets.m_destX; + py = m_targets.m_destY; + pz = m_targets.m_destZ; + } + // Summon in random point all other units if location present + else + m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz); + } + // Summon if dest location not present near caster + else + m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize()); + + spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation()); + + if(!spawnCreature->IsPositionValid()) + { + sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY()); + delete spawnCreature; + return; + } + + if(duration > 0) + spawnCreature->SetDuration(duration); + + spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); + spawnCreature->setPowerType(POWER_MANA); + spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0); + spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); + spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0); + spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); + spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0); + spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); + spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + + spawnCreature->InitStatsForLevel(level); + spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false); + + spawnCreature->AIM_Initialize(); + + if(m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->AddGuardian(spawnCreature); + + map->Add((Creature*)spawnCreature); + } +} + +void Spell::EffectTeleUnitsFaceCaster(uint32 i) +{ + if(!unitTarget) + return; + + if(unitTarget->isInFlight()) + return; + + uint32 mapid = m_caster->GetMapId(); + float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + + float fx,fy,fz; + m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); + + if(unitTarget->GetTypeId() == TYPEID_PLAYER) + ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); + else + MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation()); +} + +void Spell::EffectLearnSkill(uint32 i) +{ + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if(damage < 0) + return; + + uint32 skillid = m_spellInfo->EffectMiscValue[i]; + uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid); + ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75); +} + +void Spell::EffectAddHonor(uint32 /*i*/) +{ + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, this->damage, ((Player*)unitTarget)->GetGUIDLow()); + + // TODO: find formula for honor reward based on player's level! + + // now fixed only for level 70 players: + if (((Player*)unitTarget)->getLevel() == 70) + ((Player*)unitTarget)->RewardHonor(NULL, 1, this->damage); +} + +void Spell::EffectTradeSkill(uint32 /*i*/) +{ + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + // uint32 skillid = m_spellInfo->EffectMiscValue[i]; + // uint16 skillmax = ((Player*)unitTarget)->(skillid); + // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75); +} + +void Spell::EffectEnchantItemPerm(uint32 i) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + if (!itemTarget) + return; + + Player* p_caster = (Player*)m_caster; + + p_caster->UpdateCraftSkill(m_spellInfo->Id); + + if (m_spellInfo->EffectMiscValue[i]) + { + uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) + return; + + // item can be in trade slot and have owner diff. from caster + Player* item_owner = itemTarget->GetOwner(); + if(!item_owner) + return; + + if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) + sLog.outCommand("GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)", + p_caster->GetName(),p_caster->GetSession()->GetAccountId(), + itemTarget->GetProto()->Name1,itemTarget->GetEntry(), + item_owner->GetName(),item_owner->GetSession()->GetAccountId()); + + // remove old enchanting before applying new if equipped + item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false); + + itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0); + + // add new enchanting if equipped + item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true); + } +} + +void Spell::EffectEnchantItemTmp(uint32 i) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* p_caster = (Player*)m_caster; + + if(!itemTarget) + return; + + uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; + + // Shaman Rockbiter Weapon + if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY) + { + int32 enchnting_damage = m_currentBasePoints[1]+1; + + // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value + // with already applied percent bonus from Elemental Weapons talent + // Note: damage calculated (correctly) with rounding int32(float(v)) but + // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime + switch(enchnting_damage) + { + // Rank 1 + case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2] + // Rank 2 + case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4] + case 5: enchant_id = 3025; break; // 20% + // Rank 3 + case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6] + case 7: enchant_id = 3027; break; // 20% + // Rank 4 + case 9: enchant_id = 3032; break; // 0% [ 7% == 6] + case 10: enchant_id = 503; break; // 14% + case 11: enchant_id = 3031; break; // 20% + // Rank 5 + case 15: enchant_id = 3035; break; // 0% + case 16: enchant_id = 1663; break; // 7% + case 17: enchant_id = 3033; break; // 14% + case 18: enchant_id = 3034; break; // 20% + // Rank 6 + case 28: enchant_id = 3038; break; // 0% + case 29: enchant_id = 683; break; // 7% + case 31: enchant_id = 3036; break; // 14% + case 33: enchant_id = 3037; break; // 20% + // Rank 7 + case 40: enchant_id = 3041; break; // 0% + case 42: enchant_id = 1664; break; // 7% + case 45: enchant_id = 3039; break; // 14% + case 48: enchant_id = 3040; break; // 20% + // Rank 8 + case 49: enchant_id = 3044; break; // 0% + case 52: enchant_id = 2632; break; // 7% + case 55: enchant_id = 3042; break; // 14% + case 58: enchant_id = 3043; break; // 20% + // Rank 9 + case 62: enchant_id = 2633; break; // 0% + case 66: enchant_id = 3018; break; // 7% + case 70: enchant_id = 3019; break; // 14% + case 74: enchant_id = 3020; break; // 20% + default: + sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage); + return; + } + } + + if (!enchant_id) + { + sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i); + return; + } + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) + { + sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id); + return; + } + + // select enchantment duration + uint32 duration; + + // rogue family enchantments exception by duration + if(m_spellInfo->Id==38615) + duration = 1800; // 30 mins + // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints) + else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE) + duration = 3600; // 1 hour + // shaman family enchantments + else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN) + duration = 1800; // 30 mins + // other cases with this SpellVisual already selected + else if(m_spellInfo->SpellVisual==215) + duration = 1800; // 30 mins + // some fishing pole bonuses + else if(m_spellInfo->SpellVisual==563) + duration = 600; // 10 mins + // shaman rockbiter enchantments + else if(m_spellInfo->SpellVisual==0) + duration = 1800; // 30 mins + else if(m_spellInfo->Id==29702) + duration = 300; // 5 mins + else if(m_spellInfo->Id==37360) + duration = 300; // 5 mins + // default case + else + duration = 3600; // 1 hour + + // item can be in trade slot and have owner diff. from caster + Player* item_owner = itemTarget->GetOwner(); + if(!item_owner) + return; + + if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) + sLog.outCommand("GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)", + p_caster->GetName(),p_caster->GetSession()->GetAccountId(), + itemTarget->GetProto()->Name1,itemTarget->GetEntry(), + item_owner->GetName(),item_owner->GetSession()->GetAccountId()); + + // remove old enchanting before applying new if equipped + item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false); + + itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0); + + // add new enchanting if equipped + item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true); +} + +void Spell::EffectTameCreature(uint32 /*i*/) +{ + if(m_caster->GetPetGUID()) + return; + + if(!unitTarget) + return; + + if(unitTarget->GetTypeId() == TYPEID_PLAYER) + return; + + Creature* creatureTarget = (Creature*)unitTarget; + + if(creatureTarget->isPet()) + return; + + if(m_caster->getClass() == CLASS_HUNTER) + { + // cast finish successfully + //SendChannelUpdate(0); + finish(); + + Pet* pet = new Pet(HUNTER_PET); + + if(!pet->CreateBaseAtCreature(creatureTarget)) + { + delete pet; + return; + } + + creatureTarget->setDeathState(JUST_DIED); + creatureTarget->RemoveCorpse(); + creatureTarget->SetHealth(0); // just for nice GM-mode view + + pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID()); + pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); + pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); + pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + + if(!pet->InitStatsForLevel(creatureTarget->getLevel())) + { + sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted."); + delete pet; + return; + } + + // prepare visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1); + + pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true); + // this enables pet details window (Shift+P) + pet->AIM_Initialize(); + pet->InitPetCreateSpells(); + pet->SetHealth(pet->GetMaxHealth()); + + MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet); + + // visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()); + + if(m_caster->GetTypeId() == TYPEID_PLAYER) + { + m_caster->SetPet(pet); + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + ((Player*)m_caster)->PetSpellInitialize(); + } + } +} + +void Spell::EffectSummonPet(uint32 i) +{ + uint32 petentry = m_spellInfo->EffectMiscValue[i]; + + Pet *OldSummon = m_caster->GetPet(); + + // if pet requested type already exist + if( OldSummon ) + { + if(petentry == 0 || OldSummon->GetEntry() == petentry) + { + // pet in corpse state can't be summoned + if( OldSummon->isDead() ) + return; + + MapManager::Instance().GetMap(OldSummon->GetMapId(), OldSummon)->Remove((Creature*)OldSummon,false); + OldSummon->SetMapId(m_caster->GetMapId()); + + float px, py, pz; + m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize()); + + OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation()); + MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->Add((Creature*)OldSummon); + + if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() ) + { + ((Player*)m_caster)->PetSpellInitialize(); + } + return; + } + + if(m_caster->GetTypeId() == TYPEID_PLAYER) + ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false); + else + return; + } + + Pet* NewSummon = new Pet; + + // petentry==0 for hunter "call pet" (current pet summoned if any) + if(NewSummon->LoadPetFromDB(m_caster,petentry)) + { + if(NewSummon->getPetType()==SUMMON_PET) + { + // Remove Demonic Sacrifice auras (known pet) + Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();) + { + if((*itr)->GetModifier()->m_miscvalue==2228) + { + m_caster->RemoveAurasDueToSpell((*itr)->GetId()); + itr = auraClassScripts.begin(); + } + else + ++itr; + } + } + + return; + } + + // not error in case fail hunter call pet + if(!petentry) + { + delete NewSummon; + return; + } + + CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(petentry); + + if(!cInfo) + { + sLog.outError("EffectSummonPet: creature entry %u not found.",petentry); + delete NewSummon; + return; + } + + Map *map = m_caster->GetMap(); + uint32 pet_number = objmgr.GeneratePetNumber(); + if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number)) + { + delete NewSummon; + return; + } + + float px, py, pz; + m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize()); + + NewSummon->Relocate(px, py, pz, m_caster->GetOrientation()); + + if(!NewSummon->IsPositionValid()) + { + sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY()); + delete NewSummon; + return; + } + + uint32 petlevel = m_caster->getLevel(); + NewSummon->setPetType(SUMMON_PET); + + uint32 faction = m_caster->getFaction(); + if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isTotem()) + { + Unit* owner = ((Totem*)m_caster)->GetOwner(); + if(owner) + faction = owner->getFaction(); + NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE); + } + + NewSummon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID()); + NewSummon->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); + NewSummon->SetUInt32Value(UNIT_NPC_FLAGS , 0); + NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction); + NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0,2048); + NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1,0); + NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,time(NULL)); + NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0); + NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000); + NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + + NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true); + // this enables pet details window (Shift+P) + + // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later + NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE); + + NewSummon->InitStatsForLevel( petlevel); + NewSummon->InitPetCreateSpells(); + + if(NewSummon->getPetType()==SUMMON_PET) + { + // Remove Demonic Sacrifice auras (new pet) + Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();) + { + if((*itr)->GetModifier()->m_miscvalue==2228) + { + m_caster->RemoveAurasDueToSpell((*itr)->GetId()); + itr = auraClassScripts.begin(); + } + else + ++itr; + } + + // generate new name for summon pet + std::string new_name=objmgr.GeneratePetName(petentry); + if(!new_name.empty()) + NewSummon->SetName(new_name); + } + else if(NewSummon->getPetType()==HUNTER_PET) + NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED); + + NewSummon->AIM_Initialize(); + NewSummon->SetHealth(NewSummon->GetMaxHealth()); + NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA)); + + map->Add((Creature*)NewSummon); + + m_caster->SetPet(NewSummon); + sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow()); + + if(m_caster->GetTypeId() == TYPEID_PLAYER) + { + NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT); + ((Player*)m_caster)->PetSpellInitialize(); + } +} + +void Spell::EffectLearnPetSpell(uint32 i) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)m_caster; + + Pet *pet = _player->GetPet(); + if(!pet) + return; + if(!pet->isAlive()) + return; + + SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); + if(!learn_spellproto) + return; + + pet->SetTP(pet->m_TrainingPoints - pet->GetTPForSpell(learn_spellproto->Id)); + pet->learnSpell(learn_spellproto->Id); + + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + _player->PetSpellInitialize(); +} + +void Spell::EffectTaunt(uint32 /*i*/) +{ + // this effect use before aura Taunt apply for prevent taunt already attacking target + // for spell as marked "non effective at already attacking target" + if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER) + { + if(unitTarget->getVictim()==m_caster) + { + SendCastResult(SPELL_FAILED_DONT_REPORT); + return; + } + } + + // Also use this effect to set the taunter's threat to the taunted creature's highest value + if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim()) + unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat()); +} + +void Spell::EffectWeaponDmg(uint32 i) +{ + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + + // multiple weapon dmg effect workaround + // execute only the last weapon damage + // and handle all effects at once + for (int j = 0; j < 3; j++) + { + switch(m_spellInfo->Effect[j]) + { + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + if (j < i) // we must calculate only at last weapon effect + return; + break; + } + } + + // some spell specific modifiers + bool customBonusDamagePercentMod = false; + float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod + float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set + float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage + bool normalized = false; + + int32 spell_bonus = 0; // bonus specific for spell + switch(m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_WARRIOR: + { + // Whirlwind, single only spell with 2 weapon white damage apply if have + if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL)) + { + if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true)) + spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized); + } + // Devastate bonus and sunder armor refresh + else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508) + { + customBonusDamagePercentMod = true; + bonusDamagePercentMod = 0.0f; // only applied if auras found + + Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE); + for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr) + { + SpellEntry const *proto = (*itr)->GetSpellProto(); + if(proto->SpellVisual == 406 && proto->SpellIconID == 565) + { + int32 duration = GetSpellDuration(proto); + (*itr)->SetAuraDuration(duration); + (*itr)->UpdateAuraDuration(); + bonusDamagePercentMod += 1.0f; // +100% + } + } + } + break; + } + case SPELLFAMILY_ROGUE: + { + // Ambush + if(m_spellInfo->SpellFamilyFlags & 0x00000200LL) + { + customBonusDamagePercentMod = true; + bonusDamagePercentMod = 2.5f; // 250% + } + // Mutilate (for each hand) + else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL) + { + bool found = false; + // fast check + if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON)) + found = true; + // full aura scan + else + { + Unit::AuraMap const& auras = unitTarget->GetAuras(); + for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) + { + if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON) + { + found = true; + break; + } + } + } + + if(found) + totalDamagePercentMod *= 1.5f; // 150% if poisoned + } + break; + } + case SPELLFAMILY_PALADIN: + { + // Seal of Command - receive benefit from Spell Damage and Healing + if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL) + { + spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo))); + spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget)); + } + break; + } + case SPELLFAMILY_SHAMAN: + { + // Skyshatter Harness item set bonus + // Stormstrike + if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL) + { + Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i) + { + // Stormstrike AP Buff + if ( (*i)->GetModifier()->m_miscvalue == 5634 ) + { + m_caster->CastSpell(m_caster,38430,true,NULL,*i); + break; + } + } + } + } + } + + int32 fixed_bonus = 0; + for (int j = 0; j < 3; j++) + { + switch(m_spellInfo->Effect[j]) + { + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + fixed_bonus += CalculateDamage(j,unitTarget); + break; + case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: + fixed_bonus += CalculateDamage(j,unitTarget); + normalized = true; + break; + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f; + + // applied only to prev.effects fixed damage + if(customBonusDamagePercentMod) + fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod); + else + fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod); + break; + default: + break; // not weapon damage effect, just skip + } + } + + // non-weapon damage + int32 bonus = spell_bonus + fixed_bonus; + + // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage + if(bonus) + { + UnitMods unitMod; + switch(m_attackType) + { + default: + case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; + case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; + case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; + } + + float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); + bonus = int32(bonus*weapon_total_pct); + } + + // + weapon damage with applied weapon% dmg to base weapon damage in call + bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod); + + // total damage + bonus = int32(bonus*totalDamagePercentMod); + + // prevent negative damage + uint32 eff_damage = uint32(bonus > 0 ? bonus : 0); + + const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS; + + uint32 hitInfo = 0; + VictimState victimState = VICTIMSTATE_NORMAL; + uint32 blocked_dmg = 0; + uint32 absorbed_dmg = 0; + uint32 resisted_dmg = 0; + CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); + + m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell); + + if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc + m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg); + + bool criticalhit = (hitInfo & HITINFO_CRITICALHIT); + m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit); + + if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg)) + { + eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg); + } + else + { + cleanDamage.damage += eff_damage; + eff_damage = 0; + } + + // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation + m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true); + + // Hemorrhage + if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000)) + { + if(m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->AddComboPoints(unitTarget, 1); + } + // Mangle (Cat): CP + if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL)) + { + if(m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->AddComboPoints(unitTarget,1); + } + + + // take ammo + if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER) + { + Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK ); + + // wands don't have ammo + if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND) + return; + + if( pItem->GetProto()->InventoryType == INVTYPE_THROWN ) + { + if(pItem->GetMaxStackCount()==1) + { + // decrease durability for non-stackable throw weapon + ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED); + } + else + { + // decrease items amount for stackable throw weapon + uint32 count = 1; + ((Player*)m_caster)->DestroyItemCount( pItem, count, true); + } + } + else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID)) + ((Player*)m_caster)->DestroyItemCount(ammo, 1, true); + } +} + +void Spell::EffectThreat(uint32 /*i*/) +{ + if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive()) + return; + + if(!unitTarget->CanHaveThreatList()) + return; + + unitTarget->AddThreat(m_caster, float(damage)); +} + +void Spell::EffectHealMaxHealth(uint32 /*i*/) +{ + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + + uint32 heal = m_caster->GetMaxHealth(); + + int32 gain = unitTarget->ModifyHealth(heal); + unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); + + m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal); +} + +void Spell::EffectInterruptCast(uint32 /*i*/) +{ + if(!unitTarget) + return; + if(!unitTarget->isAlive()) + return; + + // TODO: not all spells that used this effect apply cooldown at school spells + // also exist case: apply cooldown to interrupted cast only and to all spells + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) + { + if (unitTarget->m_currentSpells[i]) + { + // check if we can interrupt spell + if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE ) + { + unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo)); + unitTarget->InterruptSpell(i,false); + } + } + } +} + +void Spell::EffectSummonObjectWild(uint32 i) +{ + uint32 gameobject_id = m_spellInfo->EffectMiscValue[i]; + + GameObject* pGameObj = new GameObject; + + WorldObject* target = focusObject; + if( !target ) + target = m_caster; + + float x,y,z; + if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + x = m_targets.m_destX; + y = m_targets.m_destY; + z = m_targets.m_destZ; + } + else + m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE); + + Map *map = target->GetMap(); + + if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map, + x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1)) + { + delete pGameObj; + return; + } + + int32 duration = GetSpellDuration(m_spellInfo); + pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); + pGameObj->SetSpellId(m_spellInfo->Id); + + if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)... + m_caster->AddGameObject(pGameObj); + map->Add(pGameObj); + + if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS + { + if(m_caster->GetTypeId() == TYPEID_PLAYER) + { + Player *pl = (Player*)m_caster; + BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); + if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS) + { + uint32 team = ALLIANCE; + + if(pl->GetTeam() == team) + team = HORDE; + + ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team); + } + } + } + + if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY + { + if(m_caster->GetTypeId() == TYPEID_PLAYER) + { + BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); + if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS) + { + ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID()); + } + } + } + + if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry()) + { + GameObject* linkedGO = new GameObject; + if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map, + x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1)) + { + linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0); + linkedGO->SetSpellId(m_spellInfo->Id); + + m_caster->AddGameObject(linkedGO); + map->Add(linkedGO); + } + else + { + delete linkedGO; + linkedGO = NULL; + return; + } + } +} + +void Spell::EffectScriptEffect(uint32 effIndex) +{ + // TODO: we must implement hunter pet summon at login there (spell 6962) + + // by spell id + switch(m_spellInfo->Id) + { + // Bending Shinbone + case 8856: + { + if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1,5)) + { + case 1: spell_id = 8854; break; + default: spell_id = 8855; break; + } + + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + + // Healthstone creating spells + case 6201: + case 6202: + case 5699: + case 11729: + case 11730: + case 27230: + { + uint32 itemtype; + uint32 rank = 0; + Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) + { + if((*i)->GetId() == 18692) + { + rank = 1; + break; + } + else if((*i)->GetId() == 18693) + { + rank = 2; + break; + } + } + + static uint32 const itypes[6][3] = { + { 5512,19004,19005}, // Minor Healthstone + { 5511,19006,19007}, // Lesser Healthstone + { 5509,19008,19009}, // Healthstone + { 5510,19010,19011}, // Greater Healthstone + { 9421,19012,19013}, // Major Healthstone + {22103,22104,22105} // Master Healthstone + }; + + switch(m_spellInfo->Id) + { + case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone + case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone + case 5699: itemtype=itypes[2][rank];break; // Healthstone + case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone + case 11730: itemtype=itypes[4][rank];break; // Major Healthstone + case 27230: itemtype=itypes[5][rank];break; // Master Healthstone + default: + return; + } + DoCreateItem( effIndex, itemtype ); + return; + } + // Brittle Armor - need remove one 24575 Brittle Armor aura + case 24590: + unitTarget->RemoveSingleAuraFromStack(24575, 0); + unitTarget->RemoveSingleAuraFromStack(24575, 1); + return; + // Mercurial Shield - need remove one 26464 Mercurial Shield aura + case 26465: + unitTarget->RemoveSingleAuraFromStack(26464, 0); + return; + // Orb teleport spells + case 25140: + case 25143: + case 25650: + case 25652: + case 29128: + case 29129: + case 35376: + case 35727: + { + if(!unitTarget) + return; + + uint32 spellid; + switch(m_spellInfo->Id) + { + case 25140: spellid = 32571; break; + case 25143: spellid = 32572; break; + case 25650: spellid = 30140; break; + case 25652: spellid = 30141; break; + case 29128: spellid = 32568; break; + case 29129: spellid = 32569; break; + case 35376: spellid = 25649; break; + case 35727: spellid = 35730; break; + default: + return; + } + + unitTarget->CastSpell(unitTarget,spellid,false); + return; + } + + // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell) + case 22539: + case 22972: + case 22975: + case 22976: + case 22977: + case 22978: + case 22979: + case 22980: + case 22981: + case 22982: + case 22983: + case 22984: + case 22985: + { + if(!unitTarget || !unitTarget->isAlive()) + return; + + // Onyxia Scale Cloak + if(unitTarget->GetDummyAura(22683)) + return; + + // Shadow Flame + m_caster->CastSpell(unitTarget, 22682, true); + return; + } + break; + + // Summon Black Qiraji Battle Tank + case 26656: + { + if(!unitTarget) + return; + + // Prevent stacking of mounts + unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); + + // Two separate mounts depending on area id (allows use both in and out of specific instance) + if (unitTarget->GetAreaId() == 3428) + unitTarget->CastSpell(unitTarget, 25863, false); + else + unitTarget->CastSpell(unitTarget, 26655, false); + break; + } + // Piccolo of the Flaming Fire + case 17512: + { + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE); + break; + } + + // Dreaming Glory + case 28698: + { + if(!unitTarget) + return; + unitTarget->CastSpell(unitTarget, 28694, true); + break; + } + + // Netherbloom + case 28702: + { + if(!unitTarget) + return; + // 25% chance of casting a random buff + if(roll_chance_i(75)) + return; + + // triggered spells are 28703 to 28707 + // Note: some sources say, that there was the possibility of + // receiving a debuff. However, this seems to be removed by a patch. + const uint32 spellid = 28703; + + // don't overwrite an existing aura + for(uint8 i=0; i<5; i++) + if(unitTarget->HasAura(spellid+i, 0)) + return; + unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true); + break; + } + + // Nightmare Vine + case 28720: + { + if(!unitTarget) + return; + // 25% chance of casting Nightmare Pollen + if(roll_chance_i(75)) + return; + unitTarget->CastSpell(unitTarget, 28721, true); + break; + } + + // Mirren's Drinking Hat + case 29830: + { + uint32 item = 0; + switch ( urand(1,6) ) + { + case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager + case 4: case 5: item = 23585; break;// Stouthammer Lite + case 6: item = 23586; break;// Aerie Peak Pale Ale + } + if (item) + DoCreateItem(effIndex,item); + break; + } + // Improved Sprint + case 30918: + { + // Removes snares and roots. + uint32 mechanic_mask = (1<GetAuras(); + for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next) + { + next = iter; + ++next; + Aura *aur = iter->second; + if (!aur->IsPositive()) //only remove negative spells + { + // check for mechanic mask + if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask) + { + unitTarget->RemoveAurasDueToSpell(aur->GetId()); + if(Auras.empty()) + break; + else + next = Auras.begin(); + } + } + } + break; + } + case 41126: // Flame Crash + { + if(!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 41131, true); + break; + } + case 44876: // Force Cast - Portal Effect: Sunwell Isle + { + if(!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 44870, true); + break; + } + + // Goblin Weather Machine + case 46203: + { + if(!unitTarget) + return; + + uint32 spellId; + switch(rand()%4) + { + case 0: + spellId=46740; + break; + case 1: + spellId=46739; + break; + case 2: + spellId=46738; + break; + case 3: + spellId=46736; + break; + } + unitTarget->CastSpell(unitTarget, spellId, true); + break; + } + } + + if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN ) + { + switch(m_spellInfo->SpellFamilyFlags) + { + // Judgement + case 0x800000: + { + if(!unitTarget || !unitTarget->isAlive()) + return; + uint32 spellId2 = 0; + + // all seals have aura dummy + Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr) + { + SpellEntry const *spellInfo = (*itr)->GetSpellProto(); + + // search seal (all seals have judgement's aura dummy spell id in 2 effect + if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 ) + continue; + + // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE + spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1; + + if(spellId2 <= 1) + continue; + + // found, remove seal + m_caster->RemoveAurasDueToSpell((*itr)->GetId()); + + // Sanctified Judgement + Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i) + { + if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL) + { + int32 chance = (*i)->GetModifier()->m_amount; + if ( roll_chance_i(chance) ) + { + int32 mana = spellInfo->manaCost; + if ( Player* modOwner = m_caster->GetSpellModOwner() ) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana); + mana = int32(mana* 0.8f); + m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i); + } + break; + } + } + + break; + } + + m_caster->CastSpell(unitTarget,spellId2,true); + return; + } + } + } + + // normal DB scripted effect + if(!unitTarget) + return; + + sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id); + sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget); +} + +void Spell::EffectSanctuary(uint32 /*i*/) +{ + if(!unitTarget) + return; + //unitTarget->CombatStop(); + + unitTarget->CombatStop(); + unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting + // Vanish allows to remove all threat and cast regular stealth so other spells can be used + if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH)) + { + ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); + } +} + +void Spell::EffectAddComboPoints(uint32 /*i*/) +{ + if(!unitTarget) + return; + + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if(damage <= 0) + return; + + ((Player*)m_caster)->AddComboPoints(unitTarget, damage); +} + +void Spell::EffectDuel(uint32 i) +{ + if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *caster = (Player*)m_caster; + Player *target = (Player*)unitTarget; + + // caster or target already have requested duel + if( caster->duel || target->duel || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) ) + return; + + // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities) + // Don't have to check the target's map since you cannot challenge someone across maps + if( caster->GetMapId() != 0 && caster->GetMapId() != 1 && caster->GetMapId() != 530) + { + SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here + return; + } + + AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId()); + if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) ) + { + SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here + return; + } + + AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId()); + if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) ) + { + SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here + return; + } + + //CREATE DUEL FLAG OBJECT + GameObject* pGameObj = new GameObject; + + uint32 gameobject_id = m_spellInfo->EffectMiscValue[i]; + + Map *map = m_caster->GetMap(); + if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map, + m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 , + m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 , + m_caster->GetPositionZ(), + m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1)) + { + delete pGameObj; + return; + } + + pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() ); + pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 ); + int32 duration = GetSpellDuration(m_spellInfo); + pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); + pGameObj->SetSpellId(m_spellInfo->Id); + + m_caster->AddGameObject(pGameObj); + map->Add(pGameObj); + //END + + // Send request + WorldPacket data(SMSG_DUEL_REQUESTED, 16); + data << pGameObj->GetGUID(); + data << caster->GetGUID(); + caster->GetSession()->SendPacket(&data); + target->GetSession()->SendPacket(&data); + + // create duel-info + DuelInfo *duel = new DuelInfo; + duel->initiator = caster; + duel->opponent = target; + duel->startTime = 0; + duel->startTimer = 0; + caster->duel = duel; + + DuelInfo *duel2 = new DuelInfo; + duel2->initiator = caster; + duel2->opponent = caster; + duel2->startTime = 0; + duel2->startTimer = 0; + target->duel = duel2; + + caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID()); + target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID()); +} + +void Spell::EffectStuck(uint32 /*i*/) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK)) + return; + + Player* pTarget = (Player*)unitTarget; + + sLog.outDebug("Spell Effect: Stuck"); + sLog.outDetail("Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", pTarget->GetName(), pTarget->GetGUIDLow(), m_caster->GetMapId(), m_caster->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); + + if(pTarget->isInFlight()) + return; + + // homebind location is loaded always + pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0)); + + // Stuck spell trigger Hearthstone cooldown + SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690); + if(!spellInfo) + return; + Spell spell(pTarget,spellInfo,true,0); + spell.SendSpellCooldown(); +} + +void Spell::EffectSummonPlayer(uint32 /*i*/) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Evil Twin (ignore player summon, but hide this for summoner) + if(unitTarget->GetDummyAura(23445)) + return; + + float x,y,z; + m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize()); + + ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z); + + WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4); + data << uint64(m_caster->GetGUID()); // summoner guid + data << uint32(m_caster->GetZoneId()); // summoner zone + data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs + ((Player*)unitTarget)->GetSession()->SendPacket(&data); +} + +static ScriptInfo generateActivateCommand() +{ + ScriptInfo si; + si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT; + return si; +} + +void Spell::EffectActivateObject(uint32 effect_idx) +{ + if(!gameObjTarget) + return; + + static ScriptInfo activateCommand = generateActivateCommand(); + + int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx]; + + sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget); +} + +void Spell::EffectSummonTotem(uint32 i) +{ + uint8 slot = 0; + switch(m_spellInfo->EffectMiscValueB[i]) + { + case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break; + case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break; + case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break; + case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break; + // Battle standard case + case SUMMON_TYPE_TOTEM: slot = 254; break; + // jewelery statue case, like totem without slot + case SUMMON_TYPE_GUARDIAN: slot = 255; break; + default: return; + } + + if(slot < MAX_TOTEM) + { + uint64 guid = m_caster->m_TotemSlot[slot]; + if(guid != 0) + { + Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid); + if(OldTotem && OldTotem->isTotem()) + ((Totem*)OldTotem)->UnSummon(); + } + } + + uint32 team = 0; + if (m_caster->GetTypeId()==TYPEID_PLAYER) + team = ((Player*)m_caster)->GetTeam(); + + Totem* pTotem = new Totem; + + if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team )) + { + delete pTotem; + return; + } + + float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0; + + float x,y,z; + m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle); + + // totem must be at same Z in case swimming caster and etc. + if( fabs( z - m_caster->GetPositionZ() ) > 5 ) + z = m_caster->GetPositionZ(); + + pTotem->Relocate(x, y, z, m_caster->GetOrientation()); + + if(slot < MAX_TOTEM) + m_caster->m_TotemSlot[slot] = pTotem->GetGUID(); + + pTotem->SetOwner(m_caster->GetGUID()); + pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized + + int32 duration=GetSpellDuration(m_spellInfo); + if(Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration); + pTotem->SetDuration(duration); + + if (damage) // if not spell info, DB values used + { + pTotem->SetMaxHealth(damage); + pTotem->SetHealth(damage); + } + + pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id); + pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE); + + pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true); + pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true); + + pTotem->Summon(m_caster); + + if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4); + data << uint8(slot); + data << uint64(pTotem->GetGUID()); + data << uint32(duration); + data << uint32(m_spellInfo->Id); + ((Player*)m_caster)->SendDirectMessage(&data); + } +} + +void Spell::EffectEnchantHeldItem(uint32 i) +{ + // this is only item spell effect applied to main-hand weapon of target player (players in area) + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player* item_owner = (Player*)unitTarget; + Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + + if(!item ) + return; + + // must be equipped + if(!item ->IsEquipped()) + return; + + if (m_spellInfo->EffectMiscValue[i]) + { + uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; + int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first .. + if(!duration) + duration = m_currentBasePoints[i]+1; //Base points after .. + if(!duration) + duration = 10; //10 seconds for enchants which don't have listed duration + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) + return; + + // Always go to temp enchantment slot + EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT; + + // Enchantment will not be applied if a different one already exists + if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id) + return; + + // Apply the temporary enchantment + item->SetEnchantment(slot, enchant_id, duration*1000, 0); + item_owner->ApplyEnchantment(item,slot,true); + } +} + +void Spell::EffectDisEnchant(uint32 /*i*/) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* p_caster = (Player*)m_caster; + if(!itemTarget || !itemTarget->GetProto()->DisenchantID) + return; + + p_caster->UpdateCraftSkill(m_spellInfo->Id); + + ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING); + + // item will be removed at disenchanting end +} + +void Spell::EffectInebriate(uint32 /*i*/) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *player = (Player*)unitTarget; + uint16 currentDrunk = player->GetDrunkValue(); + uint16 drunkMod = damage * 256; + if (currentDrunk + drunkMod > 0xFFFF) + currentDrunk = 0xFFFF; + else + currentDrunk += drunkMod; + player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0); +} + +void Spell::EffectFeedPet(uint32 i) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)m_caster; + + if(!itemTarget) + return; + + Pet *pet = _player->GetPet(); + if(!pet) + return; + + if(!pet->isAlive()) + return; + + int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel); + if(benefit <= 0) + return; + + uint32 count = 1; + _player->DestroyItemCount(itemTarget,count,true); + // TODO: fix crash when a spell has two effects, both pointed at the same item target + + m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true); +} + +void Spell::EffectDismissPet(uint32 /*i*/) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Pet* pet = m_caster->GetPet(); + + // not let dismiss dead pet + if(!pet||!pet->isAlive()) + return; + + ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT); +} + +void Spell::EffectSummonObject(uint32 i) +{ + uint32 go_id = m_spellInfo->EffectMiscValue[i]; + + uint8 slot = 0; + switch(m_spellInfo->Effect[i]) + { + case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break; + case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break; + case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break; + case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break; + default: return; + } + + uint64 guid = m_caster->m_ObjectSlot[slot]; + if(guid != 0) + { + GameObject* obj = NULL; + if( m_caster ) + obj = ObjectAccessor::GetGameObject(*m_caster, guid); + + if(obj) obj->Delete(); + m_caster->m_ObjectSlot[slot] = 0; + } + + GameObject* pGameObj = new GameObject; + + float rot2 = sin(m_caster->GetOrientation()/2); + float rot3 = cos(m_caster->GetOrientation()/2); + + float x,y,z; + // If dest location if present + if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + x = m_targets.m_destX; + y = m_targets.m_destY; + z = m_targets.m_destZ; + } + // Summon in random point all other units if location present + else + m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE); + + Map *map = m_caster->GetMap(); + if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1)) + { + delete pGameObj; + return; + } + + pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel()); + int32 duration = GetSpellDuration(m_spellInfo); + pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); + pGameObj->SetSpellId(m_spellInfo->Id); + m_caster->AddGameObject(pGameObj); + + map->Add(pGameObj); + WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); + data << pGameObj->GetGUID(); + m_caster->SendMessageToSet(&data,true); + + m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID(); +} + +void Spell::EffectResurrect(uint32 i) +{ + if(!unitTarget) + return; + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if(unitTarget->isAlive()) + return; + if(!unitTarget->IsInWorld()) + return; + + switch (m_spellInfo->Id) + { + // Defibrillate (Goblin Jumper Cables) have 33% chance on success + case 8342: + if (roll_chance_i(67)) + { + m_caster->CastSpell(m_caster, 8338, true, m_CastItem); + return; + } + break; + // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success + case 22999: + if (roll_chance_i(50)) + { + m_caster->CastSpell(m_caster, 23055, true, m_CastItem); + return; + } + break; + default: + break; + } + + Player* pTarget = ((Player*)unitTarget); + + if(pTarget->isRessurectRequested()) // already have one active request + return; + + uint32 health = pTarget->GetMaxHealth() * damage / 100; + uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100; + + pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); + SendResurrectRequest(pTarget); +} + +void Spell::EffectAddExtraAttacks(uint32 /*i*/) +{ + if(!unitTarget || !unitTarget->isAlive()) + return; + + if( unitTarget->m_extraAttacks ) + return; + + unitTarget->m_extraAttacks = damage; +} + +void Spell::EffectParry(uint32 /*i*/) +{ + if (unitTarget->GetTypeId() == TYPEID_PLAYER) + { + ((Player*)unitTarget)->SetCanParry(true); + } +} + +void Spell::EffectBlock(uint32 /*i*/) +{ + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + ((Player*)unitTarget)->SetCanBlock(true); +} + +void Spell::EffectMomentMove(uint32 i) +{ + if(unitTarget->isInFlight()) + return; + + if( m_spellInfo->rangeIndex== 1) //self range + { + uint32 mapid = m_caster->GetMapId(); + float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + + // before caster + float fx,fy,fz; + unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); + float ox,oy,oz; + unitTarget->GetPosition(ox,oy,oz); + + float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case + if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5)) + { + fx = fx2; + fy = fy2; + fz = fz2; + unitTarget->UpdateGroundPositionZ(fx,fy,fz); + } + + if(unitTarget->GetTypeId() == TYPEID_PLAYER) + ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); + else + MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation()); + } +} + +void Spell::EffectReputation(uint32 i) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)unitTarget; + + int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1 + + uint32 faction_id = m_spellInfo->EffectMiscValue[i]; + + FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id); + + if(!factionEntry) + return; + + _player->ModifyFactionReputation(factionEntry,rep_change); +} + +void Spell::EffectQuestComplete(uint32 i) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)m_caster; + + uint32 quest_id = m_spellInfo->EffectMiscValue[i]; + _player->AreaExploredOrEventHappens(quest_id); +} + +void Spell::EffectSelfResurrect(uint32 i) +{ + if(!unitTarget || unitTarget->isAlive()) + return; + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + if(!unitTarget->IsInWorld()) + return; + + uint32 health = 0; + uint32 mana = 0; + + // flat case + if(damage < 0) + { + health = uint32(-damage); + mana = m_spellInfo->EffectMiscValue[i]; + } + // percent case + else + { + health = uint32(damage/100.0f*unitTarget->GetMaxHealth()); + if(unitTarget->GetMaxPower(POWER_MANA) > 0) + mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA)); + } + + Player *plr = ((Player*)unitTarget); + plr->ResurrectPlayer(0.0f); + + plr->SetHealth( health ); + plr->SetPower(POWER_MANA, mana ); + plr->SetPower(POWER_RAGE, 0 ); + plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) ); + + plr->SpawnCorpseBones(); + + plr->SaveToDB(); +} + +void Spell::EffectSkinning(uint32 /*i*/) +{ + if(unitTarget->GetTypeId() != TYPEID_UNIT ) + return; + if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Creature* creature = (Creature*) unitTarget; + int32 targetLevel = creature->getLevel(); + + uint32 skill; + if(creature->GetCreatureInfo()->flag1 & 256) + skill = SKILL_HERBALISM; // special case + else if(creature->GetCreatureInfo()->flag1 & 512) + skill = SKILL_MINING; // special case + else + skill = SKILL_SKINNING; // normal case + + ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING); + creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + + int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5; + + int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill); + + // Double chances for elites + ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 ); +} + +void Spell::EffectCharge(uint32 /*i*/) +{ + if(!unitTarget || !m_caster) + return; + + float x, y, z; + unitTarget->GetContactPoint(m_caster, x, y, z); + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + ((Creature *)unitTarget)->StopMoving(); + + // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags + m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1); + + if(m_caster->GetTypeId() != TYPEID_PLAYER) + MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation()); + + // not all charge effects used in negative spells + if ( !IsPositiveSpell(m_spellInfo->Id)) + m_caster->Attack(unitTarget,true); +} + +void Spell::EffectSummonCritter(uint32 i) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + Player* player = (Player*)m_caster; + + uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; + if(!pet_entry) + return; + + Pet* old_critter = player->GetMiniPet(); + + // for same pet just despawn + if(old_critter && old_critter->GetEntry() == pet_entry) + { + player->RemoveMiniPet(); + return; + } + + // despawn old pet before summon new + if(old_critter) + player->RemoveMiniPet(); + + // summon new pet + Pet* critter = new Pet(MINI_PET); + + Map *map = m_caster->GetMap(); + uint32 pet_number = objmgr.GeneratePetNumber(); + if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), + map, pet_entry, pet_number)) + { + sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry); + delete critter; + return; + } + + float x,y,z; + // If dest location if present + if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + x = m_targets.m_destX; + y = m_targets.m_destY; + z = m_targets.m_destZ; + } + // Summon if dest location not present near caster + else + m_caster->GetClosePoint(x,y,z,critter->GetObjectSize()); + + critter->Relocate(x,y,z,m_caster->GetOrientation()); + + if(!critter->IsPositionValid()) + { + sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY()); + delete critter; + return; + } + + critter->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); + critter->SetUInt64Value(UNIT_FIELD_CREATEDBY,m_caster->GetGUID()); + critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); + critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + + critter->AIM_Initialize(); + critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter... + critter->SetMaxHealth(1); + critter->SetHealth(1); + critter->SetLevel(1); + + // set timer for unsummon + int32 duration = GetSpellDuration(m_spellInfo); + if(duration > 0) + critter->SetDuration(duration); + + std::string name = player->GetName(); + name.append(petTypeSuffix[critter->getPetType()]); + critter->SetName( name ); + player->SetMiniPet(critter); + + map->Add((Creature*)critter); +} + +void Spell::EffectKnockBack(uint32 i) +{ + if(!unitTarget || !m_caster) + return; + + // Effect only works on players + if(unitTarget->GetTypeId()!=TYPEID_PLAYER) + return; + + float vsin = sin(m_caster->GetAngle(unitTarget)); + float vcos = cos(m_caster->GetAngle(unitTarget)); + + WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); + data.append(unitTarget->GetPackGUID()); + data << uint32(0); // Sequence + data << float(vcos); // x direction + data << float(vsin); // y direction + data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed + data << float(damage/-10); // Z Movement speed (vertical) + + ((Player*)unitTarget)->GetSession()->SendPacket(&data); +} + +void Spell::EffectSendTaxi(uint32 i) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]); + if(!entry) + return; + + std::vector nodes; + + nodes.resize(2); + nodes[0] = entry->from; + nodes[1] = entry->to; + + uint32 mountid = 0; + switch(m_spellInfo->Id) + { + case 31606: //Stormcrow Amulet + mountid = 17447; + break; + case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run + case 45113: //Quest - Sunwell Daily - Ship Bombing Run + case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return + mountid = 22840; + break; + case 34905: //Stealth Flight + mountid = 6851; + break; + } + + ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid); + +} + +void Spell::EffectPlayerPull(uint32 i) +{ + if(!unitTarget || !m_caster) + return; + + // Effect only works on players + if(unitTarget->GetTypeId()!=TYPEID_PLAYER) + return; + + float vsin = sin(unitTarget->GetAngle(m_caster)); + float vcos = cos(unitTarget->GetAngle(m_caster)); + + WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); + data.append(unitTarget->GetPackGUID()); + data << uint32(0); // Sequence + data << float(vcos); // x direction + data << float(vsin); // y direction + // Horizontal speed + data << float(damage ? damage : unitTarget->GetDistance2d(m_caster)); + data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed + + ((Player*)unitTarget)->GetSession()->SendPacket(&data); +} + +void Spell::EffectDispelMechanic(uint32 i) +{ + if(!unitTarget) + return; + + uint32 mechanic = m_spellInfo->EffectMiscValue[i]; + + Unit::AuraMap& Auras = unitTarget->GetAuras(); + for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next) + { + next = iter; + ++next; + SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id); + if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic) + { + unitTarget->RemoveAurasDueToSpell(spell->Id); + if(Auras.empty()) + break; + else + next = Auras.begin(); + } + } + return; +} + +void Spell::EffectSummonDeadPet(uint32 /*i*/) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + Player *_player = (Player*)m_caster; + Pet *pet = _player->GetPet(); + if(!pet) + return; + if(pet->isAlive()) + return; + if(damage < 0) + return; + pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); + pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + pet->setDeathState( ALIVE ); + pet->clearUnitState(UNIT_STAT_ALL_STATE); + pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100))); + + pet->AIM_Initialize(); + + _player->PetSpellInitialize(); + pet->SavePetToDB(PET_SAVE_AS_CURRENT); +} + +void Spell::EffectDestroyAllTotems(uint32 /*i*/) +{ + float mana = 0; + for(int slot = 0; slot < MAX_TOTEM; ++slot) + { + if(!m_caster->m_TotemSlot[slot]) + continue; + + Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]); + if(totem && totem->isTotem()) + { + uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id); + if(spellInfo) + mana += spellInfo->manaCost * damage / 100; + ((Totem*)totem)->UnSummon(); + } + } + + int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana)); + m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA); +} + +void Spell::EffectDurabilityDamage(uint32 i) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + int32 slot = m_spellInfo->EffectMiscValue[i]; + + // FIXME: some spells effects have value -1/-2 + // Possibly its mean -1 all player equipped items and -2 all items + if(slot < 0) + { + ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1)); + return; + } + + // invalid slot value + if(slot >= INVENTORY_SLOT_BAG_END) + return; + + if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot)) + ((Player*)unitTarget)->DurabilityPointsLoss(item,damage); +} + +void Spell::EffectDurabilityDamagePCT(uint32 i) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + int32 slot = m_spellInfo->EffectMiscValue[i]; + + // FIXME: some spells effects have value -1/-2 + // Possibly its mean -1 all player equipped items and -2 all items + if(slot < 0) + { + ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1)); + return; + } + + // invalid slot value + if(slot >= INVENTORY_SLOT_BAG_END) + return; + + if(damage <= 0) + return; + + if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot)) + ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f); +} + +void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/) +{ + if(!unitTarget) + return; + + unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage); +} + +void Spell::EffectTransmitted(uint32 effIndex) +{ + uint32 name_id = m_spellInfo->EffectMiscValue[effIndex]; + + GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id); + + if (!goinfo) + { + sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id); + return; + } + + float fx,fy,fz; + + if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + { + fx = m_targets.m_destX; + fy = m_targets.m_destY; + fz = m_targets.m_destZ; + } + //FIXME: this can be better check for most objects but still hack + else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0) + { + float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex])); + m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis); + } + else + { + float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); + float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); + float dis = rand_norm() * (max_dis - min_dis) + min_dis; + + m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis); + } + + Map *cMap = m_caster->GetMap(); + + if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE) + { + if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole + { // but this is not proper, we really need to ignore not materialized objects + SendCastResult(SPELL_FAILED_NOT_HERE); + SendChannelUpdate(0); + return; + } + + // replace by water level in this case + fz = cMap->GetWaterLevel(fx,fy); + } + // if gameobject is summoning object, it should be spawned right on caster's position + else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL) + { + m_caster->GetPosition(fx,fy,fz); + } + + GameObject* pGameObj = new GameObject; + + if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap, + fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1)) + { + delete pGameObj; + return; + } + + int32 duration = GetSpellDuration(m_spellInfo); + + switch(goinfo->type) + { + case GAMEOBJECT_TYPE_FISHINGNODE: + { + m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID()); + // Orientation3 + pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 2, 0.88431775569915771 ); + // Orientation4 + pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 3, -0.4668855369091033 ); + m_caster->AddGameObject(pGameObj); // will removed at spell cancel + + // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo)) + // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME) + int32 lastSec; + switch(urand(0, 3)) + { + case 0: lastSec = 3; break; + case 1: lastSec = 7; break; + case 2: lastSec = 13; break; + case 3: lastSec = 17; break; + } + + duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000; + break; + } + case GAMEOBJECT_TYPE_SUMMONING_RITUAL: + { + if(m_caster->GetTypeId()==TYPEID_PLAYER) + { + pGameObj->AddUniqueUse((Player*)m_caster); + m_caster->AddGameObject(pGameObj); // will removed at spell cancel + } + break; + } + case GAMEOBJECT_TYPE_FISHINGHOLE: + case GAMEOBJECT_TYPE_CHEST: + default: + { + break; + } + } + + pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); + + pGameObj->SetOwnerGUID(m_caster->GetGUID() ); + + pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); + pGameObj->SetSpellId(m_spellInfo->Id); + + DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n"); + //m_caster->AddGameObject(pGameObj); + //m_ObjToDel.push_back(pGameObj); + + cMap->Add(pGameObj); + + WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); + data << uint64(pGameObj->GetGUID()); + m_caster->SendMessageToSet(&data,true); + + if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry()) + { + GameObject* linkedGO = new GameObject; + if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap, + fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1)) + { + linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0); + linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); + linkedGO->SetSpellId(m_spellInfo->Id); + linkedGO->SetOwnerGUID(m_caster->GetGUID() ); + + MapManager::Instance().GetMap(linkedGO->GetMapId(), linkedGO)->Add(linkedGO); + } + else + { + delete linkedGO; + linkedGO = NULL; + return; + } + } +} + +void Spell::EffectProspecting(uint32 /*i*/) +{ + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* p_caster = (Player*)m_caster; + if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)) + return; + + if(itemTarget->GetCount() < 5) + return; + + if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING)) + { + uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING); + uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank; + p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue); + } + + ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING); +} + +void Spell::EffectSkill(uint32 /*i*/) +{ + sLog.outDebug("WORLD: SkillEFFECT"); +} + +void Spell::EffectSummonDemon(uint32 i) +{ + float px = m_targets.m_destX; + float py = m_targets.m_destY; + float pz = m_targets.m_destZ; + + Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000); + if (!Charmed) + return; + + // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster? + Charmed->SetLevel(m_caster->getLevel()); + + // TODO: Add damage/mana/hp according to level + + if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon + { + // Enslave demon effect, without mana cost and cooldown + m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved + + // Inferno effect + Charmed->CastSpell(Charmed, 22703, true, 0); + } +} + +/* There is currently no need for this effect. We handle it in BattleGround.cpp + If we would handle the resurrection here, the spiritguide would instantly disappear as the + player revives, and so we wouldn't see the spirit heal visual effect on the npc. + This is why we use a half sec delay between the visual effect and the resurrection itself */ +void Spell::EffectSpiritHeal(uint32 /*i*/) +{ + /* + if(!unitTarget || unitTarget->isAlive()) + return; + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + if(!unitTarget->IsInWorld()) + return; + + //m_spellInfo->EffectBasePoints[i]; == 99 (percent?) + //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA)); + ((Player*)unitTarget)->ResurrectPlayer(1.0f); + ((Player*)unitTarget)->SpawnCorpseBones(); + */ +} + +// remove insignia spell effect +void Spell::EffectSkinPlayerCorpse(uint32 /*i*/) +{ + sLog.outDebug("Effect: SkinPlayerCorpse"); + if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) ) + return; + + ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster ); +} + +void Spell::EffectStealBeneficialBuff(uint32 i) +{ + sLog.outDebug("Effect: StealBeneficialBuff"); + + if(!unitTarget || unitTarget==m_caster) // can't steal from self + return; + + std::vector steal_list; + // Create dispel mask by dispel type + uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) ); + Unit::AuraMap const& auras = unitTarget->GetAuras(); + for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + Aura *aur = (*itr).second; + if (aur && (1<GetSpellProto()->Dispel) & dispelMask) + { + // Need check for passive? this + if (aur->IsPositive() && !aur->IsPassive()) + steal_list.push_back(aur); + } + } + // Ok if exist some buffs for dispel try dispel it + if (!steal_list.empty()) + { + std::list < std::pair > success_list; + int32 list_size = steal_list.size(); + // Dispell N = damage buffs (or while exist buffs for dispel) + for (int32 count=0; count < damage && list_size > 0; ++count) + { + // Random select buff for dispel + Aura *aur = steal_list[urand(0, list_size-1)]; + // Not use chance for steal + // TODO possible need do it + success_list.push_back( std::pair(aur->GetId(),aur->GetCasterGUID())); + + // Remove buff from list for prevent doubles + for (std::vector::iterator j = steal_list.begin(); j != steal_list.end(); ) + { + Aura *stealed = *j; + if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID()) + { + j = steal_list.erase(j); + --list_size; + } + else + ++j; + } + } + // Really try steal and send log + if (!success_list.empty()) + { + int32 count = success_list.size(); + WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5); + data.append(unitTarget->GetPackGUID()); // Victim GUID + data.append(m_caster->GetPackGUID()); // Caster GUID + data << uint32(m_spellInfo->Id); // Dispell spell id + data << uint8(0); // not used + data << uint32(count); // count + for (std::list >::iterator j = success_list.begin(); j != success_list.end(); ++j) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first); + data << uint32(spellInfo->Id); // Spell Id + data << uint8(0); // 0 - steals !=0 transfers + unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster); + } + m_caster->SendMessageToSet(&data, true); + } + } +} + +void Spell::EffectKillCredit(uint32 i) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0); +} + +void Spell::EffectQuestFail(uint32 i) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]); +} diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp index b89346d937a..951a92cb5ad 100644 --- a/src/game/StatSystem.cpp +++ b/src/game/StatSystem.cpp @@ -1,955 +1,965 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Unit.h" -#include "Player.h" -#include "Pet.h" -#include "Creature.h" -#include "SharedDefines.h" -#include "SpellAuras.h" - -/*####################################### -######## ######## -######## PLAYERS STAT SYSTEM ######## -######## ######## -#######################################*/ - -bool Player::UpdateStats(Stats stat) -{ - if(stat > STAT_SPIRIT) - return false; - - // value = ((base_value * base_pct) + total_value) * total_pct - float value = GetTotalStatValue(stat); - - SetStat(stat, int32(value)); - - if(stat == STAT_STAMINA || stat == STAT_INTELLECT) - { - Pet *pet = GetPet(); - if(pet) - pet->UpdateStats(stat); - } - - switch(stat) - { - case STAT_STRENGTH: - UpdateAttackPowerAndDamage(); - UpdateShieldBlockValue(); - break; - case STAT_AGILITY: - UpdateArmor(); - UpdateAttackPowerAndDamage(true); - if(getClass() == CLASS_ROGUE || getClass() == CLASS_HUNTER || getClass() == CLASS_DRUID && m_form==FORM_CAT) - UpdateAttackPowerAndDamage(); - - UpdateAllCritPercentages(); - UpdateDodgePercentage(); - break; - - case STAT_STAMINA: UpdateMaxHealth(); break; - case STAT_INTELLECT: - UpdateMaxPower(POWER_MANA); - UpdateAllSpellCritChances(); - UpdateAttackPowerAndDamage(true); //SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, only intelect currently - UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently - break; - - case STAT_SPIRIT: - break; - - default: - break; - } - UpdateSpellDamageAndHealingBonus(); - UpdateManaRegen(); - return true; -} - -void Player::UpdateSpellDamageAndHealingBonus() -{ - // Magic damage modifiers implemented in Unit::SpellDamageBonus - // This information for client side use only - // Get healing bonus for all schools - SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL)); - // Get damage bonus for all schools - for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) - SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i))); -} - -bool Player::UpdateAllStats() -{ - for (int i = STAT_STRENGTH; i < MAX_STATS; i++) - { - float value = GetTotalStatValue(Stats(i)); - SetStat(Stats(i), (int32)value); - } - - UpdateAttackPowerAndDamage(); - UpdateAttackPowerAndDamage(true); - UpdateArmor(); - UpdateMaxHealth(); - - for(int i = POWER_MANA; i < MAX_POWERS; i++) - UpdateMaxPower(Powers(i)); - - UpdateAllCritPercentages(); - UpdateAllSpellCritChances(); - UpdateDefenseBonusesMod(); - UpdateShieldBlockValue(); - UpdateSpellDamageAndHealingBonus(); - UpdateManaRegen(); - UpdateExpertise(BASE_ATTACK); - UpdateExpertise(OFF_ATTACK); - for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) - UpdateResistances(i); - - return true; -} - -void Player::UpdateResistances(uint32 school) -{ - if(school > SPELL_SCHOOL_NORMAL) - { - float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); - SetResistance(SpellSchools(school), int32(value)); - - Pet *pet = GetPet(); - if(pet) - pet->UpdateResistances(school); - } - else - UpdateArmor(); -} - -void Player::UpdateArmor() -{ - float value = 0.0f; - UnitMods unitMod = UNIT_MOD_ARMOR; - - value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items) - value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items - value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats - value += GetModifierValue(unitMod, TOTAL_VALUE); - - //add dynamic flat mods - AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT); - for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) - value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f); - } - - value *= GetModifierValue(unitMod, TOTAL_PCT); - - SetArmor(int32(value)); - - Pet *pet = GetPet(); - if(pet) - pet->UpdateArmor(); -} - -float Player::GetHealthBonusFromStamina() -{ - float stamina = GetStat(STAT_STAMINA); - - float baseStam = stamina < 20 ? stamina : 20; - float moreStam = stamina - baseStam; - - return baseStam + (moreStam*10.0f); -} - -float Player::GetManaBonusFromIntellect() -{ - float intellect = GetStat(STAT_INTELLECT); - - float baseInt = intellect < 20 ? intellect : 20; - float moreInt = intellect - baseInt; - - return baseInt + (moreInt*15.0f); -} - -void Player::UpdateMaxHealth() -{ - UnitMods unitMod = UNIT_MOD_HEALTH; - - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina(); - value *= GetModifierValue(unitMod, TOTAL_PCT); - - SetMaxHealth((uint32)value); -} - -void Player::UpdateMaxPower(Powers power) -{ - UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - - float bonusPower = (power == POWER_MANA) ? GetManaBonusFromIntellect() : 0; - - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower; - value *= GetModifierValue(unitMod, TOTAL_PCT); - - SetMaxPower(power, uint32(value)); -} - -void Player::UpdateAttackPowerAndDamage(bool ranged ) -{ - float val2 = 0.0f; - float level = float(getLevel()); - - UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; - - uint16 index = UNIT_FIELD_ATTACK_POWER; - uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS; - uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; - - if(ranged) - { - index = UNIT_FIELD_RANGED_ATTACK_POWER; - index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS; - index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; - - switch(getClass()) - { - case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break; - case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break; - case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break; - case CLASS_DRUID: - switch(m_form) - { - case FORM_CAT: - case FORM_BEAR: - case FORM_DIREBEAR: - val2 = 0.0f; break; - default: - val2 = GetStat(STAT_AGILITY) - 10.0f; break; - } - break; - default: val2 = GetStat(STAT_AGILITY) - 10.0f; break; - } - } - else - { - switch(getClass()) - { - case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; - case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; - case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break; - case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break; - case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; - case CLASS_DRUID: - { - //Check if Predatory Strikes is skilled - float mLevelMult = 0.0; - switch(m_form) - { - case FORM_CAT: - case FORM_BEAR: - case FORM_DIREBEAR: - case FORM_MOONKIN: - { - Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) - { - // Predatory Strikes - if ((*itr)->GetSpellProto()->SpellIconID == 1563) - { - mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f; - break; - } - } - break; - } - } - - switch(m_form) - { - case FORM_CAT: - val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break; - case FORM_BEAR: - case FORM_DIREBEAR: - val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; - case FORM_MOONKIN: - val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; - default: - val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; - } - break; - } - case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; - case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; - case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; - } - } - - SetModifierValue(unitMod, BASE_VALUE, val2); - - float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); - - //add dynamic flat mods - if( ranged && (getClassMask() & CLASSMASK_WAND_USERS)==0) - { - AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT); - for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i) - attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f); - } - - float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; - - SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field - SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field - SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field - - //automatically update weapon damage after attack power modification - if(ranged) - { - UpdateDamagePhysical(RANGED_ATTACK); - - Pet *pet = GetPet(); //update pet's AP - if(pet) - pet->UpdateAttackPowerAndDamage(); - } - else - { - UpdateDamagePhysical(BASE_ATTACK); - if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon - UpdateDamagePhysical(OFF_ATTACK); - } -} - -void Player::UpdateShieldBlockValue() -{ - SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue()); -} - -void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage) -{ - UnitMods unitMod; - UnitMods attPower; - - switch(attType) - { - case BASE_ATTACK: - default: - unitMod = UNIT_MOD_DAMAGE_MAINHAND; - attPower = UNIT_MOD_ATTACK_POWER; - break; - case OFF_ATTACK: - unitMod = UNIT_MOD_DAMAGE_OFFHAND; - attPower = UNIT_MOD_ATTACK_POWER; - break; - case RANGED_ATTACK: - unitMod = UNIT_MOD_DAMAGE_RANGED; - attPower = UNIT_MOD_ATTACK_POWER_RANGED; - break; - } - - float att_speed = GetAPMultiplier(attType,normalized); - - float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; - float base_pct = GetModifierValue(unitMod, BASE_PCT); - float total_value = GetModifierValue(unitMod, TOTAL_VALUE); - float total_pct = GetModifierValue(unitMod, TOTAL_PCT); - - float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE); - float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE); - - if (IsInFeralForm()) //check if player is druid and in cat or bear forms - { - uint32 lvl = getLevel(); - if ( lvl > 60 ) lvl = 60; - - weapon_mindamage = lvl*0.85*att_speed; - weapon_maxdamage = lvl*1.25*att_speed; - } - else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc) - { - weapon_mindamage = BASE_MINDAMAGE; - weapon_maxdamage = BASE_MAXDAMAGE; - } - else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage - { - weapon_mindamage += GetAmmoDPS() * att_speed; - weapon_maxdamage += GetAmmoDPS() * att_speed; - } - - min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct; - max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct; -} - -void Player::UpdateDamagePhysical(WeaponAttackType attType) -{ - float mindamage; - float maxdamage; - - CalculateMinMaxDamage(attType,false,mindamage,maxdamage); - - switch(attType) - { - case BASE_ATTACK: - default: - SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage); - SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage); - break; - case OFF_ATTACK: - SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage); - SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage); - break; - case RANGED_ATTACK: - SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage); - SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage); - break; - } -} - -void Player::UpdateDefenseBonusesMod() -{ - UpdateBlockPercentage(); - UpdateParryPercentage(); - UpdateDodgePercentage(); -} - -void Player::UpdateBlockPercentage() -{ - // Base value - float value = 5.0f; - // Modify value from defense skill - value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; - // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura - value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); - // Increase from rating - value += GetRatingBonusValue(CR_BLOCK); - value = value < 0.0f ? 0.0f : value; - SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value); -} - -void Player::UpdateCritPercentage(WeaponAttackType attType) -{ - BaseModGroup modGroup; - uint16 index; - CombatRating cr; - - switch(attType) - { - case OFF_ATTACK: - modGroup = OFFHAND_CRIT_PERCENTAGE; - index = PLAYER_OFFHAND_CRIT_PERCENTAGE; - cr = CR_CRIT_MELEE; - break; - case RANGED_ATTACK: - modGroup = RANGED_CRIT_PERCENTAGE; - index = PLAYER_RANGED_CRIT_PERCENTAGE; - cr = CR_CRIT_RANGED; - break; - case BASE_ATTACK: - default: - modGroup = CRIT_PERCENTAGE; - index = PLAYER_CRIT_PERCENTAGE; - cr = CR_CRIT_MELEE; - break; - } - - float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr); - // Modify crit from weapon skill and maximized defense skill of same level victim difference - value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f; - value = value < 0.0f ? 0.0f : value; - SetStatFloatValue(index, value); -} - -void Player::UpdateAllCritPercentages() -{ - float value = GetMeleeCritFromAgility(); - - SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value); - SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value); - SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value); - - UpdateCritPercentage(BASE_ATTACK); - UpdateCritPercentage(OFF_ATTACK); - UpdateCritPercentage(RANGED_ATTACK); -} - -void Player::UpdateParryPercentage() -{ - // Base parry - float value = 5.0f; - // Modify value from defense skill - value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; - // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura - value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); - // Parry from rating - value += GetRatingBonusValue(CR_PARRY); - value = value < 0.0f ? 0.0f : value; - SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value); -} - -void Player::UpdateDodgePercentage() -{ - // Dodge from agility - float value = GetDodgeFromAgility(); - // Modify value from defense skill - value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; - // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura - value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); - // Dodge from rating - value += GetRatingBonusValue(CR_DODGE); - value = value < 0.0f ? 0.0f : value; - SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value); -} - -void Player::UpdateSpellCritChance(uint32 school) -{ - // For normal school set zero crit chance - if(school == SPELL_SCHOOL_NORMAL) - { - SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f); - return; - } - // For others recalculate it from: - float crit = 0.0f; - // Crit from Intellect - crit += GetSpellCritFromIntellect(); - // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE - crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE); - // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL - crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<GetSpellProto()->EquippedItemClass == -1) - expertise += (*itr)->GetModifier()->m_amount; - // item dependent spell - else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto())) - expertise += (*itr)->GetModifier()->m_amount; - } - - if(expertise < 0) - expertise = 0; - - switch(attack) - { - case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break; - case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break; - default: break; - } -} - -void Player::UpdateManaRegen() -{ - float Intellect = GetStat(STAT_INTELLECT); - // Mana regen from spirit and intellect - float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit(); - // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen - power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA); - - // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura - float power_regen_mp5 = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f; - - // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura - AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT); - for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f; - } - - // Bonus from some dummy auras - AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_PERIODIC_DUMMY); - for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) - if((*i)->GetId() == 34074) // Aspect of the Viper - { - power_regen_mp5 += (*i)->GetModifier()->m_amount * Intellect / 500.0f; - // Add regen bonus from level in this dummy - power_regen_mp5 += getLevel() * 35 / 100; - } - - // Set regen rate in cast state apply only on spirit based regen - int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT); - if (modManaRegenInterrupt > 100) - modManaRegenInterrupt = 100; - SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f); - - SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN, power_regen_mp5 + power_regen); -} - -void Player::_ApplyAllStatBonuses() -{ - SetCanModifyStats(false); - - _ApplyAllAuraMods(); - _ApplyAllItemMods(); - - SetCanModifyStats(true); - - UpdateAllStats(); -} - -void Player::_RemoveAllStatBonuses() -{ - SetCanModifyStats(false); - - _RemoveAllItemMods(); - _RemoveAllAuraMods(); - - SetCanModifyStats(true); - - UpdateAllStats(); -} - -/*####################################### -######## ######## -######## MOBS STAT SYSTEM ######## -######## ######## -#######################################*/ - -bool Creature::UpdateStats(Stats /*stat*/) -{ - return true; -} - -bool Creature::UpdateAllStats() -{ - UpdateMaxHealth(); - UpdateAttackPowerAndDamage(); - - for(int i = POWER_MANA; i < MAX_POWERS; ++i) - UpdateMaxPower(Powers(i)); - - for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) - UpdateResistances(i); - - return true; -} - -void Creature::UpdateResistances(uint32 school) -{ - if(school > SPELL_SCHOOL_NORMAL) - { - float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); - SetResistance(SpellSchools(school), int32(value)); - } - else - UpdateArmor(); -} - -void Creature::UpdateArmor() -{ - float value = GetTotalAuraModValue(UNIT_MOD_ARMOR); - SetArmor(int32(value)); -} - -void Creature::UpdateMaxHealth() -{ - float value = GetTotalAuraModValue(UNIT_MOD_HEALTH); - SetMaxHealth((uint32)value); -} - -void Creature::UpdateMaxPower(Powers power) -{ - UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - - float value = GetTotalAuraModValue(unitMod); - SetMaxPower(power, uint32(value)); -} - -void Creature::UpdateAttackPowerAndDamage(bool ranged) -{ - if(ranged) - return; - - //automatically update weapon damage after attack power modification - UpdateDamagePhysical(BASE_ATTACK); -} - -void Creature::UpdateDamagePhysical(WeaponAttackType attType) -{ - if(attType > BASE_ATTACK) - return; - - UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; - - float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f; - - float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; - float base_pct = GetModifierValue(unitMod, BASE_PCT); - float total_value = GetModifierValue(unitMod, TOTAL_VALUE); - float total_pct = GetModifierValue(unitMod, TOTAL_PCT); - - float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); - float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); - - float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ; - float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ; - - SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); - SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); -} - -/*####################################### -######## ######## -######## PETS STAT SYSTEM ######## -######## ######## -#######################################*/ - -bool Pet::UpdateStats(Stats stat) -{ - if(stat > STAT_SPIRIT) - return false; - - // value = ((base_value * base_pct) + total_value) * total_pct - float value = GetTotalStatValue(stat); - - Unit *owner = GetOwner(); - if ( stat == STAT_STAMINA ) - { - if(owner) - value += float(owner->GetStat(stat)) * 0.3f; - } - //warlock's and mage's pets gain 30% of owner's intellect - else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET ) - { - if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) ) - value += float(owner->GetStat(stat)) * 0.3f; - } - - SetStat(stat, int32(value)); - - switch(stat) - { - case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break; - case STAT_AGILITY: UpdateArmor(); break; - case STAT_STAMINA: UpdateMaxHealth(); break; - case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break; - case STAT_SPIRIT: - default: - break; - } - - return true; -} - -bool Pet::UpdateAllStats() -{ - for (int i = STAT_STRENGTH; i < MAX_STATS; i++) - UpdateStats(Stats(i)); - - for(int i = POWER_MANA; i < MAX_POWERS; i++) - UpdateMaxPower(Powers(i)); - - for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) - UpdateResistances(i); - - return true; -} - -void Pet::UpdateResistances(uint32 school) -{ - if(school > SPELL_SCHOOL_NORMAL) - { - float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); - - Unit *owner = GetOwner(); - // hunter and warlock pets gain 40% of owner's resistance - if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)) - value += float(owner->GetResistance(SpellSchools(school))) * 0.4f; - - SetResistance(SpellSchools(school), int32(value)); - } - else - UpdateArmor(); -} - -void Pet::UpdateArmor() -{ - float value = 0.0f; - float bonus_armor = 0.0f; - UnitMods unitMod = UNIT_MOD_ARMOR; - - Unit *owner = GetOwner(); - // hunter and warlock pets gain 35% of owner's armor value - if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)) - bonus_armor = 0.35f * float(owner->GetArmor()); - - value = GetModifierValue(unitMod, BASE_VALUE); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetStat(STAT_AGILITY) * 2.0f; - value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor; - value *= GetModifierValue(unitMod, TOTAL_PCT); - - SetArmor(int32(value)); -} - -void Pet::UpdateMaxHealth() -{ - UnitMods unitMod = UNIT_MOD_HEALTH; - float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA); - - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f; - value *= GetModifierValue(unitMod, TOTAL_PCT); - - SetMaxHealth((uint32)value); -} - -void Pet::UpdateMaxPower(Powers power) -{ - UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f; - - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f; - value *= GetModifierValue(unitMod, TOTAL_PCT); - - SetMaxPower(power, uint32(value)); -} - -void Pet::UpdateAttackPowerAndDamage(bool ranged) -{ - if(ranged) - return; - - float val = 0.0f; - float bonusAP = 0.0f; - UnitMods unitMod = UNIT_MOD_ATTACK_POWER; - - if(GetEntry() == 416) // imp's attack power - val = GetStat(STAT_STRENGTH) - 10.0f; - else - val = 2 * GetStat(STAT_STRENGTH) - 20.0f; - - Unit* owner = GetOwner(); - if( owner && owner->GetTypeId()==TYPEID_PLAYER) - { - if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power - { - bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f; - SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.125f)); - } - //demons benefit from warlocks shadow or fire damage - else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK) - { - int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); - int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW); - int32 maximum = (fire > shadow) ? fire : shadow; - if(maximum < 0) - maximum = 0; - SetBonusDamage( int32(maximum * 0.15f)); - bonusAP = maximum * 0.57f; - } - //water elementals benefit from mage's frost damage - else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE) - { - int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST); - if(frost < 0) - frost = 0; - SetBonusDamage( int32(frost * 0.4f)); - } - } - - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP); - - //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB - float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); - float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; - - //UNIT_FIELD_(RANGED)_ATTACK_POWER field - SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower); - //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field - SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod); - //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field - SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier); - - //automatically update weapon damage after attack power modification - UpdateDamagePhysical(BASE_ATTACK); -} - -void Pet::UpdateDamagePhysical(WeaponAttackType attType) -{ - if(attType > BASE_ATTACK) - return; - - UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; - - float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f; - - float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; - float base_pct = GetModifierValue(unitMod, BASE_PCT); - float total_value = GetModifierValue(unitMod, TOTAL_VALUE); - float total_pct = GetModifierValue(unitMod, TOTAL_PCT); - - float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); - float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); - - float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct; - float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct; - - // Pet's base damage changes depending on happiness - if (getPetType() == HUNTER_PET && attType == BASE_ATTACK) - { - switch(GetHappinessState()) - { - case HAPPY: - // 125% of normal damage - mindamage = mindamage * 1.25; - maxdamage = maxdamage * 1.25; - break; - case CONTENT: - // 100% of normal damage, nothing to modify - break; - case UNHAPPY: - // 75% of normal damage - mindamage = mindamage * 0.75; - maxdamage = maxdamage * 0.75; - break; - } - } - - SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); - SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Unit.h" +#include "Player.h" +#include "Pet.h" +#include "Creature.h" +#include "SharedDefines.h" +#include "SpellAuras.h" + +/*####################################### +######## ######## +######## PLAYERS STAT SYSTEM ######## +######## ######## +#######################################*/ + +bool Player::UpdateStats(Stats stat) +{ + if(stat > STAT_SPIRIT) + return false; + + // value = ((base_value * base_pct) + total_value) * total_pct + float value = GetTotalStatValue(stat); + + SetStat(stat, int32(value)); + + if(stat == STAT_STAMINA || stat == STAT_INTELLECT) + { + Pet *pet = GetPet(); + if(pet) + pet->UpdateStats(stat); + } + + switch(stat) + { + case STAT_STRENGTH: + UpdateAttackPowerAndDamage(); + UpdateShieldBlockValue(); + break; + case STAT_AGILITY: + UpdateArmor(); + UpdateAttackPowerAndDamage(true); + if(getClass() == CLASS_ROGUE || getClass() == CLASS_HUNTER || getClass() == CLASS_DRUID && m_form==FORM_CAT) + UpdateAttackPowerAndDamage(); + + UpdateAllCritPercentages(); + UpdateDodgePercentage(); + break; + + case STAT_STAMINA: UpdateMaxHealth(); break; + case STAT_INTELLECT: + UpdateMaxPower(POWER_MANA); + UpdateAllSpellCritChances(); + UpdateAttackPowerAndDamage(true); //SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, only intelect currently + UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently + break; + + case STAT_SPIRIT: + break; + + default: + break; + } + UpdateSpellDamageAndHealingBonus(); + UpdateManaRegen(); + return true; +} + +void Player::UpdateSpellDamageAndHealingBonus() +{ + // Magic damage modifiers implemented in Unit::SpellDamageBonus + // This information for client side use only + // Get healing bonus for all schools + SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL)); + // Get damage bonus for all schools + for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) + SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i))); +} + +bool Player::UpdateAllStats() +{ + for (int i = STAT_STRENGTH; i < MAX_STATS; i++) + { + float value = GetTotalStatValue(Stats(i)); + SetStat(Stats(i), (int32)value); + } + + UpdateAttackPowerAndDamage(); + UpdateAttackPowerAndDamage(true); + UpdateArmor(); + UpdateMaxHealth(); + + for(int i = POWER_MANA; i < MAX_POWERS; i++) + UpdateMaxPower(Powers(i)); + + UpdateAllCritPercentages(); + UpdateAllSpellCritChances(); + UpdateDefenseBonusesMod(); + UpdateShieldBlockValue(); + UpdateSpellDamageAndHealingBonus(); + UpdateManaRegen(); + UpdateExpertise(BASE_ATTACK); + UpdateExpertise(OFF_ATTACK); + for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + UpdateResistances(i); + + return true; +} + +void Player::UpdateResistances(uint32 school) +{ + if(school > SPELL_SCHOOL_NORMAL) + { + float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); + SetResistance(SpellSchools(school), int32(value)); + + Pet *pet = GetPet(); + if(pet) + pet->UpdateResistances(school); + } + else + UpdateArmor(); +} + +void Player::UpdateArmor() +{ + float value = 0.0f; + UnitMods unitMod = UNIT_MOD_ARMOR; + + value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items) + value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items + value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats + value += GetModifierValue(unitMod, TOTAL_VALUE); + + //add dynamic flat mods + AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT); + for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) + value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f); + } + + value *= GetModifierValue(unitMod, TOTAL_PCT); + + SetArmor(int32(value)); + + Pet *pet = GetPet(); + if(pet) + pet->UpdateArmor(); +} + +float Player::GetHealthBonusFromStamina() +{ + float stamina = GetStat(STAT_STAMINA); + + float baseStam = stamina < 20 ? stamina : 20; + float moreStam = stamina - baseStam; + + return baseStam + (moreStam*10.0f); +} + +float Player::GetManaBonusFromIntellect() +{ + float intellect = GetStat(STAT_INTELLECT); + + float baseInt = intellect < 20 ? intellect : 20; + float moreInt = intellect - baseInt; + + return baseInt + (moreInt*15.0f); +} + +void Player::UpdateMaxHealth() +{ + UnitMods unitMod = UNIT_MOD_HEALTH; + + float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); + value *= GetModifierValue(unitMod, BASE_PCT); + value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina(); + value *= GetModifierValue(unitMod, TOTAL_PCT); + + SetMaxHealth((uint32)value); +} + +void Player::UpdateMaxPower(Powers power) +{ + UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); + + float bonusPower = (power == POWER_MANA) ? GetManaBonusFromIntellect() : 0; + + float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); + value *= GetModifierValue(unitMod, BASE_PCT); + value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower; + value *= GetModifierValue(unitMod, TOTAL_PCT); + + SetMaxPower(power, uint32(value)); +} + +void Player::UpdateAttackPowerAndDamage(bool ranged ) +{ + float val2 = 0.0f; + float level = float(getLevel()); + + UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; + + uint16 index = UNIT_FIELD_ATTACK_POWER; + uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS; + uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; + + if(ranged) + { + index = UNIT_FIELD_RANGED_ATTACK_POWER; + index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS; + index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; + + switch(getClass()) + { + case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break; + case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break; + case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break; + case CLASS_DRUID: + switch(m_form) + { + case FORM_CAT: + case FORM_BEAR: + case FORM_DIREBEAR: + val2 = 0.0f; break; + default: + val2 = GetStat(STAT_AGILITY) - 10.0f; break; + } + break; + default: val2 = GetStat(STAT_AGILITY) - 10.0f; break; + } + } + else + { + switch(getClass()) + { + case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break; + case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break; + case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + case CLASS_DRUID: + { + //Check if Predatory Strikes is skilled + float mLevelMult = 0.0; + switch(m_form) + { + case FORM_CAT: + case FORM_BEAR: + case FORM_DIREBEAR: + case FORM_MOONKIN: + { + Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) + { + // Predatory Strikes + if ((*itr)->GetSpellProto()->SpellIconID == 1563) + { + mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f; + break; + } + } + break; + } + } + + switch(m_form) + { + case FORM_CAT: + val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break; + case FORM_BEAR: + case FORM_DIREBEAR: + val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + case FORM_MOONKIN: + val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + default: + val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; + } + break; + } + case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; + case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; + case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; + } + } + + SetModifierValue(unitMod, BASE_VALUE, val2); + + float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); + float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); + + //add dynamic flat mods + if( ranged && (getClassMask() & CLASSMASK_WAND_USERS)==0) + { + AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT); + for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i) + attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f); + } + + float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; + + SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field + SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field + SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field + + //automatically update weapon damage after attack power modification + if(ranged) + { + UpdateDamagePhysical(RANGED_ATTACK); + + Pet *pet = GetPet(); //update pet's AP + if(pet) + pet->UpdateAttackPowerAndDamage(); + } + else + { + UpdateDamagePhysical(BASE_ATTACK); + if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon + UpdateDamagePhysical(OFF_ATTACK); + } +} + +void Player::UpdateShieldBlockValue() +{ + SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue()); +} + +void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage) +{ + UnitMods unitMod; + UnitMods attPower; + + switch(attType) + { + case BASE_ATTACK: + default: + unitMod = UNIT_MOD_DAMAGE_MAINHAND; + attPower = UNIT_MOD_ATTACK_POWER; + break; + case OFF_ATTACK: + unitMod = UNIT_MOD_DAMAGE_OFFHAND; + attPower = UNIT_MOD_ATTACK_POWER; + break; + case RANGED_ATTACK: + unitMod = UNIT_MOD_DAMAGE_RANGED; + attPower = UNIT_MOD_ATTACK_POWER_RANGED; + break; + } + + float att_speed = GetAPMultiplier(attType,normalized); + + float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; + float base_pct = GetModifierValue(unitMod, BASE_PCT); + float total_value = GetModifierValue(unitMod, TOTAL_VALUE); + float total_pct = GetModifierValue(unitMod, TOTAL_PCT); + + float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE); + float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE); + + if (IsInFeralForm()) //check if player is druid and in cat or bear forms + { + uint32 lvl = getLevel(); + if ( lvl > 60 ) lvl = 60; + + weapon_mindamage = lvl*0.85*att_speed; + weapon_maxdamage = lvl*1.25*att_speed; + } + else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc) + { + weapon_mindamage = BASE_MINDAMAGE; + weapon_maxdamage = BASE_MAXDAMAGE; + } + else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage + { + weapon_mindamage += GetAmmoDPS() * att_speed; + weapon_maxdamage += GetAmmoDPS() * att_speed; + } + + min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct; + max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct; +} + +void Player::UpdateDamagePhysical(WeaponAttackType attType) +{ + float mindamage; + float maxdamage; + + CalculateMinMaxDamage(attType,false,mindamage,maxdamage); + + switch(attType) + { + case BASE_ATTACK: + default: + SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage); + SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage); + break; + case OFF_ATTACK: + SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage); + SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage); + break; + case RANGED_ATTACK: + SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage); + SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage); + break; + } +} + +void Player::UpdateDefenseBonusesMod() +{ + UpdateBlockPercentage(); + UpdateParryPercentage(); + UpdateDodgePercentage(); +} + +void Player::UpdateBlockPercentage() +{ + // No block + float value = 0.0f; + if(CanBlock()) + { + // Base value + value = 5.0f; + // Modify value from defense skill + value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; + // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura + value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); + // Increase from rating + value += GetRatingBonusValue(CR_BLOCK); + value = value < 0.0f ? 0.0f : value; + } + SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value); +} + +void Player::UpdateCritPercentage(WeaponAttackType attType) +{ + BaseModGroup modGroup; + uint16 index; + CombatRating cr; + + switch(attType) + { + case OFF_ATTACK: + modGroup = OFFHAND_CRIT_PERCENTAGE; + index = PLAYER_OFFHAND_CRIT_PERCENTAGE; + cr = CR_CRIT_MELEE; + break; + case RANGED_ATTACK: + modGroup = RANGED_CRIT_PERCENTAGE; + index = PLAYER_RANGED_CRIT_PERCENTAGE; + cr = CR_CRIT_RANGED; + break; + case BASE_ATTACK: + default: + modGroup = CRIT_PERCENTAGE; + index = PLAYER_CRIT_PERCENTAGE; + cr = CR_CRIT_MELEE; + break; + } + + float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr); + // Modify crit from weapon skill and maximized defense skill of same level victim difference + value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f; + value = value < 0.0f ? 0.0f : value; + SetStatFloatValue(index, value); +} + +void Player::UpdateAllCritPercentages() +{ + float value = GetMeleeCritFromAgility(); + + SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value); + SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value); + SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value); + + UpdateCritPercentage(BASE_ATTACK); + UpdateCritPercentage(OFF_ATTACK); + UpdateCritPercentage(RANGED_ATTACK); +} + +void Player::UpdateParryPercentage() +{ + // No parry + float value = 0.0f; + if (CanParry()) + { + // Base parry + value = 5.0f; + // Modify value from defense skill + value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; + // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura + value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); + // Parry from rating + value += GetRatingBonusValue(CR_PARRY); + value = value < 0.0f ? 0.0f : value; + } + SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value); +} + +void Player::UpdateDodgePercentage() +{ + // Dodge from agility + float value = GetDodgeFromAgility(); + // Modify value from defense skill + value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; + // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura + value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); + // Dodge from rating + value += GetRatingBonusValue(CR_DODGE); + value = value < 0.0f ? 0.0f : value; + SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value); +} + +void Player::UpdateSpellCritChance(uint32 school) +{ + // For normal school set zero crit chance + if(school == SPELL_SCHOOL_NORMAL) + { + SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f); + return; + } + // For others recalculate it from: + float crit = 0.0f; + // Crit from Intellect + crit += GetSpellCritFromIntellect(); + // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE + crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE); + // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL + crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<GetSpellProto()->EquippedItemClass == -1) + expertise += (*itr)->GetModifier()->m_amount; + // item dependent spell + else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto())) + expertise += (*itr)->GetModifier()->m_amount; + } + + if(expertise < 0) + expertise = 0; + + switch(attack) + { + case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break; + case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break; + default: break; + } +} + +void Player::UpdateManaRegen() +{ + float Intellect = GetStat(STAT_INTELLECT); + // Mana regen from spirit and intellect + float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit(); + // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen + power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA); + + // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura + float power_regen_mp5 = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f; + + // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura + AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT); + for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f; + } + + // Bonus from some dummy auras + AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_PERIODIC_DUMMY); + for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) + if((*i)->GetId() == 34074) // Aspect of the Viper + { + power_regen_mp5 += (*i)->GetModifier()->m_amount * Intellect / 500.0f; + // Add regen bonus from level in this dummy + power_regen_mp5 += getLevel() * 35 / 100; + } + + // Set regen rate in cast state apply only on spirit based regen + int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT); + if (modManaRegenInterrupt > 100) + modManaRegenInterrupt = 100; + SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f); + + SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN, power_regen_mp5 + power_regen); +} + +void Player::_ApplyAllStatBonuses() +{ + SetCanModifyStats(false); + + _ApplyAllAuraMods(); + _ApplyAllItemMods(); + + SetCanModifyStats(true); + + UpdateAllStats(); +} + +void Player::_RemoveAllStatBonuses() +{ + SetCanModifyStats(false); + + _RemoveAllItemMods(); + _RemoveAllAuraMods(); + + SetCanModifyStats(true); + + UpdateAllStats(); +} + +/*####################################### +######## ######## +######## MOBS STAT SYSTEM ######## +######## ######## +#######################################*/ + +bool Creature::UpdateStats(Stats /*stat*/) +{ + return true; +} + +bool Creature::UpdateAllStats() +{ + UpdateMaxHealth(); + UpdateAttackPowerAndDamage(); + + for(int i = POWER_MANA; i < MAX_POWERS; ++i) + UpdateMaxPower(Powers(i)); + + for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) + UpdateResistances(i); + + return true; +} + +void Creature::UpdateResistances(uint32 school) +{ + if(school > SPELL_SCHOOL_NORMAL) + { + float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); + SetResistance(SpellSchools(school), int32(value)); + } + else + UpdateArmor(); +} + +void Creature::UpdateArmor() +{ + float value = GetTotalAuraModValue(UNIT_MOD_ARMOR); + SetArmor(int32(value)); +} + +void Creature::UpdateMaxHealth() +{ + float value = GetTotalAuraModValue(UNIT_MOD_HEALTH); + SetMaxHealth((uint32)value); +} + +void Creature::UpdateMaxPower(Powers power) +{ + UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); + + float value = GetTotalAuraModValue(unitMod); + SetMaxPower(power, uint32(value)); +} + +void Creature::UpdateAttackPowerAndDamage(bool ranged) +{ + if(ranged) + return; + + //automatically update weapon damage after attack power modification + UpdateDamagePhysical(BASE_ATTACK); +} + +void Creature::UpdateDamagePhysical(WeaponAttackType attType) +{ + if(attType > BASE_ATTACK) + return; + + UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; + + float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f; + + float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; + float base_pct = GetModifierValue(unitMod, BASE_PCT); + float total_value = GetModifierValue(unitMod, TOTAL_VALUE); + float total_pct = GetModifierValue(unitMod, TOTAL_PCT); + + float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); + float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); + + float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ; + float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ; + + SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); + SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); +} + +/*####################################### +######## ######## +######## PETS STAT SYSTEM ######## +######## ######## +#######################################*/ + +bool Pet::UpdateStats(Stats stat) +{ + if(stat > STAT_SPIRIT) + return false; + + // value = ((base_value * base_pct) + total_value) * total_pct + float value = GetTotalStatValue(stat); + + Unit *owner = GetOwner(); + if ( stat == STAT_STAMINA ) + { + if(owner) + value += float(owner->GetStat(stat)) * 0.3f; + } + //warlock's and mage's pets gain 30% of owner's intellect + else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET ) + { + if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) ) + value += float(owner->GetStat(stat)) * 0.3f; + } + + SetStat(stat, int32(value)); + + switch(stat) + { + case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break; + case STAT_AGILITY: UpdateArmor(); break; + case STAT_STAMINA: UpdateMaxHealth(); break; + case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break; + case STAT_SPIRIT: + default: + break; + } + + return true; +} + +bool Pet::UpdateAllStats() +{ + for (int i = STAT_STRENGTH; i < MAX_STATS; i++) + UpdateStats(Stats(i)); + + for(int i = POWER_MANA; i < MAX_POWERS; i++) + UpdateMaxPower(Powers(i)); + + for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + UpdateResistances(i); + + return true; +} + +void Pet::UpdateResistances(uint32 school) +{ + if(school > SPELL_SCHOOL_NORMAL) + { + float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); + + Unit *owner = GetOwner(); + // hunter and warlock pets gain 40% of owner's resistance + if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)) + value += float(owner->GetResistance(SpellSchools(school))) * 0.4f; + + SetResistance(SpellSchools(school), int32(value)); + } + else + UpdateArmor(); +} + +void Pet::UpdateArmor() +{ + float value = 0.0f; + float bonus_armor = 0.0f; + UnitMods unitMod = UNIT_MOD_ARMOR; + + Unit *owner = GetOwner(); + // hunter and warlock pets gain 35% of owner's armor value + if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)) + bonus_armor = 0.35f * float(owner->GetArmor()); + + value = GetModifierValue(unitMod, BASE_VALUE); + value *= GetModifierValue(unitMod, BASE_PCT); + value += GetStat(STAT_AGILITY) * 2.0f; + value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor; + value *= GetModifierValue(unitMod, TOTAL_PCT); + + SetArmor(int32(value)); +} + +void Pet::UpdateMaxHealth() +{ + UnitMods unitMod = UNIT_MOD_HEALTH; + float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA); + + float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); + value *= GetModifierValue(unitMod, BASE_PCT); + value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f; + value *= GetModifierValue(unitMod, TOTAL_PCT); + + SetMaxHealth((uint32)value); +} + +void Pet::UpdateMaxPower(Powers power) +{ + UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); + float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f; + + float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); + value *= GetModifierValue(unitMod, BASE_PCT); + value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f; + value *= GetModifierValue(unitMod, TOTAL_PCT); + + SetMaxPower(power, uint32(value)); +} + +void Pet::UpdateAttackPowerAndDamage(bool ranged) +{ + if(ranged) + return; + + float val = 0.0f; + float bonusAP = 0.0f; + UnitMods unitMod = UNIT_MOD_ATTACK_POWER; + + if(GetEntry() == 416) // imp's attack power + val = GetStat(STAT_STRENGTH) - 10.0f; + else + val = 2 * GetStat(STAT_STRENGTH) - 20.0f; + + Unit* owner = GetOwner(); + if( owner && owner->GetTypeId()==TYPEID_PLAYER) + { + if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power + { + bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f; + SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.125f)); + } + //demons benefit from warlocks shadow or fire damage + else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK) + { + int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); + int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW); + int32 maximum = (fire > shadow) ? fire : shadow; + if(maximum < 0) + maximum = 0; + SetBonusDamage( int32(maximum * 0.15f)); + bonusAP = maximum * 0.57f; + } + //water elementals benefit from mage's frost damage + else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE) + { + int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST); + if(frost < 0) + frost = 0; + SetBonusDamage( int32(frost * 0.4f)); + } + } + + SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP); + + //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB + float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); + float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); + float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; + + //UNIT_FIELD_(RANGED)_ATTACK_POWER field + SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower); + //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field + SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod); + //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field + SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier); + + //automatically update weapon damage after attack power modification + UpdateDamagePhysical(BASE_ATTACK); +} + +void Pet::UpdateDamagePhysical(WeaponAttackType attType) +{ + if(attType > BASE_ATTACK) + return; + + UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; + + float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f; + + float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; + float base_pct = GetModifierValue(unitMod, BASE_PCT); + float total_value = GetModifierValue(unitMod, TOTAL_VALUE); + float total_pct = GetModifierValue(unitMod, TOTAL_PCT); + + float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); + float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); + + float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct; + float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct; + + // Pet's base damage changes depending on happiness + if (getPetType() == HUNTER_PET && attType == BASE_ATTACK) + { + switch(GetHappinessState()) + { + case HAPPY: + // 125% of normal damage + mindamage = mindamage * 1.25; + maxdamage = maxdamage * 1.25; + break; + case CONTENT: + // 100% of normal damage, nothing to modify + break; + case UNHAPPY: + // 75% of normal damage + mindamage = mindamage * 0.75; + maxdamage = maxdamage * 0.75; + break; + } + } + + SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); + SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); +} diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 442dbc1057b..18de56321de 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -1,10808 +1,10812 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Log.h" -#include "Opcodes.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Unit.h" -#include "QuestDef.h" -#include "Player.h" -#include "Creature.h" -#include "Spell.h" -#include "Group.h" -#include "SpellAuras.h" -#include "MapManager.h" -#include "ObjectAccessor.h" -#include "CreatureAI.h" -#include "Formulas.h" -#include "Pet.h" -#include "Util.h" -#include "Totem.h" -#include "BattleGround.h" -#include "InstanceSaveMgr.h" -#include "GridNotifiersImpl.h" -#include "CellImpl.h" -#include "Path.h" - -#include - -float baseMoveSpeed[MAX_MOVE_TYPE] = -{ - 2.5f, // MOVE_WALK - 7.0f, // MOVE_RUN - 1.25f, // MOVE_WALKBACK - 4.722222f, // MOVE_SWIM - 4.5f, // MOVE_SWIMBACK - 3.141594f, // MOVE_TURN - 7.0f, // MOVE_FLY - 4.5f, // MOVE_FLYBACK -}; - -// auraTypes contains attacker auras capable of proc'ing cast auras -static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_DUMMY); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL); - auraTypes.insert(SPELL_AURA_MOD_HASTE); - auraTypes.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - return auraTypes; -} - -// auraTypes contains victim auras capable of proc'ing cast auras -static Unit::AuraTypeSet GenerateVictimProcCastAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_DUMMY); - auraTypes.insert(SPELL_AURA_PRAYER_OF_MENDING); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL); - return auraTypes; -} - -// auraTypes contains auras capable of proc effect/damage (but not cast) for attacker -static Unit::AuraTypeSet GenerateAttakerProcEffectAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_MOD_DAMAGE_DONE); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE); - auraTypes.insert(SPELL_AURA_MOD_CASTING_SPEED); - auraTypes.insert(SPELL_AURA_MOD_RATING); - return auraTypes; -} - -// auraTypes contains auras capable of proc effect/damage (but not cast) for victim -static Unit::AuraTypeSet GenerateVictimProcEffectAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_MOD_RESISTANCE); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE); - auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT); - auraTypes.insert(SPELL_AURA_MOD_BLOCK_PERCENT); - auraTypes.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); - return auraTypes; -} - -static Unit::AuraTypeSet attackerProcCastAuraTypes = GenerateAttakerProcCastAuraTypes(); -static Unit::AuraTypeSet attackerProcEffectAuraTypes = GenerateAttakerProcEffectAuraTypes(); - -static Unit::AuraTypeSet victimProcCastAuraTypes = GenerateVictimProcCastAuraTypes(); -static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectAuraTypes(); - -// auraTypes contains auras capable of proc'ing for attacker and victim -static Unit::AuraTypeSet GenerateProcAuraTypes() -{ - Unit::AuraTypeSet auraTypes; - auraTypes.insert(attackerProcCastAuraTypes.begin(),attackerProcCastAuraTypes.end()); - auraTypes.insert(attackerProcEffectAuraTypes.begin(),attackerProcEffectAuraTypes.end()); - auraTypes.insert(victimProcCastAuraTypes.begin(),victimProcCastAuraTypes.end()); - auraTypes.insert(victimProcEffectAuraTypes.begin(),victimProcEffectAuraTypes.end()); - return auraTypes; -} - -static Unit::AuraTypeSet procAuraTypes = GenerateProcAuraTypes(); - -bool IsPassiveStackableSpell( uint32 spellId ) -{ - if(!IsPassiveSpell(spellId)) - return false; - - SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId); - if(!spellProto) - return false; - - for(int j = 0; j < 3; ++j) - { - if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end()) - return false; - } - - return true; -} - -Unit::Unit() -: WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this) -{ - m_objectType |= TYPEMASK_UNIT; - m_objectTypeId = TYPEID_UNIT; - // 2.3.2 - 0x70 - m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HASPOSITION); - - m_attackTimer[BASE_ATTACK] = 0; - m_attackTimer[OFF_ATTACK] = 0; - m_attackTimer[RANGED_ATTACK] = 0; - m_modAttackSpeedPct[BASE_ATTACK] = 1.0f; - m_modAttackSpeedPct[OFF_ATTACK] = 1.0f; - m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f; - - m_extraAttacks = 0; - - m_state = 0; - m_form = FORM_NONE; - m_deathState = ALIVE; - - for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) - m_currentSpells[i] = NULL; - - m_addDmgOnce = 0; - - for(int i = 0; i < MAX_TOTEM; ++i) - m_TotemSlot[i] = 0; - - m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0; - //m_Aura = NULL; - //m_AurasCheck = 2000; - //m_removeAuraTimer = 4; - //tmpAura = NULL; - waterbreath = false; - - m_Visibility = VISIBILITY_ON; - - m_detectInvisibilityMask = 0; - m_invisibilityMask = 0; - m_transform = 0; - m_ShapeShiftFormSpellId = 0; - m_canModifyStats = false; - - for (int i = 0; i < MAX_SPELL_IMMUNITY; i++) - m_spellImmune[i].clear(); - for (int i = 0; i < UNIT_MOD_END; i++) - { - m_auraModifiersGroup[i][BASE_VALUE] = 0.0f; - m_auraModifiersGroup[i][BASE_PCT] = 1.0f; - m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; - m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; - } - // implement 50% base damage from offhand - m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; - - for (int i = 0; i < 3; i++) - { - m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE; - m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE; - } - for (int i = 0; i < MAX_STATS; i++) - m_createStats[i] = 0.0f; - - m_attacking = NULL; - m_modMeleeHitChance = 0.0f; - m_modRangedHitChance = 0.0f; - m_modSpellHitChance = 0.0f; - m_baseSpellCritChance = 5; - - m_CombatTimer = 0; - m_lastManaUse = 0; - - //m_victimThreat = 0.0f; - for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) - m_threatModifier[i] = 1.0f; - m_isSorted = true; - for (int i = 0; i < MAX_MOVE_TYPE; ++i) - m_speed_rate[i] = 1.0f; - - m_removedAuras = 0; - m_charmInfo = NULL; - m_unit_movement_flags = 0; - - // remove aurastates allowing special moves - for(int i=0; i < MAX_REACTIVE; ++i) - m_reactiveTimer[i] = 0; -} - -Unit::~Unit() -{ - // set current spells as deletable - for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) - { - // spell may be safely deleted now - if (m_currentSpells[i]) m_currentSpells[i]->SetDeletable(true); - m_currentSpells[i] = NULL; - } - - RemoveAllGameObjects(); - RemoveAllDynObjects(); - - if(m_charmInfo) delete m_charmInfo; -} - -void Unit::Update( uint32 p_time ) -{ - /*if(p_time > m_AurasCheck) - { - m_AurasCheck = 2000; - _UpdateAura(); - }else - m_AurasCheck -= p_time;*/ - - // WARNING! Order of execution here is important, do not change. - // Spells must be processed with event system BEFORE they go to _UpdateSpells. - // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad. - m_Events.Update( p_time ); - _UpdateSpells( p_time ); - - // update combat timer only for players and pets - if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet() || ((Creature*)this)->isCharmed())) - { - // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away - // targets without stopping half way there and running off. - // These flags are reset after target dies or another command is given. - if( m_HostilRefManager.isEmpty() ) - { - // m_CombatTimer set at aura start and it will be freeze until aura removing - if ( m_CombatTimer <= p_time ) - ClearInCombat(); - else - m_CombatTimer -= p_time; - } - } - - if(uint32 base_att = getAttackTimer(BASE_ATTACK)) - { - setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) ); - } - - // update abilities available only for fraction of time - UpdateReactives( p_time ); - - ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth()*0.20f); - ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth()*0.35f); - - i_motionMaster.UpdateMotion(p_time); -} - -bool Unit::haveOffhandWeapon() const -{ - if(GetTypeId() == TYPEID_PLAYER) - return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true); - else - return false; -} - -void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player) -{ - float x, y, z; - if(GetMotionMaster()->GetDestination(x, y, z)) - SendMonsterMoveWithSpeed(x, y, z, GetUnitMovementFlags(), 0, player); -} - -void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime, Player* player) -{ - if (!transitTime) - { - float dx = x - GetPositionX(); - float dy = y - GetPositionY(); - float dz = z - GetPositionZ(); - - float dist = ((dx*dx) + (dy*dy) + (dz*dz)); - if(dist<0) - dist = 0; - else - dist = sqrt(dist); - - double speed = GetSpeed((MovementFlags & MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN); - if(speed<=0) - speed = 2.5f; - speed *= 0.001f; - transitTime = static_cast(dist / speed + 0.5); - } - //float orientation = (float)atan2((double)dy, (double)dx); - SendMonsterMove(x, y, z, 0, MovementFlags, transitTime, player); -} - -void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player) -{ - WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) ); - data.append(GetPackGUID()); - - // Point A, starting location - data << GetPositionX() << GetPositionY() << GetPositionZ(); - // unknown field - unrelated to orientation - // seems to increment about 1000 for every 1.7 seconds - // for now, we'll just use mstime - data << getMSTime(); - - data << uint8(type); // unknown - switch(type) - { - case 0: // normal packet - break; - case 1: // stop packet - SendMessageToSet( &data, true ); - return; - case 3: // not used currently - data << uint64(0); // probably target guid - break; - case 4: // not used currently - data << float(0); // probably orientation - break; - } - - //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim) - data << uint32(MovementFlags); - - data << Time; // Time in between points - data << uint32(1); // 1 single waypoint - data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B - - if(player) - player->GetSession()->SendPacket(&data); - else - SendMessageToSet( &data, true ); -} - -void Unit::SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags) -{ - uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32); - - uint32 pathSize = end-start; - - WorldPacket data( SMSG_MONSTER_MOVE, (GetPackGUID().size()+4+4+4+4+1+4+4+4+pathSize*4*3) ); - data.append(GetPackGUID()); - data << GetPositionX( ) - << GetPositionY( ) - << GetPositionZ( ); - data << GetOrientation( ); - data << uint8( 0 ); - data << uint32( MovementFlags ); - data << uint32( traveltime ); - data << uint32( pathSize ); - data.append( (char*)path.GetNodes(start), pathSize * 4 * 3 ); - - //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 ); - SendMessageToSet(&data, true); -} - -void Unit::resetAttackTimer(WeaponAttackType type) -{ - m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]); -} - -bool Unit::canReachWithAttack(Unit *pVictim) const -{ - assert(pVictim); - float reach = GetFloatValue(UNIT_FIELD_COMBATREACH); - if( reach <= 0.0f ) - reach = 1.0f; - return IsWithinDistInMap(pVictim, reach); -} - -void Unit::RemoveSpellsCausingAura(AuraType auraType) -{ - if (auraType >= TOTAL_AURAS) return; - AuraList::iterator iter, next; - for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next) - { - next = iter; - ++next; - - if (*iter) - { - RemoveAurasDueToSpell((*iter)->GetId()); - if (!m_modAuras[auraType].empty()) - next = m_modAuras[auraType].begin(); - else - return; - } - } -} - -bool Unit::HasAuraType(AuraType auraType) const -{ - return (!m_modAuras[auraType].empty()); -} - -/* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */ -void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage) -{ - if(!HasAuraType(auraType)) - return; - - // The chance to dispell an aura depends on the damage taken with respect to the casters level. - uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50; - float chance = float(damage) / max_dmg * 100.0f; - if (roll_chance_f(chance)) - RemoveSpellsCausingAura(auraType); -} - -uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss) -{ - if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - return 0; - - //You don't lose health from damage taken from another player while in a sanctuary - //You still see it in the combat log though - if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) - { - const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); - if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary - return 0; - } - - // remove affects from victim (including from 0 damage and DoTs) - if(pVictim != this) - pVictim->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - // remove affects from attacker at any non-DoT damage (including 0 damage) - if( damagetype != DOT) - { - RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - if(pVictim != this) - RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY); - - if(pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->IsStandState() && !pVictim->hasUnitState(UNIT_STAT_STUNDED)) - pVictim->SetStandState(PLAYER_STATE_NONE); - } - - //Script Event damage Deal - if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI()) - ((Creature *)this)->AI()->DamageDeal(pVictim, damage); - //Script Event damage taken - if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->AI() ) - ((Creature *)pVictim)->AI()->DamageTaken(this, damage); - - if(!damage) - { - // Rage from physical damage received . - if(cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE)) - ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false); - - return 0; - } - - pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage); - // root type spells do not dispell the root effect - if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT) - pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage); - - if(pVictim->GetTypeId() != TYPEID_PLAYER) - { - // no xp,health if type 8 /critters/ - if ( pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER) - { - pVictim->setDeathState(JUST_DIED); - pVictim->SetHealth(0); - - // allow loot only if has loot_id in creature_template - CreatureInfo const* cInfo = ((Creature*)pVictim)->GetCreatureInfo(); - if(cInfo && cInfo->lootid) - pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - - // some critters required for quests - if(GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID()); - - return damage; - } - - if(!pVictim->isInCombat() && ((Creature*)pVictim)->AI()) - ((Creature*)pVictim)->AI()->AttackStart(this); - } - - DEBUG_LOG("DealDamageStart"); - - uint32 health = pVictim->GetHealth(); - sLog.outDetail("deal dmg:%d to health:%d ",damage,health); - - // duel ends when player has 1 or less hp - bool duel_hasEnded = false; - if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1)) - { - // prevent kill only if killed in duel and killed by opponent or opponent controlled creature - if(((Player*)pVictim)->duel->opponent==this || ((Player*)pVictim)->duel->opponent->GetGUID() == GetOwnerGUID()) - damage = health-1; - - duel_hasEnded = true; - } - //Get in CombatState - if(pVictim != this && damagetype != DOT) - { - SetInCombatWith(pVictim); - pVictim->SetInCombatWith(this); - - if(Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself()) - SetContestedPvP(attackedPlayer); - } - - // Rage from Damage made (only from direct weapon damage) - if( cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE)) - { - uint32 weaponSpeedHitFactor; - - switch(cleanDamage->attackType) - { - case BASE_ATTACK: - { - if(cleanDamage->hitOutCome == MELEE_HIT_CRIT) - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 7); - else - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f); - - ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); - - break; - } - case OFF_ATTACK: - { - if(cleanDamage->hitOutCome == MELEE_HIT_CRIT) - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f); - else - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f); - - ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); - - break; - } - case RANGED_ATTACK: - break; - } - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER && GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)pVictim)->InBattleGround()) - { - Player *killer = ((Player*)this); - if(killer != ((Player*)pVictim)) - if(BattleGround *bg = killer->GetBattleGround()) - bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage); - } - } - - if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->isPet() && !((Creature*)pVictim)->hasLootRecipient()) - ((Creature*)pVictim)->SetLootRecipient(this); - if (health <= damage) - { - // battleground things - if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround())) - { - Player *killed = ((Player*)pVictim); - Player *killer = NULL; - if(GetTypeId() == TYPEID_PLAYER) - killer = ((Player*)this); - else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) - { - Unit *owner = GetOwner(); - if(owner && owner->GetTypeId() == TYPEID_PLAYER) - killer = ((Player*)owner); - } - - if(killer) - if(BattleGround *bg = killed->GetBattleGround()) - bg->HandleKillPlayer(killed, killer); // drop flags and etc - } - - DEBUG_LOG("DealDamage: victim just died"); - - // find player: owner of controlled `this` or `this` itself maybe - Player *player = GetCharmerOrOwnerPlayerOrPlayerItself(); - - if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->GetLootRecipient()) - player = ((Creature*)pVictim)->GetLootRecipient(); - // Reward player, his pets, and group/raid members - // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop) - if(player && player!=pVictim) - if(player->RewardPlayerAndGroupAtKill(pVictim)) - player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE); - - DEBUG_LOG("DealDamageAttackStop"); - - // stop combat - pVictim->CombatStop(); - pVictim->getHostilRefManager().deleteReferences(); - - bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795; - - // if talent known but not triggered (check priest class for speedup check) - Aura* spiritOfRedemtionTalentReady = NULL; - if( !damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION - pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST ) - { - AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); - for(AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr) - { - if((*itr)->GetSpellProto()->SpellIconID==1654) - { - spiritOfRedemtionTalentReady = *itr; - break; - } - } - } - - DEBUG_LOG("SET JUST_DIED"); - if(!spiritOfRedemtionTalentReady) - pVictim->setDeathState(JUST_DIED); - - DEBUG_LOG("DealDamageHealth1"); - - if(spiritOfRedemtionTalentReady) - { - // save value before aura remove - uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL); - if(!ressSpellId) - ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId(); - - //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) - pVictim->RemoveAllAurasOnDeath(); - - // restore for use at real death - pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL,ressSpellId); - - // FORM_SPIRITOFREDEMPTION and related auras - pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady); - } - else - pVictim->SetHealth(0); - - // remember victim PvP death for corpse type and corpse reclaim delay - // at original death (not at SpiritOfRedemtionTalent timeout) - if( pVictim->GetTypeId()==TYPEID_PLAYER && !damageFromSpiritOfRedemtionTalent ) - ((Player*)pVictim)->SetPvPDeath(player!=NULL); - - // Call KilledUnit for creatures - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) - ((Creature*)this)->AI()->KilledUnit(pVictim); - - // 10% durability loss on death - // clean InHateListOf - if (pVictim->GetTypeId() == TYPEID_PLAYER) - { - // only if not player and not controlled by player pet. And not at BG - if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround()) - { - DEBUG_LOG("We are dead, loosing 10 percents durability"); - ((Player*)pVictim)->DurabilityLossAll(0.10f,false); - // durability lost message - WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); - ((Player*)pVictim)->GetSession()->SendPacket(&data); - } - } - else // creature died - { - DEBUG_LOG("DealDamageNotPlayer"); - Creature *cVictim = (Creature*)pVictim; - - if(!cVictim->isPet()) - { - cVictim->DeleteThreatList(); - cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - } - // Call creature just died function - if (cVictim->AI()) - cVictim->AI()->JustDied(this); - - // Dungeon specific stuff, only applies to players killing creatures - if(cVictim->GetInstanceId()) - { - Map *m = cVictim->GetMap(); - Player *creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself(); - // TODO: do instance binding anyway if the charmer/owner is offline - - if(m->IsDungeon() && creditedPlayer) - { - if(m->IsRaid() || m->IsHeroic()) - { - if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) - ((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer); - } - else - { - // the reset time is set but not added to the scheduler - // until the players leave the instance - time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR; - if(InstanceSave *save = sInstanceSaveManager.GetInstanceSave(cVictim->GetInstanceId())) - if(save->GetResetTime() < resettime) save->SetResetTime(resettime); - } - } - } - } - - // last damage from non duel opponent or opponent controlled creature - if(duel_hasEnded) - { - assert(pVictim->GetTypeId()==TYPEID_PLAYER); - Player *he = (Player*)pVictim; - - assert(he->duel); - - he->duel->opponent->CombatStopWithPets(true); - he->CombatStopWithPets(true); - - he->DuelComplete(DUEL_INTERUPTED); - } - } - else // if (health <= damage) - { - DEBUG_LOG("DealDamageAlive"); - - pVictim->ModifyHealth(- (int32)damage); - - // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage - if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth()) - { - uint32 procVictim = PROC_FLAG_NONE; - - // if just dropped below 20% (for CheatDeath) - if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth()) - procVictim = PROC_FLAG_LOW_HEALTH; - - ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim); - } - - if(damagetype != DOT) - { - if(getVictim()) - { - // if have target and damage pVictim just call AI recation - if(pVictim != getVictim() && pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->AI()) - ((Creature*)pVictim)->AI()->AttackedBy(this); - } - else - { - // if not have main target then attack state with target (including AI call) - //start melee attacks only after melee hit - Attack(pVictim,(damagetype == DIRECT_DAMAGE)); - } - } - - // polymorphed and other negative transformed cases - if(pVictim->getTransForm() && pVictim->hasUnitState(UNIT_STAT_CONFUSED)) - pVictim->RemoveAurasDueToSpell(pVictim->getTransForm()); - - if(damagetype == DIRECT_DAMAGE|| damagetype == SPELL_DIRECT_DAMAGE) - pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE); - - if (pVictim->GetTypeId() != TYPEID_PLAYER) - { - if(spellProto && IsDamageToThreatSpell(spellProto)) - pVictim->AddThreat(this, damage*2, damageSchoolMask, spellProto); - else - pVictim->AddThreat(this, damage, damageSchoolMask, spellProto); - } - else // victim is a player - { - // Rage from damage received - if(this != pVictim && pVictim->getPowerType() == POWER_RAGE) - { - uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0); - ((Player*)pVictim)->RewardRage(rage_damage, 0, false); - } - - // random durability for items (HIT TAKEN) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE))) - { - EquipmentSlots slot = EquipmentSlots(urand(0,EQUIPMENT_SLOT_END-1)); - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(slot); - } - } - - if(GetTypeId()==TYPEID_PLAYER) - { - // random durability for items (HIT DONE) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE))) - { - EquipmentSlots slot = EquipmentSlots(urand(0,EQUIPMENT_SLOT_END-1)); - ((Player*)this)->DurabilityPointLossForEquipSlot(slot); - } - } - - // TODO: Store auras by interrupt flag to speed this up. - AuraMap& vAuras = pVictim->GetAuras(); - for (AuraMap::iterator i = vAuras.begin(), next; i != vAuras.end(); i = next) - { - const SpellEntry *se = i->second->GetSpellProto(); - next = i; ++next; - if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE ) - { - bool remove = true; - if (se->procFlags & (1<<3)) - { - if (!roll_chance_i(se->procChance)) - remove = false; - } - if (remove) - { - pVictim->RemoveAurasDueToSpell(i->second->GetId()); - // FIXME: this may cause the auras with proc chance to be rerolled several times - next = vAuras.begin(); - } - } - } - - if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER) - { - if( damagetype != DOT ) - { - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) - { - // skip channeled spell (processed differently below) - if (i == CURRENT_CHANNELED_SPELL) - continue; - - if(Spell* spell = pVictim->m_currentSpells[i]) - if(spell->getState() == SPELL_STATE_PREPARING) - spell->Delayed(); - } - } - - if(Spell* spell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]) - { - if (spell->getState() == SPELL_STATE_CASTING) - { - uint32 channelInterruptFlags = spell->m_spellInfo->ChannelInterruptFlags; - if( channelInterruptFlags & CHANNEL_FLAG_DELAY ) - { - if(pVictim!=this) //don't shorten the duration of channeling if you damage yourself - spell->DelayedChannel(); - } - else if( (channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) ) - { - sLog.outDetail("Spell %u canceled at damage!",spell->m_spellInfo->Id); - pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL); - } - } - else if (spell->getState() == SPELL_STATE_DELAYED) - // break channeled spell in delayed state on damage - { - sLog.outDetail("Spell %u canceled at damage!",spell->m_spellInfo->Id); - pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL); - } - } - } - - // last damage from duel opponent - if(duel_hasEnded) - { - assert(pVictim->GetTypeId()==TYPEID_PLAYER); - Player *he = (Player*)pVictim; - - assert(he->duel); - - he->SetHealth(1); - - he->duel->opponent->CombatStopWithPets(true); - he->CombatStopWithPets(true); - - he->CastSpell(he, 7267, true); // beg - he->DuelComplete(DUEL_WON); - } - } - - DEBUG_LOG("DealDamageEnd returned %d damage", damage); - - return damage; -} - -void Unit::CastStop(uint32 except_spellid) -{ - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) - if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id!=except_spellid) - InterruptSpell(i,false); -} - -void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); - - if(!spellInfo) - { - sLog.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry())); - return; - } - - CastSpell(Victim,spellInfo,triggered,castItem,triggredByAura, originalCaster); -} - -void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) -{ - if(!spellInfo) - { - sLog.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry())); - return; - } - - if (castItem) - DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); - - if(!originalCaster && triggredByAura) - originalCaster = triggredByAura->GetCasterGUID(); - - Spell *spell = new Spell(this, spellInfo, triggered, originalCaster ); - - SpellCastTargets targets; - targets.setUnitTarget( Victim ); - spell->m_CastItem = castItem; - spell->prepare(&targets, triggredByAura); -} - -void Unit::CastCustomSpell(Unit* Victim,uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); - - if(!spellInfo) - { - sLog.outError("CastCustomSpell: unknown spell id %i\n", spellId); - return; - } - - CastCustomSpell(Victim,spellInfo,bp0,bp1,bp2,triggered,castItem,triggredByAura, originalCaster); -} - -void Unit::CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) -{ - if(!spellInfo) - { - sLog.outError("CastCustomSpell: unknown spell"); - return; - } - - if (castItem) - DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); - - if(!originalCaster && triggredByAura) - originalCaster = triggredByAura->GetCasterGUID(); - - Spell *spell = new Spell(this, spellInfo, triggered, originalCaster); - - if(bp0) - spell->m_currentBasePoints[0] = *bp0-int32(spellInfo->EffectBaseDice[0]); - - if(bp1) - spell->m_currentBasePoints[1] = *bp1-int32(spellInfo->EffectBaseDice[1]); - - if(bp2) - spell->m_currentBasePoints[2] = *bp2-int32(spellInfo->EffectBaseDice[2]); - - SpellCastTargets targets; - targets.setUnitTarget( Victim ); - spell->m_CastItem = castItem; - spell->prepare(&targets, triggredByAura); -} - -// used for scripting -void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); - - if(!spellInfo) - { - sLog.outError("CastSpell(x,y,z): unknown spell id %i by caster: %s %u)", spellId,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry())); - return; - } - - CastSpell(x, y, z,spellInfo,triggered,castItem,triggredByAura, originalCaster); -} - -// used for scripting -void Unit::CastSpell(float x, float y, float z, SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) -{ - if(!spellInfo) - { - sLog.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry())); - return; - } - - if (castItem) - DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); - - if(!originalCaster && triggredByAura) - originalCaster = triggredByAura->GetCasterGUID(); - - Spell *spell = new Spell(this, spellInfo, triggered, originalCaster ); - - SpellCastTargets targets; - targets.setDestination(x, y, z); - spell->m_CastItem = castItem; - spell->prepare(&targets, triggredByAura); -} - -void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell) -{ - // TODO this in only generic way, check for exceptions - DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage); - - // Per-damage calss calculation - switch (spellInfo->DmgClass) - { - // Melee and Ranged Spells - case SPELL_DAMAGE_CLASS_RANGED: - case SPELL_DAMAGE_CLASS_MELEE: - { - // Calculate physical outcome - MeleeHitOutcome outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo); - - //Used to store the Hit Outcome - cleanDamage->hitOutCome = outcome; - - // Return miss/evade first (sends miss message) - switch(outcome) - { - case MELEE_HIT_EVADE: - { - SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_EVADES,0); - *damage = 0; - return; - } - case MELEE_HIT_MISS: - { - SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_NORMAL,0); - *damage = 0; - - if(GetTypeId()== TYPEID_PLAYER) - ((Player*)this)->UpdateWeaponSkill(BASE_ATTACK); - - CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell); - return; - } - } - - // Hitinfo, Victimstate - uint32 hitInfo = HITINFO_NORMALSWING; - VictimState victimState = VICTIMSTATE_NORMAL; - - // Physical Damage - if ( GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NORMAL ) - { - uint32 modDamage=*damage; - - // apply spellmod to Done damage - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_DAMAGE, *damage); - - //Calculate armor mitigation - uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage); - - // random durability for main hand weapon (ABSORB) - if(damageAfterArmor < *damage) - if(pVictim->GetTypeId() == TYPEID_PLAYER) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK))); - - cleanDamage->damage += *damage - damageAfterArmor; - *damage = damageAfterArmor; - } - // Magical Damage - else - { - // Calculate damage bonus - *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE); - } - - // Classify outcome - switch (outcome) - { - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: - { - uint32 bonusDmg = *damage; - - // Apply crit_damage bonus - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, bonusDmg); - - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS); - for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - bonusDmg = uint32(bonusDmg * ((*i)->GetModifier()->m_amount+100.0f)/100.0f); - - *damage += bonusDmg; - - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - { - uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage); - cleanDamage->damage += resilienceReduction; - *damage -= resilienceReduction; - } - - *crit = true; - hitInfo |= HITINFO_CRITICALHIT; - - ModifyAuraState(AURA_STATE_CRIT, true); - StartReactiveTimer( REACTIVE_CRIT ); - - if(getClass()==CLASS_HUNTER) - { - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true); - StartReactiveTimer( REACTIVE_HUNTER_CRIT ); - } - - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue()); - if (blocked_amount >= *damage) - { - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_BLOCKS; - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - } - else - { - // To Help Calculate Rage - cleanDamage->damage += blocked_amount; - *damage = *damage - blocked_amount; - } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - } - break; - } - case MELEE_HIT_PARRY: - { - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - victimState = VICTIMSTATE_PARRY; - - // Counter-attack ( explained in Unit::DoAttackDamage() ) - if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN) ) - { - // Get attack timers - float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); - float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); - - // Reduce attack time - if (pVictim->haveOffhandWeapon() && offtime < basetime) - { - float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20; - float percent60 = 3 * percent20; - if(offtime > percent20 && offtime <= percent60) - { - pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); - } - else if(offtime > percent60) - { - offtime -= 2 * percent20; - pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); - } - } - else - { - float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20; - float percent60 = 3 * percent20; - if(basetime > percent20 && basetime <= percent60) - { - pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); - } - else if(basetime > percent60) - { - basetime -= 2 * percent20; - pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); - } - } - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update victim defense ? - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (PARRY) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND); - } - - // Set parry flags - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - // Mongoose bite - set only Counterattack here - if (pVictim->getClass() == CLASS_HUNTER) - { - pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); - pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); - } - else - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - break; - } - case MELEE_HIT_DODGE: - { - if(pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateDefense(); - - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_DODGE; - - // Set dodge flags - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - // Overpower - if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) - { - ((Player*)this)->AddComboPoints(pVictim, 1); - StartReactiveTimer( REACTIVE_OVERPOWER ); - } - - // Riposte - if (pVictim->getClass() != CLASS_ROGUE) - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - break; - } - case MELEE_HIT_BLOCK: - { - uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue()); - if (blocked_amount >= *damage) - { - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_BLOCKS; - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - } - else - { - // To Help Calculate Rage - cleanDamage->damage += blocked_amount; - *damage = *damage - blocked_amount; - } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - break; - } - case MELEE_HIT_EVADE: // already processed early - case MELEE_HIT_MISS: // already processed early - case MELEE_HIT_GLANCING: - case MELEE_HIT_CRUSHING: - case MELEE_HIT_NORMAL: - break; - } - - // do all damage=0 cases here - if(*damage == 0) - CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,outcome,spellInfo,isTriggeredSpell); - - break; - } - // Magical Attacks - case SPELL_DAMAGE_CLASS_NONE: - case SPELL_DAMAGE_CLASS_MAGIC: - { - // Calculate damage bonus - *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE); - - *crit = isSpellCrit(pVictim, spellInfo, GetSpellSchoolMask(spellInfo), BASE_ATTACK); - if (*crit) - { - *damage = SpellCriticalBonus(spellInfo, *damage, pVictim); - - // Resilience - reduce crit damage - if (pVictim && pVictim->GetTypeId()==TYPEID_PLAYER) - { - uint32 damage_reduction = ((Player *)pVictim)->GetSpellCritDamageReduction(*damage); - if(*damage > damage_reduction) - *damage -= damage_reduction; - else - *damage = 0; - } - - cleanDamage->hitOutCome = MELEE_HIT_CRIT; - } - // spell proc all magic damage==0 case in this function - if(*damage == 0) - { - // Procflags - uint32 procAttacker = PROC_FLAG_HIT_SPELL; - uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE); - - ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell); - } - - break; - } - } - - // TODO this in only generic way, check for exceptions - DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage); -} - -uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage) -{ - if(!this || !pVictim) - return 0; - if(!this->isAlive() || !pVictim->isAlive()) - return 0; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); - if(!spellInfo) - return 0; - - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL); - bool crit = false; - - if (useSpellDamage) - DealFlatDamage(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell); - - // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage) - if(damage > 0) - { - // Calculate absorb & resists - uint32 absorb = 0; - uint32 resist = 0; - - CalcAbsorbResist(pVictim,GetSpellSchoolMask(spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - - //No more damage left, target absorbed and/or resisted all damage - if (damage > absorb + resist) - damage -= absorb + resist; //Remove Absorbed and Resisted from damage actually dealt - else - { - uint32 HitInfo = HITINFO_SWINGNOHITSOUND; - - if (absorb) - HitInfo |= HITINFO_ABSORB; - if (resist) - { - HitInfo |= HITINFO_RESIST; - ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, GetSpellSchoolMask(spellInfo), spellInfo,isTriggeredSpell); - } - - //Send resist - SendAttackStateUpdate(HitInfo, pVictim, 1, GetSpellSchoolMask(spellInfo), damage, absorb,resist,VICTIMSTATE_NORMAL,0); - return 0; - } - - // Deal damage done - damage = DealDamage(pVictim, damage, &cleanDamage, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellInfo), spellInfo, true); - - // Send damage log - sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u", - GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist); - - // Actual log sent to client - SendSpellNonMeleeDamageLog(pVictim, spellID, damage, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit); - - // Procflags - uint32 procAttacker = PROC_FLAG_HIT_SPELL; - uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE); - - if (crit) - { - procAttacker |= PROC_FLAG_CRIT_SPELL; - procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; - } - - ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell); - - return damage; - } - else - { - // all spell proc for 0 normal and magic damage called in DealFlatDamage - - //Check for rage - if(cleanDamage.damage) - // Rage from damage received. - if(pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE)) - ((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false); - - return 0; - } -} - -void Unit::HandleEmoteCommand(uint32 anim_id) -{ - WorldPacket data( SMSG_EMOTE, 12 ); - data << anim_id << GetGUID(); - WPAssert(data.size() == 12); - - SendMessageToSet(&data, true); -} - -uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage) -{ - uint32 newdamage = 0; - float armor = pVictim->GetArmor(); - // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura - armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); - - if (armor<0.0f) armor=0.0f; - - float tmpvalue = 0.0f; - if(getLevel() <= 59) //Level 1-59 - tmpvalue = armor / (armor + 400.0f + 85.0f * getLevel()); - else if(getLevel() < 70) //Level 60-69 - tmpvalue = armor / (armor - 22167.5f + 467.5f * getLevel()); - else //Level 70+ - tmpvalue = armor / (armor + 10557.5f); - - if(tmpvalue < 0.0f) - tmpvalue = 0.0f; - if(tmpvalue > 0.75f) - tmpvalue = 0.75f; - newdamage = uint32(damage - (damage * tmpvalue)); - - return (newdamage > 1) ? newdamage : 1; -} - -void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist) -{ - if(!pVictim || !pVictim->isAlive() || !damage) - return; - - // Magic damage, check for resists - if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL)==0) - { - // Get base victim resistance for school - float tmpvalue2 = (float)pVictim->GetResistance(GetFirstSchoolInMask(schoolMask)); - // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura - tmpvalue2 += (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask); - - tmpvalue2 *= (float)(0.15f / getLevel()); - if (tmpvalue2 < 0.0f) - tmpvalue2 = 0.0f; - if (tmpvalue2 > 0.75f) - tmpvalue2 = 0.75f; - uint32 ran = urand(0, 100); - uint32 faq[4] = {24,6,4,6}; - uint8 m = 0; - float Binom = 0.0f; - for (uint8 i = 0; i < 4; i++) - { - Binom += 2400 *( powf(tmpvalue2, i) * powf( (1-tmpvalue2), (4-i)))/faq[i]; - if (ran > Binom ) - ++m; - else - break; - } - if (damagetype == DOT && m == 4) - *resist += uint32(damage - 1); - else - *resist += uint32(damage * m / 4); - if(*resist > damage) - *resist = damage; - } - else - *resist = 0; - - int32 RemainingDamage = damage - *resist; - - // absorb without mana cost - int32 reflectDamage = 0; - Aura* reflectAura = NULL; - AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB); - for(AuraList::const_iterator i = vSchoolAbsorb.begin(), next; i != vSchoolAbsorb.end() && RemainingDamage > 0; i = next) - { - next = i; ++next; - - if (((*i)->GetModifier()->m_miscvalue & schoolMask)==0) - continue; - - // Cheat Death - if((*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && (*i)->GetSpellProto()->SpellIconID == 2109) - { - if (((Player*)pVictim)->HasSpellCooldown(31231)) - continue; - if (pVictim->GetHealth() <= RemainingDamage) - { - int32 chance = (*i)->GetModifier()->m_amount; - if (roll_chance_i(chance)) - { - pVictim->CastSpell(pVictim,31231,true); - ((Player*)pVictim)->AddSpellCooldown(31231,0,time(NULL)+60); - - // with health > 10% lost health until health==10%, in other case no losses - uint32 health10 = pVictim->GetMaxHealth()/10; - RemainingDamage = pVictim->GetHealth() > health10 ? pVictim->GetHealth() - health10 : 0; - } - } - continue; - } - - int32 currentAbsorb; - - //Reflective Shield - if ((pVictim != this) && (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && (*i)->GetSpellProto()->SpellFamilyFlags == 0x1) - { - if(Unit* caster = (*i)->GetCaster()) - { - AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k) - { - switch((*k)->GetModifier()->m_miscvalue) - { - case 5065: // Rank 1 - case 5064: // Rank 2 - case 5063: // Rank 3 - case 5062: // Rank 4 - case 5061: // Rank 5 - { - if(RemainingDamage >= (*i)->GetModifier()->m_amount) - reflectDamage = (*i)->GetModifier()->m_amount * (*k)->GetModifier()->m_amount/100; - else - reflectDamage = (*k)->GetModifier()->m_amount * RemainingDamage/100; - reflectAura = *i; - - } break; - default: break; - } - - if(reflectDamage) - break; - } - } - } - - if (RemainingDamage >= (*i)->GetModifier()->m_amount) - { - currentAbsorb = (*i)->GetModifier()->m_amount; - pVictim->RemoveAurasDueToSpell((*i)->GetId()); - next = vSchoolAbsorb.begin(); - } - else - { - currentAbsorb = RemainingDamage; - (*i)->GetModifier()->m_amount -= RemainingDamage; - } - - RemainingDamage -= currentAbsorb; - } - // do not cast spells while looping auras; auras can get invalid otherwise - if (reflectDamage) - pVictim->CastCustomSpell(this, 33619, &reflectDamage, NULL, NULL, true, NULL, reflectAura); - - // absorb by mana cost - AuraList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD); - for(AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next) - { - next = i; ++next; - - // check damage school mask - if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0) - continue; - - int32 currentAbsorb; - if (RemainingDamage >= (*i)->GetModifier()->m_amount) - currentAbsorb = (*i)->GetModifier()->m_amount; - else - currentAbsorb = RemainingDamage; - - float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()]; - if(Player *modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier); - - int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier); - if (currentAbsorb > maxAbsorb) - currentAbsorb = maxAbsorb; - - (*i)->GetModifier()->m_amount -= currentAbsorb; - if((*i)->GetModifier()->m_amount <= 0) - { - pVictim->RemoveAurasDueToSpell((*i)->GetId()); - next = vManaShield.begin(); - } - - int32 manaReduction = int32(currentAbsorb * manaMultiplier); - pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false); - - RemainingDamage -= currentAbsorb; - } - - AuraList const& vSplitDamageFlat = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT); - for(AuraList::const_iterator i = vSplitDamageFlat.begin(), next; i != vSplitDamageFlat.end() && RemainingDamage >= 0; i = next) - { - next = i; ++next; - - // check damage school mask - if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0) - continue; - - // Damage can be splitted only if aura has an alive caster - Unit *caster = (*i)->GetCaster(); - if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive()) - continue; - - int32 currentAbsorb; - if (RemainingDamage >= (*i)->GetModifier()->m_amount) - currentAbsorb = (*i)->GetModifier()->m_amount; - else - currentAbsorb = RemainingDamage; - - RemainingDamage -= currentAbsorb; - - SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, currentAbsorb, schoolMask, 0, 0, false, 0, false); - - CleanDamage cleanDamage = CleanDamage(currentAbsorb, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(caster, currentAbsorb, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); - } - - AuraList const& vSplitDamagePct = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT); - for(AuraList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next) - { - next = i; ++next; - - // check damage school mask - if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0) - continue; - - // Damage can be splitted only if aura has an alive caster - Unit *caster = (*i)->GetCaster(); - if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive()) - continue; - - int32 splitted = int32(RemainingDamage * (*i)->GetModifier()->m_amount / 100.0f); - - RemainingDamage -= splitted; - - SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, 0, 0, false, 0, false); - - CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); - } - - *absorb = damage - RemainingDamage - *resist; -} - -void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell) -{ - MeleeHitOutcome outcome; - - // If is casted Melee spell, calculate like physical - if(!spellCasted) - outcome = RollMeleeOutcomeAgainst (pVictim, attType); - else - outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted); - - if(outcome == MELEE_HIT_MISS ||outcome == MELEE_HIT_DODGE ||outcome == MELEE_HIT_BLOCK ||outcome == MELEE_HIT_PARRY) - pVictim->AddThreat(this, 0.0f); - switch(outcome) - { - case MELEE_HIT_EVADE: - { - *hitInfo |= HITINFO_MISS; - *damage = 0; - cleanDamage->damage = 0; - return; - } - case MELEE_HIT_MISS: - { - *hitInfo |= HITINFO_MISS; - *damage = 0; - cleanDamage->damage = 0; - if(GetTypeId()== TYPEID_PLAYER) - ((Player*)this)->UpdateWeaponSkill(attType); - return; - } - } - - /// If this is a creature and it attacks from behind it has a probability to daze it's victim - if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) && - GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) ) - { - // -probability is between 0% and 40% - // 20% base chance - float Probability = 20; - - //there is a newbie protection, at level 10 just 7% base chance; assuming linear function - if( pVictim->getLevel() < 30 ) - Probability = 0.65f*pVictim->getLevel()+0.5; - - uint32 VictimDefense=pVictim->GetDefenseSkillValue(this); - uint32 AttackerMeleeSkill=GetUnitMeleeSkill(pVictim); - - Probability *= AttackerMeleeSkill/(float)VictimDefense; - - if(Probability > 40.0f) - Probability = 40.0f; - - if(roll_chance_f(Probability)) - CastSpell(pVictim, 1604, true); - } - - //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL - if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) - { - uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage); - - // random durability for main hand weapon (ABSORB) - if(damageAfterArmor < *damage) - if(pVictim->GetTypeId() == TYPEID_PLAYER) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK))); - - cleanDamage->damage += *damage - damageAfterArmor; - *damage = damageAfterArmor; - } - - if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER ) - ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false); - - if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true); - - switch (outcome) - { - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: - { - //*hitInfo = 0xEA; - // 0xEA - *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8; - - // Crit bonus calc - uint32 crit_bonus; - crit_bonus = *damage; - - // Apply crit_damage bonus for melee spells - if (spellCasted) - { - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); - - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS); - for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - crit_bonus = uint32(crit_bonus * ((*i)->GetModifier()->m_amount+100.0f)/100.0f); - } - - *damage += crit_bonus; - - uint32 resilienceReduction = 0; - - if(attType == RANGED_ATTACK) - { - int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); - *damage = int32((*damage) * float((100.0f + mod)/100.0f)); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - resilienceReduction = ((Player*)pVictim)->GetRangedCritDamageReduction(*damage); - } - else - { - int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); - mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE); - *damage = int32((*damage) * float((100.0f + mod)/100.0f)); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage); - } - - *damage -= resilienceReduction; - cleanDamage->damage += resilienceReduction; - - if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER ) - ((Player*)this)->UpdateWeaponSkill(attType); - - ModifyAuraState(AURA_STATE_CRIT, true); - StartReactiveTimer( REACTIVE_CRIT ); - - if(getClass()==CLASS_HUNTER) - { - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true); - StartReactiveTimer( REACTIVE_HUNTER_CRIT ); - } - - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - *blocked_amount = pVictim->GetShieldBlockValue(); - - if (pVictim->GetUnitBlockChance()) - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - else - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - //Only set VICTIMSTATE_BLOCK on a full block - if (*blocked_amount >= uint32(*damage)) - { - *victimState = VICTIMSTATE_BLOCKS; - *blocked_amount = uint32(*damage); - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - break; - } - - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); - break; - } - case MELEE_HIT_PARRY: - { - if(attType == RANGED_ATTACK) //range attack - no parry - { - outcome = MELEE_HIT_NORMAL; - break; - } - - cleanDamage->damage += *damage; - *damage = 0; - *victimState = VICTIMSTATE_PARRY; - - // instant (maybe with small delay) counter attack - { - float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); - float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); - - // after parry nearest next attack time will reduced at %40 from full attack time. - // The delay cannot be reduced to less than 20% of your weapon's base swing delay. - if (pVictim->haveOffhandWeapon() && offtime < basetime) - { - float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20; - float percent60 = 3*percent20; - // set to 20% if in range 20%...20+40% of full time - if(offtime > percent20 && offtime <= percent60) - { - pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20)); - } - // decrease at %40 from full time - else if(offtime > percent60) - { - offtime -= 2*percent20; - pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime)); - } - // ELSE not changed - } - else - { - float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20; - float percent60 = 3*percent20; - // set to 20% if in range 20%...20+40% of full time - if(basetime > percent20 && basetime <= percent60) - { - pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20)); - } - // decrease at %40 from full time - else if(basetime > percent60) - { - basetime -= 2*percent20; - pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime)); - } - // ELSE not changed - } - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update victim defense ? - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (PARRY) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND); - } - - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - if (pVictim->getClass() == CLASS_HUNTER) - { - pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); - pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); - } - else - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; - } - case MELEE_HIT_DODGE: - { - if(attType == RANGED_ATTACK) //range attack - no dodge - { - outcome = MELEE_HIT_NORMAL; - break; - } - - cleanDamage->damage += *damage; - *damage = 0; - *victimState = VICTIMSTATE_DODGE; - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateDefense(); - - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - if (pVictim->getClass() != CLASS_ROGUE) // Riposte - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - - // Overpower - if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) - { - ((Player*)this)->AddComboPoints(pVictim, 1); - StartReactiveTimer( REACTIVE_OVERPOWER ); - } - - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; - } - case MELEE_HIT_BLOCK: - { - *blocked_amount = pVictim->GetShieldBlockValue(); - - if (pVictim->GetUnitBlockChance()) - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - else - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - //Only set VICTIMSTATE_BLOCK on a full block - if (*blocked_amount >= uint32(*damage)) - { - *victimState = VICTIMSTATE_BLOCKS; - *blocked_amount = uint32(*damage); - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - - break; - } - case MELEE_HIT_GLANCING: - { - float reducePercent = 1.0f; //damage factor - - // calculate base values and mods - float baseLowEnd = 1.3; - float baseHighEnd = 1.2; - switch(getClass()) // lowering base values for casters - { - case CLASS_SHAMAN: - case CLASS_PRIEST: - case CLASS_MAGE: - case CLASS_WARLOCK: - case CLASS_DRUID: - baseLowEnd -= 0.7; - baseHighEnd -= 0.3; - break; - } - - float maxLowEnd = 0.6; - switch(getClass()) // upper for melee classes - { - case CLASS_WARRIOR: - case CLASS_ROGUE: - maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91 - } - - // calculate values - int32 diff = int32(pVictim->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType,pVictim)); - float lowEnd = baseLowEnd - ( 0.05f * diff ); - float highEnd = baseHighEnd - ( 0.03f * diff ); - - // apply max/min bounds - if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f - lowEnd = 0.01f; - else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end - lowEnd = maxLowEnd; - - if ( highEnd < 0.2f ) //high end limits - highEnd = 0.2f; - if ( highEnd > 0.99f ) - highEnd = 0.99f; - - if(lowEnd > highEnd) // prevent negative range size - lowEnd = highEnd; - - reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd ); - - *damage = uint32(reducePercent * *damage); - cleanDamage->damage += *damage; - *hitInfo |= HITINFO_GLANCING; - break; - } - case MELEE_HIT_CRUSHING: - { - // 150% normal damage - *damage += (*damage / 2); - cleanDamage->damage = *damage; - *hitInfo |= HITINFO_CRUSHING; - // TODO: victimState, victim animation? - break; - } - default: - break; - } - - // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block - if(*victimState != VICTIMSTATE_BLOCKS) - { - MeleeDamageBonus(pVictim, damage,attType,spellCasted); - CalcAbsorbResist(pVictim, damageSchoolMask, DIRECT_DAMAGE, *damage-*blocked_amount, absorbDamage, resistDamage); - } - - if (*absorbDamage) *hitInfo |= HITINFO_ABSORB; - if (*resistDamage) *hitInfo |= HITINFO_RESIST; - - cleanDamage->damage += *blocked_amount; - - if (*damage <= *absorbDamage + *resistDamage + *blocked_amount) - { - //*hitInfo = 0x00010020; - //*hitInfo |= HITINFO_SWINGNOHITSOUND; - //*damageType = 0; - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; - } - - // update at damage Judgement aura duration that applied by attacker at victim - if(*damage) - { - AuraMap const& vAuras = pVictim->GetAuras(); - for(AuraMap::const_iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr) - { - SpellEntry const *spellInfo = (*itr).second->GetSpellProto(); - if( (spellInfo->AttributesEx3 & 0x40000) && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && - ((*itr).second->GetCasterGUID() == GetGUID() && (!spellCasted || spellCasted->Id == 35395)) ) - { - (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); - (*itr).second->UpdateAuraDuration(); - } - } - } - - CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage - *resistDamage - *blocked_amount), damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - - // victim's damage shield - // yet another hack to fix crashes related to the aura getting removed during iteration - std::set alreadyDone; - uint32 removedAuras = pVictim->m_removedAuras; - AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); - for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next) - { - ++next; - if (alreadyDone.find(*i) == alreadyDone.end()) - { - alreadyDone.insert(*i); - pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false); - if (pVictim->m_removedAuras > removedAuras) - { - removedAuras = pVictim->m_removedAuras; - next = vDamageShields.begin(); - } - } - } -} - -void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra ) -{ - if(hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNDED | UNIT_STAT_FLEEING) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) ) - return; - - if (!pVictim->isAlive()) - return; - - if(IsNonMeleeSpellCasted(false)) - return; - - uint32 hitInfo; - if (attType == BASE_ATTACK) - hitInfo = HITINFO_NORMALSWING2; - else if (attType == OFF_ATTACK) - hitInfo = HITINFO_LEFTSWING; - else - return; // ignore ranaged case - - uint32 extraAttacks = m_extraAttacks; - - // melee attack spell casted at main hand attack only - if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL]) - { - m_currentSpells[CURRENT_MELEE_SPELL]->cast(); - - // not recent extra attack only at any non extra attack (melee spell case) - if(!extra && extraAttacks) - { - while(m_extraAttacks) - { - AttackerStateUpdate(pVictim, BASE_ATTACK, true); - if(m_extraAttacks > 0) - --m_extraAttacks; - } - } - - return; - } - - VictimState victimState = VICTIMSTATE_NORMAL; - - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); - uint32 blocked_dmg = 0; - uint32 absorbed_dmg = 0; - uint32 resisted_dmg = 0; - - SpellSchoolMask meleeSchoolMask = GetMeleeDamageSchoolMask(); - - if(pVictim->IsImmunedToDamage(meleeSchoolMask,true)) // use charges - { - SendAttackStateUpdate (HITINFO_NORMALSWING, pVictim, 1, meleeSchoolMask, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0); - - // not recent extra attack only at any non extra attack (miss case) - if(!extra && extraAttacks) - { - while(m_extraAttacks) - { - AttackerStateUpdate(pVictim, BASE_ATTACK, true); - if(m_extraAttacks > 0) - --m_extraAttacks; - } - } - - return; - } - - uint32 damage = CalculateDamage (attType, false); - - DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, meleeSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType); - - if (hitInfo & HITINFO_MISS) - //send miss - SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg); - else - { - //do animation - SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg); - - if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg)) - damage -= (absorbed_dmg + resisted_dmg + blocked_dmg); - else - damage = 0; - - DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, meleeSchoolMask, NULL, true); - - if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive()) - { - for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) - ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim,attType); - } - } - - if (GetTypeId() == TYPEID_PLAYER) - DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", - GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg); - else - DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", - GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg); - - // extra attack only at any non extra attack (normal case) - if(!extra && extraAttacks) - { - while(m_extraAttacks) - { - AttackerStateUpdate(pVictim, BASE_ATTACK, true); - if(m_extraAttacks > 0) - --m_extraAttacks; - } - } -} - -MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo) -{ - // Miss chance based on melee - float miss_chance = MeleeMissChanceCalc(pVictim, attType); - - // Critical hit chance - float crit_chance = GetUnitCriticalChance(attType, pVictim); - // this is to avoid compiler issue when declaring variables inside if - float block_chance, parry_chance, dodge_chance; - - // cannot be dodged/parried/blocked - if(spellInfo->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) - { - block_chance = 0.0f; - parry_chance = 0.0f; - dodge_chance = 0.0f; - } - else - { - // parry can be avoided only by some abilites - parry_chance = pVictim->GetUnitParryChance(); - // block might be bypassed by it as well - block_chance = pVictim->GetUnitBlockChance(); - // stunned target cannot dodge and this is check in GetUnitDodgeChance() - dodge_chance = pVictim->GetUnitDodgeChance(); - } - - // Only players can have Talent&Spell bonuses - if (GetTypeId() == TYPEID_PLAYER) - { - // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura - crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, spellInfo->SchoolMask); - - if( dodge_chance != 0.0f ) // if dodge chance is already 0, ignore talents fpr speed - { - AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); - for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i) - { - // can't be dodged rogue finishing move - if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) - { - if(spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE)) - { - dodge_chance = 0.0f; - break; - } - } - } - } - } - - // Spellmods - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); - - DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance,crit_chance,dodge_chance,parry_chance, block_chance); - - return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100),int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), true); -} - -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const -{ - // This is only wrapper - - // Miss chance based on melee - float miss_chance = MeleeMissChanceCalc(pVictim, attType); - - // Critical hit chance - float crit_chance = GetUnitCriticalChance(attType, pVictim); - - // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case) - float dodge_chance = pVictim->GetUnitDodgeChance(); - float block_chance = pVictim->GetUnitBlockChance(); - float parry_chance = pVictim->GetUnitParryChance(); - - // Useful if want to specify crit & miss chances for melee, else it could be removed - DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance,crit_chance,dodge_chance,parry_chance,block_chance); - - return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), false); -} - -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const -{ - if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - return MELEE_HIT_EVADE; - - int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(pVictim); - int32 victimMaxSkillValueForLevel = pVictim->GetMaxSkillValueForLevel(this); - - int32 attackerWeaponSkill = GetWeaponSkillValue(attType,pVictim); - int32 victimDefenseSkill = pVictim->GetDefenseSkillValue(this); - - // bonus from skills is 0.04% - int32 skillBonus = 4 * ( attackerWeaponSkill - victimMaxSkillValueForLevel ); - int32 skillBonus2 = 4 * ( attackerMaxSkillValueForLevel - victimDefenseSkill ); - int32 sum = 0, tmp = 0; - int32 roll = urand (0, 10000); - - DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus); - DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d", - roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance); - - tmp = miss_chance; - - if (tmp > 0 && roll < (sum += tmp )) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS"); - return MELEE_HIT_MISS; - } - - // always crit against a sitting target (except 0 crit chance) - if( pVictim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !pVictim->IsStandState() ) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)"); - return MELEE_HIT_CRIT; - } - - // Dodge chance - - // only players can't dodge if attacker is behind - if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->HasInArc(M_PI,this)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player."); - } - else - { - // Reduce dodge chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - dodge_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100); - - // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); - - tmp = dodge_chance; - if ( (tmp > 0) // check if unit _can_ dodge - && ((tmp -= skillBonus) > 0) - && roll < (sum += tmp)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum); - return MELEE_HIT_DODGE; - } - } - - // parry & block chances - - // check if attack comes from behind, nobody can parry or block if attacker is behind - if (!pVictim->HasInArc(M_PI,this)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind."); - } - else - { - // Reduce parry chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - parry_chance-= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100); - - if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY) ) - { - int32 tmp = int32(parry_chance); - if ( (tmp > 0) // check if unit _can_ parry - && ((tmp -= skillBonus) > 0) - && (roll < (sum += tmp))) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum); - return MELEE_HIT_PARRY; - } - } - - if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK) ) - { - tmp = block_chance; - if ( (tmp > 0) // check if unit _can_ block - && ((tmp -= skillBonus) > 0) - && (roll < (sum += tmp))) - { - // Critical chance - tmp = crit_chance + skillBonus2; - if ( GetTypeId() == TYPEID_PLAYER && SpellCasted && tmp > 0 ) - { - if ( roll_chance_i(tmp/100)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT"); - return MELEE_HIT_BLOCK_CRIT; - } - } - DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); - return MELEE_HIT_BLOCK; - } - } - } - - // Critical chance - tmp = crit_chance + skillBonus2; - - if (tmp > 0 && roll < (sum += tmp)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum); - return MELEE_HIT_CRIT; - } - - // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) - if( attType != RANGED_ATTACK && !SpellCasted && - (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) && - pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() && - getLevel() < pVictim->getLevelForTarget(this) ) - { - // cap possible value (with bonuses > max skill) - int32 skill = attackerWeaponSkill; - int32 maxskill = attackerMaxSkillValueForLevel; - skill = (skill > maxskill) ? maxskill : skill; - - tmp = (10 + (victimDefenseSkill - skill)) * 100; - tmp = tmp > 4000 ? 4000 : tmp; - if (roll < (sum += tmp)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum); - return MELEE_HIT_GLANCING; - } - } - - if(GetTypeId()!=TYPEID_PLAYER && !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) && !((Creature*)this)->isPet() ) - { - // mobs can score crushing blows if they're 3 or more levels above victim - // or when their weapon skill is 15 or more above victim's defense skill - tmp = victimDefenseSkill; - int32 tmpmax = victimMaxSkillValueForLevel; - // having defense above your maximum (from items, talents etc.) has no effect - tmp = tmp > tmpmax ? tmpmax : tmp; - // tmp = mob's level * 5 - player's current defense skill - tmp = attackerMaxSkillValueForLevel - tmp; - if(tmp >= 15) - { - // add 2% chance per lacking skill point, min. is 15% - tmp = tmp * 200 - 1500; - if (roll < (sum += tmp)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum); - return MELEE_HIT_CRUSHING; - } - } - } - - DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL"); - return MELEE_HIT_NORMAL; -} - -uint32 Unit::CalculateDamage (WeaponAttackType attType, bool normalized) -{ - float min_damage, max_damage; - - if (normalized && GetTypeId()==TYPEID_PLAYER) - ((Player*)this)->CalculateMinMaxDamage(attType,normalized,min_damage, max_damage); - else - { - switch (attType) - { - case RANGED_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE); - break; - case BASE_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE); - break; - case OFF_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE); - break; - // Just for good manner - default: - min_damage = 0.0f; - max_damage = 0.0f; - break; - } - } - - if (min_damage > max_damage) - { - std::swap(min_damage,max_damage); - } - - if(max_damage == 0.0f) - max_damage = 5.0f; - - return urand((uint32)min_damage, (uint32)max_damage); -} - -float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const -{ - if(spellProto->spellLevel <= 0) - return 1.0f; - - float LvlPenalty = 0.0f; - - if(spellProto->spellLevel < 20) - LvlPenalty = 20.0f - spellProto->spellLevel * 3.75f; - float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel()); - if(LvlFactor > 1.0f) - LvlFactor = 1.0f; - - return (100.0f - LvlPenalty) * LvlFactor / 100.0f; -} - -void Unit::SendAttackStart(Unit* pVictim) -{ - WorldPacket data( SMSG_ATTACKSTART, 16 ); - data << GetGUID(); - data << pVictim->GetGUID(); - - SendMessageToSet(&data, true); - DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" ); -} - -void Unit::SendAttackStop(Unit* victim) -{ - if(!victim) - return; - - WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size - data.append(GetPackGUID()); - data.append(victim->GetPackGUID()); // can be 0x00... - data << uint32(0); // can be 0x1 - SendMessageToSet(&data, true); - sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow()); - - /*if(victim->GetTypeId() == TYPEID_UNIT) - ((Creature*)victim)->AI().EnterEvadeMode(this);*/ -} - -/* -// Melee based spells can be miss, parry or dodge on this step -// Crit or block - determined on damage calculation phase! (and can be both in some time) -float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell) -{ - // Calculate hit chance (more correct for chance mod) - int32 HitChance; - - // PvP - PvE melee chances - int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; - int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim); - if(leveldif < 3) - HitChance = 95 - leveldif; - else - HitChance = 93 - (leveldif - 2) * lchance; - - // Hit chance depends from victim auras - if(attType == RANGED_ATTACK) - HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); - else - HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); - - // Spellmod from SPELLMOD_RESIST_MISS_CHANCE - if(Player *modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance); - - // Miss = 100 - hit - float miss_chance= 100.0f - HitChance; - - // Bonuses from attacker aura and ratings - if (attType == RANGED_ATTACK) - miss_chance -= m_modRangedHitChance; - else - miss_chance -= m_modMeleeHitChance; - - // bonus from skills is 0.04% - miss_chance -= skillDiff * 0.04f; - - // Limit miss chance from 0 to 60% - if (miss_chance < 0.0f) - return 0.0f; - if (miss_chance > 60.0f) - return 60.0f; - return miss_chance; -} - -// Melee based spells hit result calculations -SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) -{ - WeaponAttackType attType = BASE_ATTACK; - - if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) - attType = RANGED_ATTACK; - - // bonus from skills is 0.04% per skill Diff - int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim)); - int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this)); - int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this)); - - uint32 roll = urand (0, 10000); - uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f); - - // Roll miss - uint32 tmp = missChance; - if (roll < tmp) - return SPELL_MISS_MISS; - - // Same spells cannot be parry/dodge - if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) - return SPELL_MISS_NONE; - - // Ranged attack can`t miss too - if (attType == RANGED_ATTACK) - return SPELL_MISS_NONE; - - bool attackFromBehind = !pVictim->HasInArc(M_PI,this); - - // Roll dodge - int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4; - // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); - - // Reduce dodge chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - if (dodgeChance < 0) - dodgeChance = 0; - - // Can`t dodge from behind in PvP (but its possible in PvE) - if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind) - dodgeChance = 0; - - // Rogue talent`s cant be dodged - AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); - for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i) - { - if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move - { - if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE)) - { - dodgeChance = 0; - break; - } - } - } - - tmp += dodgeChance; - if (roll < tmp) - return SPELL_MISS_DODGE; - - // Roll parry - int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4; - // Reduce parry chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - // Can`t parry from behind - if (parryChance < 0 || attackFromBehind) - parryChance = 0; - - tmp += parryChance; - if (roll < tmp) - return SPELL_MISS_PARRY; - - return SPELL_MISS_NONE; -}*/ - -// TODO need use unit spell resistances in calculations -SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell) -{ - // Can`t miss on dead target (on skinning for example) - if (!pVictim->isAlive()) - return SPELL_MISS_NONE; - - SpellSchoolMask schoolMask = GetSpellSchoolMask(spell); - // PvP - PvE spell misschances per leveldif > 2 - int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11; - int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim)); - - // Base hit chance from attacker and victim levels - int32 modHitChance; - if(leveldif < 3) - modHitChance = 96 - leveldif; - else - modHitChance = 94 - (leveldif - 2) * lchance; - - // Spellmod from SPELLMOD_RESIST_MISS_CHANCE - if(Player *modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); - // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras - modHitChance+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask); - // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras - modHitChance+= pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask); - // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura - if (IsAreaOfEffectSpell(spell)) - modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE); - // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST - if (IsDispelSpell(spell)) - modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST); - // Chance resist mechanic (select max value from every mechanic spell effect) - int32 resist_mech = 0; - // Get effects mechanic and chance - for(int eff = 0; eff < 3; ++eff) - { - int32 effect_mech = GetEffectMechanic(spell, eff); - if (effect_mech) - { - int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); - if (resist_mech < temp) - resist_mech = temp; - } - } - // Apply mod - modHitChance-=resist_mech; - - // Chance resist debuff - modHitChance-=pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)); - - int32 HitChance = modHitChance * 100; - // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings - HitChance += int32(m_modSpellHitChance*100.0f); - - // Decrease hit chance from victim rating bonus - if (pVictim->GetTypeId()==TYPEID_PLAYER) - HitChance -= int32(((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)*100.0f); - - if (HitChance < 100) HitChance = 100; - if (HitChance > 9900) HitChance = 9900; - - uint32 rand = urand(0,10000); - if (rand > HitChance) - return SPELL_MISS_RESIST; - return SPELL_MISS_NONE; -} - -SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool CanReflect) -{ - // Return evade for units in evade mode - if (pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - return SPELL_MISS_EVADE; - - // Check for immune (use charges) - if (pVictim->IsImmunedToSpell(spell,true)) - return SPELL_MISS_IMMUNE; - - // All positive spells can`t miss - // TODO: client not show miss log for this spells - so need find info for this in dbc and use it! - if (IsPositiveSpell(spell->Id)) - return SPELL_MISS_NONE; - - // Check for immune (use charges) - if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell),true)) - return SPELL_MISS_IMMUNE; - - // Try victim reflect spell - if (CanReflect) - { - // specialized first - Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL); - for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i) - { - if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell)) - { - int32 reflectchance = (*i)->GetModifier()->m_amount; - if (reflectchance > 0 && roll_chance_i(reflectchance)) - { - if((*i)->m_procCharges > 0) - { - --(*i)->m_procCharges; - if((*i)->m_procCharges==0) - pVictim->RemoveAurasDueToSpell((*i)->GetId()); - } - return SPELL_MISS_REFLECT; - } - } - } - - // generic reflection - Unit::AuraList const& mReflectSpells = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS); - for(Unit::AuraList::const_iterator i = mReflectSpells.begin(); i != mReflectSpells.end(); ++i) - { - int32 reflectchance = (*i)->GetModifier()->m_amount; - if (reflectchance > 0 && roll_chance_i(reflectchance)) - { - if((*i)->m_procCharges > 0) - { - --(*i)->m_procCharges; - if((*i)->m_procCharges==0) - pVictim->RemoveAurasDueToSpell((*i)->GetId()); - } - return SPELL_MISS_REFLECT; - } - } - } - - // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after) - for (int i=0;i<3;i++) - { - if (spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE || - spell->Effect[i] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE || - spell->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG || - spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL) - return SPELL_MISS_NONE; - } - - // TODO need use this code for spell hit result calculation - // now code commented for compotability - switch (spell->DmgClass) - { - case SPELL_DAMAGE_CLASS_RANGED: - case SPELL_DAMAGE_CLASS_MELEE: -// return MeleeSpellHitResult(pVictim, spell); - return SPELL_MISS_NONE; - case SPELL_DAMAGE_CLASS_NONE: - case SPELL_DAMAGE_CLASS_MAGIC: - return MagicSpellHitResult(pVictim, spell); - } - return SPELL_MISS_NONE; -} - -float Unit::MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const -{ - if(!pVictim) - return 0.0f; - - // Base misschance 5% - float misschance = 5.0f; - - // DualWield - Melee spells and physical dmg spells - 5% , white damage 24% - if (haveOffhandWeapon() && attType != RANGED_ATTACK) - { - bool isNormal = false; - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) - { - if( m_currentSpells[i] && (GetSpellSchoolMask(m_currentSpells[i]->m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL) ) - { - isNormal = true; - break; - } - } - if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL]) - { - misschance = 5.0f; - } - else - { - misschance = 24.0f; - } - } - - // PvP : PvE melee misschances per leveldif > 2 - int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; - - int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim)); - if(leveldif < 0) - leveldif = 0; - - // Hit chance from attacker based on ratings and auras - float m_modHitChance; - if (attType == RANGED_ATTACK) - m_modHitChance = m_modRangedHitChance; - else - m_modHitChance = m_modMeleeHitChance; - - if(leveldif < 3) - misschance += (leveldif - m_modHitChance); - else - misschance += ((leveldif - 2) * chance - m_modHitChance); - - // Hit chance for victim based on ratings - if (pVictim->GetTypeId()==TYPEID_PLAYER) - { - if (attType == RANGED_ATTACK) - misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED); - else - misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE); - } - - // Modify miss chance by victim auras - if(attType == RANGED_ATTACK) - misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); - else - misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); - - // Modify miss chance from skill difference ( bonus from skills is 0.04% ) - int32 skillBonus = int32(GetWeaponSkillValue(attType,pVictim)) - int32(pVictim->GetDefenseSkillValue(this)); - misschance -= skillBonus * 0.04f; - - // Limit miss chance from 0 to 60% - if ( misschance < 0.0f) - return 0.0f; - if ( misschance > 60.0f) - return 60.0f; - - return misschance; -} - -uint32 Unit::GetDefenseSkillValue(Unit const* target) const -{ - if(GetTypeId() == TYPEID_PLAYER) - { - // in PvP use full skill instead current skill value - uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER) - ? ((Player*)this)->GetMaxSkillValue(SKILL_DEFENSE) - : ((Player*)this)->GetSkillValue(SKILL_DEFENSE); - value += uint32(((Player*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL)); - return value; - } - else - return GetUnitMeleeSkill(target); -} - -float Unit::GetUnitDodgeChance() const -{ - if(hasUnitState(UNIT_STAT_STUNDED)) - return 0.0f; - if( GetTypeId() == TYPEID_PLAYER ) - return GetFloatValue(PLAYER_DODGE_PERCENTAGE); - else - { - if(((Creature const*)this)->isTotem()) - return 0.0f; - else - { - float dodge = 5.0f; - dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); - return dodge > 0.0f ? dodge : 0.0f; - } - } -} - -float Unit::GetUnitParryChance() const -{ - if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNDED)) - return 0.0f; - - float chance = 0.0f; - - if(GetTypeId() == TYPEID_PLAYER) - { - Player const* player = (Player const*)this; - if(player->CanParry() ) - { - Item *tmpitem = ((Player*)this)->GetWeaponForAttack(BASE_ATTACK,true); - if(!tmpitem) - tmpitem = ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true); - - if(tmpitem) - chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE); - } - } - else if(GetTypeId() == TYPEID_UNIT) - { - if(GetCreatureType() == CREATURE_TYPE_HUMANOID) - { - chance = 5.0f; - chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); - } - } - - return chance > 0.0f ? chance : 0.0f; -} - -float Unit::GetUnitBlockChance() const -{ - if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNDED)) - return 0.0f; - - if(GetTypeId() == TYPEID_PLAYER) - { - Item *tmpitem = ((Player const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block) - return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); - else - return 0.0f; - } - else - { - if(((Creature const*)this)->isTotem()) - return 0.0f; - else - { - float block = 5.0f; - block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); - return block > 0.0f ? block : 0.0f; - } - } -} - -float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const -{ - float crit; - - if(GetTypeId() == TYPEID_PLAYER) - { - switch(attackType) - { - case BASE_ATTACK: - crit = GetFloatValue( PLAYER_CRIT_PERCENTAGE ); - break; - case OFF_ATTACK: - crit = GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE ); - break; - case RANGED_ATTACK: - crit = GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE ); - break; - // Just for good manner - default: - crit = 0.0f; - break; - } - } - else - { - crit = 5.0f; - crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT); - } - - // flat aura mods - if(attackType == RANGED_ATTACK) - crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE); - else - crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE); - - crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); - - // reduce crit chance from Rating for players - if (pVictim->GetTypeId()==TYPEID_PLAYER) - { - if (attackType==RANGED_ATTACK) - crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED); - else - crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE); - } - - if (crit < 0.0f) - crit = 0.0f; - return crit; -} - -uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) const -{ - uint32 value = 0; - if(GetTypeId() == TYPEID_PLAYER) - { - Item* item = ((Player*)this)->GetWeaponForAttack(attType,true); - - // feral or unarmed skill only for base attack - if(attType != BASE_ATTACK && !item ) - return 0; - - if(((Player*)this)->IsInFeralForm()) - return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact - - // weaon skill or (unarmed for base attack) - uint32 skill = item ? item->GetSkill() : SKILL_UNARMED; - - // in PvP use full skill instead current skill value - value = (target && target->GetTypeId() == TYPEID_PLAYER) - ? ((Player*)this)->GetMaxSkillValue(skill) - : ((Player*)this)->GetSkillValue(skill); - // Modify value from ratings - value += uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL)); - switch (attType) - { - case BASE_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND));break; - case OFF_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND));break; - case RANGED_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED));break; - } - } - else - value = GetUnitMeleeSkill(target); - return value; -} - -void Unit::_UpdateSpells( uint32 time ) -{ - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) - _UpdateAutoRepeatSpell(); - - // remove finished spells from current pointers - for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) - { - if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED) - { - m_currentSpells[i]->SetDeletable(true); // spell may be safely deleted now - m_currentSpells[i] = NULL; // remove pointer - } - } - - // TODO: Find a better way to prevent crash when multiple auras are removed. - m_removedAuras = 0; - for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i) - if ((*i).second) - (*i).second->SetUpdated(false); - - for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next) - { - next = i; - ++next; - if ((*i).second) - { - // prevent double update - if ((*i).second->IsUpdated()) - continue; - (*i).second->SetUpdated(true); - (*i).second->Update( time ); - // several auras can be deleted due to update - if (m_removedAuras) - { - if (m_Auras.empty()) break; - next = m_Auras.begin(); - m_removedAuras = 0; - } - } - } - - for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();) - { - if ((*i).second) - { - if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) ) - { - RemoveAura(i); - } - else - { - ++i; - } - } - else - { - ++i; - } - } - - if(!m_gameObj.empty()) - { - std::list::iterator ite1, dnext1; - for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1) - { - dnext1 = ite1; - //(*i)->Update( difftime ); - if( !(*ite1)->isSpawned() ) - { - (*ite1)->SetOwnerGUID(0); - (*ite1)->SetRespawnTime(0); - (*ite1)->Delete(); - dnext1 = m_gameObj.erase(ite1); - } - else - ++dnext1; - } - } -} - -void Unit::_UpdateAutoRepeatSpell() -{ - //check "realtime" interrupts - if ( (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) ) - { - // cancel wand shoot - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - m_AutoRepeatFirstCast = true; - return; - } - - //apply delay - if ( m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 ) - setAttackTimer(RANGED_ATTACK,500); - m_AutoRepeatFirstCast = false; - - //castroutine - if (isAttackReady(RANGED_ATTACK)) - { - // Check if able to cast - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true)) - { - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - return; - } - - // we want to shoot - Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true, 0); - spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets)); - - // all went good, reset attack - resetAttackTimer(RANGED_ATTACK); - } -} - -void Unit::SetCurrentCastedSpell( Spell * pSpell ) -{ - assert(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells - - uint32 CSpellType = pSpell->GetCurrentContainer(); - - pSpell->SetDeletable(false); // spell will not be deleted until gone from current pointers - if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self - - // break same type spell if it is not delayed - InterruptSpell(CSpellType,false); - - // special breakage effects: - switch (CSpellType) - { - case CURRENT_GENERIC_SPELL: - { - // generic spells always break channeled not delayed spells - InterruptSpell(CURRENT_CHANNELED_SPELL,false); - - // autorepeat breaking - if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] ) - { - // break autorepeat if not Auto Shot - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - m_AutoRepeatFirstCast = true; - } - } break; - - case CURRENT_CHANNELED_SPELL: - { - // channel spells always break generic non-delayed and any channeled spells - InterruptSpell(CURRENT_GENERIC_SPELL,false); - InterruptSpell(CURRENT_CHANNELED_SPELL); - - // it also does break autorepeat if not Auto Shot - if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351 ) - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - } break; - - case CURRENT_AUTOREPEAT_SPELL: - { - // only Auto Shoot does not break anything - if (pSpell->m_spellInfo->Category == 351) - { - // generic autorepeats break generic non-delayed and channeled non-delayed spells - InterruptSpell(CURRENT_GENERIC_SPELL,false); - InterruptSpell(CURRENT_CHANNELED_SPELL,false); - } - // special action: set first cast flag - m_AutoRepeatFirstCast = true; - } break; - - default: - { - // other spell types don't break anything now - } break; - } - - // current spell (if it is still here) may be safely deleted now - if (m_currentSpells[CSpellType]) - m_currentSpells[CSpellType]->SetDeletable(true); - - // set new current spell - m_currentSpells[CSpellType] = pSpell; -} - -void Unit::InterruptSpell(uint32 spellType, bool withDelayed) -{ - assert(spellType < CURRENT_MAX_SPELL); - - if(m_currentSpells[spellType] && (withDelayed || m_currentSpells[spellType]->getState() != SPELL_STATE_DELAYED) ) - { - // send autorepeat cancel message for autorepeat spells - if (spellType == CURRENT_AUTOREPEAT_SPELL) - { - if(GetTypeId()==TYPEID_PLAYER) - ((Player*)this)->SendAutoRepeatCancel(); - } - - if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED) - m_currentSpells[spellType]->cancel(); - m_currentSpells[spellType]->SetDeletable(true); - m_currentSpells[spellType] = NULL; - } -} - -bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat) const -{ - // We don't do loop here to explicitly show that melee spell is excluded. - // Maybe later some special spells will be excluded too. - - // generic spells are casted when they are not finished and not delayed - if ( m_currentSpells[CURRENT_GENERIC_SPELL] && - (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && - (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) ) - return(true); - - // channeled spells may be delayed, but they are still considered casted - else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] && - (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) ) - return(true); - - // autorepeat spells may be finished or delayed, but they are still considered casted - else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] ) - return(true); - - return(false); -} - -void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) -{ - // generic spells are interrupted if they are not finished or delayed - if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id==spell_id)) - { - if ( (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && - (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) ) - m_currentSpells[CURRENT_GENERIC_SPELL]->cancel(); - m_currentSpells[CURRENT_GENERIC_SPELL]->SetDeletable(true); - m_currentSpells[CURRENT_GENERIC_SPELL] = NULL; - } - - // autorepeat spells are interrupted if they are not finished or delayed - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id==spell_id)) - { - // send disable autorepeat packet in any case - if(GetTypeId()==TYPEID_PLAYER) - ((Player*)this)->SendAutoRepeatCancel(); - - if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) && - (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) ) - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->cancel(); - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SetDeletable(true); - m_currentSpells[CURRENT_AUTOREPEAT_SPELL] = NULL; - } - - // channeled spells are interrupted if they are not finished, even if they are delayed - if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id==spell_id)) - { - if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) - m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); - m_currentSpells[CURRENT_CHANNELED_SPELL]->SetDeletable(true); - m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; - } -} - -Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const -{ - for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) - if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id==spell_id) - return m_currentSpells[i]; - return NULL; -} - -bool Unit::isInFront(Unit const* target, float distance, float arc) const -{ - return IsWithinDistInMap(target, distance) && HasInArc( arc, target ); -} - -void Unit::SetInFront(Unit const* target) -{ - SetOrientation(GetAngle(target)); -} - -bool Unit::isInBack(Unit const* target, float distance, float arc) const -{ - return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target ); -} - -bool Unit::isInAccessablePlaceFor(Creature const* c) const -{ - if(IsInWater()) - return c->canSwim(); - else - return c->canWalk(); -} - -bool Unit::IsInWater() const -{ - return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ()); -} - -bool Unit::IsUnderWater() const -{ - return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ()); -} - -void Unit::DeMorph() -{ - SetDisplayId(GetNativeDisplayId()); -} - -int32 Unit::GetTotalAuraModifier(AuraType auratype) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - modifier += (*i)->GetModifier()->m_amount; - - return modifier; -} - -float Unit::GetTotalAuraMultiplier(AuraType auratype) const -{ - float multipler = 1.0f; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - multipler *= (100.0f + (*i)->GetModifier()->m_amount)/100.0f; - - return multipler; -} - -int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - if ((*i)->GetModifier()->m_amount > modifier) - modifier = (*i)->GetModifier()->m_amount; - - return modifier; -} - -int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - if ((*i)->GetModifier()->m_amount < modifier) - modifier = (*i)->GetModifier()->m_amount; - - return modifier; -} - -int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue & misc_mask) - modifier += mod->m_amount; - } - return modifier; -} - -float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const -{ - float multipler = 1.0f; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue & misc_mask) - multipler *= (100.0f + mod->m_amount)/100.0f; - } - return multipler; -} - -int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue & misc_mask && mod->m_amount > modifier) - modifier = mod->m_amount; - } - - return modifier; -} - -int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue & misc_mask && mod->m_amount < modifier) - modifier = mod->m_amount; - } - - return modifier; -} - -int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue == misc_value) - modifier += mod->m_amount; - } - return modifier; -} - -float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const -{ - float multipler = 1.0f; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue == misc_value) - multipler *= (100.0f + mod->m_amount)/100.0f; - } - return multipler; -} - -int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue == misc_value && mod->m_amount > modifier) - modifier = mod->m_amount; - } - - return modifier; -} - -int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const -{ - int32 modifier = 0; - - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue == misc_value && mod->m_amount < modifier) - modifier = mod->m_amount; - } - - return modifier; -} - -bool Unit::AddAura(Aura *Aur) -{ - // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load) - if( !isAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 && - (GetTypeId()!=TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading()) ) - { - delete Aur; - return false; - } - - if(Aur->GetTarget() != this) - { - sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)", - Aur->GetId(),Aur->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(), - (Aur->GetTarget()->GetTypeId()==TYPEID_PLAYER?"player":"creature"),Aur->GetTarget()->GetGUIDLow()); - delete Aur; - return false; - } - - SpellEntry const* aurSpellInfo = Aur->GetSpellProto(); - - spellEffectPair spair = spellEffectPair(Aur->GetId(), Aur->GetEffIndex()); - AuraMap::iterator i = m_Auras.find( spair ); - - // take out same spell - if (i != m_Auras.end()) - { - // passive and persistent auras can stack with themselves any number of times - if (!Aur->IsPassive() && !Aur->IsPersistent()) - { - // replace aura if next will > spell StackAmount - if(aurSpellInfo->StackAmount) - { - if(m_Auras.count(spair) >= aurSpellInfo->StackAmount) - RemoveAura(i,AURA_REMOVE_BY_STACK); - } - // if StackAmount==0 not allow auras from same caster - else - { - for(AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair); ++i2) - { - if(i2->second->GetCasterGUID()==Aur->GetCasterGUID()) - { - // can be only single (this check done at _each_ aura add - RemoveAura(i2,AURA_REMOVE_BY_STACK); - break; - } - - bool stop = false; - switch(aurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()]) - { - // DoT/HoT/etc - case SPELL_AURA_PERIODIC_DAMAGE: // allow stack - case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: - case SPELL_AURA_PERIODIC_LEECH: - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_OBS_MOD_HEALTH: - case SPELL_AURA_PERIODIC_MANA_LEECH: - case SPELL_AURA_PERIODIC_ENERGIZE: - case SPELL_AURA_OBS_MOD_MANA: - case SPELL_AURA_POWER_BURN_MANA: - break; - default: // not allow - // can be only single (this check done at _each_ aura add - RemoveAura(i2,AURA_REMOVE_BY_STACK); - stop = true; - break; - } - - if(stop) - break; - } - } - } - } - - // passive auras stack with all (except passive spell proc auras) - if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) && - !(Aur->GetId() == 20584 || Aur->GetId() == 8326)) - { - if (!RemoveNoStackAurasDueToAura(Aur)) - { - delete Aur; - return false; // couldnt remove conflicting aura with higher rank - } - } - - // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura) - if (IsSingleTargetSpell(aurSpellInfo) && Aur->GetTarget()) - { - // caster pointer can be deleted in time aura remove, find it by guid at each iteration - for(;;) - { - Unit* caster = Aur->GetCaster(); - if(!caster) // caster deleted and not required adding scAura - break; - - bool restart = false; - AuraList& scAuras = caster->GetSingleCastAuras(); - for(AuraList::iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr) - { - if( (*itr)->GetTarget() != Aur->GetTarget() && - IsSingleTargetSpells((*itr)->GetSpellProto(),aurSpellInfo) ) - { - if ((*itr)->IsInUse()) - { - sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for IsSingleTargetSpell", (*itr)->GetId(), (*itr)->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex()); - continue; - } - (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex()); - restart = true; - break; - } - } - - if(!restart) - { - // done - scAuras.push_back(Aur); - break; - } - } - } - - // add aura, register in lists and arrays - Aur->_AddAura(); - m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur)); - if (Aur->GetModifier()->m_auraname < TOTAL_AURAS) - { - m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur); - } - - Aur->ApplyModifier(true,true); - sLog.outDebug("Aura %u now is in use", Aur->GetModifier()->m_auraname); - return true; -} - -void Unit::RemoveRankAurasDueToSpell(uint32 spellId) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - if(!spellInfo) - return; - AuraMap::iterator i,next; - for (i = m_Auras.begin(); i != m_Auras.end(); i = next) - { - next = i; - ++next; - uint32 i_spellId = (*i).second->GetId(); - if((*i).second && i_spellId && i_spellId != spellId) - { - if(spellmgr.IsRankSpellDueToSpell(spellInfo,i_spellId)) - { - RemoveAurasDueToSpell(i_spellId); - - if( m_Auras.empty() ) - break; - else - next = m_Auras.begin(); - } - } - } -} - -bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur) -{ - if (!Aur) - return false; - - SpellEntry const* spellProto = Aur->GetSpellProto(); - if (!spellProto) - return false; - - uint32 spellId = Aur->GetId(); - uint32 effIndex = Aur->GetEffIndex(); - - SpellSpecific spellId_spec = GetSpellSpecific(spellId); - - AuraMap::iterator i,next; - for (i = m_Auras.begin(); i != m_Auras.end(); i = next) - { - next = i; - ++next; - if (!(*i).second) continue; - - SpellEntry const* i_spellProto = (*i).second->GetSpellProto(); - - if (!i_spellProto) - continue; - - uint32 i_spellId = i_spellProto->Id; - - if(IsPassiveSpell(i_spellId)) - { - if(IsPassiveStackableSpell(i_spellId)) - continue; - - // passive non-stackable spells not stackable only with another rank of same spell - if (!spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId)) - continue; - } - - uint32 i_effIndex = (*i).second->GetEffIndex(); - - if(i_spellId == spellId) continue; - - bool is_triggered_by_spell = false; - // prevent triggered aura of removing aura that triggered it - for(int j = 0; j < 3; ++j) - if (i_spellProto->EffectTriggerSpell[j] == spellProto->Id) - is_triggered_by_spell = true; - if (is_triggered_by_spell) continue; - - for(int j = 0; j < 3; ++j) - { - // prevent remove dummy triggered spells at next effect aura add - switch(spellProto->Effect[j]) // main spell auras added added after triggred spell - { - case SPELL_EFFECT_DUMMY: - switch(spellId) - { - case 5420: if(i_spellId==34123) is_triggered_by_spell = true; break; - } - break; - } - - if(is_triggered_by_spell) - break; - - // prevent remove form main spell by triggred passive spells - switch(i_spellProto->EffectApplyAuraName[j]) // main aura added before triggered spell - { - case SPELL_AURA_MOD_SHAPESHIFT: - switch(i_spellId) - { - case 24858: if(spellId==24905) is_triggered_by_spell = true; break; - case 33891: if(spellId==5420 || spellId==34123) is_triggered_by_spell = true; break; - case 34551: if(spellId==22688) is_triggered_by_spell = true; break; - } - break; - } - } - - if(!is_triggered_by_spell) - { - SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId); - - bool is_sspc = IsSingleFromSpellSpecificPerCaster(spellId_spec,i_spellId_spec); - - if( is_sspc && Aur->GetCasterGUID() == (*i).second->GetCasterGUID() ) - { - // cannot remove higher rank - if (spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId)) - if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0) - return false; - - // Its a parent aura (create this aura in ApplyModifier) - if ((*i).second->IsInUse()) - { - sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex()); - continue; - } - RemoveAurasDueToSpell(i_spellId); - - if( m_Auras.empty() ) - break; - else - next = m_Auras.begin(); - } - else if( !is_sspc && spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) ) - { - // Its a parent aura (create this aura in ApplyModifier) - if ((*i).second->IsInUse()) - { - sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex()); - continue; - } - RemoveAurasDueToSpell(i_spellId); - - if( m_Auras.empty() ) - break; - else - next = m_Auras.begin(); - } - // Potions stack aura by aura (elixirs/flask already checked) - else if( spellProto->SpellFamilyName == SPELLFAMILY_POTION && i_spellProto->SpellFamilyName == SPELLFAMILY_POTION ) - { - if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex)) - { - if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0) - return false; // cannot remove higher rank - - // Its a parent aura (create this aura in ApplyModifier) - if ((*i).second->IsInUse()) - { - sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex()); - continue; - } - RemoveAura(i); - next = i; - } - } - } - } - return true; -} - -void Unit::RemoveAura(uint32 spellId, uint32 effindex, Aura* except) -{ - spellEffectPair spair = spellEffectPair(spellId, effindex); - for(AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);) - { - if(iter->second!=except) - { - RemoveAura(iter); - iter = m_Auras.lower_bound(spair); - } - else - ++iter; - } -} - -void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler) -{ - for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) - { - Aura *aur = iter->second; - if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID) - { - // Custom dispel case - // Unstable Affliction - if (aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (aur->GetSpellProto()->SpellFamilyFlags & 0x010000000000LL)) - { - int32 damage = aur->GetModifier()->m_amount*9; - uint64 caster_guid = aur->GetCasterGUID(); - - // Remove aura - RemoveAura(iter, AURA_REMOVE_BY_DISPEL); - - // backfire damage and silence - dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL,caster_guid); - - iter = m_Auras.begin(); // iterator can be invalidate at cast if self-dispel - } - else - RemoveAura(iter, AURA_REMOVE_BY_DISPEL); - } - else - ++iter; - } -} - -void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer) -{ - for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) - { - Aura *aur = iter->second; - if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID) - { - int32 basePoints = aur->GetBasePoints(); - // construct the new aura for the attacker - Aura * new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), &basePoints, stealer); - if(!new_aur) - continue; - - // set its duration and maximum duration - // max duration 2 minutes (in msecs) - int32 dur = aur->GetAuraDuration(); - const int32 max_dur = 2*MINUTE*1000; - new_aur->SetAuraMaxDuration( max_dur > dur ? dur : max_dur ); - new_aur->SetAuraDuration( max_dur > dur ? dur : max_dur ); - - // add the new aura to stealer - stealer->AddAura(new_aur); - - // Remove aura as dispel - RemoveAura(iter, AURA_REMOVE_BY_DISPEL); - } - else - ++iter; - } -} - -void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId) -{ - for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) - { - if (iter->second->GetId() == spellId) - RemoveAura(iter, AURA_REMOVE_BY_CANCEL); - else - ++iter; - } -} - -void Unit::RemoveAurasWithDispelType( DispelType type ) -{ - // Create dispel mask by dispel type - uint32 dispelMask = GetDispellMask(type); - // Dispel all existing auras vs current dispell type - AuraMap& auras = GetAuras(); - for(AuraMap::iterator itr = auras.begin(); itr != auras.end(); ) - { - SpellEntry const* spell = itr->second->GetSpellProto(); - if( (1<Dispel) & dispelMask ) - { - // Dispel aura - RemoveAurasDueToSpell(spell->Id); - itr = auras.begin(); - } - else - ++itr; - } -} - -void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex) -{ - AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex)); - if(iter != m_Auras.end()) - RemoveAura(iter); -} - -void Unit::RemoveAurasDueToSpell(uint32 spellId, Aura* except) -{ - for (int i = 0; i < 3; ++i) - RemoveAura(spellId,i,except); -} - -void Unit::RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId) -{ - for (int k=0; k < 3; ++k) - { - spellEffectPair spair = spellEffectPair(spellId, k); - for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);) - { - if (iter->second->GetCastItemGUID() == castItem->GetGUID()) - { - RemoveAura(iter); - iter = m_Auras.upper_bound(spair); // overwrite by more appropriate - } - else - ++iter; - } - } -} - -void Unit::RemoveAurasWithInterruptFlags(uint32 flags) -{ - for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) - { - if (iter->second->GetSpellProto()->AuraInterruptFlags & flags) - RemoveAura(iter); - else - ++iter; - } -} - -void Unit::RemoveNotOwnSingleTargetAuras() -{ - // single target auras from other casters - for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) - { - if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto())) - RemoveAura(iter); - else - ++iter; - } - - // single target auras at other targets - AuraList& scAuras = GetSingleCastAuras(); - for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end(); ) - { - Aura* aura = *iter; - if (aura->GetTarget()!=this) - { - scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveAura - aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetEffIndex()); - iter = scAuras.begin(); - } - else - ++iter; - } - -} - -void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) -{ - if (IsSingleTargetSpell((*i).second->GetSpellProto())) - { - if(Unit* caster = (*i).second->GetCaster()) - { - AuraList& scAuras = caster->GetSingleCastAuras(); - scAuras.remove((*i).second); - } - else - { - sLog.outError("Couldn't find the caster of the single target aura, may crash later!"); - assert(false); - } - } - - if ((*i).second->GetModifier()->m_auraname < TOTAL_AURAS) - { - m_modAuras[(*i).second->GetModifier()->m_auraname].remove((*i).second); - } - - // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order) - Aura* Aur = i->second; - // Set remove mode - Aur->SetRemoveMode(mode); - // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura - // remove aura from list before to prevent deleting it before - m_Auras.erase(i); - ++m_removedAuras; // internal count used by unit update - - // Status unsummoned at aura remove - Totem* statue = NULL; - if(IsChanneledSpell(Aur->GetSpellProto())) - if(Unit* caster = Aur->GetCaster()) - if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE) - statue = ((Totem*)caster); - - sLog.outDebug("Aura %u now is remove mode %d",Aur->GetModifier()->m_auraname, mode); - Aur->ApplyModifier(false,true); - Aur->_RemoveAura(); - delete Aur; - - if(statue) - statue->UnSummon(); - - // only way correctly remove all auras from list - if( m_Auras.empty() ) - i = m_Auras.end(); - else - i = m_Auras.begin(); -} - -void Unit::RemoveAllAuras() -{ - while (!m_Auras.empty()) - { - AuraMap::iterator iter = m_Auras.begin(); - RemoveAura(iter); - } -} - -void Unit::RemoveAllAurasOnDeath() -{ - // used just after dieing to remove all visible auras - // and disable the mods for the passive ones - for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) - { - if (!iter->second->IsPassive() && !iter->second->IsDeathPersistent()) - RemoveAura(iter, AURA_REMOVE_BY_DEATH); - else - ++iter; - } -} - -void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime) -{ - AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex)); - if (iter != m_Auras.end()) - { - if (iter->second->GetAuraDuration() < delaytime) - iter->second->SetAuraDuration(0); - else - iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime); - iter->second->UpdateAuraDuration(); - sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration()); - } -} - -void Unit::_RemoveAllAuraMods() -{ - for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i) - { - (*i).second->ApplyModifier(false); - } -} - -void Unit::_ApplyAllAuraMods() -{ - for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i) - { - (*i).second->ApplyModifier(true); - } -} - -Aura* Unit::GetAura(uint32 spellId, uint32 effindex) -{ - AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex)); - if (iter != m_Auras.end()) - return iter->second; - return NULL; -} - -void Unit::AddDynObject(DynamicObject* dynObj) -{ - m_dynObjGUIDs.push_back(dynObj->GetGUID()); -} - -void Unit::RemoveDynObject(uint32 spellid) -{ - if(m_dynObjGUIDs.empty()) - return; - for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) - { - DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin()); - if(!dynObj) - { - i = m_dynObjGUIDs.erase(i); - } - else if(spellid == 0 || dynObj->GetSpellId() == spellid) - { - dynObj->Delete(); - i = m_dynObjGUIDs.erase(i); - } - else - ++i; - } -} - -void Unit::RemoveAllDynObjects() -{ - while(!m_dynObjGUIDs.empty()) - { - DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin()); - if(dynObj) - dynObj->Delete(); - m_dynObjGUIDs.erase(m_dynObjGUIDs.begin()); - } -} - -DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex) -{ - for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) - { - DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin()); - if(!dynObj) - { - i = m_dynObjGUIDs.erase(i); - continue; - } - - if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex) - return dynObj; - ++i; - } - return NULL; -} - -DynamicObject * Unit::GetDynObject(uint32 spellId) -{ - for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) - { - DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin()); - if(!dynObj) - { - i = m_dynObjGUIDs.erase(i); - continue; - } - - if (dynObj->GetSpellId() == spellId) - return dynObj; - ++i; - } - return NULL; -} - -void Unit::AddGameObject(GameObject* gameObj) -{ - assert(gameObj && gameObj->GetOwnerGUID()==0); - m_gameObj.push_back(gameObj); - gameObj->SetOwnerGUID(GetGUID()); -} - -void Unit::RemoveGameObject(GameObject* gameObj, bool del) -{ - assert(gameObj && gameObj->GetOwnerGUID()==GetGUID()); - - // GO created by some spell - if ( GetTypeId()==TYPEID_PLAYER && gameObj->GetSpellId() ) - { - SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId()); - // Need activate spell use for owner - if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) - ((Player*)this)->SendCooldownEvent(createBySpell); - } - gameObj->SetOwnerGUID(0); - m_gameObj.remove(gameObj); - if(del) - { - gameObj->SetRespawnTime(0); - gameObj->Delete(); - } -} - -void Unit::RemoveGameObject(uint32 spellid, bool del) -{ - if(m_gameObj.empty()) - return; - std::list::iterator i, next; - for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next) - { - next = i; - if(spellid == 0 || (*i)->GetSpellId() == spellid) - { - (*i)->SetOwnerGUID(0); - if(del) - { - (*i)->SetRespawnTime(0); - (*i)->Delete(); - } - - next = m_gameObj.erase(i); - } - else - ++next; - } -} - -void Unit::RemoveAllGameObjects() -{ - // remove references to unit - for(std::list::iterator i = m_gameObj.begin(); i != m_gameObj.end();) - { - (*i)->SetOwnerGUID(0); - (*i)->SetRespawnTime(0); - (*i)->Delete(); - i = m_gameObj.erase(i); - } -} - -void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit) -{ - sLog.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG"); - WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size - data.append(target->GetPackGUID()); - data.append(GetPackGUID()); - data << uint32(SpellID); - data << uint32(Damage-AbsorbedDamage-Resist-Blocked); - data << uint8(damageSchoolMask); // spell school - data << uint32(AbsorbedDamage); // AbsorbedDamage - data << uint32(Resist); // resist - data << uint8(PhysicalDamage); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name - data << uint8(0); // unk isFromAura - data << uint32(Blocked); // blocked - data << uint32(CriticalHit ? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster? - data << uint8(0); // isDebug? - SendMessageToSet( &data, true ); -} - -void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo) -{ - WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1)); - data << uint32(spellID); - data << uint64(GetGUID()); - data << uint8(0); // can be 0 or 1 - data << uint32(1); // target count - // for(i = 0; i < target count; ++i) - data << uint64(target->GetGUID()); // target GUID - data << uint8(missInfo); - // end loop - SendMessageToSet(&data, true); -} - -void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount) -{ - sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); - - WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size - data << (uint32)HitInfo; - data.append(GetPackGUID()); - data.append(target->GetPackGUID()); - data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); - - data << (uint8)SwingType; // count? - - // for(i = 0; i < SwingType; ++i) - data << (uint32)damageSchoolMask; - data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount); - // still need to double check damage - data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); - data << (uint32)AbsorbDamage; - data << (uint32)Resist; - // end loop - - data << (uint32)TargetState; - - if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens - data << (uint32)0; - else - data << (uint32)-1; - - data << (uint32)0; - data << (uint32)BlockedAmount; - - SendMessageToSet( &data, true ); -} - -void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType) -{ - sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim); - if(procSpell) - sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":"")); - - // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities - // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect - // That is the question though if it's fully correct - if(procSpell && !isTriggeredSpell) - { - if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE) - { - if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE; - if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE; - if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE; - if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE; - attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon - } - else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) - { - if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED; - if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED; - if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED; - if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED; - attType = RANGED_ATTACK; - } - } - if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL))) - procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH); - - // Not much to do if no flags are set. - if (procAttacker) - { - // procces auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set - ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcEffectAuraTypes,attType, procSpell, damage, damageSchoolMask); - ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcCastAuraTypes,attType, procSpell, damage, damageSchoolMask); - } - - // Now go on with a victim's events'n'auras - // Not much to do if no flags are set or there is no victim - if(pVictim && pVictim->isAlive() && procVictim) - { - // procces auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set - pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcEffectAuraTypes,attType,procSpell, damage, damageSchoolMask); - pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcCastAuraTypes,attType,procSpell, damage, damageSchoolMask); - } -} - -void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell) -{ - if(!pVictim) - return; - - uint32 procAttacker = PROC_FLAG_NONE; - uint32 procVictim = PROC_FLAG_NONE; - - switch(outcome) - { - case MELEE_HIT_EVADE: - return; - case MELEE_HIT_MISS: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_MISS; - } - break; - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: - if(spellCasted && attType == BASE_ATTACK) - { - procAttacker |= PROC_FLAG_CRIT_SPELL; - procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - procVictim |= PROC_FLAG_BLOCK; - procAttacker |= PROC_FLAG_TARGET_BLOCK; - } - } - else if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED; - } - break; - case MELEE_HIT_PARRY: - procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY; - procVictim = PROC_FLAG_PARRY; - break; - case MELEE_HIT_BLOCK: - procAttacker = PROC_FLAG_TARGET_BLOCK; - procVictim = PROC_FLAG_BLOCK; - break; - case MELEE_HIT_DODGE: - procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY; - procVictim = PROC_FLAG_DODGE; - break; - case MELEE_HIT_CRUSHING: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED; - } - break; - default: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED; - } - break; - } - - if(damage > 0) - procVictim |= PROC_FLAG_TAKE_DAMAGE; - - if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE) - ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType); -} - -bool Unit::HandleHasteAuraProc(Unit *pVictim, SpellEntry const *hasteSpell, uint32 /*effIndex*/, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 cooldown) -{ - Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER - ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = 0; - Unit* target = pVictim; - int32 basepoints0 = 0; - - switch(hasteSpell->SpellFamilyName) - { - case SPELLFAMILY_ROGUE: - { - switch(hasteSpell->Id) - { - // Blade Flurry - case 13877: - case 33735: - { - target = SelectNearbyTarget(); - if(!target) - return false; - basepoints0 = damage; - triggered_spell_id = 22482; - break; - } - } - break; - } - } - - // processed charge only counting case - if(!triggered_spell_id) - return true; - - SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); - - if(!triggerEntry) - { - sLog.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell->Id,triggered_spell_id); - return false; - } - - // default case - if(!target || target!=this && !target->isAlive()) - return false; - - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; - - if(basepoints0) - CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - else - CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); - - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); - - return true; -} - -bool Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown) -{ - Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER - ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = 0; - Unit* target = pVictim; - int32 basepoints0 = 0; - - switch(dummySpell->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - switch (dummySpell->Id) - { - // Eye of Eye - case 9799: - case 25988: - { - // prevent damage back from weapon special attacks - if (!procSpell || procSpell->DmgClass != SPELL_DAMAGE_CLASS_MAGIC ) - return false; - - // return damage % to attacker but < 50% own total health - basepoints0 = triggeredByAura->GetModifier()->m_amount*int32(damage)/100; - if(basepoints0 > GetMaxHealth()/2) - basepoints0 = GetMaxHealth()/2; - - triggered_spell_id = 25997; - break; - } - // Sweeping Strikes - case 12328: - case 18765: - case 35429: - { - // prevent chain of triggred spell from same triggred spell - if(procSpell && procSpell->Id==26654) - return false; - - target = SelectNearbyTarget(); - if(!target) - return false; - - triggered_spell_id = 26654; - break; - } - // Unstable Power - case 24658: - { - if (!procSpell || procSpell->Id == 24659) - return false; - // Need remove one 24659 aura - RemoveSingleAuraFromStack(24659, 0); - RemoveSingleAuraFromStack(24659, 1); - return true; - } - // Restless Strength - case 24661: - { - // Need remove one 24662 aura - RemoveSingleAuraFromStack(24662, 0); - return true; - } - // Adaptive Warding (Frostfire Regalia set) - case 28764: - { - if(!procSpell) - return false; - - // find Mage Armor - bool found = false; - AuraList const& mRegenInterupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT); - for(AuraList::const_iterator iter = mRegenInterupt.begin(); iter != mRegenInterupt.end(); ++iter) - { - if(SpellEntry const* iterSpellProto = (*iter)->GetSpellProto()) - { - if(iterSpellProto->SpellFamilyName==SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags & 0x10000000)) - { - found=true; - break; - } - } - } - if(!found) - return false; - - switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) - { - case SPELL_SCHOOL_NORMAL: - case SPELL_SCHOOL_HOLY: - return false; // ignored - case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break; - case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break; - case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break; - case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break; - case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break; - default: - return false; - } - - target = this; - break; - } - // Obsidian Armor (Justice Bearer`s Pauldrons shoulder) - case 27539: - { - if(!procSpell) - return false; - - // not from DoT - bool found = false; - for(int j = 0; j < 3; ++j) - { - if(procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE||procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT) - { - found = true; - break; - } - } - if(found) - return false; - - switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) - { - case SPELL_SCHOOL_NORMAL: - return false; // ignore - case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break; - case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break; - case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break; - case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break; - case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break; - case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break; - default: - return false; - } - - target = this; - break; - } - // Mana Leech (Passive) (Priest Pet Aura) - case 28305: - { - // Cast on owner - target = GetOwner(); - if(!target) - return false; - - basepoints0 = int32(damage * 2.5f); // manaregen - triggered_spell_id = 34650; - break; - } - // Mark of Malice - case 33493: - { - // Cast finish spell at last charge - if (triggeredByAura->m_procCharges > 1) - return false; - - target = this; - triggered_spell_id = 33494; - break; - } - // Twisted Reflection (boss spell) - case 21063: - triggered_spell_id = 21064; - break; - // Vampiric Aura (boss spell) - case 38196: - { - basepoints0 = 3 * damage; // 300% - if (basepoints0 < 0) - return false; - - triggered_spell_id = 31285; - target = this; - break; - } - // Aura of Madness (Darkmoon Card: Madness trinket) - //===================================================== - // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior) - // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid) - // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid) - // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin) - // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes) - // 41005 Manic: +35 haste (spell, melee and ranged) (All classes) - // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter) - // 41011 Martyr Complex: +35 stamina (All classes) - // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) - // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) - case 39446: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Select class defined buff - switch (getClass()) - { - case CLASS_PALADIN: // 39511,40997,40998,40999,41002,41005,41009,41011,41409 - case CLASS_DRUID: // 39511,40997,40998,40999,41002,41005,41009,41011,41409 - { - uint32 RandomSpell[]={39511,40997,40998,40999,41002,41005,41009,41011,41409}; - triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; - break; - } - case CLASS_ROGUE: // 39511,40997,40998,41002,41005,41011 - case CLASS_WARRIOR: // 39511,40997,40998,41002,41005,41011 - { - uint32 RandomSpell[]={39511,40997,40998,41002,41005,41011}; - triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; - break; - } - case CLASS_PRIEST: // 40999,41002,41005,41009,41011,41406,41409 - case CLASS_SHAMAN: // 40999,41002,41005,41009,41011,41406,41409 - case CLASS_MAGE: // 40999,41002,41005,41009,41011,41406,41409 - case CLASS_WARLOCK: // 40999,41002,41005,41009,41011,41406,41409 - { - uint32 RandomSpell[]={40999,41002,41005,41009,41011,41406,41409}; - triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; - break; - } - case CLASS_HUNTER: // 40997,40999,41002,41005,41009,41011,41406,41409 - { - uint32 RandomSpell[]={40997,40999,41002,41005,41009,41011,41406,41409}; - triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; - break; - } - default: - return false; - } - - target = this; - if (roll_chance_i(10)) - ((Player*)this)->Say("This is Madness!", LANG_UNIVERSAL); - break; - } - /* - // TODO: need find item for aura and triggered spells - // Sunwell Exalted Caster Neck (??? neck) - // cast ??? Light's Wrath if Exalted by Aldor - // cast ??? Arcane Bolt if Exalted by Scryers*/ - case 46569: - return false; // disable for while - /* - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = ??? - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = ??? - break; - } - return false; - }/**/ - // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck) - // cast 45479 Light's Wrath if Exalted by Aldor - // cast 45429 Arcane Bolt if Exalted by Scryers - case 45481: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45479; - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = 45429; - break; - } - return false; - } - // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck) - // cast 45480 Light's Strength if Exalted by Aldor - // cast 45428 Arcane Strike if Exalted by Scryers - case 45482: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45480; - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = 45428; - break; - } - return false; - } - // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck) - // cast 45431 Arcane Insight if Exalted by Aldor - // cast 45432 Light's Ward if Exalted by Scryers - case 45483: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45432; - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45431; - break; - } - return false; - } - // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck) - // cast 45478 Light's Salvation if Exalted by Aldor - // cast 45430 Arcane Surge if Exalted by Scryers - case 45484: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45478; - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = 45430; - break; - } - return false; - } - } - break; - } - case SPELLFAMILY_MAGE: - { - // Magic Absorption - if (dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura - { - if (getPowerType() != POWER_MANA) - return false; - - // mana reward - basepoints0 = (triggeredByAura->GetModifier()->m_amount * GetMaxPower(POWER_MANA) / 100); - target = this; - triggered_spell_id = 29442; - break; - } - // Master of Elements - if (dummySpell->SpellIconID == 1920) - { - if(!procSpell) - return false; - - // mana cost save - basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; - if( basepoints0 <=0 ) - return false; - - target = this; - triggered_spell_id = 29077; - break; - } - switch(dummySpell->Id) - { - // Ignite - case 11119: - case 11120: - case 12846: - case 12847: - case 12848: - { - switch (dummySpell->Id) - { - case 11119: basepoints0 = int32(0.04f*damage); break; - case 11120: basepoints0 = int32(0.08f*damage); break; - case 12846: basepoints0 = int32(0.12f*damage); break; - case 12847: basepoints0 = int32(0.16f*damage); break; - case 12848: basepoints0 = int32(0.20f*damage); break; - default: - sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id); - return false; - } - - triggered_spell_id = 12654; - break; - } - // Combustion - case 11129: - { - //last charge and crit - if( triggeredByAura->m_procCharges <= 1 && (procFlag & PROC_FLAG_CRIT_SPELL) ) - { - RemoveAurasDueToSpell(28682); //-> remove Combustion auras - return true; // charge counting (will removed) - } - - CastSpell(this, 28682, true, castItem, triggeredByAura); - return(procFlag & PROC_FLAG_CRIT_SPELL);// charge update only at crit hits, no hidden cooldowns - } - } - break; - } - case SPELLFAMILY_WARRIOR: - { - // Retaliation - if(dummySpell->SpellFamilyFlags==0x0000000800000000LL) - { - // check attack comes not from behind - if (!HasInArc(M_PI, pVictim)) - return false; - - triggered_spell_id = 22858; - break; - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Seed of Corruption - if (dummySpell->SpellFamilyFlags & 0x0000001000000000LL) - { - Modifier* mod = triggeredByAura->GetModifier(); - // if damage is more than need or target die from damage deal finish spell - // FIX ME: not triggered currently at death - if( mod->m_amount <= damage || GetHealth() <= damage ) - { - // remember guid before aura delete - uint64 casterGuid = triggeredByAura->GetCasterGUID(); - - // Remove aura (before cast for prevent infinite loop handlers) - RemoveAurasDueToSpell(triggeredByAura->GetId()); - - // Cast finish spell (triggeredByAura already not exist!) - CastSpell(this, 27285, true, castItem, NULL, casterGuid); - return true; // no hidden cooldown - } - - // Damage counting - mod->m_amount-=damage; - return true; - } - // Seed of Corruption (Mobs cast) - no die req - if (dummySpell->SpellFamilyFlags == 0x00LL && dummySpell->SpellIconID == 1932) - { - Modifier* mod = triggeredByAura->GetModifier(); - // if damage is more than need deal finish spell - if( mod->m_amount <= damage ) - { - // remember guid before aura delete - uint64 casterGuid = triggeredByAura->GetCasterGUID(); - - // Remove aura (before cast for prevent infinite loop handlers) - RemoveAurasDueToSpell(triggeredByAura->GetId()); - - // Cast finish spell (triggeredByAura already not exist!) - CastSpell(this, 32865, true, castItem, NULL, casterGuid); - return true; // no hidden cooldown - } - // Damage counting - mod->m_amount-=damage; - return true; - } - switch(dummySpell->Id) - { - // Nightfall - case 18094: - case 18095: - { - target = this; - triggered_spell_id = 17941; - break; - } - //Soul Leech - case 30293: - case 30295: - case 30296: - { - // health - basepoints0 = int32(damage*triggeredByAura->GetModifier()->m_amount/100); - target = this; - triggered_spell_id = 30294; - break; - } - // Shadowflame (Voidheart Raiment set bonus) - case 37377: - { - triggered_spell_id = 37379; - break; - } - // Pet Healing (Corruptor Raiment or Rift Stalker Armor) - case 37381: - { - target = GetPet(); - if(!target) - return false; - - // heal amount - basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100; - triggered_spell_id = 37382; - break; - } - // Shadowflame Hellfire (Voidheart Raiment set bonus) - case 39437: - { - triggered_spell_id = 37378; - break; - } - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Vampiric Touch - if( dummySpell->SpellFamilyFlags & 0x0000040000000000LL ) - { - if(!pVictim || !pVictim->isAlive()) - return false; - - // pVictim is caster of aura - if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID()) - return false; - - // energize amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; - pVictim->CastCustomSpell(pVictim,34919,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - return true; // no hidden cooldown - } - switch(dummySpell->Id) - { - // Vampiric Embrace - case 15286: - { - if(!pVictim || !pVictim->isAlive()) - return false; - - // pVictim is caster of aura - if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID()) - return false; - - // heal amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; - pVictim->CastCustomSpell(pVictim,15290,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - return true; // no hidden cooldown - } - // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen) - case 40438: - { - // Shadow Word: Pain - if( procSpell->SpellFamilyFlags & 0x0000000000008000LL ) - triggered_spell_id = 40441; - // Renew - else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL ) - triggered_spell_id = 40440; - else - return false; - - target = this; - break; - } - // Oracle Healing Bonus ("Garments of the Oracle" set) - case 26169: - { - // heal amount - basepoints0 = int32(damage * 10/100); - target = this; - triggered_spell_id = 26170; - break; - } - // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set - case 39372: - { - if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW))==0 ) - return false; - - // heal amount - basepoints0 = int32(damage * 2 / 100); - target = this; - triggered_spell_id = 39373; - break; - } - // Vestments of Faith (Priest Tier 3) - 4 pieces bonus - case 28809: - { - triggered_spell_id = 28810; - break; - } - } - break; - } - case SPELLFAMILY_DRUID: - { - switch(dummySpell->Id) - { - // Healing Touch (Dreamwalker Raiment set) - case 28719: - { - // mana back - basepoints0 = int32(procSpell->manaCost * 30 / 100); - target = this; - triggered_spell_id = 28742; - break; - } - // Healing Touch Refund (Idol of Longevity trinket) - case 28847: - { - target = this; - triggered_spell_id = 28848; - break; - } - // Mana Restore (Malorne Raiment set / Malorne Regalia set) - case 37288: - case 37295: - { - target = this; - triggered_spell_id = 37238; - break; - } - // Druid Tier 6 Trinket - case 40442: - { - float chance; - - // Starfire - if( procSpell->SpellFamilyFlags & 0x0000000000000004LL ) - { - triggered_spell_id = 40445; - chance = 25.f; - } - // Rejuvenation - else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL ) - { - triggered_spell_id = 40446; - chance = 25.f; - } - // Mangle (cat/bear) - else if( procSpell->SpellFamilyFlags & 0x0000044000000000LL ) - { - triggered_spell_id = 40452; - chance = 40.f; - } - else - return false; - - if (!roll_chance_f(chance)) - return false; - - target = this; - break; - } - // Maim Interrupt - case 44835: - { - // Deadly Interrupt Effect - triggered_spell_id = 32747; - break; - } - } - break; - } - case SPELLFAMILY_ROGUE: - { - switch(dummySpell->Id) - { - // Deadly Throw Interrupt - case 32748: - { - // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw - if(this == pVictim) - return false; - - triggered_spell_id = 32747; - break; - } - } - // Quick Recovery - if( dummySpell->SpellIconID == 2116 ) - { - if(!procSpell) - return false; - - // only rogue's finishing moves (maybe need additional checks) - if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE || - (procSpell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE) == 0) - return false; - - // energy cost save - basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; - if(basepoints0 <= 0) - return false; - - target = this; - triggered_spell_id = 31663; - break; - } - break; - } - case SPELLFAMILY_HUNTER: - { - // Thrill of the Hunt - if ( dummySpell->SpellIconID == 2236 ) - { - if(!procSpell) - return false; - - // mana cost save - basepoints0 = procSpell->manaCost * 40/100; - if(basepoints0 <= 0) - return false; - - target = this; - triggered_spell_id = 34720; - break; - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Seal of Righteousness - melee proc dummy - if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggeredByAura->GetEffIndex()==0) - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - uint32 spellId; - switch (triggeredByAura->GetId()) - { - case 21084: spellId = 25742; break; // Rank 1 - case 20287: spellId = 25740; break; // Rank 2 - case 20288: spellId = 25739; break; // Rank 3 - case 20289: spellId = 25738; break; // Rank 4 - case 20290: spellId = 25737; break; // Rank 5 - case 20291: spellId = 25736; break; // Rank 6 - case 20292: spellId = 25735; break; // Rank 7 - case 20293: spellId = 25713; break; // Rank 8 - case 27155: spellId = 27156; break; // Rank 9 - default: - sLog.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura->GetId()); - return false; - } - Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - float speed = (item ? item->GetProto()->Delay : BASE_ATTACK_TIME)/1000.0f; - - float damageBasePoints; - if(item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON) - // two hand weapon - damageBasePoints=1.20f*triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f + 1; - else - // one hand weapon/no weapon - damageBasePoints=0.85f*ceil(triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f) - 1; - - int32 damagePoint = int32(damageBasePoints + 0.03f * (GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE)+GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE))/2.0f) + 1; - - // apply damage bonuses manually - if(damagePoint >= 0) - damagePoint = SpellDamageBonus(pVictim, dummySpell, damagePoint, SPELL_DIRECT_DAMAGE); - - CastCustomSpell(pVictim,spellId,&damagePoint,NULL,NULL,true,NULL, triggeredByAura); - return true; // no hidden cooldown - } - // Seal of Blood do damage trigger - if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL) - { - switch(triggeredByAura->GetEffIndex()) - { - case 0: - // prevent chain triggering - if(procSpell && procSpell->Id==31893 ) - return false; - - triggered_spell_id = 31893; - break; - case 1: - { - // damage - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; - target = this; - triggered_spell_id = 32221; - break; - } - } - } - - switch(dummySpell->Id) - { - // Holy Power (Redemption Armor set) - case 28789: - { - if(!pVictim) - return false; - - // Set class defined buff - switch (pVictim->getClass()) - { - case CLASS_PALADIN: - case CLASS_PRIEST: - case CLASS_SHAMAN: - case CLASS_DRUID: - triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. - break; - case CLASS_MAGE: - case CLASS_WARLOCK: - triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d. - break; - case CLASS_HUNTER: - case CLASS_ROGUE: - triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d. - break; - case CLASS_WARRIOR: - triggered_spell_id = 28790; // Increases the friendly target's armor - break; - default: - return false; - } - break; - } - //Seal of Vengeance - case 31801: - { - if(effIndex != 0) // effect 1,2 used by seal unleashing code - return false; - - triggered_spell_id = 31803; - break; - } - // Spiritual Att. - case 31785: - case 33776: - { - // if healed by another unit (pVictim) - if(this == pVictim) - return false; - - // heal amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; - target = this; - triggered_spell_id = 31786; - break; - } - // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) - case 40470: - { - if( !procSpell ) - return false; - - float chance; - - // Flash of light/Holy light - if( procSpell->SpellFamilyFlags & 0x00000000C0000000LL) - { - triggered_spell_id = 40471; - chance = 15.f; - } - // Judgement - else if( procSpell->SpellFamilyFlags & 0x0000000000800000LL ) - { - triggered_spell_id = 40472; - chance = 50.f; - } - else - return false; - - if (!roll_chance_f(chance)) - return false; - - break; - } - } - break; - } - case SPELLFAMILY_SHAMAN: - { - switch(dummySpell->Id) - { - // Totemic Power (The Earthshatterer set) - case 28823: - { - if( !pVictim ) - return false; - - // Set class defined buff - switch (pVictim->getClass()) - { - case CLASS_PALADIN: - case CLASS_PRIEST: - case CLASS_SHAMAN: - case CLASS_DRUID: - triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. - break; - case CLASS_MAGE: - case CLASS_WARLOCK: - triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d. - break; - case CLASS_HUNTER: - case CLASS_ROGUE: - triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d. - break; - case CLASS_WARRIOR: - triggered_spell_id = 28827; // Increases the friendly target's armor - break; - default: - return false; - } - break; - } - // Lesser Healing Wave (Totem of Flowing Water Relic) - case 28849: - { - target = this; - triggered_spell_id = 28850; - break; - } - // Windfury Weapon (Passive) 1-5 Ranks - case 33757: - { - if(GetTypeId()!=TYPEID_PLAYER) - return false; - - if(!castItem || !castItem->IsEquipped()) - return false; - - // custom cooldown processing case - if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) - return false; - - uint32 spellId; - switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT))) - { - case 283: spellId = 33757; break; //1 Rank - case 284: spellId = 33756; break; //2 Rank - case 525: spellId = 33755; break; //3 Rank - case 1669:spellId = 33754; break; //4 Rank - case 2636:spellId = 33727; break; //5 Rank - default: - { - sLog.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)", - castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)),dummySpell->Id); - return false; - } - } - - SpellEntry const* windfurySpellEntry = sSpellStore.LookupEntry(spellId); - if(!windfurySpellEntry) - { - sLog.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId); - return false; - } - - int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry,0,windfurySpellEntry->EffectBasePoints[0],pVictim); - - // Off-Hand case - if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND ) - { - // Value gained from additional AP - basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2); - triggered_spell_id = 33750; - } - // Main-Hand case - else - { - // Value gained from additional AP - basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000); - triggered_spell_id = 25504; - } - - // apply cooldown before cast to prevent processing itself - if( cooldown ) - ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); - - // Attack Twice - for ( uint32 i = 0; i<2; ++i ) - CastCustomSpell(pVictim,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - - return true; - } - // Shaman Tier 6 Trinket - case 40463: - { - if( !procSpell ) - return false; - - float chance; - if (procSpell->SpellFamilyFlags & 0x0000000000000001LL) - { - triggered_spell_id = 40465; // Lightning Bolt - chance = 15.f; - } - else if (procSpell->SpellFamilyFlags & 0x0000000000000080LL) - { - triggered_spell_id = 40465; // Lesser Healing Wave - chance = 10.f; - } - else if (procSpell->SpellFamilyFlags & 0x0000001000000000LL) - { - triggered_spell_id = 40466; // Stormstrike - chance = 50.f; - } - else - return false; - - if (!roll_chance_f(chance)) - return false; - - target = this; - break; - } - } - - // Earth Shield - if(dummySpell->SpellFamilyFlags==0x40000000000LL) - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // heal - basepoints0 = triggeredByAura->GetModifier()->m_amount; - target = this; - triggered_spell_id = 379; - break; - } - // Lightning Overload - if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura - { - if(!procSpell || GetTypeId() != TYPEID_PLAYER || !pVictim ) - return false; - - // custom cooldown processing case - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) - return false; - - uint32 spellId = 0; - // Every Lightning Bolt and Chain Lightning spell have dublicate vs half damage and zero cost - switch (procSpell->Id) - { - // Lightning Bolt - case 403: spellId = 45284; break; // Rank 1 - case 529: spellId = 45286; break; // Rank 2 - case 548: spellId = 45287; break; // Rank 3 - case 915: spellId = 45288; break; // Rank 4 - case 943: spellId = 45289; break; // Rank 5 - case 6041: spellId = 45290; break; // Rank 6 - case 10391: spellId = 45291; break; // Rank 7 - case 10392: spellId = 45292; break; // Rank 8 - case 15207: spellId = 45293; break; // Rank 9 - case 15208: spellId = 45294; break; // Rank 10 - case 25448: spellId = 45295; break; // Rank 11 - case 25449: spellId = 45296; break; // Rank 12 - // Chain Lightning - case 421: spellId = 45297; break; // Rank 1 - case 930: spellId = 45298; break; // Rank 2 - case 2860: spellId = 45299; break; // Rank 3 - case 10605: spellId = 45300; break; // Rank 4 - case 25439: spellId = 45301; break; // Rank 5 - case 25442: spellId = 45302; break; // Rank 6 - default: - sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id); - return false; - } - // No thread generated mod - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_THREAT; - mod->value = -100; - mod->type = SPELLMOD_PCT; - mod->spellId = dummySpell->Id; - mod->effectId = 0; - mod->lastAffected = NULL; - mod->mask = 0x0000000000000003LL; - mod->charges = 0; - ((Player*)this)->AddSpellMod(mod, true); - - // Remove cooldown (Chain Lightning - have Category Recovery time) - if (procSpell->SpellFamilyFlags & 0x0000000000000002LL) - ((Player*)this)->RemoveSpellCooldown(spellId); - - // Hmmm.. in most case spells alredy set half basepoints but... - // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level - // As on wiki: - // BUG: Rank 2 to 10 (and maybe 11) of Lightning Bolt will proc another Bolt with FULL damage (not halved). This bug is known and will probably be fixed soon. - // So - no add changes :) - CastSpell(pVictim, spellId, true, castItem, triggeredByAura); - - ((Player*)this)->AddSpellMod(mod, false); - - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); - - return true; - } - break; - } - default: - break; - } - - // processed charge only counting case - if(!triggered_spell_id) - return true; - - SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); - - if(!triggerEntry) - { - sLog.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id); - return false; - } - - // default case - if(!target || target!=this && !target->isAlive()) - return false; - - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; - - if(basepoints0) - CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - else - CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); - - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); - - return true; -} - -bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attackType, uint32 cooldown) -{ - SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto(); - - Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER - ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()]; - Unit* target = !(procFlags & PROC_FLAG_HEAL) && IsPositiveSpell(triggered_spell_id) ? this : pVictim; - int32 basepoints0 = 0; - - switch(auraSpellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - switch(auraSpellInfo->Id) - { - // Aegis of Preservation - case 23780: - //Aegis Heal (instead non-existed triggered spell) - triggered_spell_id = 23781; - target = this; - break; - // Elune's Touch (moonkin mana restore) - case 24905: - { - // Elune's Touch (instead non-existed triggered spell) - triggered_spell_id = 33926; - basepoints0 = int32(0.3f * GetTotalAttackPowerValue(BASE_ATTACK)); - target = this; - break; - } - // Enlightenment - case 29601: - { - // only for cast with mana price - if(!procSpell || procSpell->powerType!=POWER_MANA || procSpell->manaCost==0 && procSpell->ManaCostPercentage==0 && procSpell->manaCostPerlevel==0) - return false; - break; // fall through to normal cast - } - // Health Restore - case 33510: - { - // at melee hit call std triggered spell - if(procFlags & PROC_FLAG_HIT_MELEE) - break; // fall through to normal cast - - // Mark of Conquest - else (at range hit) called custom case - triggered_spell_id = 39557; - target = this; - break; - } - // Shaleskin - case 36576: - return true; // nothing to do - // Forgotten Knowledge (Blade of Wizardry) - case 38319: - // only for harmful enemy targeted spell - if(!pVictim || pVictim==this || !procSpell || IsPositiveSpell(procSpell->Id)) - return false; - break; // fall through to normal cast - // Aura of Wrath (Darkmoon Card: Wrath trinket bonus) - case 39442: - { - // proc only at non-crit hits - if(procFlags & (PROC_FLAG_CRIT_MELEE|PROC_FLAG_CRIT_RANGED|PROC_FLAG_CRIT_SPELL)) - return false; - break; // fall through to normal cast - } - // Augment Pain (Timbal's Focusing Crystal trinket bonus) - case 45054: - { - if(!procSpell) - return false; - - //only periodic damage can trigger spell - bool found = false; - for(int j = 0; j < 3; ++j) - { - if( procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE || - procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT || - procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_LEECH ) - { - found = true; - break; - } - } - if(!found) - return false; - - break; // fall through to normal cast - } - // Evasive Maneuvers (Commendation of Kael'thas) - case 45057: - { - // damage taken that reduces below 35% health - // does NOT mean you must have been >= 35% before - if (int32(GetHealth())-int32(damage) >= int32(GetMaxHealth()*0.35f)) - return false; - break; // fall through to normal cast - } - } - - switch(triggered_spell_id) - { - // Setup - case 15250: - { - // applied only for main target - if(!pVictim || pVictim != getVictim()) - return false; - - // continue normal case - break; - } - // Shamanistic Rage triggered spell - case 30824: - basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100); - break; - } - break; - } - case SPELLFAMILY_MAGE: - { - switch(auraSpellInfo->SpellIconID) - { - // Blazing Speed - case 2127: - //Blazing Speed (instead non-existed triggered spell) - triggered_spell_id = 31643; - target = this; - break; - } - switch(auraSpellInfo->Id) - { - // Persistent Shield (Scarab Brooch) - case 26467: - basepoints0 = int32(damage * 0.15f); - break; - } - break; - } - case SPELLFAMILY_WARRIOR: - { - //Rampage - if((auraSpellInfo->SpellFamilyFlags & 0x100000) && auraSpellInfo->SpellIconID==2006) - { - //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed) - //and effect[1]==TriggerSpell - if(auraSpellInfo->Effect[1]!=SPELL_EFFECT_TRIGGER_SPELL) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura->GetSpellProto()->Id); - return false; - } - triggered_spell_id = auraSpellInfo->EffectTriggerSpell[1]; - break; // fall through to normal cast - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Pyroclasm - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000 && auraSpellInfo->SpellIconID==1137) - { - // last case for Hellfire that damage caster also but don't must stun caster - if( pVictim == this ) - return false; - - // custom chnace - float chance = 0; - switch (triggeredByAura->GetId()) - { - case 18096: chance = 13.0f; break; - case 18073: chance = 26.0f; break; - } - if (!roll_chance_f(chance)) - return false; - - // Pyroclasm (instead non-existed triggered spell) - triggered_spell_id = 18093; - target = pVictim; - break; - } - // Drain Soul - if(auraSpellInfo->SpellFamilyFlags & 0x0000000000004000) - { - bool found = false; - Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER); - for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i) - { - //Improved Drain Soul - if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113) - { - int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this); - basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100; - - // Drain Soul - triggered_spell_id = 18371; - target = this; - found = true; - break; - } - } - if(!found) - return false; - break; // fall through to normal cast - } - break; - } - case SPELLFAMILY_PRIEST: - { - //Blessed Recovery - if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL && auraSpellInfo->SpellIconID==1875) - { - switch (triggeredByAura->GetSpellProto()->Id) - { - case 27811: triggered_spell_id = 27813; break; - case 27815: triggered_spell_id = 27817; break; - case 27816: triggered_spell_id = 27818; break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id); - return false; - } - - int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100; - basepoints0 = heal_amount/3; - target = this; - break; - } - // Shadowguard - if((auraSpellInfo->SpellFamilyFlags & 0x80000000LL) && auraSpellInfo->SpellVisual==7958) - { - switch(triggeredByAura->GetSpellProto()->Id) - { - case 18137: - triggered_spell_id = 28377; break; // Rank 1 - case 19308: - triggered_spell_id = 28378; break; // Rank 2 - case 19309: - triggered_spell_id = 28379; break; // Rank 3 - case 19310: - triggered_spell_id = 28380; break; // Rank 4 - case 19311: - triggered_spell_id = 28381; break; // Rank 5 - case 19312: - triggered_spell_id = 28382; break; // Rank 6 - case 25477: - triggered_spell_id = 28385; break; // Rank 7 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id); - return false; - } - target = pVictim; - break; - } - break; - } - case SPELLFAMILY_DRUID: - { - switch(auraSpellInfo->Id) - { - // Leader of the Pack (triggering Improved Leader of the Pack heal) - case 24932: - { - if (triggeredByAura->GetModifier()->m_amount == 0) - return false; - basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; - triggered_spell_id = 34299; - break; - }; - // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form) - case 37336: - { - switch(m_form) - { - case FORM_BEAR: - case FORM_DIREBEAR: - triggered_spell_id=37340; break;// Ursine Blessing - case FORM_CAT: - triggered_spell_id=37341; break;// Feline Blessing - case FORM_TREE: - triggered_spell_id=37342; break;// Slyvan Blessing - case FORM_MOONKIN: - triggered_spell_id=37343; break;// Lunar Blessing - case FORM_NONE: - triggered_spell_id=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN) - default: - return false; - } - - target = this; - break; - } - } - break; - } - case SPELLFAMILY_ROGUE: - { - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000LL) - { - switch(auraSpellInfo->SpellIconID) - { - // Combat Potency - case 2260: - { - // skip non offhand attacks - if(attackType!=OFF_ATTACK) - return false; - break; // fall through to normal cast - } - } - } - break; - } - case SPELLFAMILY_PALADIN: - { - if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL) - { - switch(auraSpellInfo->Id) - { - // Lightning Capacitor - case 37657: - { - // trinket ProcTriggerSpell but for safe checks for player - if(!castItem || !pVictim || !pVictim->isAlive() || GetTypeId()!=TYPEID_PLAYER) - return false; - - if(((Player*)this)->HasSpellCooldown(37657)) - return false; - - // stacking - CastSpell(this, 37658, true, castItem, triggeredByAura); - // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown - ((Player*)this)->AddSpellCooldown(37657,0,time(NULL)+(roll_chance_i(50) ? 2 : 3)); - - // counting - uint32 count = 0; - AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY); - for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr) - if((*itr)->GetId()==37658) - ++count; - - // release at 3 aura in stack - if(count <= 2) - return true; // main triggered spell casted anyway - - RemoveAurasDueToSpell(37658); - CastSpell(pVictim, 37661, true, castItem, triggeredByAura); - return true; - } - // Healing Discount - case 37705: - // Healing Trance (instead non-existed triggered spell) - triggered_spell_id = 37706; - target = this; - break; - // HoTs on Heals (Fel Reaver's Piston trinket) - case 38299: - { - // at direct heal effect - if(!procSpell || !IsSpellHaveEffect(procSpell,SPELL_EFFECT_HEAL)) - return false; - - // single proc at time - AuraList const& scAuras = GetSingleCastAuras(); - for(AuraList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr) - if((*itr)->GetId()==triggered_spell_id) - return false; - - // positive cast at victim instead self - target = pVictim; - break; - } - } - switch(auraSpellInfo->SpellIconID) - { - case 241: - { - switch(auraSpellInfo->EffectTriggerSpell[0]) - { - //Illumination - case 18350: - { - if(!procSpell) - return false; - - // procspell is triggered spell but we need mana cost of original casted spell - uint32 originalSpellId = procSpell->Id; - - // Holy Shock - if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN) - { - if(procSpell->SpellFamilyFlags & 0x0001000000000000LL) - { - switch(procSpell->Id) - { - case 25914: originalSpellId = 20473; break; - case 25913: originalSpellId = 20929; break; - case 25903: originalSpellId = 20930; break; - case 27175: originalSpellId = 27174; break; - case 33074: originalSpellId = 33072; break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id); - return false; - } - } - } - - SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId); - if(!originalSpell) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId); - return false; - } - - // percent stored in effect 1 (class scripts) base points - int32 percent = auraSpellInfo->EffectBasePoints[1]+1; - - basepoints0 = originalSpell->manaCost*percent/100; - triggered_spell_id = 20272; - target = this; - break; - } - } - break; - } - } - } - if(auraSpellInfo->SpellFamilyFlags & 0x00080000) - { - switch(auraSpellInfo->SpellIconID) - { - //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc - case 206: - { - if(!pVictim || !pVictim->isAlive()) - return false; - - uint32 spell = 0; - switch(triggeredByAura->GetSpellProto()->Id) - { - case 20186: - triggered_spell_id = 20268; // Rank 1 - break; - case 20354: - triggered_spell_id = 20352; // Rank 2 - break; - case 20355: - triggered_spell_id = 20353; // Rank 3 - break; - case 27164: - triggered_spell_id = 27165; // Rank 4 - break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura->GetSpellProto()->Id); - return false; - } - - pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID()); - return true; // no hidden cooldown - } - //Judgement of Light - case 299: - { - if(!pVictim || !pVictim->isAlive()) - return false; - - // overwrite non existing triggered spell call in spell.dbc - uint32 spell = 0; - switch(triggeredByAura->GetSpellProto()->Id) - { - case 20185: - triggered_spell_id = 20267; // Rank 1 - break; - case 20344: - triggered_spell_id = 20341; // Rank 2 - break; - case 20345: - triggered_spell_id = 20342; // Rank 3 - break; - case 20346: - triggered_spell_id = 20343; // Rank 4 - break; - case 27162: - triggered_spell_id = 27163; // Rank 5 - break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura->GetSpellProto()->Id); - return false; - } - pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID()); - return true; // no hidden cooldown - } - } - } - // custom check for proc spell - switch(auraSpellInfo->Id) - { - // Bonus Healing (item spell) - case 40971: - { - if(!pVictim || !pVictim->isAlive()) - return false; - - // bonus if health < 50% - if(pVictim->GetHealth() >= pVictim->GetMaxHealth()*triggeredByAura->GetModifier()->m_amount/100) - return false; - - // cast at target positive spell - target = pVictim; - break; - } - } - switch(triggered_spell_id) - { - // Seal of Command - case 20424: - // prevent chain of triggered spell from same triggered spell - if(procSpell && procSpell->Id==20424) - return false; - break; - } - break; - } - case SPELLFAMILY_SHAMAN: - { - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000) - { - switch(auraSpellInfo->SpellIconID) - { - case 19: - { - switch(auraSpellInfo->Id) - { - case 23551: // Lightning Shield - Tier2: 8 pieces proc shield - { - // Lightning Shield (overwrite non existing triggered spell call in spell.dbc) - triggered_spell_id = 23552; - target = pVictim; - break; - } - case 23552: // Lightning Shield - trigger shield damage - { - // Lightning Shield (overwrite non existing triggered spell call in spell.dbc) - triggered_spell_id = 27635; - target = pVictim; - break; - } - } - break; - } - // Mana Surge (Shaman T1 bonus) - case 87: - { - if(!procSpell) - return false; - - basepoints0 = procSpell->manaCost * 35/100; - triggered_spell_id = 23571; - target = this; - break; - } - //Nature's Guardian - case 2013: - { - if(GetTypeId()!=TYPEID_PLAYER) - return false; - - // damage taken that reduces below 30% health - // does NOT mean you must have been >= 30% before - if (10*(int32(GetHealth())-int32(damage)) >= 3*GetMaxHealth()) - return false; - - triggered_spell_id = 31616; - - // need check cooldown now - if( cooldown && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; - - basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; - target = this; - if(pVictim && pVictim->isAlive()) - pVictim->getThreatManager().modifyThreatPercent(this,-10); - break; - } - } - } - - // Water Shield (we can't set cooldown for main spell - it's player casted spell - if((auraSpellInfo->SpellFamilyFlags & 0x0000002000000000LL) && auraSpellInfo->SpellVisual==7358) - { - target = this; - break; - } - - // Lightning Shield - if((auraSpellInfo->SpellFamilyFlags & 0x00000400) && auraSpellInfo->SpellVisual==37) - { - // overwrite non existing triggered spell call in spell.dbc - switch(triggeredByAura->GetSpellProto()->Id) - { - case 324: - triggered_spell_id = 26364; break; // Rank 1 - case 325: - triggered_spell_id = 26365; break; // Rank 2 - case 905: - triggered_spell_id = 26366; break; // Rank 3 - case 945: - triggered_spell_id = 26367; break; // Rank 4 - case 8134: - triggered_spell_id = 26369; break; // Rank 5 - case 10431: - triggered_spell_id = 26370; break; // Rank 6 - case 10432: - triggered_spell_id = 26363; break; // Rank 7 - case 25469: - triggered_spell_id = 26371; break; // Rank 8 - case 25472: - triggered_spell_id = 26372; break; // Rank 9 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id); - return false; - } - - target = pVictim; - break; - } - break; - } - } - - // standard non-dummy case - if(!triggered_spell_id) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex()); - return false; - } - - SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); - - if(!triggerEntry) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex(),triggered_spell_id); - return false; - } - - // not allow proc extra attack spell at extra attack - if( m_extraAttacks && IsSpellHaveEffect(triggerEntry,SPELL_EFFECT_ADD_EXTRA_ATTACKS) ) - return false; - - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; - - // default case - if(!target || target!=this && !target->isAlive()) - return false; - - if(basepoints0) - CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - else - CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); - - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); - - return true; -} - -bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, int32 scriptId, uint32 damage, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown) -{ - if(!pVictim || !pVictim->isAlive()) - return false; - - Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER - ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = 0; - - switch(scriptId) - { - case 836: // Improved Blizzard (Rank 1) - { - if( !procSpell || procSpell->SpellVisual!=9487 ) - return false; - triggered_spell_id = 12484; - break; - } - case 988: // Improved Blizzard (Rank 2) - { - if( !procSpell || procSpell->SpellVisual!=9487 ) - return false; - triggered_spell_id = 12485; - break; - } - case 989: // Improved Blizzard (Rank 3) - { - if( !procSpell || procSpell->SpellVisual!=9487 ) - return false; - triggered_spell_id = 12486; - break; - } - case 4086: // Improved Mend Pet (Rank 1) - case 4087: // Improved Mend Pet (Rank 2) - { - int32 chance = triggeredByAura->GetSpellProto()->EffectBasePoints[triggeredByAura->GetEffIndex()]; - if(!roll_chance_i(chance)) - return false; - - triggered_spell_id = 24406; - break; - } - case 4533: // Dreamwalker Raiment 2 pieces bonus - { - // Chance 50% - if (!roll_chance_i(50)) - return false; - - switch (pVictim->getPowerType()) - { - case POWER_MANA: triggered_spell_id = 28722; break; - case POWER_RAGE: triggered_spell_id = 28723; break; - case POWER_ENERGY: triggered_spell_id = 28724; break; - default: - return false; - } - break; - } - case 4537: // Dreamwalker Raiment 6 pieces bonus - triggered_spell_id = 28750; // Blessing of the Claw - break; - case 5497: // Improved Mana Gems (Serpent-Coil Braid) - triggered_spell_id = 37445; // Mana Surge - break; - } - - // not processed - if(!triggered_spell_id) - return false; - - // standard non-dummy case - SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); - - if(!triggerEntry) - { - sLog.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id,scriptId); - return false; - } - - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; - - CastSpell(pVictim, triggered_spell_id, true, castItem, triggeredByAura); - - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); - - return true; -} - -void Unit::setPowerType(Powers new_powertype) -{ - SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype); - - if(GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE); - } - else if(((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(pet->isControlled()) - { - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE); - } - } - - switch(new_powertype) - { - default: - case POWER_MANA: - break; - case POWER_RAGE: - SetMaxPower(POWER_RAGE,GetCreatePowers(POWER_RAGE)); - SetPower( POWER_RAGE,0); - break; - case POWER_FOCUS: - SetMaxPower(POWER_FOCUS,GetCreatePowers(POWER_FOCUS)); - SetPower( POWER_FOCUS,GetCreatePowers(POWER_FOCUS)); - break; - case POWER_ENERGY: - SetMaxPower(POWER_ENERGY,GetCreatePowers(POWER_ENERGY)); - SetPower( POWER_ENERGY,0); - break; - case POWER_HAPPINESS: - SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS)); - SetPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS)); - break; - } -} - -FactionTemplateEntry const* Unit::getFactionTemplateEntry() const -{ - FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction()); - if(!entry) - { - static uint64 guid = 0; // prevent repeating spam same faction problem - - if(GetGUID() != guid) - { - if(GetTypeId() == TYPEID_PLAYER) - sLog.outError("Player %s have invalid faction (faction template id) #%u", ((Player*)this)->GetName(), getFaction()); - else - sLog.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction()); - guid = GetGUID(); - } - } - return entry; -} - -bool Unit::IsHostileTo(Unit const* unit) const -{ - // always non-hostile to self - if(unit==this) - return false; - - // always non-hostile to GM in GM mode - if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) - return false; - - // always hostile to enemy - if(getVictim()==unit || unit->getVictim()==this) - return true; - - // test pet/charm masters instead pers/charmeds - Unit const* testerOwner = GetCharmerOrOwner(); - Unit const* targetOwner = unit->GetCharmerOrOwner(); - - // always hostile to owner's enemy - if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner)) - return true; - - // always hostile to enemy owner - if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this)) - return true; - - // always hostile to owner of owner's enemy - if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner)) - return true; - - Unit const* tester = testerOwner ? testerOwner : this; - Unit const* target = targetOwner ? targetOwner : unit; - - // always non-hostile to target with common owner, or to owner/pet - if(tester==target) - return false; - - // special cases (Duel, etc) - if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER) - { - Player const* pTester = (Player const*)tester; - Player const* pTarget = (Player const*)target; - - // Duel - if(pTester->duel && pTester->duel->opponent == pTarget && pTester->duel->startTime != 0) - return true; - - // Group - if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup()) - return false; - - // Sanctuary - if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) - return false; - - // PvP FFA state - if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) - return true; - - //= PvP states - // Green/Blue (can't attack) - if(pTester->GetTeam()==pTarget->GetTeam()) - return false; - - // Red (can attack) if true, Blue/Yellow (can't attack) in another case - return pTester->IsPvP() && pTarget->IsPvP(); - } - - // faction base cases - FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry(); - FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry(); - if(!tester_faction || !target_faction) - return false; - - if(target->isAttackingPlayer() && tester->IsContestedGuard()) - return true; - - // PvC forced reaction and reputation case - if(tester->GetTypeId()==TYPEID_PLAYER) - { - // forced reaction - ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction); - if(forceItr!=((Player*)tester)->m_forcedReactions.end()) - return forceItr->second <= REP_HOSTILE; - - // if faction have reputation then hostile state for tester at 100% dependent from at_war state - if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction)) - if(raw_target_faction->reputationListID >=0) - if(FactionState const* factionState = ((Player*)tester)->GetFactionState(raw_target_faction)) - return (factionState->Flags & FACTION_FLAG_AT_WAR); - } - // CvP forced reaction and reputation case - else if(target->GetTypeId()==TYPEID_PLAYER) - { - // forced reaction - ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction); - if(forceItr!=((Player const*)target)->m_forcedReactions.end()) - return forceItr->second <= REP_HOSTILE; - - // apply reputation state - FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction); - if(raw_tester_faction && raw_tester_faction->reputationListID >=0 ) - return ((Player const*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE; - } - - // common faction based case (CvC,PvC,CvP) - return tester_faction->IsHostileTo(*target_faction); -} - -bool Unit::IsFriendlyTo(Unit const* unit) const -{ - // always friendly to self - if(unit==this) - return true; - - // always friendly to GM in GM mode - if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) - return true; - - // always non-friendly to enemy - if(getVictim()==unit || unit->getVictim()==this) - return false; - - // test pet/charm masters instead pers/charmeds - Unit const* testerOwner = GetCharmerOrOwner(); - Unit const* targetOwner = unit->GetCharmerOrOwner(); - - // always non-friendly to owner's enemy - if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner)) - return false; - - // always non-friendly to enemy owner - if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this)) - return false; - - // always non-friendly to owner of owner's enemy - if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner)) - return false; - - Unit const* tester = testerOwner ? testerOwner : this; - Unit const* target = targetOwner ? targetOwner : unit; - - // always friendly to target with common owner, or to owner/pet - if(tester==target) - return true; - - // special cases (Duel) - if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER) - { - Player const* pTester = (Player const*)tester; - Player const* pTarget = (Player const*)target; - - // Duel - if(pTester->duel && pTester->duel->opponent == target && pTester->duel->startTime != 0) - return false; - - // Group - if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup()) - return true; - - // Sanctuary - if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) - return true; - - // PvP FFA state - if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) - return false; - - //= PvP states - // Green/Blue (non-attackable) - if(pTester->GetTeam()==pTarget->GetTeam()) - return true; - - // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable) - return !pTarget->IsPvP(); - } - - // faction base cases - FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry(); - FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry(); - if(!tester_faction || !target_faction) - return false; - - if(target->isAttackingPlayer() && tester->IsContestedGuard()) - return false; - - // PvC forced reaction and reputation case - if(tester->GetTypeId()==TYPEID_PLAYER) - { - // forced reaction - ForcedReactions::const_iterator forceItr = ((Player const*)tester)->m_forcedReactions.find(target_faction->faction); - if(forceItr!=((Player const*)tester)->m_forcedReactions.end()) - return forceItr->second >= REP_FRIENDLY; - - // if faction have reputation then friendly state for tester at 100% dependent from at_war state - if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction)) - if(raw_target_faction->reputationListID >=0) - if(FactionState const* FactionState = ((Player*)tester)->GetFactionState(raw_target_faction)) - return !(FactionState->Flags & FACTION_FLAG_AT_WAR); - } - // CvP forced reaction and reputation case - else if(target->GetTypeId()==TYPEID_PLAYER) - { - // forced reaction - ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction); - if(forceItr!=((Player const*)target)->m_forcedReactions.end()) - return forceItr->second >= REP_FRIENDLY; - - // apply reputation state - if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction)) - if(raw_tester_faction->reputationListID >=0 ) - return ((Player const*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY; - } - - // common faction based case (CvC,PvC,CvP) - return tester_faction->IsFriendlyTo(*target_faction); -} - -bool Unit::IsHostileToPlayers() const -{ - FactionTemplateEntry const* my_faction = getFactionTemplateEntry(); - if(!my_faction) - return false; - - FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction); - if(raw_faction && raw_faction->reputationListID >=0 ) - return false; - - return my_faction->IsHostileToPlayers(); -} - -bool Unit::IsNeutralToAll() const -{ - FactionTemplateEntry const* my_faction = getFactionTemplateEntry(); - if(!my_faction) - return true; - - FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction); - if(raw_faction && raw_faction->reputationListID >=0 ) - return false; - - return my_faction->IsNeutralToAll(); -} - -bool Unit::Attack(Unit *victim, bool meleeAttack) -{ - if(!victim || victim == this) - return false; - - // dead units can neither attack nor be attacked - if(!isAlive() || !victim->isAlive()) - return false; - - // player cannot attack in mount state - if(GetTypeId()==TYPEID_PLAYER && IsMounted()) - return false; - - // nobody can attack GM in GM-mode - if(victim->GetTypeId()==TYPEID_PLAYER) - { - if(((Player*)victim)->isGameMaster()) - return false; - } - else - { - if(((Creature*)victim)->IsInEvadeMode()) - return false; - } - - // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack) - if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) - RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE); - - if (m_attacking) - { - if (m_attacking == victim) - { - // switch to melee attack from ranged/magic - if( meleeAttack && !hasUnitState(UNIT_STAT_MELEE_ATTACKING) ) - { - addUnitState(UNIT_STAT_MELEE_ATTACKING); - SendAttackStart(victim); - return true; - } - return false; - } - AttackStop(); - } - - //Set our target - SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); - - if(meleeAttack) - addUnitState(UNIT_STAT_MELEE_ATTACKING); - m_attacking = victim; - m_attacking->_addAttacker(this); - - if(m_attacking->GetTypeId()==TYPEID_UNIT && ((Creature*)m_attacking)->AI()) - ((Creature*)m_attacking)->AI()->AttackedBy(this); - - if(GetTypeId()==TYPEID_UNIT) - { - WorldPacket data(SMSG_AI_REACTION, 12); - data << GetGUID(); - data << uint32(AI_REACTION_AGGRO); // Aggro sound - ((WorldObject*)this)->SendMessageToSet(&data, true); - - ((Creature*)this)->CallAssistence(); - ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); - } - - // delay offhand weapon attack to next attack time - if(haveOffhandWeapon()) - resetAttackTimer(OFF_ATTACK); - - if(meleeAttack) - SendAttackStart(victim); - - return true; -} - -bool Unit::AttackStop() -{ - if (!m_attacking) - return false; - - Unit* victim = m_attacking; - - m_attacking->_removeAttacker(this); - m_attacking = NULL; - - //Clear our target - SetUInt64Value(UNIT_FIELD_TARGET, 0); - - clearUnitState(UNIT_STAT_MELEE_ATTACKING); - - InterruptSpell(CURRENT_MELEE_SPELL); - - if( GetTypeId()==TYPEID_UNIT ) - { - // reset call assistance - ((Creature*)this)->SetNoCallAssistence(false); - } - - SendAttackStop(victim); - - return true; -} - -void Unit::CombatStop(bool cast) -{ - if(cast& IsNonMeleeSpellCasted(false)) - InterruptNonMeleeSpells(false); - - AttackStop(); - RemoveAllAttackers(); - if( GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel - ClearInCombat(); -} - -void Unit::CombatStopWithPets(bool cast) -{ - CombatStop(cast); - if(Pet* pet = GetPet()) - pet->CombatStop(cast); - if(Unit* charm = GetCharm()) - charm->CombatStop(cast); - if(GetTypeId()==TYPEID_PLAYER) - { - GuardianPetList const& guardians = ((Player*)this)->GetGuardians(); - for(GuardianPetList::const_iterator itr = guardians.begin(); itr != guardians.end(); ++itr) - if(Unit* guardian = Unit::GetUnit(*this,*itr)) - guardian->CombatStop(cast); - } -} - -bool Unit::isAttackingPlayer() const -{ - if(hasUnitState(UNIT_STAT_ATTACK_PLAYER)) - return true; - - Pet* pet = GetPet(); - if(pet && pet->isAttackingPlayer()) - return true; - - Unit* charmed = GetCharm(); - if(charmed && charmed->isAttackingPlayer()) - return true; - - for (int8 i = 0; i < MAX_TOTEM; i++) - { - if(m_TotemSlot[i]) - { - Creature *totem = ObjectAccessor::GetCreature(*this, m_TotemSlot[i]); - if(totem && totem->isAttackingPlayer()) - return true; - } - } - - return false; -} - -void Unit::RemoveAllAttackers() -{ - while (!m_attackers.empty()) - { - AttackerSet::iterator iter = m_attackers.begin(); - if(!(*iter)->AttackStop()) - { - sLog.outError("WORLD: Unit has an attacker that isnt attacking it!"); - m_attackers.erase(iter); - } - } -} - -void Unit::ModifyAuraState(AuraState flag, bool apply) -{ - if (apply) - { - if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1))) - { - SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); - if(GetTypeId() == TYPEID_PLAYER) - { - const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - if(itr->second->state == PLAYERSPELL_REMOVED) continue; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (!spellInfo || !IsPassiveSpell(itr->first)) continue; - if (spellInfo->CasterAuraState == flag) - CastSpell(this, itr->first, true, NULL); - } - } - } - } - else - { - if (HasFlag(UNIT_FIELD_AURASTATE,1<<(flag-1))) - { - RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); - Unit::AuraMap& tAuras = GetAuras(); - for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();) - { - SpellEntry const* spellProto = (*itr).second->GetSpellProto(); - if (spellProto->CasterAuraState == flag) - { - // exceptions (applied at state but not removed at state change) - // Rampage - if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags==0x100000) - { - ++itr; - continue; - } - - RemoveAura(itr); - } - else - ++itr; - } - } - } -} - -Unit *Unit::GetOwner() const -{ - uint64 ownerid = GetOwnerGUID(); - if(!ownerid) - return NULL; - return ObjectAccessor::GetUnit(*this, ownerid); -} - -Unit *Unit::GetCharmer() const -{ - if(uint64 charmerid = GetCharmerGUID()) - return ObjectAccessor::GetUnit(*this, charmerid); - return NULL; -} - -Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() -{ - uint64 guid = GetCharmerOrOwnerGUID(); - if(IS_PLAYER_GUID(guid)) - return ObjectAccessor::GetPlayer(*this, guid); - - return GetTypeId()==TYPEID_PLAYER ? (Player*)this : NULL; -} - -Pet* Unit::GetPet() const -{ - if(uint64 pet_guid = GetPetGUID()) - { - if(Pet* pet = ObjectAccessor::GetPet(pet_guid)) - return pet; - - sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid)); - const_cast(this)->SetPet(0); - } - - return NULL; -} - -Unit* Unit::GetCharm() const -{ - if(uint64 charm_guid = GetCharmGUID()) - { - if(Unit* pet = ObjectAccessor::GetUnit(*this, charm_guid)) - return pet; - - sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid)); - const_cast(this)->SetCharm(0); - } - - return NULL; -} - -void Unit::SetPet(Pet* pet) -{ - SetUInt64Value(UNIT_FIELD_SUMMON,pet ? pet->GetGUID() : 0); - - // FIXME: hack, speed must be set only at follow - if(pet) - for(int i = 0; i < MAX_MOVE_TYPE; ++i) - pet->SetSpeed(UnitMoveType(i),m_speed_rate[i],true); -} - -void Unit::SetCharm(Unit* charmed) -{ - SetUInt64Value(UNIT_FIELD_CHARM,charmed ? charmed->GetGUID() : 0); -} - -void Unit::UnsummonAllTotems() -{ - for (int8 i = 0; i < MAX_TOTEM; ++i) - { - if(!m_TotemSlot[i]) - continue; - - Creature *OldTotem = ObjectAccessor::GetCreature(*this, m_TotemSlot[i]); - if (OldTotem && OldTotem->isTotem()) - ((Totem*)OldTotem)->UnSummon(); - } -} - -void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical) -{ - // we guess size - WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+1)); - data.append(pVictim->GetPackGUID()); - data.append(GetPackGUID()); - data << uint32(SpellID); - data << uint32(Damage); - data << uint8(critical ? 1 : 0); - data << uint8(0); // unused in client? - SendMessageToSet(&data, true); -} - -void Unit::SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers powertype, bool critical) -{ - WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1)); - data.append(pVictim->GetPackGUID()); - data.append(GetPackGUID()); - data << uint32(SpellID); - data << uint32(powertype); - data << uint32(Damage); - //data << uint8(critical ? 1 : 0); // removed in 2.4.0 - SendMessageToSet(&data, true); -} - -uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype) -{ - if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE ) - return pdamage; - - int32 BonusDamage = 0; - if( GetTypeId()==TYPEID_UNIT ) - { - // Pets just add their bonus damage to their spell damage - // note that their spell damage is just gain of their own auras - if (((Creature*)this)->isPet()) - { - BonusDamage = ((Pet*)this)->GetBonusDamage(); - } - // For totems get damage bonus from owner (statue isn't totem in fact) - else if (((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE) - { - if(Unit* owner = GetOwner()) - return owner->SpellDamageBonus(pVictim, spellProto, pdamage, damagetype); - } - } - - // Damage Done - uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); - - // Taken/Done fixed damage bonus auras - int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto))+BonusDamage; - int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), pVictim); - - // Damage over Time spells bonus calculation - float DotFactor = 1.0f; - if(damagetype == DOT) - { - int32 DotDuration = GetSpellDuration(spellProto); - // 200% limit - if(DotDuration > 0) - { - if(DotDuration > 30000) DotDuration = 30000; - if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f; - int x = 0; - for(int j = 0; j < 3; j++) - { - if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && ( - spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE || - spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) ) - { - x = j; - break; - } - } - int DotTicks = 6; - if(spellProto->EffectAmplitude[x] != 0) - DotTicks = DotDuration / spellProto->EffectAmplitude[x]; - if(DotTicks) - { - DoneAdvertisedBenefit /= DotTicks; - TakenAdvertisedBenefit /= DotTicks; - } - } - } - - // Taken/Done total percent damage auras - float DoneTotalMod = 1.0f; - float TakenTotalMod = 1.0f; - - // ..done - AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) - { - if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) && - (*i)->GetSpellProto()->EquippedItemClass == -1 && - // -1 == any item class (not wand then) - (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 ) - // 0 == any inventory type (not wand then) - { - DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; - } - } - - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS); - for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; - - // ..taken - AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); - for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i) - if( (*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto) ) - TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; - - // .. taken pct: scripted (increases damage of * against targets *) - AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) - { - switch((*i)->GetModifier()->m_miscvalue) - { - //Molten Fury - case 4920: case 4919: - if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT)) - TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; break; - } - } - // .. taken pct: dummy auras - AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); - for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - { - switch((*i)->GetSpellProto()->SpellIconID) - { - //Cheat Death - case 2109: - if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) ) - { - if(pVictim->GetTypeId() != TYPEID_PLAYER) - continue; - float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4; - if (mod < (*i)->GetModifier()->m_amount) - mod = (*i)->GetModifier()->m_amount; - TakenTotalMod *= (mod+100.0f)/100.0f; - } - break; - //Mangle - case 2312: - for(int j=0;j<3;j++) - { - if(GetEffectMechanic(spellProto, j)==MECHANIC_BLEED) - { - TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; - break; - } - } - break; - } - } - - // Distribute Damage over multiple effects, reduce by AoE - CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - - // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - for(int j = 0; j < 3; ++j) - { - if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || - spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH ) - { - CastingTime /= 2; - break; - } - } - - switch(spellProto->SpellFamilyName) - { - case SPELLFAMILY_MAGE: - // Ignite - do not modify, it is (8*Rank)% damage of procing Spell - if(spellProto->Id==12654) - { - return pdamage; - } - // Ice Lance - else if((spellProto->SpellFamilyFlags & 0x20000LL) && spellProto->SpellIconID == 186) - { - CastingTime /= 3; // applied 1/3 bonuses in case generic target - if(pVictim->isFrozen()) // and compensate this for frozen target. - TakenTotalMod *= 3.0f; - } - // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage - else if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 184 ) - { - DotFactor = damagetype == DOT ? 0.2f : 1.0f; - CastingTime = damagetype == DOT ? 3500 : 4025; - } - // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage - else if((spellProto->SpellFamilyFlags & 0x1LL) && spellProto->SpellIconID == 185) - { - CastingTime = 3500; - DotFactor = damagetype == DOT ? 0.0f : 1.0f; - } - // Molten armor - else if (spellProto->SpellFamilyFlags & 0x0000000800000000LL) - { - CastingTime = 0; - } - // Arcane Missiles triggered spell - else if ((spellProto->SpellFamilyFlags & 0x200000LL) && spellProto->SpellIconID == 225) - { - CastingTime = 1000; - } - // Blizzard triggered spell - else if ((spellProto->SpellFamilyFlags & 0x80080LL) && spellProto->SpellIconID == 285) - { - CastingTime = 500; - } - break; - case SPELLFAMILY_WARLOCK: - // Life Tap - if((spellProto->SpellFamilyFlags & 0x40000LL) && spellProto->SpellIconID == 208) - { - CastingTime = 2800; // 80% from +shadow damage - DoneTotalMod = 1.0f; - TakenTotalMod = 1.0f; - } - // Dark Pact - else if((spellProto->SpellFamilyFlags & 0x80000000LL) && spellProto->SpellIconID == 154 && GetPetGUID()) - { - CastingTime = 3360; // 96% from +shadow damage - DoneTotalMod = 1.0f; - TakenTotalMod = 1.0f; - } - // Soul Fire - 115% of Fire Damage - else if((spellProto->SpellFamilyFlags & 0x8000000000LL) && spellProto->SpellIconID == 184) - { - CastingTime = 4025; - } - // Curse of Agony - 120% of Shadow Damage - else if((spellProto->SpellFamilyFlags & 0x0000000400LL) && spellProto->SpellIconID == 544) - { - DotFactor = 1.2f; - } - // Drain Mana - 0% of Shadow Damage - else if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 548) - { - CastingTime = 0; - } - // Drain Soul 214.3% - else if ((spellProto->SpellFamilyFlags & 0x4000LL) && spellProto->SpellIconID == 113 ) - { - CastingTime = 7500; - } - // Hellfire - else if ((spellProto->SpellFamilyFlags & 0x40LL) && spellProto->SpellIconID == 937) - { - CastingTime = damagetype == DOT ? 5000 : 500; // self damage seems to be so - } - // Unstable Affliction - 180% - else if (spellProto->Id == 31117 && spellProto->SpellIconID == 232) - { - CastingTime = 6300; - } - // Corruption 93% - else if ((spellProto->SpellFamilyFlags & 0x2LL) && spellProto->SpellIconID == 313) - { - DotFactor = 0.93f; - } - break; - case SPELLFAMILY_PALADIN: - // Consecration - 95% of Holy Damage - if((spellProto->SpellFamilyFlags & 0x20LL) && spellProto->SpellIconID == 51) - { - DotFactor = 0.95f; - CastingTime = 3500; - } - // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed - else if((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 25) - { - Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - float wspeed = GetAttackTime(BASE_ATTACK)/1000.0f; - - if( item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON) - CastingTime = uint32(wspeed*3500*0.102f); - else - CastingTime = uint32(wspeed*3500*0.098f); - } - // Judgement of Righteousness - 73% - else if ((spellProto->SpellFamilyFlags & 1024) && spellProto->SpellIconID == 25) - { - CastingTime = 2555; - } - // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications - else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2292) - { - DotFactor = 0.17f; - CastingTime = 3500; - } - // Holy shield - 5% of Holy Damage - else if ((spellProto->SpellFamilyFlags & 0x4000000000LL) && spellProto->SpellIconID == 453) - { - CastingTime = 175; - } - // Blessing of Sanctuary - 0% - else if ((spellProto->SpellFamilyFlags & 0x10000000LL) && spellProto->SpellIconID == 29) - { - CastingTime = 0; - } - // Seal of Righteousness trigger - already computed for parent spell - else if ( spellProto->SpellFamilyName==SPELLFAMILY_PALADIN && spellProto->SpellIconID==25 && spellProto->AttributesEx4 & 0x00800000LL ) - { - return pdamage; - } - break; - case SPELLFAMILY_SHAMAN: - // totem attack - if (spellProto->SpellFamilyFlags & 0x000040000000LL) - { - if (spellProto->SpellIconID == 33) // Fire Nova totem attack must be 21.4%(untested) - CastingTime = 749; // ignore CastingTime and use as modifier - else if (spellProto->SpellIconID == 680) // Searing Totem attack 8% - CastingTime = 280; // ignore CastingTime and use as modifier - else if (spellProto->SpellIconID == 37) // Magma totem attack must be 6.67%(untested) - CastingTime = 234; // ignore CastingTimePenalty and use as modifier - } - // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge - else if( (spellProto->SpellFamilyFlags & 0x00000000400LL) || spellProto->Id == 23552) - CastingTime = 1155; // ignore CastingTimePenalty and use as modifier - break; - case SPELLFAMILY_PRIEST: - // Mana Burn - 0% of Shadow Damage - if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 212) - { - CastingTime = 0; - } - // Mind Flay - 59% of Shadow Damage - else if((spellProto->SpellFamilyFlags & 0x800000LL) && spellProto->SpellIconID == 548) - { - CastingTime = 2065; - } - // Holy Fire - 86.71%, DoT - 16.5% - else if ((spellProto->SpellFamilyFlags & 0x100000LL) && spellProto->SpellIconID == 156) - { - DotFactor = damagetype == DOT ? 0.165f : 1.0f; - CastingTime = damagetype == DOT ? 3500 : 3035; - } - // Shadowguard - 28% per charge - else if ((spellProto->SpellFamilyFlags & 0x2000000LL) && spellProto->SpellIconID == 19) - { - CastingTime = 980; - } - // Touch of Weakeness - 10% - else if ((spellProto->SpellFamilyFlags & 0x80000LL) && spellProto->SpellIconID == 1591) - { - CastingTime = 350; - } - // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras) - else if (spellProto->SpellFamilyFlags == 0 && spellProto->SpellIconID == 566) - { - CastingTime = 0; - } - // Holy Nova - 14% - else if ((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 1874) - { - CastingTime = 500; - } - break; - case SPELLFAMILY_DRUID: - // Hurricane triggered spell - if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 220) - { - CastingTime = 500; - } - break; - case SPELLFAMILY_WARRIOR: - case SPELLFAMILY_HUNTER: - case SPELLFAMILY_ROGUE: - CastingTime = 0; - break; - default: - break; - } - - float LvlPenalty = CalculateLevelPenalty(spellProto); - - // Spellmod SpellDamage - float SpellModSpellDamage = 100.0f; - - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage); - - SpellModSpellDamage /= 100.0f; - - float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty; - float TakenActualBenefit = TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty; - - float tmpDamage = (float(pdamage)+DoneActualBenefit)*DoneTotalMod; - - // Add flat bonus from spell damage versus - tmpDamage += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask); - - // apply spellmod to Done damage - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); - - tmpDamage = (tmpDamage+TakenActualBenefit)*TakenTotalMod; - - if( GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() ) - tmpDamage *= ((Creature*)this)->GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->rank); - - return tmpDamage > 0 ? uint32(tmpDamage) : 0; -} - -int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask) -{ - int32 DoneAdvertisedBenefit = 0; - - // ..done - AuraList const& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); - for(AuraList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i) - if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0 && - (*i)->GetSpellProto()->EquippedItemClass == -1 && - // -1 == any item class (not wand then) - (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 ) - // 0 == any inventory type (not wand then) - DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount; - - if (GetTypeId() == TYPEID_PLAYER) - { - // Damage bonus from stats - AuraList const& mDamageDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT); - for(AuraList::const_iterator i = mDamageDoneOfStatPercent.begin();i != mDamageDoneOfStatPercent.end(); ++i) - { - if((*i)->GetModifier()->m_miscvalue & schoolMask) - { - SpellEntry const* iSpellProto = (*i)->GetSpellProto(); - uint8 eff = (*i)->GetEffIndex(); - - // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index) - Stats usedStat = STAT_INTELLECT; - if(eff < 2 && iSpellProto->EffectApplyAuraName[eff+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT) - usedStat = Stats(iSpellProto->EffectMiscValue[eff+1]); - - DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f); - } - } - // ... and attack power - AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER); - for(AuraList::const_iterator i =mDamageDonebyAP.begin();i != mDamageDonebyAP.end(); ++i) - if ((*i)->GetModifier()->m_miscvalue & schoolMask) - DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f); - - } - return DoneAdvertisedBenefit; -} - -int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim) -{ - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - - int32 TakenAdvertisedBenefit = 0; - // ..done (for creature type by mask) in taken - AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE); - for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount; - - // ..taken - AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN); - for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i) - if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) - TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount; - - return TakenAdvertisedBenefit; -} - -bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) -{ - // not criting spell - if((spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_CRIT)) - return false; - - float crit_chance = 0.0f; - switch(spellProto->DmgClass) - { - case SPELL_DAMAGE_CLASS_NONE: - return false; - case SPELL_DAMAGE_CLASS_MAGIC: - { - if (schoolMask & SPELL_SCHOOL_MASK_NORMAL) - crit_chance = 0.0f; - // For other schools - else if (GetTypeId() == TYPEID_PLAYER) - crit_chance = GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask)); - else - { - crit_chance = m_baseSpellCritChance; - crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); - } - // taken - if (pVictim && !IsPositiveSpell(spellProto->Id)) - { - // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE - crit_chance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask); - // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE - crit_chance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); - // Modify by player victim resilience - if (pVictim->GetTypeId() == TYPEID_PLAYER) - crit_chance -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); - // scripted (increase crit chance ... against ... target by x% - if(pVictim->isFrozen()) // Shatter - { - AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) - { - switch((*i)->GetModifier()->m_miscvalue) - { - case 849: crit_chance+= 10.0f; break; //Shatter Rank 1 - case 910: crit_chance+= 20.0f; break; //Shatter Rank 2 - case 911: crit_chance+= 30.0f; break; //Shatter Rank 3 - case 912: crit_chance+= 40.0f; break; //Shatter Rank 4 - case 913: crit_chance+= 50.0f; break; //Shatter Rank 5 - } - } - } - } - break; - } - case SPELL_DAMAGE_CLASS_MELEE: - case SPELL_DAMAGE_CLASS_RANGED: - { - if (pVictim) - { - crit_chance = GetUnitCriticalChance(attackType, pVictim); - crit_chance+= (int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetDefenseSkillValue(this))) * 0.04f; - crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); - } - break; - } - default: - return false; - } - // percent done - // only players use intelligence for critical chance computations - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); - - crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f; - if (roll_chance_f(crit_chance)) - return true; - return false; -} - -uint32 Unit::SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim) -{ - // Calculate critical bonus - int32 crit_bonus; - switch(spellProto->DmgClass) - { - case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% - case SPELL_DAMAGE_CLASS_RANGED: - // TODO: write here full calculation for melee/ranged spells - crit_bonus = damage; - break; - default: - crit_bonus = damage / 2; // for spells is 50% - break; - } - - // adds additional damage to crit_bonus (from talents) - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); - - if(pVictim) - { - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask)); - } - - if(crit_bonus > 0) - damage += crit_bonus; - - return damage; -} - -uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim) -{ - // For totems get healing bonus from owner (statue isn't totem in fact) - if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE) - if(Unit* owner = GetOwner()) - return owner->SpellHealingBonus(spellProto, healamount, damagetype, pVictim); - - // Healing Done - - // These Spells are doing fixed amount of healing (TODO found less hack-like check) - if(spellProto->Id == 15290 || spellProto->Id == 39373 || spellProto->Id == 33778 || spellProto->Id == 379 || spellProto->Id == 38395) - return healamount; - - - int32 AdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto)); - uint32 CastingTime = GetSpellCastTime(spellProto); - - // Healing Taken - AdvertisedBenefit += SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), pVictim); - - // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light - if (spellProto->SpellFamilyName == SPELLFAMILY_PALADIN && (spellProto->SpellFamilyFlags & 0x00000000C0000000LL)) - { - AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); - for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) - { - if((*i)->GetSpellProto()->SpellVisual == 9180) - { - // Flash of Light - if ((spellProto->SpellFamilyFlags & 0x0000000040000000LL) && (*i)->GetEffIndex() == 1) - AdvertisedBenefit += (*i)->GetModifier()->m_amount; - // Holy Light - else if ((spellProto->SpellFamilyFlags & 0x0000000080000000LL) && (*i)->GetEffIndex() == 0) - AdvertisedBenefit += (*i)->GetModifier()->m_amount; - } - } - } - - float ActualBenefit = 0.0f; - - if (AdvertisedBenefit != 0) - { - // Healing over Time spells - float DotFactor = 1.0f; - if(damagetype == DOT) - { - int32 DotDuration = GetSpellDuration(spellProto); - if(DotDuration > 0) - { - // 200% limit - if(DotDuration > 30000) DotDuration = 30000; - if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f; - int x = 0; - for(int j = 0; j < 3; j++) - { - if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && ( - spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_HEAL || - spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) ) - { - x = j; - break; - } - } - int DotTicks = 6; - if(spellProto->EffectAmplitude[x] != 0) - DotTicks = DotDuration / spellProto->EffectAmplitude[x]; - if(DotTicks) - AdvertisedBenefit /= DotTicks; - } - } - - // distribute healing to all effects, reduce AoE damage - CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - - // 0% bonus for damage and healing spells for leech spells from healing bonus - for(int j = 0; j < 3; ++j) - { - if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || - spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH ) - { - CastingTime = 0; - break; - } - } - - // Exception - switch (spellProto->SpellFamilyName) - { - case SPELLFAMILY_SHAMAN: - // Healing stream from totem (add 6% per tick from hill bonus owner) - if (spellProto->SpellFamilyFlags & 0x000000002000LL) - CastingTime = 210; - // Earth Shield 30% per charge - else if (spellProto->SpellFamilyFlags & 0x40000000000LL) - CastingTime = 1050; - break; - case SPELLFAMILY_DRUID: - // Lifebloom - if (spellProto->SpellFamilyFlags & 0x1000000000LL) - { - CastingTime = damagetype == DOT ? 3500 : 1200; - DotFactor = damagetype == DOT ? 0.519f : 1.0f; - } - // Tranquility triggered spell - else if (spellProto->SpellFamilyFlags & 0x80LL) - CastingTime = 667; - // Rejuvenation - else if (spellProto->SpellFamilyFlags & 0x10LL) - DotFactor = 0.845f; - // Regrowth - else if (spellProto->SpellFamilyFlags & 0x40LL) - { - DotFactor = damagetype == DOT ? 0.705f : 1.0f; - CastingTime = damagetype == DOT ? 3500 : 1010; - } - break; - case SPELLFAMILY_PRIEST: - // Holy Nova - 14% - if ((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 1874) - CastingTime = 500; - break; - case SPELLFAMILY_PALADIN: - // Seal and Judgement of Light - if ( spellProto->SpellFamilyFlags & 0x100040000LL ) - CastingTime = 0; - break; - case SPELLFAMILY_WARRIOR: - case SPELLFAMILY_ROGUE: - case SPELLFAMILY_HUNTER: - CastingTime = 0; - break; - } - - float LvlPenalty = CalculateLevelPenalty(spellProto); - - // Spellmod SpellDamage - float SpellModSpellDamage = 100.0f; - - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage); - - SpellModSpellDamage /= 100.0f; - - ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty; - } - - // use float as more appropriate for negative values and percent applying - float heal = healamount + ActualBenefit; - - // TODO: check for ALL/SPELLS type - // Healing done percent - AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); - for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i) - heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; - - // apply spellmod to Done amount - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); - - // Healing Wave cast - if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags & 0x0000000000000040LL) - { - // Search for Healing Way on Victim (stack up to 3 time) - int32 pctMod = 0; - Unit::AuraList const& auraDummy = pVictim->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr!=auraDummy.end(); ++itr) - if((*itr)->GetId() == 29203) - pctMod += (*itr)->GetModifier()->m_amount; - // Apply bonus - if (pctMod) - heal = heal * (100 + pctMod) / 100; - } - - // Healing taken percent - float minval = pVictim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT); - if(minval) - heal *= (100.0f + minval) / 100.0f; - - float maxval = pVictim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT); - if(maxval) - heal *= (100.0f + maxval) / 100.0f; - - if (heal < 0) heal = 0; - - return uint32(heal); -} - -int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask) -{ - int32 AdvertisedBenefit = 0; - - AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE); - for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i) - if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) - AdvertisedBenefit += (*i)->GetModifier()->m_amount; - - // Healing bonus of spirit, intellect and strength - if (GetTypeId() == TYPEID_PLAYER) - { - // Healing bonus from stats - AuraList const& mHealingDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT); - for(AuraList::const_iterator i = mHealingDoneOfStatPercent.begin();i != mHealingDoneOfStatPercent.end(); ++i) - { - // stat used dependent from misc value (stat index) - Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]); - AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f); - } - - // ... and attack power - AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER); - for(AuraList::const_iterator i = mHealingDonebyAP.begin();i != mHealingDonebyAP.end(); ++i) - if ((*i)->GetModifier()->m_miscvalue & schoolMask) - AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f); - } - return AdvertisedBenefit; -} - -int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim) -{ - int32 AdvertisedBenefit = 0; - AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING); - for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i) - if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) - AdvertisedBenefit += (*i)->GetModifier()->m_amount; - return AdvertisedBenefit; -} - -bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask, bool useCharges) -{ - // no charges dependent checks - SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; - for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) - if(itr->type & shoolMask) - return true; - - // charges dependent checks - SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE]; - for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr) - { - if(itr->type & shoolMask) - { - if(useCharges) - { - AuraList const& auraDamageImmunity = GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY); - for(AuraList::const_iterator auraItr = auraDamageImmunity.begin(); auraItr != auraDamageImmunity.end(); ++auraItr) - { - if((*auraItr)->GetId()==itr->spellId) - { - if((*auraItr)->m_procCharges > 0) - { - --(*auraItr)->m_procCharges; - if((*auraItr)->m_procCharges==0) - RemoveAurasDueToSpell(itr->spellId); - } - break; - } - } - } - return true; - } - } - - return false; -} - -bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges) -{ - if (!spellInfo) - return false; - - // no charges first - - //FIX ME this hack: don't get feared if stunned - if (spellInfo->Mechanic == MECHANIC_FEAR ) - { - if ( hasUnitState(UNIT_STAT_STUNDED) ) - return true; - } - - // not have spells with charges currently - SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL]; - for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr) - if(itr->type == spellInfo->Dispel) - return true; - - if( !(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE)) // unaffected by school immunity - { - // not have spells with charges currently - SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; - for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) - if( !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) && - (itr->type & GetSpellSchoolMask(spellInfo)) ) - return true; - } - - // charges dependent checks - - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; - for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - { - if(itr->type == spellInfo->Mechanic) - { - if(useCharges) - { - AuraList const& auraMechImmunity = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY); - for(AuraList::const_iterator auraItr = auraMechImmunity.begin(); auraItr != auraMechImmunity.end(); ++auraItr) - { - if((*auraItr)->GetId()==itr->spellId) - { - if((*auraItr)->m_procCharges > 0) - { - --(*auraItr)->m_procCharges; - if((*auraItr)->m_procCharges==0) - RemoveAurasDueToSpell(itr->spellId); - } - break; - } - } - } - return true; - } - } - - return false; -} - -bool Unit::IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const -{ - //If m_immuneToEffect type contain this effect type, IMMUNE effect. - SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT]; - for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr) - if(itr->type == effect) - return true; - - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; - for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - if(itr->type == mechanic) - return true; - - return false; -} - -bool Unit::IsDamageToThreatSpell(SpellEntry const * spellInfo) const -{ - if(!spellInfo) - return false; - - uint32 family = spellInfo->SpellFamilyName; - uint64 flags = spellInfo->SpellFamilyFlags; - - if((family == 5 && flags == 256) || //Searing Pain - (family == 6 && flags == 8192) || //Mind Blast - (family == 11 && flags == 1048576)) //Earth Shock - return true; - - return false; -} - -void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attType, SpellEntry const *spellProto) -{ - if(!pVictim) - return; - - if(*pdamage == 0) - return; - - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - - // Taken/Done fixed damage bonus auras - int32 DoneFlatBenefit = 0; - int32 TakenFlatBenefit = 0; - - // ..done (for creature type by mask) in taken - AuraList const& mDamageDoneCreature = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE); - for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - DoneFlatBenefit += (*i)->GetModifier()->m_amount; - - // ..done - // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage - - // ..done (base at attack power for marked target and base at attack power for creature type) - int32 APbonus = 0; - if(attType == RANGED_ATTACK) - { - APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS); - - // ..done (base at attack power and creature type) - AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS); - for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - APbonus += (*i)->GetModifier()->m_amount; - } - else - { - APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS); - - // ..done (base at attack power and creature type) - AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS); - for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - APbonus += (*i)->GetModifier()->m_amount; - } - - if (APbonus!=0) // Can be negative - { - bool normalized = false; - if(spellProto) - { - for (uint8 i = 0; i<3;i++) - { - if (spellProto->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG) - { - normalized = true; - break; - } - } - } - - DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType,normalized)); - } - - // ..taken - AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN); - for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i) - if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) - TakenFlatBenefit += (*i)->GetModifier()->m_amount; - - if(attType!=RANGED_ATTACK) - TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN); - else - TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN); - - // Done/Taken total percent damage auras - float DoneTotalMod = 1; - float TakenTotalMod = 1; - - // ..done - // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage - // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage - - AuraList const& mDamageDoneVersus = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS); - for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; - - // ..taken - AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); - for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i) - if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) - TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; - - // .. taken pct: dummy auras - AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); - for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - { - switch((*i)->GetSpellProto()->SpellIconID) - { - //Cheat Death - case 2109: - if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) - { - if(pVictim->GetTypeId() != TYPEID_PLAYER) - continue; - float mod = ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*(-8.0f); - if (mod < (*i)->GetModifier()->m_amount) - mod = (*i)->GetModifier()->m_amount; - TakenTotalMod *= (mod+100.0f)/100.0f; - } - break; - //Mangle - case 2312: - if(spellProto==NULL) - break; - // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG) - if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && (spellProto->SpellFamilyFlags==0x00008000LL)) - TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; - break; - } - } - - // .. taken pct: class scripts - AuraList const& mclassScritAuras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(AuraList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i) - { - switch((*i)->GetMiscValue()) - { - case 6427: case 6428: // Dirty Deeds - if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) - { - Aura* eff0 = GetAura((*i)->GetId(),0); - if(!eff0 || (*i)->GetEffIndex()!=1) - { - sLog.outError("Spell structure of DD (%u) changed.",(*i)->GetId()); - continue; - } - - // effect 0 have expected value but in negative state - TakenTotalMod *= (-eff0->GetModifier()->m_amount+100.0f)/100.0f; - } - break; - } - } - - if(attType != RANGED_ATTACK) - { - AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT); - for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i) - TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; - } - else - { - AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT); - for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i) - TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; - } - - float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod; - - // apply spellmod to Done damage - if(spellProto) - { - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage); - } - - tmpDamage = (tmpDamage + TakenFlatBenefit)*TakenTotalMod; - - // bonus result can be negative - *pdamage = tmpDamage > 0 ? uint32(tmpDamage) : 0; -} - -void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply) -{ - if (apply) - { - for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next) - { - next = itr; ++next; - if(itr->type == type) - { - m_spellImmune[op].erase(itr); - next = m_spellImmune[op].begin(); - } - } - SpellImmune Immune; - Immune.spellId = spellId; - Immune.type = type; - m_spellImmune[op].push_back(Immune); - } - else - { - for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr) - { - if(itr->spellId == spellId) - { - m_spellImmune[op].erase(itr); - break; - } - } - } - -} - -void Unit::ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply) -{ - ApplySpellImmune(spellProto->Id,IMMUNITY_DISPEL, type, apply); - - if (apply && spellProto->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY) - RemoveAurasWithDispelType(type); -} - -float Unit::GetWeaponProcChance() const -{ - // normalized proc chance for weapon attack speed - // (odd formulae...) - if(isAttackReady(BASE_ATTACK)) - return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f); - else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) - return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f); - return 0; -} - -float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const -{ - // proc per minute chance calculation - if (PPM <= 0) return 0.0f; - uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) - return result; -} - -void Unit::Mount(uint32 mount) -{ - if(!mount) - return; - - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING); - - SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount); - - SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); - - // unsummon pet - if(GetTypeId() == TYPEID_PLAYER) - { - Pet* pet = GetPet(); - if(pet) - { - if(pet->isControlled()) - { - ((Player*)this)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber()); - ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - } - - ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT); - } - else - ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); - } -} - -void Unit::Unmount() -{ - if(!IsMounted()) - return; - - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED); - - SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); - RemoveFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); - - // only resummon old pet if the player is already added to a map - // this prevents adding a pet to a not created map which would otherwise cause a crash - // (it could probably happen when logging in after a previous crash) - if(GetTypeId() == TYPEID_PLAYER && IsInWorld() && ((Player*)this)->GetTemporaryUnsummonedPetNumber() && isAlive()) - { - Pet* NewPet = new Pet; - if(!NewPet->LoadPetFromDB(this, 0, ((Player*)this)->GetTemporaryUnsummonedPetNumber(), true)) - delete NewPet; - - ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); - } -} - -void Unit::SetInCombatWith(Unit* enemy) -{ - Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf(); - if(eOwner->IsPvP()) - { - SetInCombatState(true); - return; - } - - //check for duel - if(eOwner->GetTypeId() == TYPEID_PLAYER && ((Player*)eOwner)->duel) - { - Unit const* myOwner = GetCharmerOrOwnerOrSelf(); - if(((Player const*)eOwner)->duel->opponent == myOwner) - { - SetInCombatState(true); - return; - } - } - SetInCombatState(false); -} - -void Unit::SetInCombatState(bool PvP) -{ - // only alive units can be in combat - if(!isAlive()) - return; - - if(PvP) - m_CombatTimer = 5000; - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - - if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())) - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); -} - -void Unit::ClearInCombat() -{ - m_CombatTimer = 0; - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - - if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())) - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); - - // Player's state will be cleared in Player::UpdateContestedPvP - if(GetTypeId()!=TYPEID_PLAYER) - clearUnitState(UNIT_STAT_ATTACK_PLAYER); -} - -bool Unit::isTargetableForAttack() const -{ - if (GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster()) - return false; - - if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) - return false; - - return isAlive() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/; -} - -int32 Unit::ModifyHealth(int32 dVal) -{ - int32 gain = 0; - - if(dVal==0) - return 0; - - int32 curHealth = (int32)GetHealth(); - - int32 val = dVal + curHealth; - if(val <= 0) - { - SetHealth(0); - return -curHealth; - } - - int32 maxHealth = (int32)GetMaxHealth(); - - if(val < maxHealth) - { - SetHealth(val); - gain = val - curHealth; - } - else if(curHealth != maxHealth) - { - SetHealth(maxHealth); - gain = maxHealth - curHealth; - } - - return gain; -} - -int32 Unit::ModifyPower(Powers power, int32 dVal) -{ - int32 gain = 0; - - if(dVal==0) - return 0; - - int32 curPower = (int32)GetPower(power); - - int32 val = dVal + curPower; - if(val <= 0) - { - SetPower(power,0); - return -curPower; - } - - int32 maxPower = (int32)GetMaxPower(power); - - if(val < maxPower) - { - SetPower(power,val); - gain = val - curPower; - } - else if(curPower != maxPower) - { - SetPower(power,maxPower); - gain = maxPower - curPower; - } - - return gain; -} - -bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList) const -{ - if(!u) - return false; - - // Always can see self - if (u==this) - return true; - - // player visible for other player if not logout and at same transport - // including case when player is out of world - bool at_same_transport = - GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER && - !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() && - !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() && - ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport(); - - // not in world - if(!at_same_transport && (!IsInWorld() || !u->IsInWorld())) - return false; - - // forbidden to seen (at GM respawn command) - if(m_Visibility==VISIBILITY_RESPAWN) - return false; - - // always seen by owner - if(GetCharmerOrOwnerGUID()==u->GetGUID()) - return true; - - // Grid dead/alive checks - if( u->GetTypeId()==TYPEID_PLAYER) - { - // non visible at grid for any stealth state - if(!IsVisibleInGridForPlayer((Player *)u)) - return false; - - // if player is dead then he can't detect anyone in anycases - if(!u->isAlive()) - detect = false; - } - else - { - // all dead creatures/players not visible for any creatures - if(!u->isAlive() || !isAlive()) - return false; - } - - // different visible distance checks - if(u->isInFlight()) // what see player in flight - { - // use object grey distance for all (only see objects any way) - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) - return false; - } - else if(!isAlive()) // distance for show body - { - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) - return false; - } - else if(GetTypeId()==TYPEID_PLAYER) // distance for show player - { - if(u->GetTypeId()==TYPEID_PLAYER) - { - // Players far than max visible distance for player or not in our map are not visible too - if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) - return false; - } - else - { - // Units far than max visible distance for creature or not in our map are not visible too - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) - return false; - } - } - else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed - { - // Pet/charmed far than max visible distance for player or not in our map are not visible too - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) - return false; - } - else // distance for show creature - { - // Units far than max visible distance for creature or not in our map are not visible too - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) - return false; - } - - // Visible units, always are visible for all units, except for units under invisibility - if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask==0) - return true; - - // GMs see any players, not higher GMs and all units - if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster()) - { - if(GetTypeId() == TYPEID_PLAYER) - return ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity(); - else - return true; - } - - // non faction visibility non-breakable for non-GMs - if (m_Visibility == VISIBILITY_OFF) - return false; - - // raw invisibility - bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask !=0); - - // detectable invisibility case - if( invisible && ( - // Invisible units, always are visible for units under same invisibility type - (m_invisibilityMask & u->m_invisibilityMask)!=0 || - // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect) - u->canDetectInvisibilityOf(this) || - // Units that can detect invisibility always are visible for units that can be detected - canDetectInvisibilityOf(u) )) - { - invisible = false; - } - - // special cases for always overwrite invisibility/stealth - if(invisible || m_Visibility == VISIBILITY_GROUP_STEALTH) - { - // non-hostile case - if (!u->IsHostileTo(this)) - { - // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting) - if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER) - { - if(((Player*)this)->IsGroupVisibleFor(((Player*)u))) - return true; - - // else apply same rules as for hostile case (detecting check for stealth) - } - } - // hostile case - else - { - // Hunter mark functionality - AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); - for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if((*iter)->GetCasterGUID()==u->GetGUID()) - return true; - - // else apply detecting check for stealth - } - - // none other cases for detect invisibility, so invisible - if(invisible) - return false; - - // else apply stealth detecting check - } - - // unit got in stealth in this moment and must ignore old detected state - if (m_Visibility == VISIBILITY_GROUP_NO_DETECT) - return false; - - // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible - if (m_Visibility != VISIBILITY_GROUP_STEALTH) - return true; - - // NOW ONLY STEALTH CASE - - // stealth and detected and visible for some seconds - if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->m_DetectInvTimer > 300 && ((Player*)u)->HaveAtClient(this)) - return true; - - //if in non-detect mode then invisible for unit - if (!detect) - return false; - - // Special cases - - // If is attacked then stealth is lost, some creature can use stealth too - if( !getAttackers().empty() ) - return true; - - // If there is collision rogue is seen regardless of level difference - // TODO: check sizes in DB - float distance = GetDistance(u); - if (distance < 0.24f) - return true; - - //If a mob or player is stunned he will not be able to detect stealth - if (u->hasUnitState(UNIT_STAT_STUNDED) && (u != this)) - return false; - - // Creature can detect target only in aggro radius - if(u->GetTypeId() != TYPEID_PLAYER) - { - //Always invisible from back and out of aggro range - bool isInFront = u->isInFront(this,((Creature const*)u)->GetAttackDistance(this)); - if(!isInFront) - return false; - } - else - { - //Always invisible from back - bool isInFront = u->isInFront(this,(GetTypeId()==TYPEID_PLAYER || GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature()); - if(!isInFront) - return false; - } - - // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los - if(!u->HasAuraType(SPELL_AURA_DETECT_STEALTH)) - { - //Calculation if target is in front - - //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) - float visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/100.0f); - - //Visible distance is modified by - //-Level Diff (every level diff = 1.0f in visible distance) - visibleDistance += int32(u->getLevelForTarget(this)) - int32(this->getLevelForTarget(u)); - - //This allows to check talent tree and will add addition stealth dependent on used points) - int32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL); - if(stealthMod < 0) - stealthMod = 0; - - //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) - //based on wowwiki every 5 mod we have 1 more level diff in calculation - visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT)) - stealthMod)/5.0f; - - if(distance > visibleDistance) - return false; - } - - // Now check is target visible with LoS - float ox,oy,oz; - u->GetPosition(ox,oy,oz); - return IsWithinLOS(ox,oy,oz); -} - -void Unit::SetVisibility(UnitVisibility x) -{ - m_Visibility = x; - - if(IsInWorld()) - { - Map *m = MapManager::Instance().GetMap(GetMapId(), this); - - if(GetTypeId()==TYPEID_PLAYER) - m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); - else - m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); - } -} - -bool Unit::canDetectInvisibilityOf(Unit const* u) const -{ - if(uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask)) - { - for(uint32 i = 0; i < 10; ++i) - { - if(((1 << i) & mask)==0) - continue; - - // find invisibility level - uint32 invLevel = 0; - Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY); - for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr) - if(((*itr)->GetModifier()->m_miscvalue)==i && invLevel < (*itr)->GetModifier()->m_amount) - invLevel = (*itr)->GetModifier()->m_amount; - - // find invisibility detect level - uint32 detectLevel = 0; - Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION); - for(Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr) - if(((*itr)->GetModifier()->m_miscvalue)==i && detectLevel < (*itr)->GetModifier()->m_amount) - detectLevel = (*itr)->GetModifier()->m_amount; - - if(i==6 && GetTypeId()==TYPEID_PLAYER) // special drunk detection case - { - detectLevel = ((Player*)this)->GetDrunkValue(); - } - - if(invLevel <= detectLevel) - return true; - } - } - - return false; -} - -void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) -{ - int32 main_speed_mod = 0; - float stack_bonus = 1.0f; - float non_stack_bonus = 1.0f; - - switch(mtype) - { - case MOVE_WALK: - return; - case MOVE_RUN: - { - if (IsMounted()) // Use on mount auras - { - main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED); - stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS); - non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK))/100.0f; - } - else - { - main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED); - stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS); - non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK))/100.0f; - } - break; - } - case MOVE_WALKBACK: - return; - case MOVE_SWIM: - { - main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED); - break; - } - case MOVE_SWIMBACK: - return; - case MOVE_FLY: - { - if (IsMounted()) // Use on mount auras - main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED); - else // Use not mount (shapeshift for example) auras (should stack) - main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT); - stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS); - non_stack_bonus = (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK))/100.0f; - break; - } - case MOVE_FLYBACK: - return; - default: - sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype); - return; - } - - float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus; - // now we ready for speed calculation - float speed = main_speed_mod ? bonus*(100.0f + main_speed_mod)/100.0f : bonus; - - switch(mtype) - { - case MOVE_RUN: - case MOVE_SWIM: - case MOVE_FLY: - { - // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need - // TODO: possible affect only on MOVE_RUN - if(int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED)) - { - // Use speed from aura - float max_speed = normalization / baseMoveSpeed[mtype]; - if (speed > max_speed) - speed = max_speed; - } - break; - } - default: - break; - } - - // Apply strongest slow aura mod to speed - int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); - if (slow) - speed *=(100.0f + slow)/100.0f; - SetSpeed(mtype, speed, forced); -} - -float Unit::GetSpeed( UnitMoveType mtype ) const -{ - return m_speed_rate[mtype]*baseMoveSpeed[mtype]; -} - -void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) -{ - if (rate < 0) - rate = 0.0f; - - // Update speed only on change - if (m_speed_rate[mtype] == rate) - return; - - m_speed_rate[mtype] = rate; - - propagateSpeedChange(); - - // Send speed change packet only for player - if (GetTypeId()!=TYPEID_PLAYER) - return; - - WorldPacket data; - if(!forced) - { - switch(mtype) - { - case MOVE_WALK: - data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+1+4+4+4+4+4+4+4); - break; - case MOVE_RUN: - data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+1+4+4+4+4+4+4+4); - break; - case MOVE_WALKBACK: - data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); - break; - case MOVE_SWIM: - data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+1+4+4+4+4+4+4+4); - break; - case MOVE_SWIMBACK: - data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); - break; - case MOVE_TURN: - data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+1+4+4+4+4+4+4+4); - break; - case MOVE_FLY: - data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+1+4+4+4+4+4+4+4); - break; - case MOVE_FLYBACK: - data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); - break; - default: - sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype); - return; - } - - data.append(GetPackGUID()); - data << uint32(0); //movement flags - data << uint8(0); //unk - data << uint32(getMSTime()); - data << float(GetPositionX()); - data << float(GetPositionY()); - data << float(GetPositionZ()); - data << float(GetOrientation()); - data << uint32(0); //flag unk - data << float(GetSpeed(mtype)); - SendMessageToSet( &data, true ); - } - else - { - // register forced speed changes for WorldSession::HandleForceSpeedChangeAck - // and do it only for real sent packets and use run for run/mounted as client expected - ++((Player*)this)->m_forced_speed_changes[mtype]; - switch(mtype) - { - case MOVE_WALK: - data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16); - break; - case MOVE_RUN: - data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 17); - break; - case MOVE_WALKBACK: - data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16); - break; - case MOVE_SWIM: - data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16); - break; - case MOVE_SWIMBACK: - data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16); - break; - case MOVE_TURN: - data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16); - break; - case MOVE_FLY: - data.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE, 16); - break; - case MOVE_FLYBACK: - data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16); - break; - default: - sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype); - return; - } - data.append(GetPackGUID()); - data << (uint32)0; - if (mtype == MOVE_RUN) - data << uint8(0); // new 2.1.0 - data << float(GetSpeed(mtype)); - SendMessageToSet( &data, true ); - } - if(Pet* pet = GetPet()) - pet->SetSpeed(MOVE_RUN, m_speed_rate[mtype],forced); -} - -void Unit::SetHover(bool on) -{ - if(on) - CastSpell(this,11010,true); - else - RemoveAurasDueToSpell(11010); -} - -void Unit::setDeathState(DeathState s) -{ - if (s != ALIVE && s!= JUST_ALIVED) - { - CombatStop(); - DeleteThreatList(); - ClearComboPointHolders(); // any combo points pointed to unit lost at it death - - if(IsNonMeleeSpellCasted(false)) - InterruptNonMeleeSpells(false); - } - - if (s == JUST_DIED) - { - RemoveAllAurasOnDeath(); - UnsummonAllTotems(); - - ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); - ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); - // remove aurastates allowing special moves - ClearAllReactives(); - ClearDiminishings(); - } - else if(s == JUST_ALIVED) - { - RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground) - } - - if (m_deathState != ALIVE && s == ALIVE) - { - //_ApplyAllAuraMods(); - } - m_deathState = s; -} - -/*######################################## -######## ######## -######## AGGRO SYSTEM ######## -######## ######## -########################################*/ -bool Unit::CanHaveThreatList() const -{ - // only creatures can have threat list - if( GetTypeId() != TYPEID_UNIT ) - return false; - - // only alive units can have threat list - if( !isAlive() ) - return false; - - // pets and totems can not have threat list - if( ((Creature*)this)->isPet() || ((Creature*)this)->isTotem() ) - return false; - - return true; -} - -//====================================================================== - -float Unit::ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask) -{ - if(!HasAuraType(SPELL_AURA_MOD_THREAT)) - return threat; - - SpellSchools school = GetFirstSchoolInMask(schoolMask); - - return threat * m_threatModifier[school]; -} - -//====================================================================== - -void Unit::AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask, SpellEntry const *threatSpell) -{ - // Only mobs can manage threat lists - if(CanHaveThreatList()) - m_ThreatManager.addThreat(pVictim, threat, schoolMask, threatSpell); -} - -//====================================================================== - -void Unit::DeleteThreatList() -{ - m_ThreatManager.clearReferences(); -} - -//====================================================================== - -void Unit::TauntApply(Unit* taunter) -{ - assert(GetTypeId()== TYPEID_UNIT); - - if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster())) - return; - - if(!CanHaveThreatList()) - return; - - Unit *target = getVictim(); - if(target && target == taunter) - return; - - SetInFront(taunter); - if (((Creature*)this)->AI()) - ((Creature*)this)->AI()->AttackStart(taunter); - - m_ThreatManager.tauntApply(taunter); -} - -//====================================================================== - -void Unit::TauntFadeOut(Unit *taunter) -{ - assert(GetTypeId()== TYPEID_UNIT); - - if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster())) - return; - - if(!CanHaveThreatList()) - return; - - Unit *target = getVictim(); - if(!target || target != taunter) - return; - - if(m_ThreatManager.isThreatListEmpty()) - { - if(((Creature*)this)->AI()) - ((Creature*)this)->AI()->EnterEvadeMode(); - return; - } - - m_ThreatManager.tauntFadeOut(taunter); - target = m_ThreatManager.getHostilTarget(); - - if (target && target != taunter) - { - SetInFront(target); - if (((Creature*)this)->AI()) - ((Creature*)this)->AI()->AttackStart(target); - } -} - -//====================================================================== - -bool Unit::SelectHostilTarget() -{ - //function provides main threat functionality - //next-victim-selection algorithm and evade mode are called - //threat list sorting etc. - - assert(GetTypeId()== TYPEID_UNIT); - Unit* target = NULL; - - //This function only useful once AI has been initilazied - if (!((Creature*)this)->AI()) - return false; - - if(!m_ThreatManager.isThreatListEmpty()) - { - if(!HasAuraType(SPELL_AURA_MOD_TAUNT)) - { - target = m_ThreatManager.getHostilTarget(); - } - } - - if(target) - { - if(!hasUnitState(UNIT_STAT_STUNDED)) - SetInFront(target); - ((Creature*)this)->AI()->AttackStart(target); - return true; - } - - // no target but something prevent go to evade mode - if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT) ) - return false; - - // last case when creature don't must go to evade mode: - // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list - // for example at owner command to pet attack some far away creature - // Note: creature not have targeted movement generator but have attacker in this case - if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE ) - { - for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) - { - if( (*itr)->IsInMap(this) && (*itr)->isTargetableForAttack() && (*itr)->isInAccessablePlaceFor((Creature*)this) ) - return false; - } - } - - // enter in evade mode in other case - ((Creature*)this)->AI()->EnterEvadeMode(); - - return false; -} - -//====================================================================== -//====================================================================== -//====================================================================== - -int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_index, int32 effBasePoints, Unit const* target) -{ - Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL; - - uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0; - - int32 level = int32(getLevel()) - int32(spellProto->spellLevel); - if (level > spellProto->maxLevel && spellProto->maxLevel > 0) - level = spellProto->maxLevel; - - float basePointsPerLevel = spellProto->EffectRealPointsPerLevel[effect_index]; - float randomPointsPerLevel = spellProto->EffectDicePerLevel[effect_index]; - int32 basePoints = int32(effBasePoints + level * basePointsPerLevel); - int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel); - float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index]; - - // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell - int32 randvalue = spellProto->EffectBaseDice[effect_index] >= randomPoints ? spellProto->EffectBaseDice[effect_index]:irand(spellProto->EffectBaseDice[effect_index], randomPoints); - int32 value = basePoints + randvalue; - //random damage - if(comboDamage != 0 && unitPlayer && target && (target->GetGUID() == unitPlayer->GetComboTarget())) - value += (int32)(comboDamage * comboPoints); - - if(Player* modOwner = GetSpellModOwner()) - { - modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_ALL_EFFECTS, value); - switch(effect_index) - { - case 0: - modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT1, value); - break; - case 1: - modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT2, value); - break; - case 2: - modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT3, value); - break; - } - } - - if(spellProto->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION && spellProto->spellLevel && - spellProto->Effect[effect_index] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && - spellProto->Effect[effect_index] != SPELL_EFFECT_KNOCK_BACK) - value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f)); - - return value; -} - -int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_index, Unit const* target) -{ - Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL; - - uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0; - - int32 minduration = GetSpellDuration(spellProto); - int32 maxduration = GetSpellMaxDuration(spellProto); - - int32 duration; - - if( minduration != -1 && minduration != maxduration ) - duration = minduration + int32((maxduration - minduration) * comboPoints / 5); - else - duration = minduration; - - if (duration > 0) - { - int32 mechanic = GetEffectMechanic(spellProto, effect_index); - // Find total mod value (negative bonus) - int32 durationMod_always = target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic); - // Find max mod (negative bonus) - int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic); - - int32 durationMod = 0; - // Select strongest negative mod - if (durationMod_always > durationMod_not_stack) - durationMod = durationMod_not_stack; - else - durationMod = durationMod_always; - - if (durationMod != 0) - duration = int32(int64(duration) * (100+durationMod) /100); - - if (duration < 0) duration = 0; - } - - return duration; -} - -DiminishingLevels Unit::GetDiminishing(DiminishingGroup group) -{ - for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) - { - if(i->DRGroup != group) - continue; - - if(!i->hitCount) - return DIMINISHING_LEVEL_1; - - if(!i->hitTime) - return DIMINISHING_LEVEL_1; - - // If last spell was casted more than 15 seconds ago - reset the count. - if(i->stack==0 && getMSTimeDiff(i->hitTime,getMSTime()) > 15000) - { - i->hitCount = DIMINISHING_LEVEL_1; - return DIMINISHING_LEVEL_1; - } - // or else increase the count. - else - { - return DiminishingLevels(i->hitCount); - } - } - return DIMINISHING_LEVEL_1; -} - -void Unit::IncrDiminishing(DiminishingGroup group) -{ - // Checking for existing in the table - bool IsExist = false; - for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) - { - if(i->DRGroup != group) - continue; - - IsExist = true; - if(i->hitCount < DIMINISHING_LEVEL_IMMUNE) - i->hitCount += 1; - - break; - } - - if(!IsExist) - m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2)); -} - -void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level) -{ - if(duration == -1 || group == DIMINISHING_NONE || caster->IsFriendlyTo(this) ) - return; - - // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0) - if(duration > 10000 && IsDiminishingReturnsGroupDurationLimited(group)) - { - // test pet/charm masters instead pets/charmeds - Unit const* targetOwner = GetCharmerOrOwner(); - Unit const* casterOwner = caster->GetCharmerOrOwner(); - - Unit const* target = targetOwner ? targetOwner : this; - Unit const* source = casterOwner ? casterOwner : caster; - - if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER) - duration = 10000; - } - - float mod = 1.0f; - - // Some diminishings applies to mobs too (for example, Stun) - if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL) - { - DiminishingLevels diminish = Level; - switch(diminish) - { - case DIMINISHING_LEVEL_1: break; - case DIMINISHING_LEVEL_2: mod = 0.5f; break; - case DIMINISHING_LEVEL_3: mod = 0.25f; break; - case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f;break; - default: break; - } - } - - duration = int32(duration * mod); -} - -void Unit::ApplyDiminishingAura( DiminishingGroup group, bool apply ) -{ - // Checking for existing in the table - for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) - { - if(i->DRGroup != group) - continue; - - i->hitTime = getMSTime(); - - if(apply) - i->stack += 1; - else if(i->stack) - i->stack -= 1; - - break; - } -} - -Unit* Unit::GetUnit(WorldObject& object, uint64 guid) -{ - return ObjectAccessor::GetUnit(object,guid); -} - -bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const -{ - return isVisibleForOrDetect(u,false,inVisibleList); -} - -uint32 Unit::GetCreatureType() const -{ - if(GetTypeId() == TYPEID_PLAYER) - { - SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(((Player*)this)->m_form); - if(ssEntry && ssEntry->creatureType > 0) - return ssEntry->creatureType; - else - return CREATURE_TYPE_HUMANOID; - } - else - return ((Creature*)this)->GetCreatureInfo()->type; -} - -/*####################################### -######## ######## -######## STAT SYSTEM ######## -######## ######## -#######################################*/ - -bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply) -{ - if(unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) - { - sLog.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!"); - return false; - } - - float val = 1.0f; - - switch(modifierType) - { - case BASE_VALUE: - case TOTAL_VALUE: - m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; - break; - case BASE_PCT: - case TOTAL_PCT: - if(amount <= -100.0f) //small hack-fix for -100% modifiers - amount = -200.0f; - - val = (100.0f + amount) / 100.0f; - m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f/val); - break; - - default: - break; - } - - if(!CanModifyStats()) - return false; - - switch(unitMod) - { - case UNIT_MOD_STAT_STRENGTH: - case UNIT_MOD_STAT_AGILITY: - case UNIT_MOD_STAT_STAMINA: - case UNIT_MOD_STAT_INTELLECT: - case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break; - - case UNIT_MOD_ARMOR: UpdateArmor(); break; - case UNIT_MOD_HEALTH: UpdateMaxHealth(); break; - - case UNIT_MOD_MANA: - case UNIT_MOD_RAGE: - case UNIT_MOD_FOCUS: - case UNIT_MOD_ENERGY: - case UNIT_MOD_HAPPINESS: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break; - - case UNIT_MOD_RESISTANCE_HOLY: - case UNIT_MOD_RESISTANCE_FIRE: - case UNIT_MOD_RESISTANCE_NATURE: - case UNIT_MOD_RESISTANCE_FROST: - case UNIT_MOD_RESISTANCE_SHADOW: - case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break; - - case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break; - case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break; - - case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break; - case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break; - case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break; - - default: - break; - } - - return true; -} - -float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const -{ - if( unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) - { - sLog.outError("ERROR: trial to access nonexisted modifier value from UnitMods!"); - return 0.0f; - } - - if(modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f) - return 0.0f; - - return m_auraModifiersGroup[unitMod][modifierType]; -} - -float Unit::GetTotalStatValue(Stats stat) const -{ - UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat); - - if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) - return 0.0f; - - // value = ((base_value * base_pct) + total_value) * total_pct - float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat); - value *= m_auraModifiersGroup[unitMod][BASE_PCT]; - value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; - value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; - - return value; -} - -float Unit::GetTotalAuraModValue(UnitMods unitMod) const -{ - if(unitMod >= UNIT_MOD_END) - { - sLog.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!"); - return 0.0f; - } - - if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) - return 0.0f; - - float value = m_auraModifiersGroup[unitMod][BASE_VALUE]; - value *= m_auraModifiersGroup[unitMod][BASE_PCT]; - value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; - value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; - - return value; -} - -SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const -{ - SpellSchools school = SPELL_SCHOOL_NORMAL; - - switch(unitMod) - { - case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break; - case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break; - case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break; - case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break; - case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break; - case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break; - - default: - break; - } - - return school; -} - -Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const -{ - Stats stat = STAT_STRENGTH; - - switch(unitMod) - { - case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break; - case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break; - case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break; - case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break; - case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break; - - default: - break; - } - - return stat; -} - -Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const -{ - Powers power = POWER_MANA; - - switch(unitMod) - { - case UNIT_MOD_MANA: power = POWER_MANA; break; - case UNIT_MOD_RAGE: power = POWER_RAGE; break; - case UNIT_MOD_FOCUS: power = POWER_FOCUS; break; - case UNIT_MOD_ENERGY: power = POWER_ENERGY; break; - case UNIT_MOD_HAPPINESS: power = POWER_HAPPINESS; break; - - default: - break; - } - - return power; -} - -float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const -{ - UnitMods unitMod = (attType == RANGED_ATTACK) ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; - - float val = GetTotalAuraModValue(unitMod); - if(val < 0.0f) - val = 0.0f; - - return val; -} - -float Unit::GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const -{ - if (attType == OFF_ATTACK && !haveOffhandWeapon()) - return 0.0f; - - return m_weaponDamage[attType][type]; -} - -void Unit::SetLevel(uint32 lvl) -{ - SetUInt32Value(UNIT_FIELD_LEVEL, lvl); - - // group update - if ((GetTypeId() == TYPEID_PLAYER) && ((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL); -} - -void Unit::SetHealth(uint32 val) -{ - uint32 maxHealth = GetMaxHealth(); - if(maxHealth < val) - val = maxHealth; - - SetUInt32Value(UNIT_FIELD_HEALTH, val); - - // group update - if(GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP); - } - else if(((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(pet->isControlled()) - { - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP); - } - } -} - -void Unit::SetMaxHealth(uint32 val) -{ - uint32 health = GetHealth(); - SetUInt32Value(UNIT_FIELD_MAXHEALTH, val); - - // group update - if(GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP); - } - else if(((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(pet->isControlled()) - { - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP); - } - } - - if(val < health) - SetHealth(val); -} - -void Unit::SetPower(Powers power, uint32 val) -{ - uint32 maxPower = GetMaxPower(power); - if(maxPower < val) - val = maxPower; - - SetStatInt32Value(UNIT_FIELD_POWER1 + power, val); - - // group update - if(GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); - } - else if(((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(pet->isControlled()) - { - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); - } - - // Update the pet's character sheet with happiness damage bonus - if(pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS) - { - pet->UpdateDamagePhysical(BASE_ATTACK); - } - } -} - -void Unit::SetMaxPower(Powers power, uint32 val) -{ - uint32 cur_power = GetPower(power); - SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + power, val); - - // group update - if(GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); - } - else if(((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(pet->isControlled()) - { - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); - } - } - - if(val < cur_power) - SetPower(power, val); -} - -void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply) -{ - ApplyModUInt32Value(UNIT_FIELD_POWER1+power, val, apply); - - // group update - if(GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); - } - else if(((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(pet->isControlled()) - { - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); - } - } -} - -void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply) -{ - ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1+power, val, apply); - - // group update - if(GetTypeId() == TYPEID_PLAYER) - { - if(((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); - } - else if(((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(pet->isControlled()) - { - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); - } - } -} - -void Unit::ApplyAuraProcTriggerDamage( Aura* aura, bool apply ) -{ - AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE]; - if(apply) - tAuraProcTriggerDamage.push_back(aura); - else - tAuraProcTriggerDamage.remove(aura); -} - -uint32 Unit::GetCreatePowers( Powers power ) const -{ - // POWER_FOCUS and POWER_HAPPINESS only have hunter pet - switch(power) - { - case POWER_MANA: return GetCreateMana(); - case POWER_RAGE: return 1000; - case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100); - case POWER_ENERGY: return 100; - case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000); - } - - return 0; -} - -void Unit::AddToWorld() -{ - Object::AddToWorld(); -} - -void Unit::RemoveFromWorld() -{ - // cleanup - if(IsInWorld()) - { - RemoveNotOwnSingleTargetAuras(); - } - - Object::RemoveFromWorld(); -} - -void Unit::CleanupsBeforeDelete() -{ - if(m_uint32Values) // only for fully created object - { - InterruptNonMeleeSpells(true); - m_Events.KillAllEvents(); - CombatStop(); - ClearComboPointHolders(); - DeleteThreatList(); - getHostilRefManager().setOnlineOfflineState(false); - RemoveAllAuras(); - RemoveAllGameObjects(); - RemoveAllDynObjects(); - GetMotionMaster()->Clear(false); // remove different non-standard movement generators. - } - RemoveFromWorld(); -} - -CharmInfo* Unit::InitCharmInfo(Unit *charm) -{ - if(!m_charmInfo) - m_charmInfo = new CharmInfo(charm); - return m_charmInfo; -} - -CharmInfo::CharmInfo(Unit* unit) -: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_ReactSate(REACT_PASSIVE), m_petnumber(0) -{ - for(int i =0; i<4; ++i) - { - m_charmspells[i].spellId = 0; - m_charmspells[i].active = ACT_DISABLED; - } -} - -void CharmInfo::InitPetActionBar() -{ - // the first 3 SpellOrActions are attack, follow and stay - for(uint32 i = 0; i < 3; i++) - { - PetActionBar[i].Type = ACT_COMMAND; - PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i; - - PetActionBar[i + 7].Type = ACT_REACTION; - PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i; - } - for(uint32 i=0; i < 4; i++) - { - PetActionBar[i + 3].Type = ACT_DISABLED; - PetActionBar[i + 3].SpellOrAction = 0; - } -} - -void CharmInfo::InitEmptyActionBar() -{ - for(uint32 x = 1; x < 10; ++x) - { - PetActionBar[x].Type = ACT_CAST; - PetActionBar[x].SpellOrAction = 0; - } - PetActionBar[0].Type = ACT_COMMAND; - PetActionBar[0].SpellOrAction = COMMAND_ATTACK; -} - -void CharmInfo::InitPossessCreateSpells() -{ - if(m_unit->GetTypeId() == TYPEID_PLAYER) - return; - - InitEmptyActionBar(); //charm action bar - - for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) - { - if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) - m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); - else - AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_CAST); - } -} - -void CharmInfo::InitCharmCreateSpells() -{ - if(m_unit->GetTypeId() == TYPEID_PLAYER) //charmed players don't have spells - { - InitEmptyActionBar(); - return; - } - - InitPetActionBar(); - - for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) - { - uint32 spellId = ((Creature*)m_unit)->m_spells[x]; - m_charmspells[x].spellId = spellId; - - if(!spellId) - continue; - - if (IsPassiveSpell(spellId)) - { - m_unit->CastSpell(m_unit, spellId, true); - m_charmspells[x].active = ACT_PASSIVE; - } - else - { - ActiveStates newstate; - bool onlyselfcast = true; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - - if(!spellInfo) onlyselfcast = false; - for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away - { - if(spellInfo->EffectImplicitTargetA[i] != TARGET_SELF && spellInfo->EffectImplicitTargetA[i] != 0) - onlyselfcast = false; - } - - if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable - newstate = ACT_DISABLED; - else - newstate = ACT_CAST; - - AddSpellToAB(0, spellId, newstate); - } - } -} - -bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate) -{ - for(uint8 i = 0; i < 10; i++) - { - if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_CAST) && PetActionBar[i].SpellOrAction == oldid) - { - PetActionBar[i].SpellOrAction = newid; - if(!oldid) - { - if(newstate == ACT_DECIDE) - PetActionBar[i].Type = ACT_DISABLED; - else - PetActionBar[i].Type = newstate; - } - - return true; - } - } - return false; -} - -void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply) -{ - if(IsPassiveSpell(spellid)) - return; - - for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) - { - if(spellid == m_charmspells[x].spellId) - { - m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED; - } - } -} - -void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow) -{ - m_petnumber = petnumber; - if(statwindow) - m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber); - else - m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0); -} - -bool Unit::isFrozen() const -{ - AuraList const& mRoot = GetAurasByType(SPELL_AURA_MOD_ROOT); - for(AuraList::const_iterator i = mRoot.begin(); i != mRoot.end(); ++i) - if( GetSpellSchoolMask((*i)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST) - return true; - return false; -} - -struct ProcTriggeredData -{ - ProcTriggeredData(SpellEntry const * _spellInfo, uint32 _spellParam, Aura* _triggeredByAura, uint32 _cooldown) - : spellInfo(_spellInfo), spellParam(_spellParam), triggeredByAura(_triggeredByAura), - triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex())), - cooldown(_cooldown) - {} - - SpellEntry const * spellInfo; - uint32 spellParam; - Aura* triggeredByAura; - Unit::spellEffectPair triggeredByAura_SpellPair; - uint32 cooldown; -}; - -typedef std::list< ProcTriggeredData > ProcTriggeredList; - -void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask ) -{ - for(AuraTypeSet::const_iterator aur = procAuraTypes.begin(); aur != procAuraTypes.end(); ++aur) - { - // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE) - ProcTriggeredList procTriggered; - - AuraList const& auras = GetAurasByType(*aur); - for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) - { - next = i; ++next; - - SpellEntry const *spellProto = (*i)->GetSpellProto(); - if(!spellProto) - continue; - - SpellProcEventEntry const *spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id); - if(!spellProcEvent) - { - // used to prevent spam in log about same non-handled spells - static std::set nonHandledSpellProcSet; - - if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end()) - { - sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's")); - nonHandledSpellProcSet.insert(spellProto->Id); - } - - // spell.dbc use totally different flags, that only can create problems if used. - continue; - } - - // Check spellProcEvent data requirements - if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag)) - continue; - - // Check if current equipment allows aura to proc - if(!isVictim && GetTypeId() == TYPEID_PLAYER ) - { - if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON) - { - Item *item = ((Player*)this)->GetWeaponForAttack(attType,true); - - if(!item || !((1<GetProto()->SubClass) & spellProto->EquippedItemSubClassMask)) - continue; - } - else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR) - { - // Check if player is wearing shield - Item *item = ((Player*)this)->GetShield(true); - if(!item || !((1<GetProto()->SubClass) & spellProto->EquippedItemSubClassMask)) - continue; - } - } - - float chance = (float)spellProto->procChance; - - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance); - - if(!isVictim && spellProcEvent->ppmRate != 0) - { - uint32 WeaponSpeed = GetAttackTime(attType); - chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate); - } - - if(roll_chance_f(chance)) - { - uint32 cooldown = spellProcEvent->cooldown; - - uint32 i_spell_eff = (*i)->GetEffIndex(); - - int32 i_spell_param; - switch(*aur) - { - case SPELL_AURA_PROC_TRIGGER_SPELL: - i_spell_param = procFlag; - break; - case SPELL_AURA_DUMMY: - case SPELL_AURA_PRAYER_OF_MENDING: - case SPELL_AURA_MOD_HASTE: - i_spell_param = i_spell_eff; - break; - case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: - i_spell_param = (*i)->GetModifier()->m_miscvalue; - break; - default: - i_spell_param = (*i)->GetModifier()->m_amount; - break; - } - - procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i, cooldown) ); - } - } - - // Handle effects proceed this time - for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i) - { - // Some auras can be deleted in function called in this loop (except first, ofc) - // Until storing auras in std::multimap to hard check deleting by another way - if(i != procTriggered.begin()) - { - bool found = false; - AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); - AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); - for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) - { - if(itr->second==i->triggeredByAura) - { - found = true; - break; - } - } - - if(!found) - { - sLog.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur,i->triggeredByAura_SpellPair.first,i->triggeredByAura_SpellPair.second); - sLog.outError("It can be deleted one from early proccesed auras:"); - for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2) - sLog.outError(" Spell aura %u (id:%u effect:%u)",*aur,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second); - sLog.outError(" "); - continue; - } - } - - // save charges existence before processing to prevent crash at access to deleted triggered aura after - bool triggeredByAuraWithCharges = i->triggeredByAura->m_procCharges > 0; - - bool casted = false; - switch(*aur) - { - case SPELL_AURA_PROC_TRIGGER_SPELL: - { - sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - casted = HandleProcTriggerSpell(pTarget, damage, i->triggeredByAura, procSpell,i->spellParam,attType,i->cooldown); - break; - } - case SPELL_AURA_PROC_TRIGGER_DAMAGE: - { - sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i->spellParam, i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - uint32 damage = i->spellParam; - SpellNonMeleeDamageLog(pTarget, i->spellInfo->Id, damage, true, true); - casted = true; - break; - } - case SPELL_AURA_DUMMY: - { - sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - casted = HandleDummyAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown); - break; - } - case SPELL_AURA_PRAYER_OF_MENDING: - { - sLog.outDebug("ProcDamageAndSpell(mending): casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - - // aura can be deleted at casts - int32 heal = i->triggeredByAura->GetModifier()->m_amount; - uint64 caster_guid = i->triggeredByAura->GetCasterGUID(); - - // jumps - int32 jumps = i->triggeredByAura->m_procCharges-1; - - // current aura expire - i->triggeredByAura->m_procCharges = 1; // will removed at next charges decrease - - // next target selection - if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid)) - { - Aura* aura = i->triggeredByAura; - - SpellEntry const* spellProto = aura->GetSpellProto(); - uint32 effIdx = aura->GetEffIndex(); - - float radius; - if (spellProto->EffectRadiusIndex[effIdx]) - radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx])); - else - radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex)); - - if(Player* caster = ((Player*)aura->GetCaster())) - { - caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL); - - if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius)) - { - // aura will applied from caster, but spell casted from current aura holder - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_CHARGES; - mod->value = jumps-5; // negative - mod->type = SPELLMOD_FLAT; - mod->spellId = spellProto->Id; - mod->effectId = effIdx; - mod->lastAffected = NULL; - mod->mask = spellProto->SpellFamilyFlags; - mod->charges = 0; - - caster->AddSpellMod(mod, true); - CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,aura,caster->GetGUID()); - caster->AddSpellMod(mod, false); - } - } - } - - // heal - CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid); - casted = true; - break; - } - case SPELL_AURA_MOD_HASTE: - { - sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - casted = HandleHasteAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown); - break; - } - case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: - { - // nothing do, just charges counter - // but count only in case appropriate school damage - casted = i->triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask; - break; - } - case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: - { - sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - casted = HandleOverrideClassScriptAuraProc(pTarget, i->spellParam, damage, i->triggeredByAura, procSpell,i->cooldown); - break; - } - default: - { - // nothing do, just charges counter - casted = true; - break; - } - } - - // Update charge (aura can be removed by triggers) - if(casted && triggeredByAuraWithCharges) - { - // need found aura (can be dropped by triggers) - AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); - AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); - for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) - { - if(itr->second == i->triggeredByAura) - { - if(i->triggeredByAura->m_procCharges > 0) - i->triggeredByAura->m_procCharges -= 1; - - i->triggeredByAura->UpdateAuraCharges(); - break; - } - } - } - } - - // Safely remove auras with zero charges - for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) - { - next = i; ++next; - if((*i)->m_procCharges == 0) - { - RemoveAurasDueToSpell((*i)->GetId()); - next = auras.begin(); - } - } - } -} - -SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const -{ - return SPELL_SCHOOL_MASK_NORMAL; -} - -Player* Unit::GetSpellModOwner() -{ - if(GetTypeId()==TYPEID_PLAYER) - return (Player*)this; - if(((Creature*)this)->isPet() || ((Creature*)this)->isTotem()) - { - Unit* owner = GetOwner(); - if(owner && owner->GetTypeId()==TYPEID_PLAYER) - return (Player*)owner; - } - return NULL; -} - -///----------Pet responses methods----------------- -void Unit::SendPetCastFail(uint32 spellid, uint8 msg) -{ - Unit *owner = GetCharmerOrOwner(); - if(!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_PET_CAST_FAILED, (4+1)); - data << uint32(spellid); - data << uint8(msg); - ((Player*)owner)->GetSession()->SendPacket(&data); -} - -void Unit::SendPetActionFeedback (uint8 msg) -{ - Unit* owner = GetOwner(); - if(!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_PET_ACTION_FEEDBACK, 1); - data << uint8(msg); - ((Player*)owner)->GetSession()->SendPacket(&data); -} - -void Unit::SendPetTalk (uint32 pettalk) -{ - Unit* owner = GetOwner(); - if(!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_PET_ACTION_SOUND, 8+4); - data << uint64(GetGUID()); - data << uint32(pettalk); - ((Player*)owner)->GetSession()->SendPacket(&data); -} - -void Unit::SendPetSpellCooldown (uint32 spellid, time_t cooltime) -{ - Unit* owner = GetOwner(); - if(!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4); - data << uint64(GetGUID()); - data << uint8(0x0); - data << uint32(spellid); - data << uint32(cooltime); - - ((Player*)owner)->GetSession()->SendPacket(&data); -} - -void Unit::SendPetClearCooldown (uint32 spellid) -{ - Unit* owner = GetOwner(); - if(!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(spellid); - data << uint64(GetGUID()); - ((Player*)owner)->GetSession()->SendPacket(&data); -} - -void Unit::SendPetAIReaction(uint64 guid) -{ - Unit* owner = GetOwner(); - if(!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_AI_REACTION, 12); - data << uint64(guid) << uint32(00000002); - ((Player*)owner)->GetSession()->SendPacket(&data); -} - -///----------End of Pet responses methods---------- - -void Unit::StopMoving() -{ - clearUnitState(UNIT_STAT_MOVING); - - // send explicit stop packet - // rely on vmaps here because for exemple stormwind is in air - float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true); - //if (fabs(GetPositionZ() - z) < 2.0f) - // Relocate(GetPositionX(), GetPositionY(), z); - Relocate(GetPositionX(), GetPositionY(),GetPositionZ()); - - SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0); - - // update position and orientation; - WorldPacket data; - BuildHeartBeatMsg(&data); - SendMessageToSet(&data,false); -} - -void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID) -{ - if( apply ) - { - if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING)) - return; - - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - - GetMotionMaster()->MovementExpired(false); - CastStop(GetGUID()==casterGUID ? spellID : 0); - - Unit* caster = ObjectAccessor::GetUnit(*this,casterGUID); - - GetMotionMaster()->MoveFleeing(caster); // caster==NULL processed in MoveFleeing - } - else - { - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - - GetMotionMaster()->MovementExpired(false); - - if( GetTypeId() != TYPEID_PLAYER && isAlive() ) - { - // restore appropriate movement generator - if(getVictim()) - GetMotionMaster()->MoveChase(getVictim()); - else - GetMotionMaster()->Initialize(); - - // attack caster if can - Unit* caster = ObjectAccessor::GetObjectInWorld(casterGUID, (Unit*)NULL); - if(caster && caster != getVictim() && ((Creature*)this)->AI()) - ((Creature*)this)->AI()->AttackStart(caster); - } - } - - if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SetClientControl(this, !apply); -} - -void Unit::SetConfused(bool apply, uint64 casterGUID, uint32 spellID) -{ - if( apply ) - { - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - - CastStop(GetGUID()==casterGUID ? spellID : 0); - - GetMotionMaster()->MoveConfused(); - } - else - { - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - - GetMotionMaster()->MovementExpired(false); - - if (GetTypeId() == TYPEID_UNIT) - { - // if in combat restore movement generator - if(getVictim()) - GetMotionMaster()->MoveChase(getVictim()); - } - } - - if(GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SetClientControl(this, !apply); -} - -bool Unit::IsSitState() const -{ - uint8 s = getStandState(); - return s == PLAYER_STATE_SIT_CHAIR || s == PLAYER_STATE_SIT_LOW_CHAIR || - s == PLAYER_STATE_SIT_MEDIUM_CHAIR || s == PLAYER_STATE_SIT_HIGH_CHAIR || - s == PLAYER_STATE_SIT; -} - -bool Unit::IsStandState() const -{ - uint8 s = getStandState(); - return !IsSitState() && s != PLAYER_STATE_SLEEP && s != PLAYER_STATE_KNEEL; -} - -void Unit::SetStandState(uint8 state) -{ - SetByteValue(UNIT_FIELD_BYTES_1, 0, state); - - if (IsStandState()) - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED); - - if(GetTypeId()==TYPEID_PLAYER) - { - WorldPacket data(SMSG_STANDSTATE_UPDATE, 1); - data << (uint8)state; - ((Player*)this)->GetSession()->SendPacket(&data); - } -} - -bool Unit::IsPolymorphed() const -{ - return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH; -} - -void Unit::SetDisplayId(uint32 modelId) -{ - SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId); - - if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(!pet->isControlled()) - return; - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); - } -} - -void Unit::ClearComboPointHolders() -{ - while(!m_ComboPointHolders.empty()) - { - uint32 lowguid = *m_ComboPointHolders.begin(); - - Player* plr = objmgr.GetPlayer(MAKE_NEW_GUID(lowguid, 0, HIGHGUID_PLAYER)); - if(plr && plr->GetComboTarget()==GetGUID()) // recheck for safe - plr->ClearComboPoints(); // remove also guid from m_ComboPointHolders; - else - m_ComboPointHolders.erase(lowguid); // or remove manually - } -} - -void Unit::ClearAllReactives() -{ - - for(int i=0; i < MAX_REACTIVE; ++i) - m_reactiveTimer[i] = 0; - - if (HasAuraState( AURA_STATE_DEFENSE)) - ModifyAuraState(AURA_STATE_DEFENSE, false); - if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_PARRY)) - ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); - if (HasAuraState( AURA_STATE_CRIT)) - ModifyAuraState(AURA_STATE_CRIT, false); - if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE) ) - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false); - - if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->ClearComboPoints(); -} - -void Unit::UpdateReactives( uint32 p_time ) -{ - for(int i = 0; i < MAX_REACTIVE; ++i) - { - ReactiveType reactive = ReactiveType(i); - - if(!m_reactiveTimer[reactive]) - continue; - - if ( m_reactiveTimer[reactive] <= p_time) - { - m_reactiveTimer[reactive] = 0; - - switch ( reactive ) - { - case REACTIVE_DEFENSE: - if (HasAuraState(AURA_STATE_DEFENSE)) - ModifyAuraState(AURA_STATE_DEFENSE, false); - break; - case REACTIVE_HUNTER_PARRY: - if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) - ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); - break; - case REACTIVE_CRIT: - if (HasAuraState(AURA_STATE_CRIT)) - ModifyAuraState(AURA_STATE_CRIT, false); - break; - case REACTIVE_HUNTER_CRIT: - if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE) ) - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false); - break; - case REACTIVE_OVERPOWER: - if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->ClearComboPoints(); - break; - default: - break; - } - } - else - { - m_reactiveTimer[reactive] -= p_time; - } - } -} - -Unit* Unit::SelectNearbyTarget() const -{ - CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list targets; - - { - MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, ATTACK_DISTANCE); - MaNGOS::UnitListSearcher searcher(targets, u_check); - - TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); - TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); - cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); - } - - // remove current target - if(getVictim()) - targets.remove(getVictim()); - - // remove not LoS targets - for(std::list::iterator tIter = targets.begin(); tIter != targets.end();) - { - if(!IsWithinLOSInMap(*tIter)) - { - std::list::iterator tIter2 = tIter; - ++tIter; - targets.erase(tIter2); - } - else - ++tIter; - } - - // no appropriate targets - if(targets.empty()) - return NULL; - - // select random - uint32 rIdx = urand(0,targets.size()-1); - std::list::const_iterator tcIter = targets.begin(); - for(uint32 i = 0; i < rIdx; ++i) - ++tcIter; - - return *tcIter; -} - -void Unit::ApplyAttackTimePercentMod( WeaponAttackType att,float val, bool apply ) -{ - if(val > 0) - { - ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply); - ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att,val,!apply); - } - else - { - ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply); - ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att,-val,apply); - } -} - -void Unit::ApplyCastTimePercentMod(float val, bool apply ) -{ - if(val > 0) - ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,val,!apply); - else - ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,-val,apply); -} - -uint32 Unit::GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ) -{ - if (CastingTime > 7000) CastingTime = 7000; - if (CastingTime < 1500) CastingTime = 1500; - - if(damagetype == DOT && !IsChanneledSpell(spellProto)) - CastingTime = 3500; - - int32 overTime = 0; - uint8 effects = 0; - bool DirectDamage = false; - bool AreaEffect = false; - - for ( uint32 i=0; i<3;i++) - { - switch ( spellProto->Effect[i] ) - { - case SPELL_EFFECT_SCHOOL_DAMAGE: - case SPELL_EFFECT_POWER_DRAIN: - case SPELL_EFFECT_HEALTH_LEECH: - case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: - case SPELL_EFFECT_POWER_BURN: - case SPELL_EFFECT_HEAL: - DirectDamage = true; - break; - case SPELL_EFFECT_APPLY_AURA: - switch ( spellProto->EffectApplyAuraName[i] ) - { - case SPELL_AURA_PERIODIC_DAMAGE: - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_PERIODIC_LEECH: - if ( GetSpellDuration(spellProto) ) - overTime = GetSpellDuration(spellProto); - break; - default: - // -5% per additional effect - ++effects; - break; - } - default: - break; - } - - if(IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetA[i])) || IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetB[i]))) - AreaEffect = true; - } - - // Combined Spells with Both Over Time and Direct Damage - if ( overTime > 0 && CastingTime > 0 && DirectDamage ) - { - // mainly for DoTs which are 3500 here otherwise - uint32 OriginalCastTime = GetSpellCastTime(spellProto); - if (OriginalCastTime > 7000) OriginalCastTime = 7000; - if (OriginalCastTime < 1500) OriginalCastTime = 1500; - // Portion to Over Time - float PtOT = (overTime / 15000.f) / ((overTime / 15000.f) + (OriginalCastTime / 3500.f)); - - if ( damagetype == DOT ) - CastingTime = uint32(CastingTime * PtOT); - else if ( PtOT < 1.0f ) - CastingTime = uint32(CastingTime * (1 - PtOT)); - else - CastingTime = 0; - } - - // Area Effect Spells receive only half of bonus - if ( AreaEffect ) - CastingTime /= 2; - - // -5% of total per any additional effect - for ( uint8 i=0; i 175 ) - { - CastingTime -= 175; - } - else - { - CastingTime = 0; - break; - } - } - - return CastingTime; -} - -void Unit::UpdateAuraForGroup(uint8 slot) -{ - if(GetTypeId() == TYPEID_PLAYER) - { - Player* player = (Player*)this; - if(player->GetGroup()) - { - player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS); - player->SetAuraUpdateMask(slot); - } - } - else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) - { - Pet *pet = ((Pet*)this); - if(pet->isControlled()) - { - Unit *owner = GetOwner(); - if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - { - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS); - pet->SetAuraUpdateMask(slot); - } - } - } -} - -float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) -{ - if (!normalized || GetTypeId() != TYPEID_PLAYER) - return float(GetAttackTime(attType))/1000.0f; - - Item *Weapon = ((Player*)this)->GetWeaponForAttack(attType); - if (!Weapon) - return 2.4; // fist attack - - switch (Weapon->GetProto()->InventoryType) - { - case INVTYPE_2HWEAPON: - return 3.3; - case INVTYPE_RANGED: - case INVTYPE_RANGEDRIGHT: - case INVTYPE_THROWN: - return 2.8; - case INVTYPE_WEAPON: - case INVTYPE_WEAPONMAINHAND: - case INVTYPE_WEAPONOFFHAND: - default: - return Weapon->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_DAGGER ? 1.7 : 2.4; - } -} - -Aura* Unit::GetDummyAura( uint32 spell_id ) const -{ - Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) - if ((*itr)->GetId() == spell_id) - return *itr; - - return NULL; -} - -bool Unit::IsUnderLastManaUseEffect() const -{ - return getMSTimeDiff(m_lastManaUse,getMSTime()) < 5000; -} - -void Unit::SetContestedPvP(Player *attackedPlayer) -{ - Player* player = GetCharmerOrOwnerPlayerOrPlayerItself(); - - if(!player || attackedPlayer && (attackedPlayer == player || player->duel && player->duel->opponent == attackedPlayer)) - return; - - player->SetContestedPvPTimer(30000); - if(!player->hasUnitState(UNIT_STAT_ATTACK_PLAYER)) - { - player->addUnitState(UNIT_STAT_ATTACK_PLAYER); - player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP); - // call MoveInLineOfSight for nearby contested guards - SetVisibility(GetVisibility()); - } - if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER)) - { - addUnitState(UNIT_STAT_ATTACK_PLAYER); - // call MoveInLineOfSight for nearby contested guards - SetVisibility(GetVisibility()); - } -} - -void Unit::AddPetAura(PetAura const* petSpell) -{ - m_petAuras.insert(petSpell); - if(Pet* pet = GetPet()) - pet->CastPetAura(petSpell); -} - -void Unit::RemovePetAura(PetAura const* petSpell) -{ - m_petAuras.erase(petSpell); - if(Pet* pet = GetPet()) - pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry())); -} +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Log.h" +#include "Opcodes.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Unit.h" +#include "QuestDef.h" +#include "Player.h" +#include "Creature.h" +#include "Spell.h" +#include "Group.h" +#include "SpellAuras.h" +#include "MapManager.h" +#include "ObjectAccessor.h" +#include "CreatureAI.h" +#include "Formulas.h" +#include "Pet.h" +#include "Util.h" +#include "Totem.h" +#include "BattleGround.h" +#include "InstanceSaveMgr.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "Path.h" + +#include + +float baseMoveSpeed[MAX_MOVE_TYPE] = +{ + 2.5f, // MOVE_WALK + 7.0f, // MOVE_RUN + 1.25f, // MOVE_WALKBACK + 4.722222f, // MOVE_SWIM + 4.5f, // MOVE_SWIMBACK + 3.141594f, // MOVE_TURN + 7.0f, // MOVE_FLY + 4.5f, // MOVE_FLYBACK +}; + +// auraTypes contains attacker auras capable of proc'ing cast auras +static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes() +{ + static Unit::AuraTypeSet auraTypes; + auraTypes.insert(SPELL_AURA_DUMMY); + auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL); + auraTypes.insert(SPELL_AURA_MOD_HASTE); + auraTypes.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + return auraTypes; +} + +// auraTypes contains victim auras capable of proc'ing cast auras +static Unit::AuraTypeSet GenerateVictimProcCastAuraTypes() +{ + static Unit::AuraTypeSet auraTypes; + auraTypes.insert(SPELL_AURA_DUMMY); + auraTypes.insert(SPELL_AURA_PRAYER_OF_MENDING); + auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL); + return auraTypes; +} + +// auraTypes contains auras capable of proc effect/damage (but not cast) for attacker +static Unit::AuraTypeSet GenerateAttakerProcEffectAuraTypes() +{ + static Unit::AuraTypeSet auraTypes; + auraTypes.insert(SPELL_AURA_MOD_DAMAGE_DONE); + auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE); + auraTypes.insert(SPELL_AURA_MOD_CASTING_SPEED); + auraTypes.insert(SPELL_AURA_MOD_RATING); + return auraTypes; +} + +// auraTypes contains auras capable of proc effect/damage (but not cast) for victim +static Unit::AuraTypeSet GenerateVictimProcEffectAuraTypes() +{ + static Unit::AuraTypeSet auraTypes; + auraTypes.insert(SPELL_AURA_MOD_RESISTANCE); + auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE); + auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT); + auraTypes.insert(SPELL_AURA_MOD_BLOCK_PERCENT); + auraTypes.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); + return auraTypes; +} + +static Unit::AuraTypeSet attackerProcCastAuraTypes = GenerateAttakerProcCastAuraTypes(); +static Unit::AuraTypeSet attackerProcEffectAuraTypes = GenerateAttakerProcEffectAuraTypes(); + +static Unit::AuraTypeSet victimProcCastAuraTypes = GenerateVictimProcCastAuraTypes(); +static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectAuraTypes(); + +// auraTypes contains auras capable of proc'ing for attacker and victim +static Unit::AuraTypeSet GenerateProcAuraTypes() +{ + Unit::AuraTypeSet auraTypes; + auraTypes.insert(attackerProcCastAuraTypes.begin(),attackerProcCastAuraTypes.end()); + auraTypes.insert(attackerProcEffectAuraTypes.begin(),attackerProcEffectAuraTypes.end()); + auraTypes.insert(victimProcCastAuraTypes.begin(),victimProcCastAuraTypes.end()); + auraTypes.insert(victimProcEffectAuraTypes.begin(),victimProcEffectAuraTypes.end()); + return auraTypes; +} + +static Unit::AuraTypeSet procAuraTypes = GenerateProcAuraTypes(); + +bool IsPassiveStackableSpell( uint32 spellId ) +{ + if(!IsPassiveSpell(spellId)) + return false; + + SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId); + if(!spellProto) + return false; + + for(int j = 0; j < 3; ++j) + { + if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end()) + return false; + } + + return true; +} + +Unit::Unit() +: WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this) +{ + m_objectType |= TYPEMASK_UNIT; + m_objectTypeId = TYPEID_UNIT; + // 2.3.2 - 0x70 + m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HASPOSITION); + + m_attackTimer[BASE_ATTACK] = 0; + m_attackTimer[OFF_ATTACK] = 0; + m_attackTimer[RANGED_ATTACK] = 0; + m_modAttackSpeedPct[BASE_ATTACK] = 1.0f; + m_modAttackSpeedPct[OFF_ATTACK] = 1.0f; + m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f; + + m_extraAttacks = 0; + + m_state = 0; + m_form = FORM_NONE; + m_deathState = ALIVE; + + for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) + m_currentSpells[i] = NULL; + + m_addDmgOnce = 0; + + for(int i = 0; i < MAX_TOTEM; ++i) + m_TotemSlot[i] = 0; + + m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0; + //m_Aura = NULL; + //m_AurasCheck = 2000; + //m_removeAuraTimer = 4; + //tmpAura = NULL; + waterbreath = false; + + m_Visibility = VISIBILITY_ON; + + m_detectInvisibilityMask = 0; + m_invisibilityMask = 0; + m_transform = 0; + m_ShapeShiftFormSpellId = 0; + m_canModifyStats = false; + + for (int i = 0; i < MAX_SPELL_IMMUNITY; i++) + m_spellImmune[i].clear(); + for (int i = 0; i < UNIT_MOD_END; i++) + { + m_auraModifiersGroup[i][BASE_VALUE] = 0.0f; + m_auraModifiersGroup[i][BASE_PCT] = 1.0f; + m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; + m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; + } + // implement 50% base damage from offhand + m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; + + for (int i = 0; i < 3; i++) + { + m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE; + m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE; + } + for (int i = 0; i < MAX_STATS; i++) + m_createStats[i] = 0.0f; + + m_attacking = NULL; + m_modMeleeHitChance = 0.0f; + m_modRangedHitChance = 0.0f; + m_modSpellHitChance = 0.0f; + m_baseSpellCritChance = 5; + + m_CombatTimer = 0; + m_lastManaUse = 0; + + //m_victimThreat = 0.0f; + for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) + m_threatModifier[i] = 1.0f; + m_isSorted = true; + for (int i = 0; i < MAX_MOVE_TYPE; ++i) + m_speed_rate[i] = 1.0f; + + m_removedAuras = 0; + m_charmInfo = NULL; + m_unit_movement_flags = 0; + + // remove aurastates allowing special moves + for(int i=0; i < MAX_REACTIVE; ++i) + m_reactiveTimer[i] = 0; +} + +Unit::~Unit() +{ + // set current spells as deletable + for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) + { + // spell may be safely deleted now + if (m_currentSpells[i]) m_currentSpells[i]->SetDeletable(true); + m_currentSpells[i] = NULL; + } + + RemoveAllGameObjects(); + RemoveAllDynObjects(); + + if(m_charmInfo) delete m_charmInfo; +} + +void Unit::Update( uint32 p_time ) +{ + /*if(p_time > m_AurasCheck) + { + m_AurasCheck = 2000; + _UpdateAura(); + }else + m_AurasCheck -= p_time;*/ + + // WARNING! Order of execution here is important, do not change. + // Spells must be processed with event system BEFORE they go to _UpdateSpells. + // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad. + m_Events.Update( p_time ); + _UpdateSpells( p_time ); + + // update combat timer only for players and pets + if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet() || ((Creature*)this)->isCharmed())) + { + // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away + // targets without stopping half way there and running off. + // These flags are reset after target dies or another command is given. + if( m_HostilRefManager.isEmpty() ) + { + // m_CombatTimer set at aura start and it will be freeze until aura removing + if ( m_CombatTimer <= p_time ) + ClearInCombat(); + else + m_CombatTimer -= p_time; + } + } + + if(uint32 base_att = getAttackTimer(BASE_ATTACK)) + { + setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) ); + } + + // update abilities available only for fraction of time + UpdateReactives( p_time ); + + ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth()*0.20f); + ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth()*0.35f); + + i_motionMaster.UpdateMotion(p_time); +} + +bool Unit::haveOffhandWeapon() const +{ + if(GetTypeId() == TYPEID_PLAYER) + return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true); + else + return false; +} + +void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player) +{ + float x, y, z; + if(GetMotionMaster()->GetDestination(x, y, z)) + SendMonsterMoveWithSpeed(x, y, z, GetUnitMovementFlags(), 0, player); +} + +void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime, Player* player) +{ + if (!transitTime) + { + float dx = x - GetPositionX(); + float dy = y - GetPositionY(); + float dz = z - GetPositionZ(); + + float dist = ((dx*dx) + (dy*dy) + (dz*dz)); + if(dist<0) + dist = 0; + else + dist = sqrt(dist); + + double speed = GetSpeed((MovementFlags & MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN); + if(speed<=0) + speed = 2.5f; + speed *= 0.001f; + transitTime = static_cast(dist / speed + 0.5); + } + //float orientation = (float)atan2((double)dy, (double)dx); + SendMonsterMove(x, y, z, 0, MovementFlags, transitTime, player); +} + +void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player) +{ + WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) ); + data.append(GetPackGUID()); + + // Point A, starting location + data << GetPositionX() << GetPositionY() << GetPositionZ(); + // unknown field - unrelated to orientation + // seems to increment about 1000 for every 1.7 seconds + // for now, we'll just use mstime + data << getMSTime(); + + data << uint8(type); // unknown + switch(type) + { + case 0: // normal packet + break; + case 1: // stop packet + SendMessageToSet( &data, true ); + return; + case 3: // not used currently + data << uint64(0); // probably target guid + break; + case 4: // not used currently + data << float(0); // probably orientation + break; + } + + //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim) + data << uint32(MovementFlags); + + data << Time; // Time in between points + data << uint32(1); // 1 single waypoint + data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B + + if(player) + player->GetSession()->SendPacket(&data); + else + SendMessageToSet( &data, true ); +} + +void Unit::SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags) +{ + uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32); + + uint32 pathSize = end-start; + + WorldPacket data( SMSG_MONSTER_MOVE, (GetPackGUID().size()+4+4+4+4+1+4+4+4+pathSize*4*3) ); + data.append(GetPackGUID()); + data << GetPositionX( ) + << GetPositionY( ) + << GetPositionZ( ); + data << GetOrientation( ); + data << uint8( 0 ); + data << uint32( MovementFlags ); + data << uint32( traveltime ); + data << uint32( pathSize ); + data.append( (char*)path.GetNodes(start), pathSize * 4 * 3 ); + + //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 ); + SendMessageToSet(&data, true); +} + +void Unit::resetAttackTimer(WeaponAttackType type) +{ + m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]); +} + +bool Unit::canReachWithAttack(Unit *pVictim) const +{ + assert(pVictim); + float reach = GetFloatValue(UNIT_FIELD_COMBATREACH); + if( reach <= 0.0f ) + reach = 1.0f; + return IsWithinDistInMap(pVictim, reach); +} + +void Unit::RemoveSpellsCausingAura(AuraType auraType) +{ + if (auraType >= TOTAL_AURAS) return; + AuraList::iterator iter, next; + for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next) + { + next = iter; + ++next; + + if (*iter) + { + RemoveAurasDueToSpell((*iter)->GetId()); + if (!m_modAuras[auraType].empty()) + next = m_modAuras[auraType].begin(); + else + return; + } + } +} + +bool Unit::HasAuraType(AuraType auraType) const +{ + return (!m_modAuras[auraType].empty()); +} + +/* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */ +void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage) +{ + if(!HasAuraType(auraType)) + return; + + // The chance to dispell an aura depends on the damage taken with respect to the casters level. + uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50; + float chance = float(damage) / max_dmg * 100.0f; + if (roll_chance_f(chance)) + RemoveSpellsCausingAura(auraType); +} + +uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss) +{ + if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + return 0; + + //You don't lose health from damage taken from another player while in a sanctuary + //You still see it in the combat log though + if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + { + const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); + if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary + return 0; + } + + // remove affects from victim (including from 0 damage and DoTs) + if(pVictim != this) + pVictim->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + + // remove affects from attacker at any non-DoT damage (including 0 damage) + if( damagetype != DOT) + { + RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + if(pVictim != this) + RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY); + + if(pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->IsStandState() && !pVictim->hasUnitState(UNIT_STAT_STUNDED)) + pVictim->SetStandState(PLAYER_STATE_NONE); + } + + //Script Event damage Deal + if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI()) + ((Creature *)this)->AI()->DamageDeal(pVictim, damage); + //Script Event damage taken + if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->AI() ) + ((Creature *)pVictim)->AI()->DamageTaken(this, damage); + + if(!damage) + { + // Rage from physical damage received . + if(cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE)) + ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false); + + return 0; + } + + pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage); + // root type spells do not dispell the root effect + if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT) + pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage); + + if(pVictim->GetTypeId() != TYPEID_PLAYER) + { + // no xp,health if type 8 /critters/ + if ( pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER) + { + pVictim->setDeathState(JUST_DIED); + pVictim->SetHealth(0); + + // allow loot only if has loot_id in creature_template + CreatureInfo const* cInfo = ((Creature*)pVictim)->GetCreatureInfo(); + if(cInfo && cInfo->lootid) + pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + // some critters required for quests + if(GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID()); + + return damage; + } + + if(!pVictim->isInCombat() && ((Creature*)pVictim)->AI()) + ((Creature*)pVictim)->AI()->AttackStart(this); + } + + DEBUG_LOG("DealDamageStart"); + + uint32 health = pVictim->GetHealth(); + sLog.outDetail("deal dmg:%d to health:%d ",damage,health); + + // duel ends when player has 1 or less hp + bool duel_hasEnded = false; + if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1)) + { + // prevent kill only if killed in duel and killed by opponent or opponent controlled creature + if(((Player*)pVictim)->duel->opponent==this || ((Player*)pVictim)->duel->opponent->GetGUID() == GetOwnerGUID()) + damage = health-1; + + duel_hasEnded = true; + } + //Get in CombatState + if(pVictim != this && damagetype != DOT) + { + SetInCombatWith(pVictim); + pVictim->SetInCombatWith(this); + + if(Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself()) + SetContestedPvP(attackedPlayer); + } + + // Rage from Damage made (only from direct weapon damage) + if( cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE)) + { + uint32 weaponSpeedHitFactor; + + switch(cleanDamage->attackType) + { + case BASE_ATTACK: + { + if(cleanDamage->hitOutCome == MELEE_HIT_CRIT) + weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 7); + else + weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f); + + ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); + + break; + } + case OFF_ATTACK: + { + if(cleanDamage->hitOutCome == MELEE_HIT_CRIT) + weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f); + else + weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f); + + ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); + + break; + } + case RANGED_ATTACK: + break; + } + } + + if(pVictim->GetTypeId() == TYPEID_PLAYER && GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)pVictim)->InBattleGround()) + { + Player *killer = ((Player*)this); + if(killer != ((Player*)pVictim)) + if(BattleGround *bg = killer->GetBattleGround()) + bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage); + } + } + + if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->isPet() && !((Creature*)pVictim)->hasLootRecipient()) + ((Creature*)pVictim)->SetLootRecipient(this); + if (health <= damage) + { + // battleground things + if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround())) + { + Player *killed = ((Player*)pVictim); + Player *killer = NULL; + if(GetTypeId() == TYPEID_PLAYER) + killer = ((Player*)this); + else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) + { + Unit *owner = GetOwner(); + if(owner && owner->GetTypeId() == TYPEID_PLAYER) + killer = ((Player*)owner); + } + + if(killer) + if(BattleGround *bg = killed->GetBattleGround()) + bg->HandleKillPlayer(killed, killer); // drop flags and etc + } + + DEBUG_LOG("DealDamage: victim just died"); + + // find player: owner of controlled `this` or `this` itself maybe + Player *player = GetCharmerOrOwnerPlayerOrPlayerItself(); + + if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->GetLootRecipient()) + player = ((Creature*)pVictim)->GetLootRecipient(); + // Reward player, his pets, and group/raid members + // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop) + if(player && player!=pVictim) + if(player->RewardPlayerAndGroupAtKill(pVictim)) + player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE); + + DEBUG_LOG("DealDamageAttackStop"); + + // stop combat + pVictim->CombatStop(); + pVictim->getHostilRefManager().deleteReferences(); + + bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795; + + // if talent known but not triggered (check priest class for speedup check) + Aura* spiritOfRedemtionTalentReady = NULL; + if( !damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION + pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST ) + { + AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr) + { + if((*itr)->GetSpellProto()->SpellIconID==1654) + { + spiritOfRedemtionTalentReady = *itr; + break; + } + } + } + + DEBUG_LOG("SET JUST_DIED"); + if(!spiritOfRedemtionTalentReady) + pVictim->setDeathState(JUST_DIED); + + DEBUG_LOG("DealDamageHealth1"); + + if(spiritOfRedemtionTalentReady) + { + // save value before aura remove + uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL); + if(!ressSpellId) + ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId(); + + //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) + pVictim->RemoveAllAurasOnDeath(); + + // restore for use at real death + pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL,ressSpellId); + + // FORM_SPIRITOFREDEMPTION and related auras + pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady); + } + else + pVictim->SetHealth(0); + + // remember victim PvP death for corpse type and corpse reclaim delay + // at original death (not at SpiritOfRedemtionTalent timeout) + if( pVictim->GetTypeId()==TYPEID_PLAYER && !damageFromSpiritOfRedemtionTalent ) + ((Player*)pVictim)->SetPvPDeath(player!=NULL); + + // Call KilledUnit for creatures + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) + ((Creature*)this)->AI()->KilledUnit(pVictim); + + // 10% durability loss on death + // clean InHateListOf + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + // only if not player and not controlled by player pet. And not at BG + if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround()) + { + DEBUG_LOG("We are dead, loosing 10 percents durability"); + ((Player*)pVictim)->DurabilityLossAll(0.10f,false); + // durability lost message + WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); + ((Player*)pVictim)->GetSession()->SendPacket(&data); + } + } + else // creature died + { + DEBUG_LOG("DealDamageNotPlayer"); + Creature *cVictim = (Creature*)pVictim; + + if(!cVictim->isPet()) + { + cVictim->DeleteThreatList(); + cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + // Call creature just died function + if (cVictim->AI()) + cVictim->AI()->JustDied(this); + + // Dungeon specific stuff, only applies to players killing creatures + if(cVictim->GetInstanceId()) + { + Map *m = cVictim->GetMap(); + Player *creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself(); + // TODO: do instance binding anyway if the charmer/owner is offline + + if(m->IsDungeon() && creditedPlayer) + { + if(m->IsRaid() || m->IsHeroic()) + { + if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) + ((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer); + } + else + { + // the reset time is set but not added to the scheduler + // until the players leave the instance + time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR; + if(InstanceSave *save = sInstanceSaveManager.GetInstanceSave(cVictim->GetInstanceId())) + if(save->GetResetTime() < resettime) save->SetResetTime(resettime); + } + } + } + } + + // last damage from non duel opponent or opponent controlled creature + if(duel_hasEnded) + { + assert(pVictim->GetTypeId()==TYPEID_PLAYER); + Player *he = (Player*)pVictim; + + assert(he->duel); + + he->duel->opponent->CombatStopWithPets(true); + he->CombatStopWithPets(true); + + he->DuelComplete(DUEL_INTERUPTED); + } + } + else // if (health <= damage) + { + DEBUG_LOG("DealDamageAlive"); + + pVictim->ModifyHealth(- (int32)damage); + + // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage + if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth()) + { + uint32 procVictim = PROC_FLAG_NONE; + + // if just dropped below 20% (for CheatDeath) + if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth()) + procVictim = PROC_FLAG_LOW_HEALTH; + + ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim); + } + + if(damagetype != DOT) + { + if(getVictim()) + { + // if have target and damage pVictim just call AI recation + if(pVictim != getVictim() && pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->AI()) + ((Creature*)pVictim)->AI()->AttackedBy(this); + } + else + { + // if not have main target then attack state with target (including AI call) + //start melee attacks only after melee hit + Attack(pVictim,(damagetype == DIRECT_DAMAGE)); + } + } + + // polymorphed and other negative transformed cases + if(pVictim->getTransForm() && pVictim->hasUnitState(UNIT_STAT_CONFUSED)) + pVictim->RemoveAurasDueToSpell(pVictim->getTransForm()); + + if(damagetype == DIRECT_DAMAGE|| damagetype == SPELL_DIRECT_DAMAGE) + pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE); + + if (pVictim->GetTypeId() != TYPEID_PLAYER) + { + if(spellProto && IsDamageToThreatSpell(spellProto)) + pVictim->AddThreat(this, damage*2, damageSchoolMask, spellProto); + else + pVictim->AddThreat(this, damage, damageSchoolMask, spellProto); + } + else // victim is a player + { + // Rage from damage received + if(this != pVictim && pVictim->getPowerType() == POWER_RAGE) + { + uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0); + ((Player*)pVictim)->RewardRage(rage_damage, 0, false); + } + + // random durability for items (HIT TAKEN) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE))) + { + EquipmentSlots slot = EquipmentSlots(urand(0,EQUIPMENT_SLOT_END-1)); + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(slot); + } + } + + if(GetTypeId()==TYPEID_PLAYER) + { + // random durability for items (HIT DONE) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE))) + { + EquipmentSlots slot = EquipmentSlots(urand(0,EQUIPMENT_SLOT_END-1)); + ((Player*)this)->DurabilityPointLossForEquipSlot(slot); + } + } + + // TODO: Store auras by interrupt flag to speed this up. + AuraMap& vAuras = pVictim->GetAuras(); + for (AuraMap::iterator i = vAuras.begin(), next; i != vAuras.end(); i = next) + { + const SpellEntry *se = i->second->GetSpellProto(); + next = i; ++next; + if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE ) + { + bool remove = true; + if (se->procFlags & (1<<3)) + { + if (!roll_chance_i(se->procChance)) + remove = false; + } + if (remove) + { + pVictim->RemoveAurasDueToSpell(i->second->GetId()); + // FIXME: this may cause the auras with proc chance to be rerolled several times + next = vAuras.begin(); + } + } + } + + if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER) + { + if( damagetype != DOT ) + { + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) + { + // skip channeled spell (processed differently below) + if (i == CURRENT_CHANNELED_SPELL) + continue; + + if(Spell* spell = pVictim->m_currentSpells[i]) + if(spell->getState() == SPELL_STATE_PREPARING) + spell->Delayed(); + } + } + + if(Spell* spell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]) + { + if (spell->getState() == SPELL_STATE_CASTING) + { + uint32 channelInterruptFlags = spell->m_spellInfo->ChannelInterruptFlags; + if( channelInterruptFlags & CHANNEL_FLAG_DELAY ) + { + if(pVictim!=this) //don't shorten the duration of channeling if you damage yourself + spell->DelayedChannel(); + } + else if( (channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) ) + { + sLog.outDetail("Spell %u canceled at damage!",spell->m_spellInfo->Id); + pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL); + } + } + else if (spell->getState() == SPELL_STATE_DELAYED) + // break channeled spell in delayed state on damage + { + sLog.outDetail("Spell %u canceled at damage!",spell->m_spellInfo->Id); + pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL); + } + } + } + + // last damage from duel opponent + if(duel_hasEnded) + { + assert(pVictim->GetTypeId()==TYPEID_PLAYER); + Player *he = (Player*)pVictim; + + assert(he->duel); + + he->SetHealth(1); + + he->duel->opponent->CombatStopWithPets(true); + he->CombatStopWithPets(true); + + he->CastSpell(he, 7267, true); // beg + he->DuelComplete(DUEL_WON); + } + } + + DEBUG_LOG("DealDamageEnd returned %d damage", damage); + + return damage; +} + +void Unit::CastStop(uint32 except_spellid) +{ + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) + if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id!=except_spellid) + InterruptSpell(i,false); +} + +void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); + + if(!spellInfo) + { + sLog.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry())); + return; + } + + CastSpell(Victim,spellInfo,triggered,castItem,triggredByAura, originalCaster); +} + +void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) +{ + if(!spellInfo) + { + sLog.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry())); + return; + } + + if (castItem) + DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); + + if(!originalCaster && triggredByAura) + originalCaster = triggredByAura->GetCasterGUID(); + + Spell *spell = new Spell(this, spellInfo, triggered, originalCaster ); + + SpellCastTargets targets; + targets.setUnitTarget( Victim ); + spell->m_CastItem = castItem; + spell->prepare(&targets, triggredByAura); +} + +void Unit::CastCustomSpell(Unit* Victim,uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); + + if(!spellInfo) + { + sLog.outError("CastCustomSpell: unknown spell id %i\n", spellId); + return; + } + + CastCustomSpell(Victim,spellInfo,bp0,bp1,bp2,triggered,castItem,triggredByAura, originalCaster); +} + +void Unit::CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) +{ + if(!spellInfo) + { + sLog.outError("CastCustomSpell: unknown spell"); + return; + } + + if (castItem) + DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); + + if(!originalCaster && triggredByAura) + originalCaster = triggredByAura->GetCasterGUID(); + + Spell *spell = new Spell(this, spellInfo, triggered, originalCaster); + + if(bp0) + spell->m_currentBasePoints[0] = *bp0-int32(spellInfo->EffectBaseDice[0]); + + if(bp1) + spell->m_currentBasePoints[1] = *bp1-int32(spellInfo->EffectBaseDice[1]); + + if(bp2) + spell->m_currentBasePoints[2] = *bp2-int32(spellInfo->EffectBaseDice[2]); + + SpellCastTargets targets; + targets.setUnitTarget( Victim ); + spell->m_CastItem = castItem; + spell->prepare(&targets, triggredByAura); +} + +// used for scripting +void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); + + if(!spellInfo) + { + sLog.outError("CastSpell(x,y,z): unknown spell id %i by caster: %s %u)", spellId,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry())); + return; + } + + CastSpell(x, y, z,spellInfo,triggered,castItem,triggredByAura, originalCaster); +} + +// used for scripting +void Unit::CastSpell(float x, float y, float z, SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster) +{ + if(!spellInfo) + { + sLog.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry())); + return; + } + + if (castItem) + DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); + + if(!originalCaster && triggredByAura) + originalCaster = triggredByAura->GetCasterGUID(); + + Spell *spell = new Spell(this, spellInfo, triggered, originalCaster ); + + SpellCastTargets targets; + targets.setDestination(x, y, z); + spell->m_CastItem = castItem; + spell->prepare(&targets, triggredByAura); +} + +void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell) +{ + // TODO this in only generic way, check for exceptions + DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage); + + // Per-damage calss calculation + switch (spellInfo->DmgClass) + { + // Melee and Ranged Spells + case SPELL_DAMAGE_CLASS_RANGED: + case SPELL_DAMAGE_CLASS_MELEE: + { + // Calculate physical outcome + MeleeHitOutcome outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo); + + //Used to store the Hit Outcome + cleanDamage->hitOutCome = outcome; + + // Return miss/evade first (sends miss message) + switch(outcome) + { + case MELEE_HIT_EVADE: + { + SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_EVADES,0); + *damage = 0; + return; + } + case MELEE_HIT_MISS: + { + SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_NORMAL,0); + *damage = 0; + + if(GetTypeId()== TYPEID_PLAYER) + ((Player*)this)->UpdateWeaponSkill(BASE_ATTACK); + + CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell); + return; + } + } + + // Hitinfo, Victimstate + uint32 hitInfo = HITINFO_NORMALSWING; + VictimState victimState = VICTIMSTATE_NORMAL; + + // Physical Damage + if ( GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NORMAL ) + { + uint32 modDamage=*damage; + + // apply spellmod to Done damage + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_DAMAGE, *damage); + + //Calculate armor mitigation + uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage); + + // random durability for main hand weapon (ABSORB) + if(damageAfterArmor < *damage) + if(pVictim->GetTypeId() == TYPEID_PLAYER) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB))) + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK))); + + cleanDamage->damage += *damage - damageAfterArmor; + *damage = damageAfterArmor; + } + // Magical Damage + else + { + // Calculate damage bonus + *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE); + } + + // Classify outcome + switch (outcome) + { + case MELEE_HIT_BLOCK_CRIT: + case MELEE_HIT_CRIT: + { + uint32 bonusDmg = *damage; + + // Apply crit_damage bonus + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, bonusDmg); + + uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); + AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS); + for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) + if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) + bonusDmg = uint32(bonusDmg * ((*i)->GetModifier()->m_amount+100.0f)/100.0f); + + *damage += bonusDmg; + + // Resilience - reduce crit damage + if (pVictim->GetTypeId()==TYPEID_PLAYER) + { + uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage); + cleanDamage->damage += resilienceReduction; + *damage -= resilienceReduction; + } + + *crit = true; + hitInfo |= HITINFO_CRITICALHIT; + + ModifyAuraState(AURA_STATE_CRIT, true); + StartReactiveTimer( REACTIVE_CRIT ); + + if(getClass()==CLASS_HUNTER) + { + ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true); + StartReactiveTimer( REACTIVE_HUNTER_CRIT ); + } + + if ( outcome == MELEE_HIT_BLOCK_CRIT ) + { + uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue()); + if (blocked_amount >= *damage) + { + hitInfo |= HITINFO_SWINGNOHITSOUND; + victimState = VICTIMSTATE_BLOCKS; + cleanDamage->damage += *damage; // To Help Calculate Rage + *damage = 0; + } + else + { + // To Help Calculate Rage + cleanDamage->damage += blocked_amount; + *damage = *damage - blocked_amount; + } + + pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + + if(pVictim->GetTypeId() == TYPEID_PLAYER) + { + // Update defense + ((Player*)pVictim)->UpdateDefense(); + + // random durability for main hand weapon (BLOCK) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); + } + } + break; + } + case MELEE_HIT_PARRY: + { + cleanDamage->damage += *damage; // To Help Calculate Rage + *damage = 0; + victimState = VICTIMSTATE_PARRY; + + // Counter-attack ( explained in Unit::DoAttackDamage() ) + if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN) ) + { + // Get attack timers + float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); + float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); + + // Reduce attack time + if (pVictim->haveOffhandWeapon() && offtime < basetime) + { + float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20; + float percent60 = 3 * percent20; + if(offtime > percent20 && offtime <= percent60) + { + pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); + } + else if(offtime > percent60) + { + offtime -= 2 * percent20; + pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); + } + } + else + { + float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20; + float percent60 = 3 * percent20; + if(basetime > percent20 && basetime <= percent60) + { + pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); + } + else if(basetime > percent60) + { + basetime -= 2 * percent20; + pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); + } + } + } + + if(pVictim->GetTypeId() == TYPEID_PLAYER) + { + // Update victim defense ? + ((Player*)pVictim)->UpdateDefense(); + + // random durability for main hand weapon (PARRY) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY))) + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND); + } + + // Set parry flags + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + + // Mongoose bite - set only Counterattack here + if (pVictim->getClass() == CLASS_HUNTER) + { + pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); + pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); + } + else + { + pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + } + break; + } + case MELEE_HIT_DODGE: + { + if(pVictim->GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->UpdateDefense(); + + cleanDamage->damage += *damage; // To Help Calculate Rage + *damage = 0; + hitInfo |= HITINFO_SWINGNOHITSOUND; + victimState = VICTIMSTATE_DODGE; + + // Set dodge flags + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + + // Overpower + if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) + { + ((Player*)this)->AddComboPoints(pVictim, 1); + StartReactiveTimer( REACTIVE_OVERPOWER ); + } + + // Riposte + if (pVictim->getClass() != CLASS_ROGUE) + { + pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + } + break; + } + case MELEE_HIT_BLOCK: + { + uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue()); + if (blocked_amount >= *damage) + { + hitInfo |= HITINFO_SWINGNOHITSOUND; + victimState = VICTIMSTATE_BLOCKS; + cleanDamage->damage += *damage; // To Help Calculate Rage + *damage = 0; + } + else + { + // To Help Calculate Rage + cleanDamage->damage += blocked_amount; + *damage = *damage - blocked_amount; + } + + pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + + if(pVictim->GetTypeId() == TYPEID_PLAYER) + { + // Update defense + ((Player*)pVictim)->UpdateDefense(); + + // random durability for main hand weapon (BLOCK) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); + } + break; + } + case MELEE_HIT_EVADE: // already processed early + case MELEE_HIT_MISS: // already processed early + case MELEE_HIT_GLANCING: + case MELEE_HIT_CRUSHING: + case MELEE_HIT_NORMAL: + break; + } + + // do all damage=0 cases here + if(*damage == 0) + CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,outcome,spellInfo,isTriggeredSpell); + + break; + } + // Magical Attacks + case SPELL_DAMAGE_CLASS_NONE: + case SPELL_DAMAGE_CLASS_MAGIC: + { + // Calculate damage bonus + *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE); + + *crit = isSpellCrit(pVictim, spellInfo, GetSpellSchoolMask(spellInfo), BASE_ATTACK); + if (*crit) + { + *damage = SpellCriticalBonus(spellInfo, *damage, pVictim); + + // Resilience - reduce crit damage + if (pVictim && pVictim->GetTypeId()==TYPEID_PLAYER) + { + uint32 damage_reduction = ((Player *)pVictim)->GetSpellCritDamageReduction(*damage); + if(*damage > damage_reduction) + *damage -= damage_reduction; + else + *damage = 0; + } + + cleanDamage->hitOutCome = MELEE_HIT_CRIT; + } + // spell proc all magic damage==0 case in this function + if(*damage == 0) + { + // Procflags + uint32 procAttacker = PROC_FLAG_HIT_SPELL; + uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE); + + ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell); + } + + break; + } + } + + // TODO this in only generic way, check for exceptions + DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage); +} + +uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage) +{ + if(!this || !pVictim) + return 0; + if(!this->isAlive() || !pVictim->isAlive()) + return 0; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); + if(!spellInfo) + return 0; + + CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL); + bool crit = false; + + if (useSpellDamage) + DealFlatDamage(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell); + + // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage) + if(damage > 0) + { + // Calculate absorb & resists + uint32 absorb = 0; + uint32 resist = 0; + + CalcAbsorbResist(pVictim,GetSpellSchoolMask(spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + + //No more damage left, target absorbed and/or resisted all damage + if (damage > absorb + resist) + damage -= absorb + resist; //Remove Absorbed and Resisted from damage actually dealt + else + { + uint32 HitInfo = HITINFO_SWINGNOHITSOUND; + + if (absorb) + HitInfo |= HITINFO_ABSORB; + if (resist) + { + HitInfo |= HITINFO_RESIST; + ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, GetSpellSchoolMask(spellInfo), spellInfo,isTriggeredSpell); + } + + //Send resist + SendAttackStateUpdate(HitInfo, pVictim, 1, GetSpellSchoolMask(spellInfo), damage, absorb,resist,VICTIMSTATE_NORMAL,0); + return 0; + } + + // Deal damage done + damage = DealDamage(pVictim, damage, &cleanDamage, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellInfo), spellInfo, true); + + // Send damage log + sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u", + GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist); + + // Actual log sent to client + SendSpellNonMeleeDamageLog(pVictim, spellID, damage, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit); + + // Procflags + uint32 procAttacker = PROC_FLAG_HIT_SPELL; + uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE); + + if (crit) + { + procAttacker |= PROC_FLAG_CRIT_SPELL; + procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; + } + + ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell); + + return damage; + } + else + { + // all spell proc for 0 normal and magic damage called in DealFlatDamage + + //Check for rage + if(cleanDamage.damage) + // Rage from damage received. + if(pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE)) + ((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false); + + return 0; + } +} + +void Unit::HandleEmoteCommand(uint32 anim_id) +{ + WorldPacket data( SMSG_EMOTE, 12 ); + data << anim_id << GetGUID(); + WPAssert(data.size() == 12); + + SendMessageToSet(&data, true); +} + +uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage) +{ + uint32 newdamage = 0; + float armor = pVictim->GetArmor(); + // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura + armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); + + if (armor<0.0f) armor=0.0f; + + float tmpvalue = 0.0f; + if(getLevel() <= 59) //Level 1-59 + tmpvalue = armor / (armor + 400.0f + 85.0f * getLevel()); + else if(getLevel() < 70) //Level 60-69 + tmpvalue = armor / (armor - 22167.5f + 467.5f * getLevel()); + else //Level 70+ + tmpvalue = armor / (armor + 10557.5f); + + if(tmpvalue < 0.0f) + tmpvalue = 0.0f; + if(tmpvalue > 0.75f) + tmpvalue = 0.75f; + newdamage = uint32(damage - (damage * tmpvalue)); + + return (newdamage > 1) ? newdamage : 1; +} + +void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist) +{ + if(!pVictim || !pVictim->isAlive() || !damage) + return; + + // Magic damage, check for resists + if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL)==0) + { + // Get base victim resistance for school + float tmpvalue2 = (float)pVictim->GetResistance(GetFirstSchoolInMask(schoolMask)); + // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura + tmpvalue2 += (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask); + + tmpvalue2 *= (float)(0.15f / getLevel()); + if (tmpvalue2 < 0.0f) + tmpvalue2 = 0.0f; + if (tmpvalue2 > 0.75f) + tmpvalue2 = 0.75f; + uint32 ran = urand(0, 100); + uint32 faq[4] = {24,6,4,6}; + uint8 m = 0; + float Binom = 0.0f; + for (uint8 i = 0; i < 4; i++) + { + Binom += 2400 *( powf(tmpvalue2, i) * powf( (1-tmpvalue2), (4-i)))/faq[i]; + if (ran > Binom ) + ++m; + else + break; + } + if (damagetype == DOT && m == 4) + *resist += uint32(damage - 1); + else + *resist += uint32(damage * m / 4); + if(*resist > damage) + *resist = damage; + } + else + *resist = 0; + + int32 RemainingDamage = damage - *resist; + + // absorb without mana cost + int32 reflectDamage = 0; + Aura* reflectAura = NULL; + AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB); + for(AuraList::const_iterator i = vSchoolAbsorb.begin(), next; i != vSchoolAbsorb.end() && RemainingDamage > 0; i = next) + { + next = i; ++next; + + if (((*i)->GetModifier()->m_miscvalue & schoolMask)==0) + continue; + + // Cheat Death + if((*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && (*i)->GetSpellProto()->SpellIconID == 2109) + { + if (((Player*)pVictim)->HasSpellCooldown(31231)) + continue; + if (pVictim->GetHealth() <= RemainingDamage) + { + int32 chance = (*i)->GetModifier()->m_amount; + if (roll_chance_i(chance)) + { + pVictim->CastSpell(pVictim,31231,true); + ((Player*)pVictim)->AddSpellCooldown(31231,0,time(NULL)+60); + + // with health > 10% lost health until health==10%, in other case no losses + uint32 health10 = pVictim->GetMaxHealth()/10; + RemainingDamage = pVictim->GetHealth() > health10 ? pVictim->GetHealth() - health10 : 0; + } + } + continue; + } + + int32 currentAbsorb; + + //Reflective Shield + if ((pVictim != this) && (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && (*i)->GetSpellProto()->SpellFamilyFlags == 0x1) + { + if(Unit* caster = (*i)->GetCaster()) + { + AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k) + { + switch((*k)->GetModifier()->m_miscvalue) + { + case 5065: // Rank 1 + case 5064: // Rank 2 + case 5063: // Rank 3 + case 5062: // Rank 4 + case 5061: // Rank 5 + { + if(RemainingDamage >= (*i)->GetModifier()->m_amount) + reflectDamage = (*i)->GetModifier()->m_amount * (*k)->GetModifier()->m_amount/100; + else + reflectDamage = (*k)->GetModifier()->m_amount * RemainingDamage/100; + reflectAura = *i; + + } break; + default: break; + } + + if(reflectDamage) + break; + } + } + } + + if (RemainingDamage >= (*i)->GetModifier()->m_amount) + { + currentAbsorb = (*i)->GetModifier()->m_amount; + pVictim->RemoveAurasDueToSpell((*i)->GetId()); + next = vSchoolAbsorb.begin(); + } + else + { + currentAbsorb = RemainingDamage; + (*i)->GetModifier()->m_amount -= RemainingDamage; + } + + RemainingDamage -= currentAbsorb; + } + // do not cast spells while looping auras; auras can get invalid otherwise + if (reflectDamage) + pVictim->CastCustomSpell(this, 33619, &reflectDamage, NULL, NULL, true, NULL, reflectAura); + + // absorb by mana cost + AuraList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD); + for(AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next) + { + next = i; ++next; + + // check damage school mask + if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0) + continue; + + int32 currentAbsorb; + if (RemainingDamage >= (*i)->GetModifier()->m_amount) + currentAbsorb = (*i)->GetModifier()->m_amount; + else + currentAbsorb = RemainingDamage; + + float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()]; + if(Player *modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier); + + int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier); + if (currentAbsorb > maxAbsorb) + currentAbsorb = maxAbsorb; + + (*i)->GetModifier()->m_amount -= currentAbsorb; + if((*i)->GetModifier()->m_amount <= 0) + { + pVictim->RemoveAurasDueToSpell((*i)->GetId()); + next = vManaShield.begin(); + } + + int32 manaReduction = int32(currentAbsorb * manaMultiplier); + pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false); + + RemainingDamage -= currentAbsorb; + } + + AuraList const& vSplitDamageFlat = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT); + for(AuraList::const_iterator i = vSplitDamageFlat.begin(), next; i != vSplitDamageFlat.end() && RemainingDamage >= 0; i = next) + { + next = i; ++next; + + // check damage school mask + if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0) + continue; + + // Damage can be splitted only if aura has an alive caster + Unit *caster = (*i)->GetCaster(); + if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive()) + continue; + + int32 currentAbsorb; + if (RemainingDamage >= (*i)->GetModifier()->m_amount) + currentAbsorb = (*i)->GetModifier()->m_amount; + else + currentAbsorb = RemainingDamage; + + RemainingDamage -= currentAbsorb; + + SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, currentAbsorb, schoolMask, 0, 0, false, 0, false); + + CleanDamage cleanDamage = CleanDamage(currentAbsorb, BASE_ATTACK, MELEE_HIT_NORMAL); + DealDamage(caster, currentAbsorb, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); + } + + AuraList const& vSplitDamagePct = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT); + for(AuraList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next) + { + next = i; ++next; + + // check damage school mask + if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0) + continue; + + // Damage can be splitted only if aura has an alive caster + Unit *caster = (*i)->GetCaster(); + if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive()) + continue; + + int32 splitted = int32(RemainingDamage * (*i)->GetModifier()->m_amount / 100.0f); + + RemainingDamage -= splitted; + + SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, 0, 0, false, 0, false); + + CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL); + DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); + } + + *absorb = damage - RemainingDamage - *resist; +} + +void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell) +{ + MeleeHitOutcome outcome; + + // If is casted Melee spell, calculate like physical + if(!spellCasted) + outcome = RollMeleeOutcomeAgainst (pVictim, attType); + else + outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted); + + if(outcome == MELEE_HIT_MISS ||outcome == MELEE_HIT_DODGE ||outcome == MELEE_HIT_BLOCK ||outcome == MELEE_HIT_PARRY) + pVictim->AddThreat(this, 0.0f); + switch(outcome) + { + case MELEE_HIT_EVADE: + { + *hitInfo |= HITINFO_MISS; + *damage = 0; + cleanDamage->damage = 0; + return; + } + case MELEE_HIT_MISS: + { + *hitInfo |= HITINFO_MISS; + *damage = 0; + cleanDamage->damage = 0; + if(GetTypeId()== TYPEID_PLAYER) + ((Player*)this)->UpdateWeaponSkill(attType); + return; + } + } + + /// If this is a creature and it attacks from behind it has a probability to daze it's victim + if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) && + GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) ) + { + // -probability is between 0% and 40% + // 20% base chance + float Probability = 20; + + //there is a newbie protection, at level 10 just 7% base chance; assuming linear function + if( pVictim->getLevel() < 30 ) + Probability = 0.65f*pVictim->getLevel()+0.5; + + uint32 VictimDefense=pVictim->GetDefenseSkillValue(this); + uint32 AttackerMeleeSkill=GetUnitMeleeSkill(pVictim); + + Probability *= AttackerMeleeSkill/(float)VictimDefense; + + if(Probability > 40.0f) + Probability = 40.0f; + + if(roll_chance_f(Probability)) + CastSpell(pVictim, 1604, true); + } + + //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL + if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) + { + uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage); + + // random durability for main hand weapon (ABSORB) + if(damageAfterArmor < *damage) + if(pVictim->GetTypeId() == TYPEID_PLAYER) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB))) + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK))); + + cleanDamage->damage += *damage - damageAfterArmor; + *damage = damageAfterArmor; + } + + if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER ) + ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false); + + if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true); + + switch (outcome) + { + case MELEE_HIT_BLOCK_CRIT: + case MELEE_HIT_CRIT: + { + //*hitInfo = 0xEA; + // 0xEA + *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8; + + // Crit bonus calc + uint32 crit_bonus; + crit_bonus = *damage; + + // Apply crit_damage bonus for melee spells + if (spellCasted) + { + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + + uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); + AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS); + for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) + if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) + crit_bonus = uint32(crit_bonus * ((*i)->GetModifier()->m_amount+100.0f)/100.0f); + } + + *damage += crit_bonus; + + uint32 resilienceReduction = 0; + + if(attType == RANGED_ATTACK) + { + int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); + *damage = int32((*damage) * float((100.0f + mod)/100.0f)); + // Resilience - reduce crit damage + if (pVictim->GetTypeId()==TYPEID_PLAYER) + resilienceReduction = ((Player*)pVictim)->GetRangedCritDamageReduction(*damage); + } + else + { + int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); + mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE); + *damage = int32((*damage) * float((100.0f + mod)/100.0f)); + // Resilience - reduce crit damage + if (pVictim->GetTypeId()==TYPEID_PLAYER) + resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage); + } + + *damage -= resilienceReduction; + cleanDamage->damage += resilienceReduction; + + if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER ) + ((Player*)this)->UpdateWeaponSkill(attType); + + ModifyAuraState(AURA_STATE_CRIT, true); + StartReactiveTimer( REACTIVE_CRIT ); + + if(getClass()==CLASS_HUNTER) + { + ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true); + StartReactiveTimer( REACTIVE_HUNTER_CRIT ); + } + + if ( outcome == MELEE_HIT_BLOCK_CRIT ) + { + *blocked_amount = pVictim->GetShieldBlockValue(); + + if (pVictim->GetUnitBlockChance()) + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); + else + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + + //Only set VICTIMSTATE_BLOCK on a full block + if (*blocked_amount >= uint32(*damage)) + { + *victimState = VICTIMSTATE_BLOCKS; + *blocked_amount = uint32(*damage); + } + + if(pVictim->GetTypeId() == TYPEID_PLAYER) + { + // Update defense + ((Player*)pVictim)->UpdateDefense(); + + // random durability for main hand weapon (BLOCK) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); + } + + pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + break; + } + + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); + break; + } + case MELEE_HIT_PARRY: + { + if(attType == RANGED_ATTACK) //range attack - no parry + { + outcome = MELEE_HIT_NORMAL; + break; + } + + cleanDamage->damage += *damage; + *damage = 0; + *victimState = VICTIMSTATE_PARRY; + + // instant (maybe with small delay) counter attack + { + float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); + float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); + + // after parry nearest next attack time will reduced at %40 from full attack time. + // The delay cannot be reduced to less than 20% of your weapon's base swing delay. + if (pVictim->haveOffhandWeapon() && offtime < basetime) + { + float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20; + float percent60 = 3*percent20; + // set to 20% if in range 20%...20+40% of full time + if(offtime > percent20 && offtime <= percent60) + { + pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20)); + } + // decrease at %40 from full time + else if(offtime > percent60) + { + offtime -= 2*percent20; + pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime)); + } + // ELSE not changed + } + else + { + float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20; + float percent60 = 3*percent20; + // set to 20% if in range 20%...20+40% of full time + if(basetime > percent20 && basetime <= percent60) + { + pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20)); + } + // decrease at %40 from full time + else if(basetime > percent60) + { + basetime -= 2*percent20; + pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime)); + } + // ELSE not changed + } + } + + if(pVictim->GetTypeId() == TYPEID_PLAYER) + { + // Update victim defense ? + ((Player*)pVictim)->UpdateDefense(); + + // random durability for main hand weapon (PARRY) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY))) + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND); + } + + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + + if (pVictim->getClass() == CLASS_HUNTER) + { + pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); + pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); + } + else + { + pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + } + + CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); + return; + } + case MELEE_HIT_DODGE: + { + if(attType == RANGED_ATTACK) //range attack - no dodge + { + outcome = MELEE_HIT_NORMAL; + break; + } + + cleanDamage->damage += *damage; + *damage = 0; + *victimState = VICTIMSTATE_DODGE; + + if(pVictim->GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->UpdateDefense(); + + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + + if (pVictim->getClass() != CLASS_ROGUE) // Riposte + { + pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + } + + // Overpower + if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) + { + ((Player*)this)->AddComboPoints(pVictim, 1); + StartReactiveTimer( REACTIVE_OVERPOWER ); + } + + CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); + return; + } + case MELEE_HIT_BLOCK: + { + *blocked_amount = pVictim->GetShieldBlockValue(); + + if (pVictim->GetUnitBlockChance()) + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); + else + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + + //Only set VICTIMSTATE_BLOCK on a full block + if (*blocked_amount >= uint32(*damage)) + { + *victimState = VICTIMSTATE_BLOCKS; + *blocked_amount = uint32(*damage); + } + + if(pVictim->GetTypeId() == TYPEID_PLAYER) + { + // Update defense + ((Player*)pVictim)->UpdateDefense(); + + // random durability for main hand weapon (BLOCK) + if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); + } + + pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + + break; + } + case MELEE_HIT_GLANCING: + { + float reducePercent = 1.0f; //damage factor + + // calculate base values and mods + float baseLowEnd = 1.3; + float baseHighEnd = 1.2; + switch(getClass()) // lowering base values for casters + { + case CLASS_SHAMAN: + case CLASS_PRIEST: + case CLASS_MAGE: + case CLASS_WARLOCK: + case CLASS_DRUID: + baseLowEnd -= 0.7; + baseHighEnd -= 0.3; + break; + } + + float maxLowEnd = 0.6; + switch(getClass()) // upper for melee classes + { + case CLASS_WARRIOR: + case CLASS_ROGUE: + maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91 + } + + // calculate values + int32 diff = int32(pVictim->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType,pVictim)); + float lowEnd = baseLowEnd - ( 0.05f * diff ); + float highEnd = baseHighEnd - ( 0.03f * diff ); + + // apply max/min bounds + if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f + lowEnd = 0.01f; + else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end + lowEnd = maxLowEnd; + + if ( highEnd < 0.2f ) //high end limits + highEnd = 0.2f; + if ( highEnd > 0.99f ) + highEnd = 0.99f; + + if(lowEnd > highEnd) // prevent negative range size + lowEnd = highEnd; + + reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd ); + + *damage = uint32(reducePercent * *damage); + cleanDamage->damage += *damage; + *hitInfo |= HITINFO_GLANCING; + break; + } + case MELEE_HIT_CRUSHING: + { + // 150% normal damage + *damage += (*damage / 2); + cleanDamage->damage = *damage; + *hitInfo |= HITINFO_CRUSHING; + // TODO: victimState, victim animation? + break; + } + default: + break; + } + + // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block + if(*victimState != VICTIMSTATE_BLOCKS) + { + MeleeDamageBonus(pVictim, damage,attType,spellCasted); + CalcAbsorbResist(pVictim, damageSchoolMask, DIRECT_DAMAGE, *damage-*blocked_amount, absorbDamage, resistDamage); + } + + if (*absorbDamage) *hitInfo |= HITINFO_ABSORB; + if (*resistDamage) *hitInfo |= HITINFO_RESIST; + + cleanDamage->damage += *blocked_amount; + + if (*damage <= *absorbDamage + *resistDamage + *blocked_amount) + { + //*hitInfo = 0x00010020; + //*hitInfo |= HITINFO_SWINGNOHITSOUND; + //*damageType = 0; + CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); + return; + } + + // update at damage Judgement aura duration that applied by attacker at victim + if(*damage) + { + AuraMap const& vAuras = pVictim->GetAuras(); + for(AuraMap::const_iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr) + { + SpellEntry const *spellInfo = (*itr).second->GetSpellProto(); + if( (spellInfo->AttributesEx3 & 0x40000) && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && + ((*itr).second->GetCasterGUID() == GetGUID() && (!spellCasted || spellCasted->Id == 35395)) ) + { + (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); + (*itr).second->UpdateAuraDuration(); + } + } + } + + CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage - *resistDamage - *blocked_amount), damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); + + // victim's damage shield + // yet another hack to fix crashes related to the aura getting removed during iteration + std::set alreadyDone; + uint32 removedAuras = pVictim->m_removedAuras; + AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); + for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next) + { + ++next; + if (alreadyDone.find(*i) == alreadyDone.end()) + { + alreadyDone.insert(*i); + pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false); + if (pVictim->m_removedAuras > removedAuras) + { + removedAuras = pVictim->m_removedAuras; + next = vDamageShields.begin(); + } + } + } +} + +void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra ) +{ + if(hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNDED | UNIT_STAT_FLEEING) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) ) + return; + + if (!pVictim->isAlive()) + return; + + if(IsNonMeleeSpellCasted(false)) + return; + + uint32 hitInfo; + if (attType == BASE_ATTACK) + hitInfo = HITINFO_NORMALSWING2; + else if (attType == OFF_ATTACK) + hitInfo = HITINFO_LEFTSWING; + else + return; // ignore ranaged case + + uint32 extraAttacks = m_extraAttacks; + + // melee attack spell casted at main hand attack only + if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL]) + { + m_currentSpells[CURRENT_MELEE_SPELL]->cast(); + + // not recent extra attack only at any non extra attack (melee spell case) + if(!extra && extraAttacks) + { + while(m_extraAttacks) + { + AttackerStateUpdate(pVictim, BASE_ATTACK, true); + if(m_extraAttacks > 0) + --m_extraAttacks; + } + } + + return; + } + + VictimState victimState = VICTIMSTATE_NORMAL; + + CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); + uint32 blocked_dmg = 0; + uint32 absorbed_dmg = 0; + uint32 resisted_dmg = 0; + + SpellSchoolMask meleeSchoolMask = GetMeleeDamageSchoolMask(); + + if(pVictim->IsImmunedToDamage(meleeSchoolMask,true)) // use charges + { + SendAttackStateUpdate (HITINFO_NORMALSWING, pVictim, 1, meleeSchoolMask, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0); + + // not recent extra attack only at any non extra attack (miss case) + if(!extra && extraAttacks) + { + while(m_extraAttacks) + { + AttackerStateUpdate(pVictim, BASE_ATTACK, true); + if(m_extraAttacks > 0) + --m_extraAttacks; + } + } + + return; + } + + uint32 damage = CalculateDamage (attType, false); + + DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, meleeSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType); + + if (hitInfo & HITINFO_MISS) + //send miss + SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg); + else + { + //do animation + SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg); + + if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg)) + damage -= (absorbed_dmg + resisted_dmg + blocked_dmg); + else + damage = 0; + + DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, meleeSchoolMask, NULL, true); + + if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive()) + { + for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) + ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim,attType); + } + } + + if (GetTypeId() == TYPEID_PLAYER) + DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", + GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg); + else + DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", + GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg); + + // extra attack only at any non extra attack (normal case) + if(!extra && extraAttacks) + { + while(m_extraAttacks) + { + AttackerStateUpdate(pVictim, BASE_ATTACK, true); + if(m_extraAttacks > 0) + --m_extraAttacks; + } + } +} + +MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo) +{ + // Miss chance based on melee + float miss_chance = MeleeMissChanceCalc(pVictim, attType); + + // Critical hit chance + float crit_chance = GetUnitCriticalChance(attType, pVictim); + // this is to avoid compiler issue when declaring variables inside if + float block_chance, parry_chance, dodge_chance; + + // cannot be dodged/parried/blocked + if(spellInfo->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) + { + block_chance = 0.0f; + parry_chance = 0.0f; + dodge_chance = 0.0f; + } + else + { + // parry can be avoided only by some abilites + parry_chance = pVictim->GetUnitParryChance(); + // block might be bypassed by it as well + block_chance = pVictim->GetUnitBlockChance(); + // stunned target cannot dodge and this is check in GetUnitDodgeChance() + dodge_chance = pVictim->GetUnitDodgeChance(); + } + + // Only players can have Talent&Spell bonuses + if (GetTypeId() == TYPEID_PLAYER) + { + // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura + crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, spellInfo->SchoolMask); + + if( dodge_chance != 0.0f ) // if dodge chance is already 0, ignore talents fpr speed + { + AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); + for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i) + { + // can't be dodged rogue finishing move + if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) + { + if(spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE)) + { + dodge_chance = 0.0f; + break; + } + } + } + } + } + + // Spellmods + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); + + DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance,crit_chance,dodge_chance,parry_chance, block_chance); + + return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100),int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), true); +} + +MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const +{ + // This is only wrapper + + // Miss chance based on melee + float miss_chance = MeleeMissChanceCalc(pVictim, attType); + + // Critical hit chance + float crit_chance = GetUnitCriticalChance(attType, pVictim); + + // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case) + float dodge_chance = pVictim->GetUnitDodgeChance(); + float block_chance = pVictim->GetUnitBlockChance(); + float parry_chance = pVictim->GetUnitParryChance(); + + // Useful if want to specify crit & miss chances for melee, else it could be removed + DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance,crit_chance,dodge_chance,parry_chance,block_chance); + + return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), false); +} + +MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const +{ + if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + return MELEE_HIT_EVADE; + + int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(pVictim); + int32 victimMaxSkillValueForLevel = pVictim->GetMaxSkillValueForLevel(this); + + int32 attackerWeaponSkill = GetWeaponSkillValue(attType,pVictim); + int32 victimDefenseSkill = pVictim->GetDefenseSkillValue(this); + + // bonus from skills is 0.04% + int32 skillBonus = 4 * ( attackerWeaponSkill - victimMaxSkillValueForLevel ); + int32 skillBonus2 = 4 * ( attackerMaxSkillValueForLevel - victimDefenseSkill ); + int32 sum = 0, tmp = 0; + int32 roll = urand (0, 10000); + + DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus); + DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d", + roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance); + + tmp = miss_chance; + + if (tmp > 0 && roll < (sum += tmp )) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS"); + return MELEE_HIT_MISS; + } + + // always crit against a sitting target (except 0 crit chance) + if( pVictim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !pVictim->IsStandState() ) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)"); + return MELEE_HIT_CRIT; + } + + // Dodge chance + + // only players can't dodge if attacker is behind + if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->HasInArc(M_PI,this)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player."); + } + else + { + // Reduce dodge chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + dodge_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100); + + // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE + dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); + + tmp = dodge_chance; + if ( (tmp > 0) // check if unit _can_ dodge + && ((tmp -= skillBonus) > 0) + && roll < (sum += tmp)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum); + return MELEE_HIT_DODGE; + } + } + + // parry & block chances + + // check if attack comes from behind, nobody can parry or block if attacker is behind + if (!pVictim->HasInArc(M_PI,this)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind."); + } + else + { + // Reduce parry chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + parry_chance-= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100); + + if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY) ) + { + int32 tmp = int32(parry_chance); + if ( (tmp > 0) // check if unit _can_ parry + && ((tmp -= skillBonus) > 0) + && (roll < (sum += tmp))) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum); + return MELEE_HIT_PARRY; + } + } + + if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK) ) + { + tmp = block_chance; + if ( (tmp > 0) // check if unit _can_ block + && ((tmp -= skillBonus) > 0) + && (roll < (sum += tmp))) + { + // Critical chance + tmp = crit_chance + skillBonus2; + if ( GetTypeId() == TYPEID_PLAYER && SpellCasted && tmp > 0 ) + { + if ( roll_chance_i(tmp/100)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT"); + return MELEE_HIT_BLOCK_CRIT; + } + } + DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); + return MELEE_HIT_BLOCK; + } + } + } + + // Critical chance + tmp = crit_chance + skillBonus2; + + if (tmp > 0 && roll < (sum += tmp)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum); + return MELEE_HIT_CRIT; + } + + // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) + if( attType != RANGED_ATTACK && !SpellCasted && + (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) && + pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() && + getLevel() < pVictim->getLevelForTarget(this) ) + { + // cap possible value (with bonuses > max skill) + int32 skill = attackerWeaponSkill; + int32 maxskill = attackerMaxSkillValueForLevel; + skill = (skill > maxskill) ? maxskill : skill; + + tmp = (10 + (victimDefenseSkill - skill)) * 100; + tmp = tmp > 4000 ? 4000 : tmp; + if (roll < (sum += tmp)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum); + return MELEE_HIT_GLANCING; + } + } + + if(GetTypeId()!=TYPEID_PLAYER && !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) && !((Creature*)this)->isPet() ) + { + // mobs can score crushing blows if they're 3 or more levels above victim + // or when their weapon skill is 15 or more above victim's defense skill + tmp = victimDefenseSkill; + int32 tmpmax = victimMaxSkillValueForLevel; + // having defense above your maximum (from items, talents etc.) has no effect + tmp = tmp > tmpmax ? tmpmax : tmp; + // tmp = mob's level * 5 - player's current defense skill + tmp = attackerMaxSkillValueForLevel - tmp; + if(tmp >= 15) + { + // add 2% chance per lacking skill point, min. is 15% + tmp = tmp * 200 - 1500; + if (roll < (sum += tmp)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum); + return MELEE_HIT_CRUSHING; + } + } + } + + DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL"); + return MELEE_HIT_NORMAL; +} + +uint32 Unit::CalculateDamage (WeaponAttackType attType, bool normalized) +{ + float min_damage, max_damage; + + if (normalized && GetTypeId()==TYPEID_PLAYER) + ((Player*)this)->CalculateMinMaxDamage(attType,normalized,min_damage, max_damage); + else + { + switch (attType) + { + case RANGED_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE); + break; + case BASE_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE); + break; + case OFF_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE); + break; + // Just for good manner + default: + min_damage = 0.0f; + max_damage = 0.0f; + break; + } + } + + if (min_damage > max_damage) + { + std::swap(min_damage,max_damage); + } + + if(max_damage == 0.0f) + max_damage = 5.0f; + + return urand((uint32)min_damage, (uint32)max_damage); +} + +float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const +{ + if(spellProto->spellLevel <= 0) + return 1.0f; + + float LvlPenalty = 0.0f; + + if(spellProto->spellLevel < 20) + LvlPenalty = 20.0f - spellProto->spellLevel * 3.75f; + float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel()); + if(LvlFactor > 1.0f) + LvlFactor = 1.0f; + + return (100.0f - LvlPenalty) * LvlFactor / 100.0f; +} + +void Unit::SendAttackStart(Unit* pVictim) +{ + WorldPacket data( SMSG_ATTACKSTART, 16 ); + data << GetGUID(); + data << pVictim->GetGUID(); + + SendMessageToSet(&data, true); + DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" ); +} + +void Unit::SendAttackStop(Unit* victim) +{ + if(!victim) + return; + + WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size + data.append(GetPackGUID()); + data.append(victim->GetPackGUID()); // can be 0x00... + data << uint32(0); // can be 0x1 + SendMessageToSet(&data, true); + sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow()); + + /*if(victim->GetTypeId() == TYPEID_UNIT) + ((Creature*)victim)->AI().EnterEvadeMode(this);*/ +} + +/* +// Melee based spells can be miss, parry or dodge on this step +// Crit or block - determined on damage calculation phase! (and can be both in some time) +float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell) +{ + // Calculate hit chance (more correct for chance mod) + int32 HitChance; + + // PvP - PvE melee chances + int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; + int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim); + if(leveldif < 3) + HitChance = 95 - leveldif; + else + HitChance = 93 - (leveldif - 2) * lchance; + + // Hit chance depends from victim auras + if(attType == RANGED_ATTACK) + HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); + else + HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); + + // Spellmod from SPELLMOD_RESIST_MISS_CHANCE + if(Player *modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance); + + // Miss = 100 - hit + float miss_chance= 100.0f - HitChance; + + // Bonuses from attacker aura and ratings + if (attType == RANGED_ATTACK) + miss_chance -= m_modRangedHitChance; + else + miss_chance -= m_modMeleeHitChance; + + // bonus from skills is 0.04% + miss_chance -= skillDiff * 0.04f; + + // Limit miss chance from 0 to 60% + if (miss_chance < 0.0f) + return 0.0f; + if (miss_chance > 60.0f) + return 60.0f; + return miss_chance; +} + +// Melee based spells hit result calculations +SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) +{ + WeaponAttackType attType = BASE_ATTACK; + + if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) + attType = RANGED_ATTACK; + + // bonus from skills is 0.04% per skill Diff + int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim)); + int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this)); + int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this)); + + uint32 roll = urand (0, 10000); + uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f); + + // Roll miss + uint32 tmp = missChance; + if (roll < tmp) + return SPELL_MISS_MISS; + + // Same spells cannot be parry/dodge + if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) + return SPELL_MISS_NONE; + + // Ranged attack can`t miss too + if (attType == RANGED_ATTACK) + return SPELL_MISS_NONE; + + bool attackFromBehind = !pVictim->HasInArc(M_PI,this); + + // Roll dodge + int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4; + // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE + dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); + + // Reduce dodge chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); + if (dodgeChance < 0) + dodgeChance = 0; + + // Can`t dodge from behind in PvP (but its possible in PvE) + if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind) + dodgeChance = 0; + + // Rogue talent`s cant be dodged + AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); + for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i) + { + if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move + { + if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE)) + { + dodgeChance = 0; + break; + } + } + } + + tmp += dodgeChance; + if (roll < tmp) + return SPELL_MISS_DODGE; + + // Roll parry + int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4; + // Reduce parry chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); + // Can`t parry from behind + if (parryChance < 0 || attackFromBehind) + parryChance = 0; + + tmp += parryChance; + if (roll < tmp) + return SPELL_MISS_PARRY; + + return SPELL_MISS_NONE; +}*/ + +// TODO need use unit spell resistances in calculations +SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell) +{ + // Can`t miss on dead target (on skinning for example) + if (!pVictim->isAlive()) + return SPELL_MISS_NONE; + + SpellSchoolMask schoolMask = GetSpellSchoolMask(spell); + // PvP - PvE spell misschances per leveldif > 2 + int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11; + int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim)); + + // Base hit chance from attacker and victim levels + int32 modHitChance; + if(leveldif < 3) + modHitChance = 96 - leveldif; + else + modHitChance = 94 - (leveldif - 2) * lchance; + + // Spellmod from SPELLMOD_RESIST_MISS_CHANCE + if(Player *modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); + // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras + modHitChance+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask); + // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras + modHitChance+= pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask); + // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura + if (IsAreaOfEffectSpell(spell)) + modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE); + // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST + if (IsDispelSpell(spell)) + modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST); + // Chance resist mechanic (select max value from every mechanic spell effect) + int32 resist_mech = 0; + // Get effects mechanic and chance + for(int eff = 0; eff < 3; ++eff) + { + int32 effect_mech = GetEffectMechanic(spell, eff); + if (effect_mech) + { + int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); + if (resist_mech < temp) + resist_mech = temp; + } + } + // Apply mod + modHitChance-=resist_mech; + + // Chance resist debuff + modHitChance-=pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)); + + int32 HitChance = modHitChance * 100; + // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings + HitChance += int32(m_modSpellHitChance*100.0f); + + // Decrease hit chance from victim rating bonus + if (pVictim->GetTypeId()==TYPEID_PLAYER) + HitChance -= int32(((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)*100.0f); + + if (HitChance < 100) HitChance = 100; + if (HitChance > 9900) HitChance = 9900; + + uint32 rand = urand(0,10000); + if (rand > HitChance) + return SPELL_MISS_RESIST; + return SPELL_MISS_NONE; +} + +SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool CanReflect) +{ + // Return evade for units in evade mode + if (pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + return SPELL_MISS_EVADE; + + // Check for immune (use charges) + if (pVictim->IsImmunedToSpell(spell,true)) + return SPELL_MISS_IMMUNE; + + // All positive spells can`t miss + // TODO: client not show miss log for this spells - so need find info for this in dbc and use it! + if (IsPositiveSpell(spell->Id)) + return SPELL_MISS_NONE; + + // Check for immune (use charges) + if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell),true)) + return SPELL_MISS_IMMUNE; + + // Try victim reflect spell + if (CanReflect) + { + // specialized first + Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL); + for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i) + { + if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell)) + { + int32 reflectchance = (*i)->GetModifier()->m_amount; + if (reflectchance > 0 && roll_chance_i(reflectchance)) + { + if((*i)->m_procCharges > 0) + { + --(*i)->m_procCharges; + if((*i)->m_procCharges==0) + pVictim->RemoveAurasDueToSpell((*i)->GetId()); + } + return SPELL_MISS_REFLECT; + } + } + } + + // generic reflection + Unit::AuraList const& mReflectSpells = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS); + for(Unit::AuraList::const_iterator i = mReflectSpells.begin(); i != mReflectSpells.end(); ++i) + { + int32 reflectchance = (*i)->GetModifier()->m_amount; + if (reflectchance > 0 && roll_chance_i(reflectchance)) + { + if((*i)->m_procCharges > 0) + { + --(*i)->m_procCharges; + if((*i)->m_procCharges==0) + pVictim->RemoveAurasDueToSpell((*i)->GetId()); + } + return SPELL_MISS_REFLECT; + } + } + } + + // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after) + for (int i=0;i<3;i++) + { + if (spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE || + spell->Effect[i] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE || + spell->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG || + spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL) + return SPELL_MISS_NONE; + } + + // TODO need use this code for spell hit result calculation + // now code commented for compotability + switch (spell->DmgClass) + { + case SPELL_DAMAGE_CLASS_RANGED: + case SPELL_DAMAGE_CLASS_MELEE: +// return MeleeSpellHitResult(pVictim, spell); + return SPELL_MISS_NONE; + case SPELL_DAMAGE_CLASS_NONE: + case SPELL_DAMAGE_CLASS_MAGIC: + return MagicSpellHitResult(pVictim, spell); + } + return SPELL_MISS_NONE; +} + +float Unit::MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const +{ + if(!pVictim) + return 0.0f; + + // Base misschance 5% + float misschance = 5.0f; + + // DualWield - Melee spells and physical dmg spells - 5% , white damage 24% + if (haveOffhandWeapon() && attType != RANGED_ATTACK) + { + bool isNormal = false; + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) + { + if( m_currentSpells[i] && (GetSpellSchoolMask(m_currentSpells[i]->m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL) ) + { + isNormal = true; + break; + } + } + if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL]) + { + misschance = 5.0f; + } + else + { + misschance = 24.0f; + } + } + + // PvP : PvE melee misschances per leveldif > 2 + int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; + + int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim)); + if(leveldif < 0) + leveldif = 0; + + // Hit chance from attacker based on ratings and auras + float m_modHitChance; + if (attType == RANGED_ATTACK) + m_modHitChance = m_modRangedHitChance; + else + m_modHitChance = m_modMeleeHitChance; + + if(leveldif < 3) + misschance += (leveldif - m_modHitChance); + else + misschance += ((leveldif - 2) * chance - m_modHitChance); + + // Hit chance for victim based on ratings + if (pVictim->GetTypeId()==TYPEID_PLAYER) + { + if (attType == RANGED_ATTACK) + misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED); + else + misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE); + } + + // Modify miss chance by victim auras + if(attType == RANGED_ATTACK) + misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); + else + misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); + + // Modify miss chance from skill difference ( bonus from skills is 0.04% ) + int32 skillBonus = int32(GetWeaponSkillValue(attType,pVictim)) - int32(pVictim->GetDefenseSkillValue(this)); + misschance -= skillBonus * 0.04f; + + // Limit miss chance from 0 to 60% + if ( misschance < 0.0f) + return 0.0f; + if ( misschance > 60.0f) + return 60.0f; + + return misschance; +} + +uint32 Unit::GetDefenseSkillValue(Unit const* target) const +{ + if(GetTypeId() == TYPEID_PLAYER) + { + // in PvP use full skill instead current skill value + uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER) + ? ((Player*)this)->GetMaxSkillValue(SKILL_DEFENSE) + : ((Player*)this)->GetSkillValue(SKILL_DEFENSE); + value += uint32(((Player*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL)); + return value; + } + else + return GetUnitMeleeSkill(target); +} + +float Unit::GetUnitDodgeChance() const +{ + if(hasUnitState(UNIT_STAT_STUNDED)) + return 0.0f; + if( GetTypeId() == TYPEID_PLAYER ) + return GetFloatValue(PLAYER_DODGE_PERCENTAGE); + else + { + if(((Creature const*)this)->isTotem()) + return 0.0f; + else + { + float dodge = 5.0f; + dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); + return dodge > 0.0f ? dodge : 0.0f; + } + } +} + +float Unit::GetUnitParryChance() const +{ + if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNDED)) + return 0.0f; + + float chance = 0.0f; + + if(GetTypeId() == TYPEID_PLAYER) + { + Player const* player = (Player const*)this; + if(player->CanParry() ) + { + Item *tmpitem = player->GetWeaponForAttack(BASE_ATTACK,true); + if(!tmpitem) + tmpitem = player->GetWeaponForAttack(OFF_ATTACK,true); + + if(tmpitem) + chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE); + } + } + else if(GetTypeId() == TYPEID_UNIT) + { + if(GetCreatureType() == CREATURE_TYPE_HUMANOID) + { + chance = 5.0f; + chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); + } + } + + return chance > 0.0f ? chance : 0.0f; +} + +float Unit::GetUnitBlockChance() const +{ + if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNDED)) + return 0.0f; + + if(GetTypeId() == TYPEID_PLAYER) + { + Player const* player = (Player const*)this; + if(player->CanBlock() ) + { + Item *tmpitem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block) + return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); + } + // is player but has no block ability or no not broken shield equiped + return 0.0f; + } + else + { + if(((Creature const*)this)->isTotem()) + return 0.0f; + else + { + float block = 5.0f; + block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); + return block > 0.0f ? block : 0.0f; + } + } +} + +float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const +{ + float crit; + + if(GetTypeId() == TYPEID_PLAYER) + { + switch(attackType) + { + case BASE_ATTACK: + crit = GetFloatValue( PLAYER_CRIT_PERCENTAGE ); + break; + case OFF_ATTACK: + crit = GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE ); + break; + case RANGED_ATTACK: + crit = GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE ); + break; + // Just for good manner + default: + crit = 0.0f; + break; + } + } + else + { + crit = 5.0f; + crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT); + } + + // flat aura mods + if(attackType == RANGED_ATTACK) + crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE); + else + crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE); + + crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); + + // reduce crit chance from Rating for players + if (pVictim->GetTypeId()==TYPEID_PLAYER) + { + if (attackType==RANGED_ATTACK) + crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED); + else + crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE); + } + + if (crit < 0.0f) + crit = 0.0f; + return crit; +} + +uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) const +{ + uint32 value = 0; + if(GetTypeId() == TYPEID_PLAYER) + { + Item* item = ((Player*)this)->GetWeaponForAttack(attType,true); + + // feral or unarmed skill only for base attack + if(attType != BASE_ATTACK && !item ) + return 0; + + if(((Player*)this)->IsInFeralForm()) + return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact + + // weaon skill or (unarmed for base attack) + uint32 skill = item ? item->GetSkill() : SKILL_UNARMED; + + // in PvP use full skill instead current skill value + value = (target && target->GetTypeId() == TYPEID_PLAYER) + ? ((Player*)this)->GetMaxSkillValue(skill) + : ((Player*)this)->GetSkillValue(skill); + // Modify value from ratings + value += uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL)); + switch (attType) + { + case BASE_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND));break; + case OFF_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND));break; + case RANGED_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED));break; + } + } + else + value = GetUnitMeleeSkill(target); + return value; +} + +void Unit::_UpdateSpells( uint32 time ) +{ + if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) + _UpdateAutoRepeatSpell(); + + // remove finished spells from current pointers + for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) + { + if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED) + { + m_currentSpells[i]->SetDeletable(true); // spell may be safely deleted now + m_currentSpells[i] = NULL; // remove pointer + } + } + + // TODO: Find a better way to prevent crash when multiple auras are removed. + m_removedAuras = 0; + for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i) + if ((*i).second) + (*i).second->SetUpdated(false); + + for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next) + { + next = i; + ++next; + if ((*i).second) + { + // prevent double update + if ((*i).second->IsUpdated()) + continue; + (*i).second->SetUpdated(true); + (*i).second->Update( time ); + // several auras can be deleted due to update + if (m_removedAuras) + { + if (m_Auras.empty()) break; + next = m_Auras.begin(); + m_removedAuras = 0; + } + } + } + + for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();) + { + if ((*i).second) + { + if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) ) + { + RemoveAura(i); + } + else + { + ++i; + } + } + else + { + ++i; + } + } + + if(!m_gameObj.empty()) + { + std::list::iterator ite1, dnext1; + for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1) + { + dnext1 = ite1; + //(*i)->Update( difftime ); + if( !(*ite1)->isSpawned() ) + { + (*ite1)->SetOwnerGUID(0); + (*ite1)->SetRespawnTime(0); + (*ite1)->Delete(); + dnext1 = m_gameObj.erase(ite1); + } + else + ++dnext1; + } + } +} + +void Unit::_UpdateAutoRepeatSpell() +{ + //check "realtime" interrupts + if ( (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) ) + { + // cancel wand shoot + if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + m_AutoRepeatFirstCast = true; + return; + } + + //apply delay + if ( m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 ) + setAttackTimer(RANGED_ATTACK,500); + m_AutoRepeatFirstCast = false; + + //castroutine + if (isAttackReady(RANGED_ATTACK)) + { + // Check if able to cast + if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true)) + { + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + return; + } + + // we want to shoot + Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true, 0); + spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets)); + + // all went good, reset attack + resetAttackTimer(RANGED_ATTACK); + } +} + +void Unit::SetCurrentCastedSpell( Spell * pSpell ) +{ + assert(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells + + uint32 CSpellType = pSpell->GetCurrentContainer(); + + pSpell->SetDeletable(false); // spell will not be deleted until gone from current pointers + if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self + + // break same type spell if it is not delayed + InterruptSpell(CSpellType,false); + + // special breakage effects: + switch (CSpellType) + { + case CURRENT_GENERIC_SPELL: + { + // generic spells always break channeled not delayed spells + InterruptSpell(CURRENT_CHANNELED_SPELL,false); + + // autorepeat breaking + if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] ) + { + // break autorepeat if not Auto Shot + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + m_AutoRepeatFirstCast = true; + } + } break; + + case CURRENT_CHANNELED_SPELL: + { + // channel spells always break generic non-delayed and any channeled spells + InterruptSpell(CURRENT_GENERIC_SPELL,false); + InterruptSpell(CURRENT_CHANNELED_SPELL); + + // it also does break autorepeat if not Auto Shot + if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351 ) + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + } break; + + case CURRENT_AUTOREPEAT_SPELL: + { + // only Auto Shoot does not break anything + if (pSpell->m_spellInfo->Category == 351) + { + // generic autorepeats break generic non-delayed and channeled non-delayed spells + InterruptSpell(CURRENT_GENERIC_SPELL,false); + InterruptSpell(CURRENT_CHANNELED_SPELL,false); + } + // special action: set first cast flag + m_AutoRepeatFirstCast = true; + } break; + + default: + { + // other spell types don't break anything now + } break; + } + + // current spell (if it is still here) may be safely deleted now + if (m_currentSpells[CSpellType]) + m_currentSpells[CSpellType]->SetDeletable(true); + + // set new current spell + m_currentSpells[CSpellType] = pSpell; +} + +void Unit::InterruptSpell(uint32 spellType, bool withDelayed) +{ + assert(spellType < CURRENT_MAX_SPELL); + + if(m_currentSpells[spellType] && (withDelayed || m_currentSpells[spellType]->getState() != SPELL_STATE_DELAYED) ) + { + // send autorepeat cancel message for autorepeat spells + if (spellType == CURRENT_AUTOREPEAT_SPELL) + { + if(GetTypeId()==TYPEID_PLAYER) + ((Player*)this)->SendAutoRepeatCancel(); + } + + if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED) + m_currentSpells[spellType]->cancel(); + m_currentSpells[spellType]->SetDeletable(true); + m_currentSpells[spellType] = NULL; + } +} + +bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat) const +{ + // We don't do loop here to explicitly show that melee spell is excluded. + // Maybe later some special spells will be excluded too. + + // generic spells are casted when they are not finished and not delayed + if ( m_currentSpells[CURRENT_GENERIC_SPELL] && + (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && + (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) ) + return(true); + + // channeled spells may be delayed, but they are still considered casted + else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] && + (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) ) + return(true); + + // autorepeat spells may be finished or delayed, but they are still considered casted + else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] ) + return(true); + + return(false); +} + +void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) +{ + // generic spells are interrupted if they are not finished or delayed + if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id==spell_id)) + { + if ( (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && + (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) ) + m_currentSpells[CURRENT_GENERIC_SPELL]->cancel(); + m_currentSpells[CURRENT_GENERIC_SPELL]->SetDeletable(true); + m_currentSpells[CURRENT_GENERIC_SPELL] = NULL; + } + + // autorepeat spells are interrupted if they are not finished or delayed + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id==spell_id)) + { + // send disable autorepeat packet in any case + if(GetTypeId()==TYPEID_PLAYER) + ((Player*)this)->SendAutoRepeatCancel(); + + if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) && + (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) ) + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->cancel(); + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SetDeletable(true); + m_currentSpells[CURRENT_AUTOREPEAT_SPELL] = NULL; + } + + // channeled spells are interrupted if they are not finished, even if they are delayed + if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id==spell_id)) + { + if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) + m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); + m_currentSpells[CURRENT_CHANNELED_SPELL]->SetDeletable(true); + m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; + } +} + +Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const +{ + for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) + if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id==spell_id) + return m_currentSpells[i]; + return NULL; +} + +bool Unit::isInFront(Unit const* target, float distance, float arc) const +{ + return IsWithinDistInMap(target, distance) && HasInArc( arc, target ); +} + +void Unit::SetInFront(Unit const* target) +{ + SetOrientation(GetAngle(target)); +} + +bool Unit::isInBack(Unit const* target, float distance, float arc) const +{ + return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target ); +} + +bool Unit::isInAccessablePlaceFor(Creature const* c) const +{ + if(IsInWater()) + return c->canSwim(); + else + return c->canWalk() || c->canFly(); +} + +bool Unit::IsInWater() const +{ + return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ()); +} + +bool Unit::IsUnderWater() const +{ + return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ()); +} + +void Unit::DeMorph() +{ + SetDisplayId(GetNativeDisplayId()); +} + +int32 Unit::GetTotalAuraModifier(AuraType auratype) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + modifier += (*i)->GetModifier()->m_amount; + + return modifier; +} + +float Unit::GetTotalAuraMultiplier(AuraType auratype) const +{ + float multipler = 1.0f; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + multipler *= (100.0f + (*i)->GetModifier()->m_amount)/100.0f; + + return multipler; +} + +int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + if ((*i)->GetModifier()->m_amount > modifier) + modifier = (*i)->GetModifier()->m_amount; + + return modifier; +} + +int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + if ((*i)->GetModifier()->m_amount < modifier) + modifier = (*i)->GetModifier()->m_amount; + + return modifier; +} + +int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue & misc_mask) + modifier += mod->m_amount; + } + return modifier; +} + +float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const +{ + float multipler = 1.0f; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue & misc_mask) + multipler *= (100.0f + mod->m_amount)/100.0f; + } + return multipler; +} + +int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue & misc_mask && mod->m_amount > modifier) + modifier = mod->m_amount; + } + + return modifier; +} + +int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue & misc_mask && mod->m_amount < modifier) + modifier = mod->m_amount; + } + + return modifier; +} + +int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue == misc_value) + modifier += mod->m_amount; + } + return modifier; +} + +float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const +{ + float multipler = 1.0f; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue == misc_value) + multipler *= (100.0f + mod->m_amount)/100.0f; + } + return multipler; +} + +int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue == misc_value && mod->m_amount > modifier) + modifier = mod->m_amount; + } + + return modifier; +} + +int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const +{ + int32 modifier = 0; + + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue == misc_value && mod->m_amount < modifier) + modifier = mod->m_amount; + } + + return modifier; +} + +bool Unit::AddAura(Aura *Aur) +{ + // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load) + if( !isAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 && + (GetTypeId()!=TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading()) ) + { + delete Aur; + return false; + } + + if(Aur->GetTarget() != this) + { + sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)", + Aur->GetId(),Aur->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(), + (Aur->GetTarget()->GetTypeId()==TYPEID_PLAYER?"player":"creature"),Aur->GetTarget()->GetGUIDLow()); + delete Aur; + return false; + } + + SpellEntry const* aurSpellInfo = Aur->GetSpellProto(); + + spellEffectPair spair = spellEffectPair(Aur->GetId(), Aur->GetEffIndex()); + AuraMap::iterator i = m_Auras.find( spair ); + + // take out same spell + if (i != m_Auras.end()) + { + // passive and persistent auras can stack with themselves any number of times + if (!Aur->IsPassive() && !Aur->IsPersistent()) + { + // replace aura if next will > spell StackAmount + if(aurSpellInfo->StackAmount) + { + if(m_Auras.count(spair) >= aurSpellInfo->StackAmount) + RemoveAura(i,AURA_REMOVE_BY_STACK); + } + // if StackAmount==0 not allow auras from same caster + else + { + for(AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair); ++i2) + { + if(i2->second->GetCasterGUID()==Aur->GetCasterGUID()) + { + // can be only single (this check done at _each_ aura add + RemoveAura(i2,AURA_REMOVE_BY_STACK); + break; + } + + bool stop = false; + switch(aurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()]) + { + // DoT/HoT/etc + case SPELL_AURA_PERIODIC_DAMAGE: // allow stack + case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: + case SPELL_AURA_PERIODIC_LEECH: + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_OBS_MOD_HEALTH: + case SPELL_AURA_PERIODIC_MANA_LEECH: + case SPELL_AURA_PERIODIC_ENERGIZE: + case SPELL_AURA_OBS_MOD_MANA: + case SPELL_AURA_POWER_BURN_MANA: + break; + default: // not allow + // can be only single (this check done at _each_ aura add + RemoveAura(i2,AURA_REMOVE_BY_STACK); + stop = true; + break; + } + + if(stop) + break; + } + } + } + } + + // passive auras stack with all (except passive spell proc auras) + if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) && + !(Aur->GetId() == 20584 || Aur->GetId() == 8326)) + { + if (!RemoveNoStackAurasDueToAura(Aur)) + { + delete Aur; + return false; // couldnt remove conflicting aura with higher rank + } + } + + // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura) + if (IsSingleTargetSpell(aurSpellInfo) && Aur->GetTarget()) + { + // caster pointer can be deleted in time aura remove, find it by guid at each iteration + for(;;) + { + Unit* caster = Aur->GetCaster(); + if(!caster) // caster deleted and not required adding scAura + break; + + bool restart = false; + AuraList& scAuras = caster->GetSingleCastAuras(); + for(AuraList::iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr) + { + if( (*itr)->GetTarget() != Aur->GetTarget() && + IsSingleTargetSpells((*itr)->GetSpellProto(),aurSpellInfo) ) + { + if ((*itr)->IsInUse()) + { + sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for IsSingleTargetSpell", (*itr)->GetId(), (*itr)->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex()); + continue; + } + (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex()); + restart = true; + break; + } + } + + if(!restart) + { + // done + scAuras.push_back(Aur); + break; + } + } + } + + // add aura, register in lists and arrays + Aur->_AddAura(); + m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur)); + if (Aur->GetModifier()->m_auraname < TOTAL_AURAS) + { + m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur); + } + + Aur->ApplyModifier(true,true); + sLog.outDebug("Aura %u now is in use", Aur->GetModifier()->m_auraname); + return true; +} + +void Unit::RemoveRankAurasDueToSpell(uint32 spellId) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if(!spellInfo) + return; + AuraMap::iterator i,next; + for (i = m_Auras.begin(); i != m_Auras.end(); i = next) + { + next = i; + ++next; + uint32 i_spellId = (*i).second->GetId(); + if((*i).second && i_spellId && i_spellId != spellId) + { + if(spellmgr.IsRankSpellDueToSpell(spellInfo,i_spellId)) + { + RemoveAurasDueToSpell(i_spellId); + + if( m_Auras.empty() ) + break; + else + next = m_Auras.begin(); + } + } + } +} + +bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur) +{ + if (!Aur) + return false; + + SpellEntry const* spellProto = Aur->GetSpellProto(); + if (!spellProto) + return false; + + uint32 spellId = Aur->GetId(); + uint32 effIndex = Aur->GetEffIndex(); + + SpellSpecific spellId_spec = GetSpellSpecific(spellId); + + AuraMap::iterator i,next; + for (i = m_Auras.begin(); i != m_Auras.end(); i = next) + { + next = i; + ++next; + if (!(*i).second) continue; + + SpellEntry const* i_spellProto = (*i).second->GetSpellProto(); + + if (!i_spellProto) + continue; + + uint32 i_spellId = i_spellProto->Id; + + if(IsPassiveSpell(i_spellId)) + { + if(IsPassiveStackableSpell(i_spellId)) + continue; + + // passive non-stackable spells not stackable only with another rank of same spell + if (!spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId)) + continue; + } + + uint32 i_effIndex = (*i).second->GetEffIndex(); + + if(i_spellId == spellId) continue; + + bool is_triggered_by_spell = false; + // prevent triggered aura of removing aura that triggered it + for(int j = 0; j < 3; ++j) + if (i_spellProto->EffectTriggerSpell[j] == spellProto->Id) + is_triggered_by_spell = true; + if (is_triggered_by_spell) continue; + + for(int j = 0; j < 3; ++j) + { + // prevent remove dummy triggered spells at next effect aura add + switch(spellProto->Effect[j]) // main spell auras added added after triggred spell + { + case SPELL_EFFECT_DUMMY: + switch(spellId) + { + case 5420: if(i_spellId==34123) is_triggered_by_spell = true; break; + } + break; + } + + if(is_triggered_by_spell) + break; + + // prevent remove form main spell by triggred passive spells + switch(i_spellProto->EffectApplyAuraName[j]) // main aura added before triggered spell + { + case SPELL_AURA_MOD_SHAPESHIFT: + switch(i_spellId) + { + case 24858: if(spellId==24905) is_triggered_by_spell = true; break; + case 33891: if(spellId==5420 || spellId==34123) is_triggered_by_spell = true; break; + case 34551: if(spellId==22688) is_triggered_by_spell = true; break; + } + break; + } + } + + if(!is_triggered_by_spell) + { + SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId); + + bool is_sspc = IsSingleFromSpellSpecificPerCaster(spellId_spec,i_spellId_spec); + + if( is_sspc && Aur->GetCasterGUID() == (*i).second->GetCasterGUID() ) + { + // cannot remove higher rank + if (spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId)) + if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0) + return false; + + // Its a parent aura (create this aura in ApplyModifier) + if ((*i).second->IsInUse()) + { + sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex()); + continue; + } + RemoveAurasDueToSpell(i_spellId); + + if( m_Auras.empty() ) + break; + else + next = m_Auras.begin(); + } + else if( !is_sspc && spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) ) + { + // Its a parent aura (create this aura in ApplyModifier) + if ((*i).second->IsInUse()) + { + sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex()); + continue; + } + RemoveAurasDueToSpell(i_spellId); + + if( m_Auras.empty() ) + break; + else + next = m_Auras.begin(); + } + // Potions stack aura by aura (elixirs/flask already checked) + else if( spellProto->SpellFamilyName == SPELLFAMILY_POTION && i_spellProto->SpellFamilyName == SPELLFAMILY_POTION ) + { + if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex)) + { + if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0) + return false; // cannot remove higher rank + + // Its a parent aura (create this aura in ApplyModifier) + if ((*i).second->IsInUse()) + { + sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex()); + continue; + } + RemoveAura(i); + next = i; + } + } + } + } + return true; +} + +void Unit::RemoveAura(uint32 spellId, uint32 effindex, Aura* except) +{ + spellEffectPair spair = spellEffectPair(spellId, effindex); + for(AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);) + { + if(iter->second!=except) + { + RemoveAura(iter); + iter = m_Auras.lower_bound(spair); + } + else + ++iter; + } +} + +void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler) +{ + for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) + { + Aura *aur = iter->second; + if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID) + { + // Custom dispel case + // Unstable Affliction + if (aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (aur->GetSpellProto()->SpellFamilyFlags & 0x010000000000LL)) + { + int32 damage = aur->GetModifier()->m_amount*9; + uint64 caster_guid = aur->GetCasterGUID(); + + // Remove aura + RemoveAura(iter, AURA_REMOVE_BY_DISPEL); + + // backfire damage and silence + dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL,caster_guid); + + iter = m_Auras.begin(); // iterator can be invalidate at cast if self-dispel + } + else + RemoveAura(iter, AURA_REMOVE_BY_DISPEL); + } + else + ++iter; + } +} + +void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer) +{ + for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) + { + Aura *aur = iter->second; + if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID) + { + int32 basePoints = aur->GetBasePoints(); + // construct the new aura for the attacker + Aura * new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), &basePoints, stealer); + if(!new_aur) + continue; + + // set its duration and maximum duration + // max duration 2 minutes (in msecs) + int32 dur = aur->GetAuraDuration(); + const int32 max_dur = 2*MINUTE*1000; + new_aur->SetAuraMaxDuration( max_dur > dur ? dur : max_dur ); + new_aur->SetAuraDuration( max_dur > dur ? dur : max_dur ); + + // add the new aura to stealer + stealer->AddAura(new_aur); + + // Remove aura as dispel + RemoveAura(iter, AURA_REMOVE_BY_DISPEL); + } + else + ++iter; + } +} + +void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId) +{ + for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) + { + if (iter->second->GetId() == spellId) + RemoveAura(iter, AURA_REMOVE_BY_CANCEL); + else + ++iter; + } +} + +void Unit::RemoveAurasWithDispelType( DispelType type ) +{ + // Create dispel mask by dispel type + uint32 dispelMask = GetDispellMask(type); + // Dispel all existing auras vs current dispell type + AuraMap& auras = GetAuras(); + for(AuraMap::iterator itr = auras.begin(); itr != auras.end(); ) + { + SpellEntry const* spell = itr->second->GetSpellProto(); + if( (1<Dispel) & dispelMask ) + { + // Dispel aura + RemoveAurasDueToSpell(spell->Id); + itr = auras.begin(); + } + else + ++itr; + } +} + +void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex) +{ + AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex)); + if(iter != m_Auras.end()) + RemoveAura(iter); +} + +void Unit::RemoveAurasDueToSpell(uint32 spellId, Aura* except) +{ + for (int i = 0; i < 3; ++i) + RemoveAura(spellId,i,except); +} + +void Unit::RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId) +{ + for (int k=0; k < 3; ++k) + { + spellEffectPair spair = spellEffectPair(spellId, k); + for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);) + { + if (iter->second->GetCastItemGUID() == castItem->GetGUID()) + { + RemoveAura(iter); + iter = m_Auras.upper_bound(spair); // overwrite by more appropriate + } + else + ++iter; + } + } +} + +void Unit::RemoveAurasWithInterruptFlags(uint32 flags) +{ + for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) + { + if (iter->second->GetSpellProto()->AuraInterruptFlags & flags) + RemoveAura(iter); + else + ++iter; + } +} + +void Unit::RemoveNotOwnSingleTargetAuras() +{ + // single target auras from other casters + for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) + { + if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto())) + RemoveAura(iter); + else + ++iter; + } + + // single target auras at other targets + AuraList& scAuras = GetSingleCastAuras(); + for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end(); ) + { + Aura* aura = *iter; + if (aura->GetTarget()!=this) + { + scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveAura + aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetEffIndex()); + iter = scAuras.begin(); + } + else + ++iter; + } + +} + +void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) +{ + if (IsSingleTargetSpell((*i).second->GetSpellProto())) + { + if(Unit* caster = (*i).second->GetCaster()) + { + AuraList& scAuras = caster->GetSingleCastAuras(); + scAuras.remove((*i).second); + } + else + { + sLog.outError("Couldn't find the caster of the single target aura, may crash later!"); + assert(false); + } + } + + if ((*i).second->GetModifier()->m_auraname < TOTAL_AURAS) + { + m_modAuras[(*i).second->GetModifier()->m_auraname].remove((*i).second); + } + + // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order) + Aura* Aur = i->second; + // Set remove mode + Aur->SetRemoveMode(mode); + // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura + // remove aura from list before to prevent deleting it before + m_Auras.erase(i); + ++m_removedAuras; // internal count used by unit update + + // Status unsummoned at aura remove + Totem* statue = NULL; + if(IsChanneledSpell(Aur->GetSpellProto())) + if(Unit* caster = Aur->GetCaster()) + if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE) + statue = ((Totem*)caster); + + sLog.outDebug("Aura %u now is remove mode %d",Aur->GetModifier()->m_auraname, mode); + Aur->ApplyModifier(false,true); + Aur->_RemoveAura(); + delete Aur; + + if(statue) + statue->UnSummon(); + + // only way correctly remove all auras from list + if( m_Auras.empty() ) + i = m_Auras.end(); + else + i = m_Auras.begin(); +} + +void Unit::RemoveAllAuras() +{ + while (!m_Auras.empty()) + { + AuraMap::iterator iter = m_Auras.begin(); + RemoveAura(iter); + } +} + +void Unit::RemoveAllAurasOnDeath() +{ + // used just after dieing to remove all visible auras + // and disable the mods for the passive ones + for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) + { + if (!iter->second->IsPassive() && !iter->second->IsDeathPersistent()) + RemoveAura(iter, AURA_REMOVE_BY_DEATH); + else + ++iter; + } +} + +void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime) +{ + AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex)); + if (iter != m_Auras.end()) + { + if (iter->second->GetAuraDuration() < delaytime) + iter->second->SetAuraDuration(0); + else + iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime); + iter->second->UpdateAuraDuration(); + sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration()); + } +} + +void Unit::_RemoveAllAuraMods() +{ + for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i) + { + (*i).second->ApplyModifier(false); + } +} + +void Unit::_ApplyAllAuraMods() +{ + for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i) + { + (*i).second->ApplyModifier(true); + } +} + +Aura* Unit::GetAura(uint32 spellId, uint32 effindex) +{ + AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex)); + if (iter != m_Auras.end()) + return iter->second; + return NULL; +} + +void Unit::AddDynObject(DynamicObject* dynObj) +{ + m_dynObjGUIDs.push_back(dynObj->GetGUID()); +} + +void Unit::RemoveDynObject(uint32 spellid) +{ + if(m_dynObjGUIDs.empty()) + return; + for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) + { + DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin()); + if(!dynObj) + { + i = m_dynObjGUIDs.erase(i); + } + else if(spellid == 0 || dynObj->GetSpellId() == spellid) + { + dynObj->Delete(); + i = m_dynObjGUIDs.erase(i); + } + else + ++i; + } +} + +void Unit::RemoveAllDynObjects() +{ + while(!m_dynObjGUIDs.empty()) + { + DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin()); + if(dynObj) + dynObj->Delete(); + m_dynObjGUIDs.erase(m_dynObjGUIDs.begin()); + } +} + +DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex) +{ + for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) + { + DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin()); + if(!dynObj) + { + i = m_dynObjGUIDs.erase(i); + continue; + } + + if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex) + return dynObj; + ++i; + } + return NULL; +} + +DynamicObject * Unit::GetDynObject(uint32 spellId) +{ + for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) + { + DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin()); + if(!dynObj) + { + i = m_dynObjGUIDs.erase(i); + continue; + } + + if (dynObj->GetSpellId() == spellId) + return dynObj; + ++i; + } + return NULL; +} + +void Unit::AddGameObject(GameObject* gameObj) +{ + assert(gameObj && gameObj->GetOwnerGUID()==0); + m_gameObj.push_back(gameObj); + gameObj->SetOwnerGUID(GetGUID()); +} + +void Unit::RemoveGameObject(GameObject* gameObj, bool del) +{ + assert(gameObj && gameObj->GetOwnerGUID()==GetGUID()); + + // GO created by some spell + if ( GetTypeId()==TYPEID_PLAYER && gameObj->GetSpellId() ) + { + SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId()); + // Need activate spell use for owner + if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) + ((Player*)this)->SendCooldownEvent(createBySpell); + } + gameObj->SetOwnerGUID(0); + m_gameObj.remove(gameObj); + if(del) + { + gameObj->SetRespawnTime(0); + gameObj->Delete(); + } +} + +void Unit::RemoveGameObject(uint32 spellid, bool del) +{ + if(m_gameObj.empty()) + return; + std::list::iterator i, next; + for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next) + { + next = i; + if(spellid == 0 || (*i)->GetSpellId() == spellid) + { + (*i)->SetOwnerGUID(0); + if(del) + { + (*i)->SetRespawnTime(0); + (*i)->Delete(); + } + + next = m_gameObj.erase(i); + } + else + ++next; + } +} + +void Unit::RemoveAllGameObjects() +{ + // remove references to unit + for(std::list::iterator i = m_gameObj.begin(); i != m_gameObj.end();) + { + (*i)->SetOwnerGUID(0); + (*i)->SetRespawnTime(0); + (*i)->Delete(); + i = m_gameObj.erase(i); + } +} + +void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit) +{ + sLog.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG"); + WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size + data.append(target->GetPackGUID()); + data.append(GetPackGUID()); + data << uint32(SpellID); + data << uint32(Damage-AbsorbedDamage-Resist-Blocked); + data << uint8(damageSchoolMask); // spell school + data << uint32(AbsorbedDamage); // AbsorbedDamage + data << uint32(Resist); // resist + data << uint8(PhysicalDamage); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name + data << uint8(0); // unk isFromAura + data << uint32(Blocked); // blocked + data << uint32(CriticalHit ? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster? + data << uint8(0); // isDebug? + SendMessageToSet( &data, true ); +} + +void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo) +{ + WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1)); + data << uint32(spellID); + data << uint64(GetGUID()); + data << uint8(0); // can be 0 or 1 + data << uint32(1); // target count + // for(i = 0; i < target count; ++i) + data << uint64(target->GetGUID()); // target GUID + data << uint8(missInfo); + // end loop + SendMessageToSet(&data, true); +} + +void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount) +{ + sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); + + WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size + data << (uint32)HitInfo; + data.append(GetPackGUID()); + data.append(target->GetPackGUID()); + data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); + + data << (uint8)SwingType; // count? + + // for(i = 0; i < SwingType; ++i) + data << (uint32)damageSchoolMask; + data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount); + // still need to double check damage + data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); + data << (uint32)AbsorbDamage; + data << (uint32)Resist; + // end loop + + data << (uint32)TargetState; + + if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens + data << (uint32)0; + else + data << (uint32)-1; + + data << (uint32)0; + data << (uint32)BlockedAmount; + + SendMessageToSet( &data, true ); +} + +void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType) +{ + sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim); + if(procSpell) + sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":"")); + + // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities + // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect + // That is the question though if it's fully correct + if(procSpell && !isTriggeredSpell) + { + if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE) + { + if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE; + if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE; + if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE; + if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE; + attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon + } + else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) + { + if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED; + if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED; + if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED; + if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED; + attType = RANGED_ATTACK; + } + } + if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL))) + procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH); + + // Not much to do if no flags are set. + if (procAttacker) + { + // procces auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set + ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcEffectAuraTypes,attType, procSpell, damage, damageSchoolMask); + ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcCastAuraTypes,attType, procSpell, damage, damageSchoolMask); + } + + // Now go on with a victim's events'n'auras + // Not much to do if no flags are set or there is no victim + if(pVictim && pVictim->isAlive() && procVictim) + { + // procces auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set + pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcEffectAuraTypes,attType,procSpell, damage, damageSchoolMask); + pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcCastAuraTypes,attType,procSpell, damage, damageSchoolMask); + } +} + +void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell) +{ + if(!pVictim) + return; + + uint32 procAttacker = PROC_FLAG_NONE; + uint32 procVictim = PROC_FLAG_NONE; + + switch(outcome) + { + case MELEE_HIT_EVADE: + return; + case MELEE_HIT_MISS: + if(attType == BASE_ATTACK || attType == OFF_ATTACK) + { + procAttacker = PROC_FLAG_MISS; + } + break; + case MELEE_HIT_BLOCK_CRIT: + case MELEE_HIT_CRIT: + if(spellCasted && attType == BASE_ATTACK) + { + procAttacker |= PROC_FLAG_CRIT_SPELL; + procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; + if ( outcome == MELEE_HIT_BLOCK_CRIT ) + { + procVictim |= PROC_FLAG_BLOCK; + procAttacker |= PROC_FLAG_TARGET_BLOCK; + } + } + else if(attType == BASE_ATTACK || attType == OFF_ATTACK) + { + procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE; + procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE; + } + else + { + procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED; + procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED; + } + break; + case MELEE_HIT_PARRY: + procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY; + procVictim = PROC_FLAG_PARRY; + break; + case MELEE_HIT_BLOCK: + procAttacker = PROC_FLAG_TARGET_BLOCK; + procVictim = PROC_FLAG_BLOCK; + break; + case MELEE_HIT_DODGE: + procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY; + procVictim = PROC_FLAG_DODGE; + break; + case MELEE_HIT_CRUSHING: + if(attType == BASE_ATTACK || attType == OFF_ATTACK) + { + procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE; + procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE; + } + else + { + procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED; + procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED; + } + break; + default: + if(attType == BASE_ATTACK || attType == OFF_ATTACK) + { + procAttacker = PROC_FLAG_HIT_MELEE; + procVictim = PROC_FLAG_STRUCK_MELEE; + } + else + { + procAttacker = PROC_FLAG_HIT_RANGED; + procVictim = PROC_FLAG_STRUCK_RANGED; + } + break; + } + + if(damage > 0) + procVictim |= PROC_FLAG_TAKE_DAMAGE; + + if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE) + ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType); +} + +bool Unit::HandleHasteAuraProc(Unit *pVictim, SpellEntry const *hasteSpell, uint32 /*effIndex*/, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 cooldown) +{ + Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER + ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; + + uint32 triggered_spell_id = 0; + Unit* target = pVictim; + int32 basepoints0 = 0; + + switch(hasteSpell->SpellFamilyName) + { + case SPELLFAMILY_ROGUE: + { + switch(hasteSpell->Id) + { + // Blade Flurry + case 13877: + case 33735: + { + target = SelectNearbyTarget(); + if(!target) + return false; + basepoints0 = damage; + triggered_spell_id = 22482; + break; + } + } + break; + } + } + + // processed charge only counting case + if(!triggered_spell_id) + return true; + + SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); + + if(!triggerEntry) + { + sLog.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell->Id,triggered_spell_id); + return false; + } + + // default case + if(!target || target!=this && !target->isAlive()) + return false; + + if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) + return false; + + if(basepoints0) + CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + else + CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); + + if( cooldown && GetTypeId()==TYPEID_PLAYER ) + ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); + + return true; +} + +bool Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown) +{ + Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER + ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; + + uint32 triggered_spell_id = 0; + Unit* target = pVictim; + int32 basepoints0 = 0; + + switch(dummySpell->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + switch (dummySpell->Id) + { + // Eye of Eye + case 9799: + case 25988: + { + // prevent damage back from weapon special attacks + if (!procSpell || procSpell->DmgClass != SPELL_DAMAGE_CLASS_MAGIC ) + return false; + + // return damage % to attacker but < 50% own total health + basepoints0 = triggeredByAura->GetModifier()->m_amount*int32(damage)/100; + if(basepoints0 > GetMaxHealth()/2) + basepoints0 = GetMaxHealth()/2; + + triggered_spell_id = 25997; + break; + } + // Sweeping Strikes + case 12328: + case 18765: + case 35429: + { + // prevent chain of triggred spell from same triggred spell + if(procSpell && procSpell->Id==26654) + return false; + + target = SelectNearbyTarget(); + if(!target) + return false; + + triggered_spell_id = 26654; + break; + } + // Unstable Power + case 24658: + { + if (!procSpell || procSpell->Id == 24659) + return false; + // Need remove one 24659 aura + RemoveSingleAuraFromStack(24659, 0); + RemoveSingleAuraFromStack(24659, 1); + return true; + } + // Restless Strength + case 24661: + { + // Need remove one 24662 aura + RemoveSingleAuraFromStack(24662, 0); + return true; + } + // Adaptive Warding (Frostfire Regalia set) + case 28764: + { + if(!procSpell) + return false; + + // find Mage Armor + bool found = false; + AuraList const& mRegenInterupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT); + for(AuraList::const_iterator iter = mRegenInterupt.begin(); iter != mRegenInterupt.end(); ++iter) + { + if(SpellEntry const* iterSpellProto = (*iter)->GetSpellProto()) + { + if(iterSpellProto->SpellFamilyName==SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags & 0x10000000)) + { + found=true; + break; + } + } + } + if(!found) + return false; + + switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) + { + case SPELL_SCHOOL_NORMAL: + case SPELL_SCHOOL_HOLY: + return false; // ignored + case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break; + case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break; + case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break; + case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break; + case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break; + default: + return false; + } + + target = this; + break; + } + // Obsidian Armor (Justice Bearer`s Pauldrons shoulder) + case 27539: + { + if(!procSpell) + return false; + + // not from DoT + bool found = false; + for(int j = 0; j < 3; ++j) + { + if(procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE||procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT) + { + found = true; + break; + } + } + if(found) + return false; + + switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) + { + case SPELL_SCHOOL_NORMAL: + return false; // ignore + case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break; + case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break; + case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break; + case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break; + case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break; + case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break; + default: + return false; + } + + target = this; + break; + } + // Mana Leech (Passive) (Priest Pet Aura) + case 28305: + { + // Cast on owner + target = GetOwner(); + if(!target) + return false; + + basepoints0 = int32(damage * 2.5f); // manaregen + triggered_spell_id = 34650; + break; + } + // Mark of Malice + case 33493: + { + // Cast finish spell at last charge + if (triggeredByAura->m_procCharges > 1) + return false; + + target = this; + triggered_spell_id = 33494; + break; + } + // Twisted Reflection (boss spell) + case 21063: + triggered_spell_id = 21064; + break; + // Vampiric Aura (boss spell) + case 38196: + { + basepoints0 = 3 * damage; // 300% + if (basepoints0 < 0) + return false; + + triggered_spell_id = 31285; + target = this; + break; + } + // Aura of Madness (Darkmoon Card: Madness trinket) + //===================================================== + // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior) + // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid) + // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid) + // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin) + // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes) + // 41005 Manic: +35 haste (spell, melee and ranged) (All classes) + // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter) + // 41011 Martyr Complex: +35 stamina (All classes) + // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) + // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) + case 39446: + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // Select class defined buff + switch (getClass()) + { + case CLASS_PALADIN: // 39511,40997,40998,40999,41002,41005,41009,41011,41409 + case CLASS_DRUID: // 39511,40997,40998,40999,41002,41005,41009,41011,41409 + { + uint32 RandomSpell[]={39511,40997,40998,40999,41002,41005,41009,41011,41409}; + triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; + break; + } + case CLASS_ROGUE: // 39511,40997,40998,41002,41005,41011 + case CLASS_WARRIOR: // 39511,40997,40998,41002,41005,41011 + { + uint32 RandomSpell[]={39511,40997,40998,41002,41005,41011}; + triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; + break; + } + case CLASS_PRIEST: // 40999,41002,41005,41009,41011,41406,41409 + case CLASS_SHAMAN: // 40999,41002,41005,41009,41011,41406,41409 + case CLASS_MAGE: // 40999,41002,41005,41009,41011,41406,41409 + case CLASS_WARLOCK: // 40999,41002,41005,41009,41011,41406,41409 + { + uint32 RandomSpell[]={40999,41002,41005,41009,41011,41406,41409}; + triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; + break; + } + case CLASS_HUNTER: // 40997,40999,41002,41005,41009,41011,41406,41409 + { + uint32 RandomSpell[]={40997,40999,41002,41005,41009,41011,41406,41409}; + triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; + break; + } + default: + return false; + } + + target = this; + if (roll_chance_i(10)) + ((Player*)this)->Say("This is Madness!", LANG_UNIVERSAL); + break; + } + /* + // TODO: need find item for aura and triggered spells + // Sunwell Exalted Caster Neck (??? neck) + // cast ??? Light's Wrath if Exalted by Aldor + // cast ??? Arcane Bolt if Exalted by Scryers*/ + case 46569: + return false; // disable for while + /* + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = ??? + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = ??? + break; + } + return false; + }/**/ + // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck) + // cast 45479 Light's Wrath if Exalted by Aldor + // cast 45429 Arcane Bolt if Exalted by Scryers + case 45481: + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45479; + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = 45429; + break; + } + return false; + } + // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck) + // cast 45480 Light's Strength if Exalted by Aldor + // cast 45428 Arcane Strike if Exalted by Scryers + case 45482: + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45480; + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = 45428; + break; + } + return false; + } + // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck) + // cast 45431 Arcane Insight if Exalted by Aldor + // cast 45432 Light's Ward if Exalted by Scryers + case 45483: + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45432; + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45431; + break; + } + return false; + } + // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck) + // cast 45478 Light's Salvation if Exalted by Aldor + // cast 45430 Arcane Surge if Exalted by Scryers + case 45484: + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45478; + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = 45430; + break; + } + return false; + } + } + break; + } + case SPELLFAMILY_MAGE: + { + // Magic Absorption + if (dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura + { + if (getPowerType() != POWER_MANA) + return false; + + // mana reward + basepoints0 = (triggeredByAura->GetModifier()->m_amount * GetMaxPower(POWER_MANA) / 100); + target = this; + triggered_spell_id = 29442; + break; + } + // Master of Elements + if (dummySpell->SpellIconID == 1920) + { + if(!procSpell) + return false; + + // mana cost save + basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; + if( basepoints0 <=0 ) + return false; + + target = this; + triggered_spell_id = 29077; + break; + } + switch(dummySpell->Id) + { + // Ignite + case 11119: + case 11120: + case 12846: + case 12847: + case 12848: + { + switch (dummySpell->Id) + { + case 11119: basepoints0 = int32(0.04f*damage); break; + case 11120: basepoints0 = int32(0.08f*damage); break; + case 12846: basepoints0 = int32(0.12f*damage); break; + case 12847: basepoints0 = int32(0.16f*damage); break; + case 12848: basepoints0 = int32(0.20f*damage); break; + default: + sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id); + return false; + } + + triggered_spell_id = 12654; + break; + } + // Combustion + case 11129: + { + //last charge and crit + if( triggeredByAura->m_procCharges <= 1 && (procFlag & PROC_FLAG_CRIT_SPELL) ) + { + RemoveAurasDueToSpell(28682); //-> remove Combustion auras + return true; // charge counting (will removed) + } + + CastSpell(this, 28682, true, castItem, triggeredByAura); + return(procFlag & PROC_FLAG_CRIT_SPELL);// charge update only at crit hits, no hidden cooldowns + } + } + break; + } + case SPELLFAMILY_WARRIOR: + { + // Retaliation + if(dummySpell->SpellFamilyFlags==0x0000000800000000LL) + { + // check attack comes not from behind + if (!HasInArc(M_PI, pVictim)) + return false; + + triggered_spell_id = 22858; + break; + } + break; + } + case SPELLFAMILY_WARLOCK: + { + // Seed of Corruption + if (dummySpell->SpellFamilyFlags & 0x0000001000000000LL) + { + Modifier* mod = triggeredByAura->GetModifier(); + // if damage is more than need or target die from damage deal finish spell + // FIX ME: not triggered currently at death + if( mod->m_amount <= damage || GetHealth() <= damage ) + { + // remember guid before aura delete + uint64 casterGuid = triggeredByAura->GetCasterGUID(); + + // Remove aura (before cast for prevent infinite loop handlers) + RemoveAurasDueToSpell(triggeredByAura->GetId()); + + // Cast finish spell (triggeredByAura already not exist!) + CastSpell(this, 27285, true, castItem, NULL, casterGuid); + return true; // no hidden cooldown + } + + // Damage counting + mod->m_amount-=damage; + return true; + } + // Seed of Corruption (Mobs cast) - no die req + if (dummySpell->SpellFamilyFlags == 0x00LL && dummySpell->SpellIconID == 1932) + { + Modifier* mod = triggeredByAura->GetModifier(); + // if damage is more than need deal finish spell + if( mod->m_amount <= damage ) + { + // remember guid before aura delete + uint64 casterGuid = triggeredByAura->GetCasterGUID(); + + // Remove aura (before cast for prevent infinite loop handlers) + RemoveAurasDueToSpell(triggeredByAura->GetId()); + + // Cast finish spell (triggeredByAura already not exist!) + CastSpell(this, 32865, true, castItem, NULL, casterGuid); + return true; // no hidden cooldown + } + // Damage counting + mod->m_amount-=damage; + return true; + } + switch(dummySpell->Id) + { + // Nightfall + case 18094: + case 18095: + { + target = this; + triggered_spell_id = 17941; + break; + } + //Soul Leech + case 30293: + case 30295: + case 30296: + { + // health + basepoints0 = int32(damage*triggeredByAura->GetModifier()->m_amount/100); + target = this; + triggered_spell_id = 30294; + break; + } + // Shadowflame (Voidheart Raiment set bonus) + case 37377: + { + triggered_spell_id = 37379; + break; + } + // Pet Healing (Corruptor Raiment or Rift Stalker Armor) + case 37381: + { + target = GetPet(); + if(!target) + return false; + + // heal amount + basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100; + triggered_spell_id = 37382; + break; + } + // Shadowflame Hellfire (Voidheart Raiment set bonus) + case 39437: + { + triggered_spell_id = 37378; + break; + } + } + break; + } + case SPELLFAMILY_PRIEST: + { + // Vampiric Touch + if( dummySpell->SpellFamilyFlags & 0x0000040000000000LL ) + { + if(!pVictim || !pVictim->isAlive()) + return false; + + // pVictim is caster of aura + if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID()) + return false; + + // energize amount + basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + pVictim->CastCustomSpell(pVictim,34919,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + return true; // no hidden cooldown + } + switch(dummySpell->Id) + { + // Vampiric Embrace + case 15286: + { + if(!pVictim || !pVictim->isAlive()) + return false; + + // pVictim is caster of aura + if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID()) + return false; + + // heal amount + basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + pVictim->CastCustomSpell(pVictim,15290,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + return true; // no hidden cooldown + } + // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen) + case 40438: + { + // Shadow Word: Pain + if( procSpell->SpellFamilyFlags & 0x0000000000008000LL ) + triggered_spell_id = 40441; + // Renew + else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL ) + triggered_spell_id = 40440; + else + return false; + + target = this; + break; + } + // Oracle Healing Bonus ("Garments of the Oracle" set) + case 26169: + { + // heal amount + basepoints0 = int32(damage * 10/100); + target = this; + triggered_spell_id = 26170; + break; + } + // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set + case 39372: + { + if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW))==0 ) + return false; + + // heal amount + basepoints0 = int32(damage * 2 / 100); + target = this; + triggered_spell_id = 39373; + break; + } + // Vestments of Faith (Priest Tier 3) - 4 pieces bonus + case 28809: + { + triggered_spell_id = 28810; + break; + } + } + break; + } + case SPELLFAMILY_DRUID: + { + switch(dummySpell->Id) + { + // Healing Touch (Dreamwalker Raiment set) + case 28719: + { + // mana back + basepoints0 = int32(procSpell->manaCost * 30 / 100); + target = this; + triggered_spell_id = 28742; + break; + } + // Healing Touch Refund (Idol of Longevity trinket) + case 28847: + { + target = this; + triggered_spell_id = 28848; + break; + } + // Mana Restore (Malorne Raiment set / Malorne Regalia set) + case 37288: + case 37295: + { + target = this; + triggered_spell_id = 37238; + break; + } + // Druid Tier 6 Trinket + case 40442: + { + float chance; + + // Starfire + if( procSpell->SpellFamilyFlags & 0x0000000000000004LL ) + { + triggered_spell_id = 40445; + chance = 25.f; + } + // Rejuvenation + else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL ) + { + triggered_spell_id = 40446; + chance = 25.f; + } + // Mangle (cat/bear) + else if( procSpell->SpellFamilyFlags & 0x0000044000000000LL ) + { + triggered_spell_id = 40452; + chance = 40.f; + } + else + return false; + + if (!roll_chance_f(chance)) + return false; + + target = this; + break; + } + // Maim Interrupt + case 44835: + { + // Deadly Interrupt Effect + triggered_spell_id = 32747; + break; + } + } + break; + } + case SPELLFAMILY_ROGUE: + { + switch(dummySpell->Id) + { + // Deadly Throw Interrupt + case 32748: + { + // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw + if(this == pVictim) + return false; + + triggered_spell_id = 32747; + break; + } + } + // Quick Recovery + if( dummySpell->SpellIconID == 2116 ) + { + if(!procSpell) + return false; + + // only rogue's finishing moves (maybe need additional checks) + if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE || + (procSpell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE) == 0) + return false; + + // energy cost save + basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; + if(basepoints0 <= 0) + return false; + + target = this; + triggered_spell_id = 31663; + break; + } + break; + } + case SPELLFAMILY_HUNTER: + { + // Thrill of the Hunt + if ( dummySpell->SpellIconID == 2236 ) + { + if(!procSpell) + return false; + + // mana cost save + basepoints0 = procSpell->manaCost * 40/100; + if(basepoints0 <= 0) + return false; + + target = this; + triggered_spell_id = 34720; + break; + } + break; + } + case SPELLFAMILY_PALADIN: + { + // Seal of Righteousness - melee proc dummy + if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggeredByAura->GetEffIndex()==0) + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + uint32 spellId; + switch (triggeredByAura->GetId()) + { + case 21084: spellId = 25742; break; // Rank 1 + case 20287: spellId = 25740; break; // Rank 2 + case 20288: spellId = 25739; break; // Rank 3 + case 20289: spellId = 25738; break; // Rank 4 + case 20290: spellId = 25737; break; // Rank 5 + case 20291: spellId = 25736; break; // Rank 6 + case 20292: spellId = 25735; break; // Rank 7 + case 20293: spellId = 25713; break; // Rank 8 + case 27155: spellId = 27156; break; // Rank 9 + default: + sLog.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura->GetId()); + return false; + } + Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + float speed = (item ? item->GetProto()->Delay : BASE_ATTACK_TIME)/1000.0f; + + float damageBasePoints; + if(item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON) + // two hand weapon + damageBasePoints=1.20f*triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f + 1; + else + // one hand weapon/no weapon + damageBasePoints=0.85f*ceil(triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f) - 1; + + int32 damagePoint = int32(damageBasePoints + 0.03f * (GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE)+GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE))/2.0f) + 1; + + // apply damage bonuses manually + if(damagePoint >= 0) + damagePoint = SpellDamageBonus(pVictim, dummySpell, damagePoint, SPELL_DIRECT_DAMAGE); + + CastCustomSpell(pVictim,spellId,&damagePoint,NULL,NULL,true,NULL, triggeredByAura); + return true; // no hidden cooldown + } + // Seal of Blood do damage trigger + if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL) + { + switch(triggeredByAura->GetEffIndex()) + { + case 0: + // prevent chain triggering + if(procSpell && procSpell->Id==31893 ) + return false; + + triggered_spell_id = 31893; + break; + case 1: + { + // damage + basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + target = this; + triggered_spell_id = 32221; + break; + } + } + } + + switch(dummySpell->Id) + { + // Holy Power (Redemption Armor set) + case 28789: + { + if(!pVictim) + return false; + + // Set class defined buff + switch (pVictim->getClass()) + { + case CLASS_PALADIN: + case CLASS_PRIEST: + case CLASS_SHAMAN: + case CLASS_DRUID: + triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d. + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d. + break; + case CLASS_WARRIOR: + triggered_spell_id = 28790; // Increases the friendly target's armor + break; + default: + return false; + } + break; + } + //Seal of Vengeance + case 31801: + { + if(effIndex != 0) // effect 1,2 used by seal unleashing code + return false; + + triggered_spell_id = 31803; + break; + } + // Spiritual Att. + case 31785: + case 33776: + { + // if healed by another unit (pVictim) + if(this == pVictim) + return false; + + // heal amount + basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + target = this; + triggered_spell_id = 31786; + break; + } + // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) + case 40470: + { + if( !procSpell ) + return false; + + float chance; + + // Flash of light/Holy light + if( procSpell->SpellFamilyFlags & 0x00000000C0000000LL) + { + triggered_spell_id = 40471; + chance = 15.f; + } + // Judgement + else if( procSpell->SpellFamilyFlags & 0x0000000000800000LL ) + { + triggered_spell_id = 40472; + chance = 50.f; + } + else + return false; + + if (!roll_chance_f(chance)) + return false; + + break; + } + } + break; + } + case SPELLFAMILY_SHAMAN: + { + switch(dummySpell->Id) + { + // Totemic Power (The Earthshatterer set) + case 28823: + { + if( !pVictim ) + return false; + + // Set class defined buff + switch (pVictim->getClass()) + { + case CLASS_PALADIN: + case CLASS_PRIEST: + case CLASS_SHAMAN: + case CLASS_DRUID: + triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d. + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d. + break; + case CLASS_WARRIOR: + triggered_spell_id = 28827; // Increases the friendly target's armor + break; + default: + return false; + } + break; + } + // Lesser Healing Wave (Totem of Flowing Water Relic) + case 28849: + { + target = this; + triggered_spell_id = 28850; + break; + } + // Windfury Weapon (Passive) 1-5 Ranks + case 33757: + { + if(GetTypeId()!=TYPEID_PLAYER) + return false; + + if(!castItem || !castItem->IsEquipped()) + return false; + + // custom cooldown processing case + if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) + return false; + + uint32 spellId; + switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT))) + { + case 283: spellId = 33757; break; //1 Rank + case 284: spellId = 33756; break; //2 Rank + case 525: spellId = 33755; break; //3 Rank + case 1669:spellId = 33754; break; //4 Rank + case 2636:spellId = 33727; break; //5 Rank + default: + { + sLog.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)", + castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)),dummySpell->Id); + return false; + } + } + + SpellEntry const* windfurySpellEntry = sSpellStore.LookupEntry(spellId); + if(!windfurySpellEntry) + { + sLog.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId); + return false; + } + + int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry,0,windfurySpellEntry->EffectBasePoints[0],pVictim); + + // Off-Hand case + if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND ) + { + // Value gained from additional AP + basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2); + triggered_spell_id = 33750; + } + // Main-Hand case + else + { + // Value gained from additional AP + basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000); + triggered_spell_id = 25504; + } + + // apply cooldown before cast to prevent processing itself + if( cooldown ) + ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); + + // Attack Twice + for ( uint32 i = 0; i<2; ++i ) + CastCustomSpell(pVictim,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + + return true; + } + // Shaman Tier 6 Trinket + case 40463: + { + if( !procSpell ) + return false; + + float chance; + if (procSpell->SpellFamilyFlags & 0x0000000000000001LL) + { + triggered_spell_id = 40465; // Lightning Bolt + chance = 15.f; + } + else if (procSpell->SpellFamilyFlags & 0x0000000000000080LL) + { + triggered_spell_id = 40465; // Lesser Healing Wave + chance = 10.f; + } + else if (procSpell->SpellFamilyFlags & 0x0000001000000000LL) + { + triggered_spell_id = 40466; // Stormstrike + chance = 50.f; + } + else + return false; + + if (!roll_chance_f(chance)) + return false; + + target = this; + break; + } + } + + // Earth Shield + if(dummySpell->SpellFamilyFlags==0x40000000000LL) + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // heal + basepoints0 = triggeredByAura->GetModifier()->m_amount; + target = this; + triggered_spell_id = 379; + break; + } + // Lightning Overload + if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura + { + if(!procSpell || GetTypeId() != TYPEID_PLAYER || !pVictim ) + return false; + + // custom cooldown processing case + if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) + return false; + + uint32 spellId = 0; + // Every Lightning Bolt and Chain Lightning spell have dublicate vs half damage and zero cost + switch (procSpell->Id) + { + // Lightning Bolt + case 403: spellId = 45284; break; // Rank 1 + case 529: spellId = 45286; break; // Rank 2 + case 548: spellId = 45287; break; // Rank 3 + case 915: spellId = 45288; break; // Rank 4 + case 943: spellId = 45289; break; // Rank 5 + case 6041: spellId = 45290; break; // Rank 6 + case 10391: spellId = 45291; break; // Rank 7 + case 10392: spellId = 45292; break; // Rank 8 + case 15207: spellId = 45293; break; // Rank 9 + case 15208: spellId = 45294; break; // Rank 10 + case 25448: spellId = 45295; break; // Rank 11 + case 25449: spellId = 45296; break; // Rank 12 + // Chain Lightning + case 421: spellId = 45297; break; // Rank 1 + case 930: spellId = 45298; break; // Rank 2 + case 2860: spellId = 45299; break; // Rank 3 + case 10605: spellId = 45300; break; // Rank 4 + case 25439: spellId = 45301; break; // Rank 5 + case 25442: spellId = 45302; break; // Rank 6 + default: + sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id); + return false; + } + // No thread generated mod + SpellModifier *mod = new SpellModifier; + mod->op = SPELLMOD_THREAT; + mod->value = -100; + mod->type = SPELLMOD_PCT; + mod->spellId = dummySpell->Id; + mod->effectId = 0; + mod->lastAffected = NULL; + mod->mask = 0x0000000000000003LL; + mod->charges = 0; + ((Player*)this)->AddSpellMod(mod, true); + + // Remove cooldown (Chain Lightning - have Category Recovery time) + if (procSpell->SpellFamilyFlags & 0x0000000000000002LL) + ((Player*)this)->RemoveSpellCooldown(spellId); + + // Hmmm.. in most case spells alredy set half basepoints but... + // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level + // As on wiki: + // BUG: Rank 2 to 10 (and maybe 11) of Lightning Bolt will proc another Bolt with FULL damage (not halved). This bug is known and will probably be fixed soon. + // So - no add changes :) + CastSpell(pVictim, spellId, true, castItem, triggeredByAura); + + ((Player*)this)->AddSpellMod(mod, false); + + if( cooldown && GetTypeId()==TYPEID_PLAYER ) + ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); + + return true; + } + break; + } + default: + break; + } + + // processed charge only counting case + if(!triggered_spell_id) + return true; + + SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); + + if(!triggerEntry) + { + sLog.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id); + return false; + } + + // default case + if(!target || target!=this && !target->isAlive()) + return false; + + if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) + return false; + + if(basepoints0) + CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + else + CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); + + if( cooldown && GetTypeId()==TYPEID_PLAYER ) + ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); + + return true; +} + +bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attackType, uint32 cooldown) +{ + SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto(); + + Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER + ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; + + uint32 triggered_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()]; + Unit* target = !(procFlags & PROC_FLAG_HEAL) && IsPositiveSpell(triggered_spell_id) ? this : pVictim; + int32 basepoints0 = 0; + + switch(auraSpellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + switch(auraSpellInfo->Id) + { + // Aegis of Preservation + case 23780: + //Aegis Heal (instead non-existed triggered spell) + triggered_spell_id = 23781; + target = this; + break; + // Elune's Touch (moonkin mana restore) + case 24905: + { + // Elune's Touch (instead non-existed triggered spell) + triggered_spell_id = 33926; + basepoints0 = int32(0.3f * GetTotalAttackPowerValue(BASE_ATTACK)); + target = this; + break; + } + // Enlightenment + case 29601: + { + // only for cast with mana price + if(!procSpell || procSpell->powerType!=POWER_MANA || procSpell->manaCost==0 && procSpell->ManaCostPercentage==0 && procSpell->manaCostPerlevel==0) + return false; + break; // fall through to normal cast + } + // Health Restore + case 33510: + { + // at melee hit call std triggered spell + if(procFlags & PROC_FLAG_HIT_MELEE) + break; // fall through to normal cast + + // Mark of Conquest - else (at range hit) called custom case + triggered_spell_id = 39557; + target = this; + break; + } + // Shaleskin + case 36576: + return true; // nothing to do + // Forgotten Knowledge (Blade of Wizardry) + case 38319: + // only for harmful enemy targeted spell + if(!pVictim || pVictim==this || !procSpell || IsPositiveSpell(procSpell->Id)) + return false; + break; // fall through to normal cast + // Aura of Wrath (Darkmoon Card: Wrath trinket bonus) + case 39442: + { + // proc only at non-crit hits + if(procFlags & (PROC_FLAG_CRIT_MELEE|PROC_FLAG_CRIT_RANGED|PROC_FLAG_CRIT_SPELL)) + return false; + break; // fall through to normal cast + } + // Augment Pain (Timbal's Focusing Crystal trinket bonus) + case 45054: + { + if(!procSpell) + return false; + + //only periodic damage can trigger spell + bool found = false; + for(int j = 0; j < 3; ++j) + { + if( procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE || + procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT || + procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_LEECH ) + { + found = true; + break; + } + } + if(!found) + return false; + + break; // fall through to normal cast + } + // Evasive Maneuvers (Commendation of Kael'thas) + case 45057: + { + // damage taken that reduces below 35% health + // does NOT mean you must have been >= 35% before + if (int32(GetHealth())-int32(damage) >= int32(GetMaxHealth()*0.35f)) + return false; + break; // fall through to normal cast + } + } + + switch(triggered_spell_id) + { + // Setup + case 15250: + { + // applied only for main target + if(!pVictim || pVictim != getVictim()) + return false; + + // continue normal case + break; + } + // Shamanistic Rage triggered spell + case 30824: + basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100); + break; + } + break; + } + case SPELLFAMILY_MAGE: + { + switch(auraSpellInfo->SpellIconID) + { + // Blazing Speed + case 2127: + //Blazing Speed (instead non-existed triggered spell) + triggered_spell_id = 31643; + target = this; + break; + } + switch(auraSpellInfo->Id) + { + // Persistent Shield (Scarab Brooch) + case 26467: + basepoints0 = int32(damage * 0.15f); + break; + } + break; + } + case SPELLFAMILY_WARRIOR: + { + //Rampage + if((auraSpellInfo->SpellFamilyFlags & 0x100000) && auraSpellInfo->SpellIconID==2006) + { + //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed) + //and effect[1]==TriggerSpell + if(auraSpellInfo->Effect[1]!=SPELL_EFFECT_TRIGGER_SPELL) + { + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura->GetSpellProto()->Id); + return false; + } + triggered_spell_id = auraSpellInfo->EffectTriggerSpell[1]; + break; // fall through to normal cast + } + break; + } + case SPELLFAMILY_WARLOCK: + { + // Pyroclasm + if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000 && auraSpellInfo->SpellIconID==1137) + { + // last case for Hellfire that damage caster also but don't must stun caster + if( pVictim == this ) + return false; + + // custom chnace + float chance = 0; + switch (triggeredByAura->GetId()) + { + case 18096: chance = 13.0f; break; + case 18073: chance = 26.0f; break; + } + if (!roll_chance_f(chance)) + return false; + + // Pyroclasm (instead non-existed triggered spell) + triggered_spell_id = 18093; + target = pVictim; + break; + } + // Drain Soul + if(auraSpellInfo->SpellFamilyFlags & 0x0000000000004000) + { + bool found = false; + Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER); + for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i) + { + //Improved Drain Soul + if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113) + { + int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this); + basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100; + + // Drain Soul + triggered_spell_id = 18371; + target = this; + found = true; + break; + } + } + if(!found) + return false; + break; // fall through to normal cast + } + break; + } + case SPELLFAMILY_PRIEST: + { + //Blessed Recovery + if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL && auraSpellInfo->SpellIconID==1875) + { + switch (triggeredByAura->GetSpellProto()->Id) + { + case 27811: triggered_spell_id = 27813; break; + case 27815: triggered_spell_id = 27817; break; + case 27816: triggered_spell_id = 27818; break; + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id); + return false; + } + + int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100; + basepoints0 = heal_amount/3; + target = this; + break; + } + // Shadowguard + if((auraSpellInfo->SpellFamilyFlags & 0x80000000LL) && auraSpellInfo->SpellVisual==7958) + { + switch(triggeredByAura->GetSpellProto()->Id) + { + case 18137: + triggered_spell_id = 28377; break; // Rank 1 + case 19308: + triggered_spell_id = 28378; break; // Rank 2 + case 19309: + triggered_spell_id = 28379; break; // Rank 3 + case 19310: + triggered_spell_id = 28380; break; // Rank 4 + case 19311: + triggered_spell_id = 28381; break; // Rank 5 + case 19312: + triggered_spell_id = 28382; break; // Rank 6 + case 25477: + triggered_spell_id = 28385; break; // Rank 7 + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id); + return false; + } + target = pVictim; + break; + } + break; + } + case SPELLFAMILY_DRUID: + { + switch(auraSpellInfo->Id) + { + // Leader of the Pack (triggering Improved Leader of the Pack heal) + case 24932: + { + if (triggeredByAura->GetModifier()->m_amount == 0) + return false; + basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; + triggered_spell_id = 34299; + break; + }; + // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form) + case 37336: + { + switch(m_form) + { + case FORM_BEAR: + case FORM_DIREBEAR: + triggered_spell_id=37340; break;// Ursine Blessing + case FORM_CAT: + triggered_spell_id=37341; break;// Feline Blessing + case FORM_TREE: + triggered_spell_id=37342; break;// Slyvan Blessing + case FORM_MOONKIN: + triggered_spell_id=37343; break;// Lunar Blessing + case FORM_NONE: + triggered_spell_id=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN) + default: + return false; + } + + target = this; + break; + } + } + break; + } + case SPELLFAMILY_ROGUE: + { + if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000LL) + { + switch(auraSpellInfo->SpellIconID) + { + // Combat Potency + case 2260: + { + // skip non offhand attacks + if(attackType!=OFF_ATTACK) + return false; + break; // fall through to normal cast + } + } + } + break; + } + case SPELLFAMILY_PALADIN: + { + if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL) + { + switch(auraSpellInfo->Id) + { + // Lightning Capacitor + case 37657: + { + // trinket ProcTriggerSpell but for safe checks for player + if(!castItem || !pVictim || !pVictim->isAlive() || GetTypeId()!=TYPEID_PLAYER) + return false; + + if(((Player*)this)->HasSpellCooldown(37657)) + return false; + + // stacking + CastSpell(this, 37658, true, castItem, triggeredByAura); + // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown + ((Player*)this)->AddSpellCooldown(37657,0,time(NULL)+(roll_chance_i(50) ? 2 : 3)); + + // counting + uint32 count = 0; + AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr) + if((*itr)->GetId()==37658) + ++count; + + // release at 3 aura in stack + if(count <= 2) + return true; // main triggered spell casted anyway + + RemoveAurasDueToSpell(37658); + CastSpell(pVictim, 37661, true, castItem, triggeredByAura); + return true; + } + // Healing Discount + case 37705: + // Healing Trance (instead non-existed triggered spell) + triggered_spell_id = 37706; + target = this; + break; + // HoTs on Heals (Fel Reaver's Piston trinket) + case 38299: + { + // at direct heal effect + if(!procSpell || !IsSpellHaveEffect(procSpell,SPELL_EFFECT_HEAL)) + return false; + + // single proc at time + AuraList const& scAuras = GetSingleCastAuras(); + for(AuraList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr) + if((*itr)->GetId()==triggered_spell_id) + return false; + + // positive cast at victim instead self + target = pVictim; + break; + } + } + switch(auraSpellInfo->SpellIconID) + { + case 241: + { + switch(auraSpellInfo->EffectTriggerSpell[0]) + { + //Illumination + case 18350: + { + if(!procSpell) + return false; + + // procspell is triggered spell but we need mana cost of original casted spell + uint32 originalSpellId = procSpell->Id; + + // Holy Shock + if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN) + { + if(procSpell->SpellFamilyFlags & 0x0001000000000000LL) + { + switch(procSpell->Id) + { + case 25914: originalSpellId = 20473; break; + case 25913: originalSpellId = 20929; break; + case 25903: originalSpellId = 20930; break; + case 27175: originalSpellId = 27174; break; + case 33074: originalSpellId = 33072; break; + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id); + return false; + } + } + } + + SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId); + if(!originalSpell) + { + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId); + return false; + } + + // percent stored in effect 1 (class scripts) base points + int32 percent = auraSpellInfo->EffectBasePoints[1]+1; + + basepoints0 = originalSpell->manaCost*percent/100; + triggered_spell_id = 20272; + target = this; + break; + } + } + break; + } + } + } + if(auraSpellInfo->SpellFamilyFlags & 0x00080000) + { + switch(auraSpellInfo->SpellIconID) + { + //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc + case 206: + { + if(!pVictim || !pVictim->isAlive()) + return false; + + uint32 spell = 0; + switch(triggeredByAura->GetSpellProto()->Id) + { + case 20186: + triggered_spell_id = 20268; // Rank 1 + break; + case 20354: + triggered_spell_id = 20352; // Rank 2 + break; + case 20355: + triggered_spell_id = 20353; // Rank 3 + break; + case 27164: + triggered_spell_id = 27165; // Rank 4 + break; + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura->GetSpellProto()->Id); + return false; + } + + pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID()); + return true; // no hidden cooldown + } + //Judgement of Light + case 299: + { + if(!pVictim || !pVictim->isAlive()) + return false; + + // overwrite non existing triggered spell call in spell.dbc + uint32 spell = 0; + switch(triggeredByAura->GetSpellProto()->Id) + { + case 20185: + triggered_spell_id = 20267; // Rank 1 + break; + case 20344: + triggered_spell_id = 20341; // Rank 2 + break; + case 20345: + triggered_spell_id = 20342; // Rank 3 + break; + case 20346: + triggered_spell_id = 20343; // Rank 4 + break; + case 27162: + triggered_spell_id = 27163; // Rank 5 + break; + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura->GetSpellProto()->Id); + return false; + } + pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID()); + return true; // no hidden cooldown + } + } + } + // custom check for proc spell + switch(auraSpellInfo->Id) + { + // Bonus Healing (item spell) + case 40971: + { + if(!pVictim || !pVictim->isAlive()) + return false; + + // bonus if health < 50% + if(pVictim->GetHealth() >= pVictim->GetMaxHealth()*triggeredByAura->GetModifier()->m_amount/100) + return false; + + // cast at target positive spell + target = pVictim; + break; + } + } + switch(triggered_spell_id) + { + // Seal of Command + case 20424: + // prevent chain of triggered spell from same triggered spell + if(procSpell && procSpell->Id==20424) + return false; + break; + } + break; + } + case SPELLFAMILY_SHAMAN: + { + if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000) + { + switch(auraSpellInfo->SpellIconID) + { + case 19: + { + switch(auraSpellInfo->Id) + { + case 23551: // Lightning Shield - Tier2: 8 pieces proc shield + { + // Lightning Shield (overwrite non existing triggered spell call in spell.dbc) + triggered_spell_id = 23552; + target = pVictim; + break; + } + case 23552: // Lightning Shield - trigger shield damage + { + // Lightning Shield (overwrite non existing triggered spell call in spell.dbc) + triggered_spell_id = 27635; + target = pVictim; + break; + } + } + break; + } + // Mana Surge (Shaman T1 bonus) + case 87: + { + if(!procSpell) + return false; + + basepoints0 = procSpell->manaCost * 35/100; + triggered_spell_id = 23571; + target = this; + break; + } + //Nature's Guardian + case 2013: + { + if(GetTypeId()!=TYPEID_PLAYER) + return false; + + // damage taken that reduces below 30% health + // does NOT mean you must have been >= 30% before + if (10*(int32(GetHealth())-int32(damage)) >= 3*GetMaxHealth()) + return false; + + triggered_spell_id = 31616; + + // need check cooldown now + if( cooldown && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) + return false; + + basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; + target = this; + if(pVictim && pVictim->isAlive()) + pVictim->getThreatManager().modifyThreatPercent(this,-10); + break; + } + } + } + + // Water Shield (we can't set cooldown for main spell - it's player casted spell + if((auraSpellInfo->SpellFamilyFlags & 0x0000002000000000LL) && auraSpellInfo->SpellVisual==7358) + { + target = this; + break; + } + + // Lightning Shield + if((auraSpellInfo->SpellFamilyFlags & 0x00000400) && auraSpellInfo->SpellVisual==37) + { + // overwrite non existing triggered spell call in spell.dbc + switch(triggeredByAura->GetSpellProto()->Id) + { + case 324: + triggered_spell_id = 26364; break; // Rank 1 + case 325: + triggered_spell_id = 26365; break; // Rank 2 + case 905: + triggered_spell_id = 26366; break; // Rank 3 + case 945: + triggered_spell_id = 26367; break; // Rank 4 + case 8134: + triggered_spell_id = 26369; break; // Rank 5 + case 10431: + triggered_spell_id = 26370; break; // Rank 6 + case 10432: + triggered_spell_id = 26363; break; // Rank 7 + case 25469: + triggered_spell_id = 26371; break; // Rank 8 + case 25472: + triggered_spell_id = 26372; break; // Rank 9 + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id); + return false; + } + + target = pVictim; + break; + } + break; + } + } + + // standard non-dummy case + if(!triggered_spell_id) + { + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex()); + return false; + } + + SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); + + if(!triggerEntry) + { + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex(),triggered_spell_id); + return false; + } + + // not allow proc extra attack spell at extra attack + if( m_extraAttacks && IsSpellHaveEffect(triggerEntry,SPELL_EFFECT_ADD_EXTRA_ATTACKS) ) + return false; + + if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) + return false; + + // default case + if(!target || target!=this && !target->isAlive()) + return false; + + if(basepoints0) + CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + else + CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); + + if( cooldown && GetTypeId()==TYPEID_PLAYER ) + ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); + + return true; +} + +bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, int32 scriptId, uint32 damage, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown) +{ + if(!pVictim || !pVictim->isAlive()) + return false; + + Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER + ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; + + uint32 triggered_spell_id = 0; + + switch(scriptId) + { + case 836: // Improved Blizzard (Rank 1) + { + if( !procSpell || procSpell->SpellVisual!=9487 ) + return false; + triggered_spell_id = 12484; + break; + } + case 988: // Improved Blizzard (Rank 2) + { + if( !procSpell || procSpell->SpellVisual!=9487 ) + return false; + triggered_spell_id = 12485; + break; + } + case 989: // Improved Blizzard (Rank 3) + { + if( !procSpell || procSpell->SpellVisual!=9487 ) + return false; + triggered_spell_id = 12486; + break; + } + case 4086: // Improved Mend Pet (Rank 1) + case 4087: // Improved Mend Pet (Rank 2) + { + int32 chance = triggeredByAura->GetSpellProto()->EffectBasePoints[triggeredByAura->GetEffIndex()]; + if(!roll_chance_i(chance)) + return false; + + triggered_spell_id = 24406; + break; + } + case 4533: // Dreamwalker Raiment 2 pieces bonus + { + // Chance 50% + if (!roll_chance_i(50)) + return false; + + switch (pVictim->getPowerType()) + { + case POWER_MANA: triggered_spell_id = 28722; break; + case POWER_RAGE: triggered_spell_id = 28723; break; + case POWER_ENERGY: triggered_spell_id = 28724; break; + default: + return false; + } + break; + } + case 4537: // Dreamwalker Raiment 6 pieces bonus + triggered_spell_id = 28750; // Blessing of the Claw + break; + case 5497: // Improved Mana Gems (Serpent-Coil Braid) + triggered_spell_id = 37445; // Mana Surge + break; + } + + // not processed + if(!triggered_spell_id) + return false; + + // standard non-dummy case + SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); + + if(!triggerEntry) + { + sLog.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id,scriptId); + return false; + } + + if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) + return false; + + CastSpell(pVictim, triggered_spell_id, true, castItem, triggeredByAura); + + if( cooldown && GetTypeId()==TYPEID_PLAYER ) + ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); + + return true; +} + +void Unit::setPowerType(Powers new_powertype) +{ + SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype); + + if(GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE); + } + else if(((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(pet->isControlled()) + { + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE); + } + } + + switch(new_powertype) + { + default: + case POWER_MANA: + break; + case POWER_RAGE: + SetMaxPower(POWER_RAGE,GetCreatePowers(POWER_RAGE)); + SetPower( POWER_RAGE,0); + break; + case POWER_FOCUS: + SetMaxPower(POWER_FOCUS,GetCreatePowers(POWER_FOCUS)); + SetPower( POWER_FOCUS,GetCreatePowers(POWER_FOCUS)); + break; + case POWER_ENERGY: + SetMaxPower(POWER_ENERGY,GetCreatePowers(POWER_ENERGY)); + SetPower( POWER_ENERGY,0); + break; + case POWER_HAPPINESS: + SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS)); + SetPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS)); + break; + } +} + +FactionTemplateEntry const* Unit::getFactionTemplateEntry() const +{ + FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction()); + if(!entry) + { + static uint64 guid = 0; // prevent repeating spam same faction problem + + if(GetGUID() != guid) + { + if(GetTypeId() == TYPEID_PLAYER) + sLog.outError("Player %s have invalid faction (faction template id) #%u", ((Player*)this)->GetName(), getFaction()); + else + sLog.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction()); + guid = GetGUID(); + } + } + return entry; +} + +bool Unit::IsHostileTo(Unit const* unit) const +{ + // always non-hostile to self + if(unit==this) + return false; + + // always non-hostile to GM in GM mode + if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) + return false; + + // always hostile to enemy + if(getVictim()==unit || unit->getVictim()==this) + return true; + + // test pet/charm masters instead pers/charmeds + Unit const* testerOwner = GetCharmerOrOwner(); + Unit const* targetOwner = unit->GetCharmerOrOwner(); + + // always hostile to owner's enemy + if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner)) + return true; + + // always hostile to enemy owner + if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this)) + return true; + + // always hostile to owner of owner's enemy + if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner)) + return true; + + Unit const* tester = testerOwner ? testerOwner : this; + Unit const* target = targetOwner ? targetOwner : unit; + + // always non-hostile to target with common owner, or to owner/pet + if(tester==target) + return false; + + // special cases (Duel, etc) + if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER) + { + Player const* pTester = (Player const*)tester; + Player const* pTarget = (Player const*)target; + + // Duel + if(pTester->duel && pTester->duel->opponent == pTarget && pTester->duel->startTime != 0) + return true; + + // Group + if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup()) + return false; + + // Sanctuary + if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) + return false; + + // PvP FFA state + if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) + return true; + + //= PvP states + // Green/Blue (can't attack) + if(pTester->GetTeam()==pTarget->GetTeam()) + return false; + + // Red (can attack) if true, Blue/Yellow (can't attack) in another case + return pTester->IsPvP() && pTarget->IsPvP(); + } + + // faction base cases + FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry(); + FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry(); + if(!tester_faction || !target_faction) + return false; + + if(target->isAttackingPlayer() && tester->IsContestedGuard()) + return true; + + // PvC forced reaction and reputation case + if(tester->GetTypeId()==TYPEID_PLAYER) + { + // forced reaction + ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction); + if(forceItr!=((Player*)tester)->m_forcedReactions.end()) + return forceItr->second <= REP_HOSTILE; + + // if faction have reputation then hostile state for tester at 100% dependent from at_war state + if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction)) + if(raw_target_faction->reputationListID >=0) + if(FactionState const* factionState = ((Player*)tester)->GetFactionState(raw_target_faction)) + return (factionState->Flags & FACTION_FLAG_AT_WAR); + } + // CvP forced reaction and reputation case + else if(target->GetTypeId()==TYPEID_PLAYER) + { + // forced reaction + ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction); + if(forceItr!=((Player const*)target)->m_forcedReactions.end()) + return forceItr->second <= REP_HOSTILE; + + // apply reputation state + FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction); + if(raw_tester_faction && raw_tester_faction->reputationListID >=0 ) + return ((Player const*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE; + } + + // common faction based case (CvC,PvC,CvP) + return tester_faction->IsHostileTo(*target_faction); +} + +bool Unit::IsFriendlyTo(Unit const* unit) const +{ + // always friendly to self + if(unit==this) + return true; + + // always friendly to GM in GM mode + if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) + return true; + + // always non-friendly to enemy + if(getVictim()==unit || unit->getVictim()==this) + return false; + + // test pet/charm masters instead pers/charmeds + Unit const* testerOwner = GetCharmerOrOwner(); + Unit const* targetOwner = unit->GetCharmerOrOwner(); + + // always non-friendly to owner's enemy + if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner)) + return false; + + // always non-friendly to enemy owner + if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this)) + return false; + + // always non-friendly to owner of owner's enemy + if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner)) + return false; + + Unit const* tester = testerOwner ? testerOwner : this; + Unit const* target = targetOwner ? targetOwner : unit; + + // always friendly to target with common owner, or to owner/pet + if(tester==target) + return true; + + // special cases (Duel) + if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER) + { + Player const* pTester = (Player const*)tester; + Player const* pTarget = (Player const*)target; + + // Duel + if(pTester->duel && pTester->duel->opponent == target && pTester->duel->startTime != 0) + return false; + + // Group + if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup()) + return true; + + // Sanctuary + if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) + return true; + + // PvP FFA state + if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) + return false; + + //= PvP states + // Green/Blue (non-attackable) + if(pTester->GetTeam()==pTarget->GetTeam()) + return true; + + // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable) + return !pTarget->IsPvP(); + } + + // faction base cases + FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry(); + FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry(); + if(!tester_faction || !target_faction) + return false; + + if(target->isAttackingPlayer() && tester->IsContestedGuard()) + return false; + + // PvC forced reaction and reputation case + if(tester->GetTypeId()==TYPEID_PLAYER) + { + // forced reaction + ForcedReactions::const_iterator forceItr = ((Player const*)tester)->m_forcedReactions.find(target_faction->faction); + if(forceItr!=((Player const*)tester)->m_forcedReactions.end()) + return forceItr->second >= REP_FRIENDLY; + + // if faction have reputation then friendly state for tester at 100% dependent from at_war state + if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction)) + if(raw_target_faction->reputationListID >=0) + if(FactionState const* FactionState = ((Player*)tester)->GetFactionState(raw_target_faction)) + return !(FactionState->Flags & FACTION_FLAG_AT_WAR); + } + // CvP forced reaction and reputation case + else if(target->GetTypeId()==TYPEID_PLAYER) + { + // forced reaction + ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction); + if(forceItr!=((Player const*)target)->m_forcedReactions.end()) + return forceItr->second >= REP_FRIENDLY; + + // apply reputation state + if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction)) + if(raw_tester_faction->reputationListID >=0 ) + return ((Player const*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY; + } + + // common faction based case (CvC,PvC,CvP) + return tester_faction->IsFriendlyTo(*target_faction); +} + +bool Unit::IsHostileToPlayers() const +{ + FactionTemplateEntry const* my_faction = getFactionTemplateEntry(); + if(!my_faction) + return false; + + FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction); + if(raw_faction && raw_faction->reputationListID >=0 ) + return false; + + return my_faction->IsHostileToPlayers(); +} + +bool Unit::IsNeutralToAll() const +{ + FactionTemplateEntry const* my_faction = getFactionTemplateEntry(); + if(!my_faction) + return true; + + FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction); + if(raw_faction && raw_faction->reputationListID >=0 ) + return false; + + return my_faction->IsNeutralToAll(); +} + +bool Unit::Attack(Unit *victim, bool meleeAttack) +{ + if(!victim || victim == this) + return false; + + // dead units can neither attack nor be attacked + if(!isAlive() || !victim->isAlive()) + return false; + + // player cannot attack in mount state + if(GetTypeId()==TYPEID_PLAYER && IsMounted()) + return false; + + // nobody can attack GM in GM-mode + if(victim->GetTypeId()==TYPEID_PLAYER) + { + if(((Player*)victim)->isGameMaster()) + return false; + } + else + { + if(((Creature*)victim)->IsInEvadeMode()) + return false; + } + + // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack) + if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) + RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE); + + if (m_attacking) + { + if (m_attacking == victim) + { + // switch to melee attack from ranged/magic + if( meleeAttack && !hasUnitState(UNIT_STAT_MELEE_ATTACKING) ) + { + addUnitState(UNIT_STAT_MELEE_ATTACKING); + SendAttackStart(victim); + return true; + } + return false; + } + AttackStop(); + } + + //Set our target + SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); + + if(meleeAttack) + addUnitState(UNIT_STAT_MELEE_ATTACKING); + m_attacking = victim; + m_attacking->_addAttacker(this); + + if(m_attacking->GetTypeId()==TYPEID_UNIT && ((Creature*)m_attacking)->AI()) + ((Creature*)m_attacking)->AI()->AttackedBy(this); + + if(GetTypeId()==TYPEID_UNIT) + { + WorldPacket data(SMSG_AI_REACTION, 12); + data << GetGUID(); + data << uint32(AI_REACTION_AGGRO); // Aggro sound + ((WorldObject*)this)->SendMessageToSet(&data, true); + + ((Creature*)this)->CallAssistence(); + ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); + } + + // delay offhand weapon attack to next attack time + if(haveOffhandWeapon()) + resetAttackTimer(OFF_ATTACK); + + if(meleeAttack) + SendAttackStart(victim); + + return true; +} + +bool Unit::AttackStop() +{ + if (!m_attacking) + return false; + + Unit* victim = m_attacking; + + m_attacking->_removeAttacker(this); + m_attacking = NULL; + + //Clear our target + SetUInt64Value(UNIT_FIELD_TARGET, 0); + + clearUnitState(UNIT_STAT_MELEE_ATTACKING); + + InterruptSpell(CURRENT_MELEE_SPELL); + + if( GetTypeId()==TYPEID_UNIT ) + { + // reset call assistance + ((Creature*)this)->SetNoCallAssistence(false); + } + + SendAttackStop(victim); + + return true; +} + +void Unit::CombatStop(bool cast) +{ + if(cast& IsNonMeleeSpellCasted(false)) + InterruptNonMeleeSpells(false); + + AttackStop(); + RemoveAllAttackers(); + if( GetTypeId()==TYPEID_PLAYER ) + ((Player*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel + ClearInCombat(); +} + +void Unit::CombatStopWithPets(bool cast) +{ + CombatStop(cast); + if(Pet* pet = GetPet()) + pet->CombatStop(cast); + if(Unit* charm = GetCharm()) + charm->CombatStop(cast); + if(GetTypeId()==TYPEID_PLAYER) + { + GuardianPetList const& guardians = ((Player*)this)->GetGuardians(); + for(GuardianPetList::const_iterator itr = guardians.begin(); itr != guardians.end(); ++itr) + if(Unit* guardian = Unit::GetUnit(*this,*itr)) + guardian->CombatStop(cast); + } +} + +bool Unit::isAttackingPlayer() const +{ + if(hasUnitState(UNIT_STAT_ATTACK_PLAYER)) + return true; + + Pet* pet = GetPet(); + if(pet && pet->isAttackingPlayer()) + return true; + + Unit* charmed = GetCharm(); + if(charmed && charmed->isAttackingPlayer()) + return true; + + for (int8 i = 0; i < MAX_TOTEM; i++) + { + if(m_TotemSlot[i]) + { + Creature *totem = ObjectAccessor::GetCreature(*this, m_TotemSlot[i]); + if(totem && totem->isAttackingPlayer()) + return true; + } + } + + return false; +} + +void Unit::RemoveAllAttackers() +{ + while (!m_attackers.empty()) + { + AttackerSet::iterator iter = m_attackers.begin(); + if(!(*iter)->AttackStop()) + { + sLog.outError("WORLD: Unit has an attacker that isnt attacking it!"); + m_attackers.erase(iter); + } + } +} + +void Unit::ModifyAuraState(AuraState flag, bool apply) +{ + if (apply) + { + if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1))) + { + SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); + if(GetTypeId() == TYPEID_PLAYER) + { + const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + if(itr->second->state == PLAYERSPELL_REMOVED) continue; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + if (!spellInfo || !IsPassiveSpell(itr->first)) continue; + if (spellInfo->CasterAuraState == flag) + CastSpell(this, itr->first, true, NULL); + } + } + } + } + else + { + if (HasFlag(UNIT_FIELD_AURASTATE,1<<(flag-1))) + { + RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); + Unit::AuraMap& tAuras = GetAuras(); + for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();) + { + SpellEntry const* spellProto = (*itr).second->GetSpellProto(); + if (spellProto->CasterAuraState == flag) + { + // exceptions (applied at state but not removed at state change) + // Rampage + if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags==0x100000) + { + ++itr; + continue; + } + + RemoveAura(itr); + } + else + ++itr; + } + } + } +} + +Unit *Unit::GetOwner() const +{ + uint64 ownerid = GetOwnerGUID(); + if(!ownerid) + return NULL; + return ObjectAccessor::GetUnit(*this, ownerid); +} + +Unit *Unit::GetCharmer() const +{ + if(uint64 charmerid = GetCharmerGUID()) + return ObjectAccessor::GetUnit(*this, charmerid); + return NULL; +} + +Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() +{ + uint64 guid = GetCharmerOrOwnerGUID(); + if(IS_PLAYER_GUID(guid)) + return ObjectAccessor::GetPlayer(*this, guid); + + return GetTypeId()==TYPEID_PLAYER ? (Player*)this : NULL; +} + +Pet* Unit::GetPet() const +{ + if(uint64 pet_guid = GetPetGUID()) + { + if(Pet* pet = ObjectAccessor::GetPet(pet_guid)) + return pet; + + sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid)); + const_cast(this)->SetPet(0); + } + + return NULL; +} + +Unit* Unit::GetCharm() const +{ + if(uint64 charm_guid = GetCharmGUID()) + { + if(Unit* pet = ObjectAccessor::GetUnit(*this, charm_guid)) + return pet; + + sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid)); + const_cast(this)->SetCharm(0); + } + + return NULL; +} + +void Unit::SetPet(Pet* pet) +{ + SetUInt64Value(UNIT_FIELD_SUMMON,pet ? pet->GetGUID() : 0); + + // FIXME: hack, speed must be set only at follow + if(pet) + for(int i = 0; i < MAX_MOVE_TYPE; ++i) + pet->SetSpeed(UnitMoveType(i),m_speed_rate[i],true); +} + +void Unit::SetCharm(Unit* charmed) +{ + SetUInt64Value(UNIT_FIELD_CHARM,charmed ? charmed->GetGUID() : 0); +} + +void Unit::UnsummonAllTotems() +{ + for (int8 i = 0; i < MAX_TOTEM; ++i) + { + if(!m_TotemSlot[i]) + continue; + + Creature *OldTotem = ObjectAccessor::GetCreature(*this, m_TotemSlot[i]); + if (OldTotem && OldTotem->isTotem()) + ((Totem*)OldTotem)->UnSummon(); + } +} + +void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical) +{ + // we guess size + WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+1)); + data.append(pVictim->GetPackGUID()); + data.append(GetPackGUID()); + data << uint32(SpellID); + data << uint32(Damage); + data << uint8(critical ? 1 : 0); + data << uint8(0); // unused in client? + SendMessageToSet(&data, true); +} + +void Unit::SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers powertype, bool critical) +{ + WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1)); + data.append(pVictim->GetPackGUID()); + data.append(GetPackGUID()); + data << uint32(SpellID); + data << uint32(powertype); + data << uint32(Damage); + //data << uint8(critical ? 1 : 0); // removed in 2.4.0 + SendMessageToSet(&data, true); +} + +uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype) +{ + if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE ) + return pdamage; + + int32 BonusDamage = 0; + if( GetTypeId()==TYPEID_UNIT ) + { + // Pets just add their bonus damage to their spell damage + // note that their spell damage is just gain of their own auras + if (((Creature*)this)->isPet()) + { + BonusDamage = ((Pet*)this)->GetBonusDamage(); + } + // For totems get damage bonus from owner (statue isn't totem in fact) + else if (((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE) + { + if(Unit* owner = GetOwner()) + return owner->SpellDamageBonus(pVictim, spellProto, pdamage, damagetype); + } + } + + // Damage Done + uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); + + // Taken/Done fixed damage bonus auras + int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto))+BonusDamage; + int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), pVictim); + + // Damage over Time spells bonus calculation + float DotFactor = 1.0f; + if(damagetype == DOT) + { + int32 DotDuration = GetSpellDuration(spellProto); + // 200% limit + if(DotDuration > 0) + { + if(DotDuration > 30000) DotDuration = 30000; + if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f; + int x = 0; + for(int j = 0; j < 3; j++) + { + if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && ( + spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE || + spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) ) + { + x = j; + break; + } + } + int DotTicks = 6; + if(spellProto->EffectAmplitude[x] != 0) + DotTicks = DotDuration / spellProto->EffectAmplitude[x]; + if(DotTicks) + { + DoneAdvertisedBenefit /= DotTicks; + TakenAdvertisedBenefit /= DotTicks; + } + } + } + + // Taken/Done total percent damage auras + float DoneTotalMod = 1.0f; + float TakenTotalMod = 1.0f; + + // ..done + AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) + { + if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) && + (*i)->GetSpellProto()->EquippedItemClass == -1 && + // -1 == any item class (not wand then) + (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 ) + // 0 == any inventory type (not wand then) + { + DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; + } + } + + uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); + AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS); + for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) + if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) + DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; + + // ..taken + AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); + for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i) + if( (*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto) ) + TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; + + // .. taken pct: scripted (increases damage of * against targets *) + AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + switch((*i)->GetModifier()->m_miscvalue) + { + //Molten Fury + case 4920: case 4919: + if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT)) + TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; break; + } + } + // .. taken pct: dummy auras + AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) + { + switch((*i)->GetSpellProto()->SpellIconID) + { + //Cheat Death + case 2109: + if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) ) + { + if(pVictim->GetTypeId() != TYPEID_PLAYER) + continue; + float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4; + if (mod < (*i)->GetModifier()->m_amount) + mod = (*i)->GetModifier()->m_amount; + TakenTotalMod *= (mod+100.0f)/100.0f; + } + break; + //Mangle + case 2312: + for(int j=0;j<3;j++) + { + if(GetEffectMechanic(spellProto, j)==MECHANIC_BLEED) + { + TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; + break; + } + } + break; + } + } + + // Distribute Damage over multiple effects, reduce by AoE + CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); + + // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing + for(int j = 0; j < 3; ++j) + { + if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || + spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH ) + { + CastingTime /= 2; + break; + } + } + + switch(spellProto->SpellFamilyName) + { + case SPELLFAMILY_MAGE: + // Ignite - do not modify, it is (8*Rank)% damage of procing Spell + if(spellProto->Id==12654) + { + return pdamage; + } + // Ice Lance + else if((spellProto->SpellFamilyFlags & 0x20000LL) && spellProto->SpellIconID == 186) + { + CastingTime /= 3; // applied 1/3 bonuses in case generic target + if(pVictim->isFrozen()) // and compensate this for frozen target. + TakenTotalMod *= 3.0f; + } + // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 184 ) + { + DotFactor = damagetype == DOT ? 0.2f : 1.0f; + CastingTime = damagetype == DOT ? 3500 : 4025; + } + // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x1LL) && spellProto->SpellIconID == 185) + { + CastingTime = 3500; + DotFactor = damagetype == DOT ? 0.0f : 1.0f; + } + // Molten armor + else if (spellProto->SpellFamilyFlags & 0x0000000800000000LL) + { + CastingTime = 0; + } + // Arcane Missiles triggered spell + else if ((spellProto->SpellFamilyFlags & 0x200000LL) && spellProto->SpellIconID == 225) + { + CastingTime = 1000; + } + // Blizzard triggered spell + else if ((spellProto->SpellFamilyFlags & 0x80080LL) && spellProto->SpellIconID == 285) + { + CastingTime = 500; + } + break; + case SPELLFAMILY_WARLOCK: + // Life Tap + if((spellProto->SpellFamilyFlags & 0x40000LL) && spellProto->SpellIconID == 208) + { + CastingTime = 2800; // 80% from +shadow damage + DoneTotalMod = 1.0f; + TakenTotalMod = 1.0f; + } + // Dark Pact + else if((spellProto->SpellFamilyFlags & 0x80000000LL) && spellProto->SpellIconID == 154 && GetPetGUID()) + { + CastingTime = 3360; // 96% from +shadow damage + DoneTotalMod = 1.0f; + TakenTotalMod = 1.0f; + } + // Soul Fire - 115% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x8000000000LL) && spellProto->SpellIconID == 184) + { + CastingTime = 4025; + } + // Curse of Agony - 120% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x0000000400LL) && spellProto->SpellIconID == 544) + { + DotFactor = 1.2f; + } + // Drain Mana - 0% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 548) + { + CastingTime = 0; + } + // Drain Soul 214.3% + else if ((spellProto->SpellFamilyFlags & 0x4000LL) && spellProto->SpellIconID == 113 ) + { + CastingTime = 7500; + } + // Hellfire + else if ((spellProto->SpellFamilyFlags & 0x40LL) && spellProto->SpellIconID == 937) + { + CastingTime = damagetype == DOT ? 5000 : 500; // self damage seems to be so + } + // Unstable Affliction - 180% + else if (spellProto->Id == 31117 && spellProto->SpellIconID == 232) + { + CastingTime = 6300; + } + // Corruption 93% + else if ((spellProto->SpellFamilyFlags & 0x2LL) && spellProto->SpellIconID == 313) + { + DotFactor = 0.93f; + } + break; + case SPELLFAMILY_PALADIN: + // Consecration - 95% of Holy Damage + if((spellProto->SpellFamilyFlags & 0x20LL) && spellProto->SpellIconID == 51) + { + DotFactor = 0.95f; + CastingTime = 3500; + } + // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed + else if((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 25) + { + Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + float wspeed = GetAttackTime(BASE_ATTACK)/1000.0f; + + if( item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON) + CastingTime = uint32(wspeed*3500*0.102f); + else + CastingTime = uint32(wspeed*3500*0.098f); + } + // Judgement of Righteousness - 73% + else if ((spellProto->SpellFamilyFlags & 1024) && spellProto->SpellIconID == 25) + { + CastingTime = 2555; + } + // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications + else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2292) + { + DotFactor = 0.17f; + CastingTime = 3500; + } + // Holy shield - 5% of Holy Damage + else if ((spellProto->SpellFamilyFlags & 0x4000000000LL) && spellProto->SpellIconID == 453) + { + CastingTime = 175; + } + // Blessing of Sanctuary - 0% + else if ((spellProto->SpellFamilyFlags & 0x10000000LL) && spellProto->SpellIconID == 29) + { + CastingTime = 0; + } + // Seal of Righteousness trigger - already computed for parent spell + else if ( spellProto->SpellFamilyName==SPELLFAMILY_PALADIN && spellProto->SpellIconID==25 && spellProto->AttributesEx4 & 0x00800000LL ) + { + return pdamage; + } + break; + case SPELLFAMILY_SHAMAN: + // totem attack + if (spellProto->SpellFamilyFlags & 0x000040000000LL) + { + if (spellProto->SpellIconID == 33) // Fire Nova totem attack must be 21.4%(untested) + CastingTime = 749; // ignore CastingTime and use as modifier + else if (spellProto->SpellIconID == 680) // Searing Totem attack 8% + CastingTime = 280; // ignore CastingTime and use as modifier + else if (spellProto->SpellIconID == 37) // Magma totem attack must be 6.67%(untested) + CastingTime = 234; // ignore CastingTimePenalty and use as modifier + } + // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge + else if( (spellProto->SpellFamilyFlags & 0x00000000400LL) || spellProto->Id == 23552) + CastingTime = 1155; // ignore CastingTimePenalty and use as modifier + break; + case SPELLFAMILY_PRIEST: + // Mana Burn - 0% of Shadow Damage + if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 212) + { + CastingTime = 0; + } + // Mind Flay - 59% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x800000LL) && spellProto->SpellIconID == 548) + { + CastingTime = 2065; + } + // Holy Fire - 86.71%, DoT - 16.5% + else if ((spellProto->SpellFamilyFlags & 0x100000LL) && spellProto->SpellIconID == 156) + { + DotFactor = damagetype == DOT ? 0.165f : 1.0f; + CastingTime = damagetype == DOT ? 3500 : 3035; + } + // Shadowguard - 28% per charge + else if ((spellProto->SpellFamilyFlags & 0x2000000LL) && spellProto->SpellIconID == 19) + { + CastingTime = 980; + } + // Touch of Weakeness - 10% + else if ((spellProto->SpellFamilyFlags & 0x80000LL) && spellProto->SpellIconID == 1591) + { + CastingTime = 350; + } + // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras) + else if (spellProto->SpellFamilyFlags == 0 && spellProto->SpellIconID == 566) + { + CastingTime = 0; + } + // Holy Nova - 14% + else if ((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 1874) + { + CastingTime = 500; + } + break; + case SPELLFAMILY_DRUID: + // Hurricane triggered spell + if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 220) + { + CastingTime = 500; + } + break; + case SPELLFAMILY_WARRIOR: + case SPELLFAMILY_HUNTER: + case SPELLFAMILY_ROGUE: + CastingTime = 0; + break; + default: + break; + } + + float LvlPenalty = CalculateLevelPenalty(spellProto); + + // Spellmod SpellDamage + float SpellModSpellDamage = 100.0f; + + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage); + + SpellModSpellDamage /= 100.0f; + + float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty; + float TakenActualBenefit = TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty; + + float tmpDamage = (float(pdamage)+DoneActualBenefit)*DoneTotalMod; + + // Add flat bonus from spell damage versus + tmpDamage += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask); + + // apply spellmod to Done damage + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); + + tmpDamage = (tmpDamage+TakenActualBenefit)*TakenTotalMod; + + if( GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() ) + tmpDamage *= ((Creature*)this)->GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->rank); + + return tmpDamage > 0 ? uint32(tmpDamage) : 0; +} + +int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask) +{ + int32 DoneAdvertisedBenefit = 0; + + // ..done + AuraList const& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); + for(AuraList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i) + if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0 && + (*i)->GetSpellProto()->EquippedItemClass == -1 && + // -1 == any item class (not wand then) + (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 ) + // 0 == any inventory type (not wand then) + DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount; + + if (GetTypeId() == TYPEID_PLAYER) + { + // Damage bonus from stats + AuraList const& mDamageDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT); + for(AuraList::const_iterator i = mDamageDoneOfStatPercent.begin();i != mDamageDoneOfStatPercent.end(); ++i) + { + if((*i)->GetModifier()->m_miscvalue & schoolMask) + { + SpellEntry const* iSpellProto = (*i)->GetSpellProto(); + uint8 eff = (*i)->GetEffIndex(); + + // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index) + Stats usedStat = STAT_INTELLECT; + if(eff < 2 && iSpellProto->EffectApplyAuraName[eff+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT) + usedStat = Stats(iSpellProto->EffectMiscValue[eff+1]); + + DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f); + } + } + // ... and attack power + AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER); + for(AuraList::const_iterator i =mDamageDonebyAP.begin();i != mDamageDonebyAP.end(); ++i) + if ((*i)->GetModifier()->m_miscvalue & schoolMask) + DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f); + + } + return DoneAdvertisedBenefit; +} + +int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim) +{ + uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); + + int32 TakenAdvertisedBenefit = 0; + // ..done (for creature type by mask) in taken + AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE); + for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i) + if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) + TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount; + + // ..taken + AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN); + for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i) + if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) + TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount; + + return TakenAdvertisedBenefit; +} + +bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) +{ + // not criting spell + if((spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_CRIT)) + return false; + + float crit_chance = 0.0f; + switch(spellProto->DmgClass) + { + case SPELL_DAMAGE_CLASS_NONE: + return false; + case SPELL_DAMAGE_CLASS_MAGIC: + { + if (schoolMask & SPELL_SCHOOL_MASK_NORMAL) + crit_chance = 0.0f; + // For other schools + else if (GetTypeId() == TYPEID_PLAYER) + crit_chance = GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask)); + else + { + crit_chance = m_baseSpellCritChance; + crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); + } + // taken + if (pVictim && !IsPositiveSpell(spellProto->Id)) + { + // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE + crit_chance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask); + // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE + crit_chance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); + // Modify by player victim resilience + if (pVictim->GetTypeId() == TYPEID_PLAYER) + crit_chance -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); + // scripted (increase crit chance ... against ... target by x% + if(pVictim->isFrozen()) // Shatter + { + AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + switch((*i)->GetModifier()->m_miscvalue) + { + case 849: crit_chance+= 10.0f; break; //Shatter Rank 1 + case 910: crit_chance+= 20.0f; break; //Shatter Rank 2 + case 911: crit_chance+= 30.0f; break; //Shatter Rank 3 + case 912: crit_chance+= 40.0f; break; //Shatter Rank 4 + case 913: crit_chance+= 50.0f; break; //Shatter Rank 5 + } + } + } + } + break; + } + case SPELL_DAMAGE_CLASS_MELEE: + case SPELL_DAMAGE_CLASS_RANGED: + { + if (pVictim) + { + crit_chance = GetUnitCriticalChance(attackType, pVictim); + crit_chance+= (int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetDefenseSkillValue(this))) * 0.04f; + crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); + } + break; + } + default: + return false; + } + // percent done + // only players use intelligence for critical chance computations + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); + + crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f; + if (roll_chance_f(crit_chance)) + return true; + return false; +} + +uint32 Unit::SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim) +{ + // Calculate critical bonus + int32 crit_bonus; + switch(spellProto->DmgClass) + { + case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% + case SPELL_DAMAGE_CLASS_RANGED: + // TODO: write here full calculation for melee/ranged spells + crit_bonus = damage; + break; + default: + crit_bonus = damage / 2; // for spells is 50% + break; + } + + // adds additional damage to crit_bonus (from talents) + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + + if(pVictim) + { + uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); + crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask)); + } + + if(crit_bonus > 0) + damage += crit_bonus; + + return damage; +} + +uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim) +{ + // For totems get healing bonus from owner (statue isn't totem in fact) + if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE) + if(Unit* owner = GetOwner()) + return owner->SpellHealingBonus(spellProto, healamount, damagetype, pVictim); + + // Healing Done + + // These Spells are doing fixed amount of healing (TODO found less hack-like check) + if(spellProto->Id == 15290 || spellProto->Id == 39373 || spellProto->Id == 33778 || spellProto->Id == 379 || spellProto->Id == 38395) + return healamount; + + + int32 AdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto)); + uint32 CastingTime = GetSpellCastTime(spellProto); + + // Healing Taken + AdvertisedBenefit += SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), pVictim); + + // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light + if (spellProto->SpellFamilyName == SPELLFAMILY_PALADIN && (spellProto->SpellFamilyFlags & 0x00000000C0000000LL)) + { + AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) + { + if((*i)->GetSpellProto()->SpellVisual == 9180) + { + // Flash of Light + if ((spellProto->SpellFamilyFlags & 0x0000000040000000LL) && (*i)->GetEffIndex() == 1) + AdvertisedBenefit += (*i)->GetModifier()->m_amount; + // Holy Light + else if ((spellProto->SpellFamilyFlags & 0x0000000080000000LL) && (*i)->GetEffIndex() == 0) + AdvertisedBenefit += (*i)->GetModifier()->m_amount; + } + } + } + + float ActualBenefit = 0.0f; + + if (AdvertisedBenefit != 0) + { + // Healing over Time spells + float DotFactor = 1.0f; + if(damagetype == DOT) + { + int32 DotDuration = GetSpellDuration(spellProto); + if(DotDuration > 0) + { + // 200% limit + if(DotDuration > 30000) DotDuration = 30000; + if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f; + int x = 0; + for(int j = 0; j < 3; j++) + { + if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && ( + spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_HEAL || + spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) ) + { + x = j; + break; + } + } + int DotTicks = 6; + if(spellProto->EffectAmplitude[x] != 0) + DotTicks = DotDuration / spellProto->EffectAmplitude[x]; + if(DotTicks) + AdvertisedBenefit /= DotTicks; + } + } + + // distribute healing to all effects, reduce AoE damage + CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); + + // 0% bonus for damage and healing spells for leech spells from healing bonus + for(int j = 0; j < 3; ++j) + { + if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || + spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH ) + { + CastingTime = 0; + break; + } + } + + // Exception + switch (spellProto->SpellFamilyName) + { + case SPELLFAMILY_SHAMAN: + // Healing stream from totem (add 6% per tick from hill bonus owner) + if (spellProto->SpellFamilyFlags & 0x000000002000LL) + CastingTime = 210; + // Earth Shield 30% per charge + else if (spellProto->SpellFamilyFlags & 0x40000000000LL) + CastingTime = 1050; + break; + case SPELLFAMILY_DRUID: + // Lifebloom + if (spellProto->SpellFamilyFlags & 0x1000000000LL) + { + CastingTime = damagetype == DOT ? 3500 : 1200; + DotFactor = damagetype == DOT ? 0.519f : 1.0f; + } + // Tranquility triggered spell + else if (spellProto->SpellFamilyFlags & 0x80LL) + CastingTime = 667; + // Rejuvenation + else if (spellProto->SpellFamilyFlags & 0x10LL) + DotFactor = 0.845f; + // Regrowth + else if (spellProto->SpellFamilyFlags & 0x40LL) + { + DotFactor = damagetype == DOT ? 0.705f : 1.0f; + CastingTime = damagetype == DOT ? 3500 : 1010; + } + break; + case SPELLFAMILY_PRIEST: + // Holy Nova - 14% + if ((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 1874) + CastingTime = 500; + break; + case SPELLFAMILY_PALADIN: + // Seal and Judgement of Light + if ( spellProto->SpellFamilyFlags & 0x100040000LL ) + CastingTime = 0; + break; + case SPELLFAMILY_WARRIOR: + case SPELLFAMILY_ROGUE: + case SPELLFAMILY_HUNTER: + CastingTime = 0; + break; + } + + float LvlPenalty = CalculateLevelPenalty(spellProto); + + // Spellmod SpellDamage + float SpellModSpellDamage = 100.0f; + + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage); + + SpellModSpellDamage /= 100.0f; + + ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty; + } + + // use float as more appropriate for negative values and percent applying + float heal = healamount + ActualBenefit; + + // TODO: check for ALL/SPELLS type + // Healing done percent + AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); + for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i) + heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; + + // apply spellmod to Done amount + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); + + // Healing Wave cast + if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags & 0x0000000000000040LL) + { + // Search for Healing Way on Victim (stack up to 3 time) + int32 pctMod = 0; + Unit::AuraList const& auraDummy = pVictim->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr!=auraDummy.end(); ++itr) + if((*itr)->GetId() == 29203) + pctMod += (*itr)->GetModifier()->m_amount; + // Apply bonus + if (pctMod) + heal = heal * (100 + pctMod) / 100; + } + + // Healing taken percent + float minval = pVictim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT); + if(minval) + heal *= (100.0f + minval) / 100.0f; + + float maxval = pVictim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT); + if(maxval) + heal *= (100.0f + maxval) / 100.0f; + + if (heal < 0) heal = 0; + + return uint32(heal); +} + +int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask) +{ + int32 AdvertisedBenefit = 0; + + AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE); + for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i) + if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) + AdvertisedBenefit += (*i)->GetModifier()->m_amount; + + // Healing bonus of spirit, intellect and strength + if (GetTypeId() == TYPEID_PLAYER) + { + // Healing bonus from stats + AuraList const& mHealingDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT); + for(AuraList::const_iterator i = mHealingDoneOfStatPercent.begin();i != mHealingDoneOfStatPercent.end(); ++i) + { + // stat used dependent from misc value (stat index) + Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]); + AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f); + } + + // ... and attack power + AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER); + for(AuraList::const_iterator i = mHealingDonebyAP.begin();i != mHealingDonebyAP.end(); ++i) + if ((*i)->GetModifier()->m_miscvalue & schoolMask) + AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f); + } + return AdvertisedBenefit; +} + +int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim) +{ + int32 AdvertisedBenefit = 0; + AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING); + for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i) + if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) + AdvertisedBenefit += (*i)->GetModifier()->m_amount; + return AdvertisedBenefit; +} + +bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask, bool useCharges) +{ + // no charges dependent checks + SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; + for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) + if(itr->type & shoolMask) + return true; + + // charges dependent checks + SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE]; + for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr) + { + if(itr->type & shoolMask) + { + if(useCharges) + { + AuraList const& auraDamageImmunity = GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY); + for(AuraList::const_iterator auraItr = auraDamageImmunity.begin(); auraItr != auraDamageImmunity.end(); ++auraItr) + { + if((*auraItr)->GetId()==itr->spellId) + { + if((*auraItr)->m_procCharges > 0) + { + --(*auraItr)->m_procCharges; + if((*auraItr)->m_procCharges==0) + RemoveAurasDueToSpell(itr->spellId); + } + break; + } + } + } + return true; + } + } + + return false; +} + +bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges) +{ + if (!spellInfo) + return false; + + // no charges first + + //FIX ME this hack: don't get feared if stunned + if (spellInfo->Mechanic == MECHANIC_FEAR ) + { + if ( hasUnitState(UNIT_STAT_STUNDED) ) + return true; + } + + // not have spells with charges currently + SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL]; + for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr) + if(itr->type == spellInfo->Dispel) + return true; + + if( !(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE)) // unaffected by school immunity + { + // not have spells with charges currently + SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; + for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) + if( !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) && + (itr->type & GetSpellSchoolMask(spellInfo)) ) + return true; + } + + // charges dependent checks + + SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; + for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) + { + if(itr->type == spellInfo->Mechanic) + { + if(useCharges) + { + AuraList const& auraMechImmunity = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY); + for(AuraList::const_iterator auraItr = auraMechImmunity.begin(); auraItr != auraMechImmunity.end(); ++auraItr) + { + if((*auraItr)->GetId()==itr->spellId) + { + if((*auraItr)->m_procCharges > 0) + { + --(*auraItr)->m_procCharges; + if((*auraItr)->m_procCharges==0) + RemoveAurasDueToSpell(itr->spellId); + } + break; + } + } + } + return true; + } + } + + return false; +} + +bool Unit::IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const +{ + //If m_immuneToEffect type contain this effect type, IMMUNE effect. + SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT]; + for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr) + if(itr->type == effect) + return true; + + SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; + for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) + if(itr->type == mechanic) + return true; + + return false; +} + +bool Unit::IsDamageToThreatSpell(SpellEntry const * spellInfo) const +{ + if(!spellInfo) + return false; + + uint32 family = spellInfo->SpellFamilyName; + uint64 flags = spellInfo->SpellFamilyFlags; + + if((family == 5 && flags == 256) || //Searing Pain + (family == 6 && flags == 8192) || //Mind Blast + (family == 11 && flags == 1048576)) //Earth Shock + return true; + + return false; +} + +void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attType, SpellEntry const *spellProto) +{ + if(!pVictim) + return; + + if(*pdamage == 0) + return; + + uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); + + // Taken/Done fixed damage bonus auras + int32 DoneFlatBenefit = 0; + int32 TakenFlatBenefit = 0; + + // ..done (for creature type by mask) in taken + AuraList const& mDamageDoneCreature = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE); + for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i) + if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) + DoneFlatBenefit += (*i)->GetModifier()->m_amount; + + // ..done + // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage + + // ..done (base at attack power for marked target and base at attack power for creature type) + int32 APbonus = 0; + if(attType == RANGED_ATTACK) + { + APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS); + + // ..done (base at attack power and creature type) + AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS); + for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i) + if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) + APbonus += (*i)->GetModifier()->m_amount; + } + else + { + APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS); + + // ..done (base at attack power and creature type) + AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS); + for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i) + if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) + APbonus += (*i)->GetModifier()->m_amount; + } + + if (APbonus!=0) // Can be negative + { + bool normalized = false; + if(spellProto) + { + for (uint8 i = 0; i<3;i++) + { + if (spellProto->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG) + { + normalized = true; + break; + } + } + } + + DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType,normalized)); + } + + // ..taken + AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN); + for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i) + if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) + TakenFlatBenefit += (*i)->GetModifier()->m_amount; + + if(attType!=RANGED_ATTACK) + TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN); + else + TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN); + + // Done/Taken total percent damage auras + float DoneTotalMod = 1; + float TakenTotalMod = 1; + + // ..done + // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage + // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage + + AuraList const& mDamageDoneVersus = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS); + for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) + if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) + DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; + + // ..taken + AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); + for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i) + if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) + TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; + + // .. taken pct: dummy auras + AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) + { + switch((*i)->GetSpellProto()->SpellIconID) + { + //Cheat Death + case 2109: + if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) + { + if(pVictim->GetTypeId() != TYPEID_PLAYER) + continue; + float mod = ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*(-8.0f); + if (mod < (*i)->GetModifier()->m_amount) + mod = (*i)->GetModifier()->m_amount; + TakenTotalMod *= (mod+100.0f)/100.0f; + } + break; + //Mangle + case 2312: + if(spellProto==NULL) + break; + // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG) + if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && (spellProto->SpellFamilyFlags==0x00008000LL)) + TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; + break; + } + } + + // .. taken pct: class scripts + AuraList const& mclassScritAuras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(AuraList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i) + { + switch((*i)->GetMiscValue()) + { + case 6427: case 6428: // Dirty Deeds + if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) + { + Aura* eff0 = GetAura((*i)->GetId(),0); + if(!eff0 || (*i)->GetEffIndex()!=1) + { + sLog.outError("Spell structure of DD (%u) changed.",(*i)->GetId()); + continue; + } + + // effect 0 have expected value but in negative state + TakenTotalMod *= (-eff0->GetModifier()->m_amount+100.0f)/100.0f; + } + break; + } + } + + if(attType != RANGED_ATTACK) + { + AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT); + for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i) + TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; + } + else + { + AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT); + for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i) + TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; + } + + float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod; + + // apply spellmod to Done damage + if(spellProto) + { + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage); + } + + tmpDamage = (tmpDamage + TakenFlatBenefit)*TakenTotalMod; + + // bonus result can be negative + *pdamage = tmpDamage > 0 ? uint32(tmpDamage) : 0; +} + +void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply) +{ + if (apply) + { + for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next) + { + next = itr; ++next; + if(itr->type == type) + { + m_spellImmune[op].erase(itr); + next = m_spellImmune[op].begin(); + } + } + SpellImmune Immune; + Immune.spellId = spellId; + Immune.type = type; + m_spellImmune[op].push_back(Immune); + } + else + { + for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr) + { + if(itr->spellId == spellId) + { + m_spellImmune[op].erase(itr); + break; + } + } + } + +} + +void Unit::ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply) +{ + ApplySpellImmune(spellProto->Id,IMMUNITY_DISPEL, type, apply); + + if (apply && spellProto->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY) + RemoveAurasWithDispelType(type); +} + +float Unit::GetWeaponProcChance() const +{ + // normalized proc chance for weapon attack speed + // (odd formulae...) + if(isAttackReady(BASE_ATTACK)) + return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f); + else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) + return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f); + return 0; +} + +float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const +{ + // proc per minute chance calculation + if (PPM <= 0) return 0.0f; + uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) + return result; +} + +void Unit::Mount(uint32 mount) +{ + if(!mount) + return; + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING); + + SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount); + + SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); + + // unsummon pet + if(GetTypeId() == TYPEID_PLAYER) + { + Pet* pet = GetPet(); + if(pet) + { + if(pet->isControlled()) + { + ((Player*)this)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber()); + ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL)); + } + + ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT); + } + else + ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); + } +} + +void Unit::Unmount() +{ + if(!IsMounted()) + return; + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED); + + SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); + RemoveFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); + + // only resummon old pet if the player is already added to a map + // this prevents adding a pet to a not created map which would otherwise cause a crash + // (it could probably happen when logging in after a previous crash) + if(GetTypeId() == TYPEID_PLAYER && IsInWorld() && ((Player*)this)->GetTemporaryUnsummonedPetNumber() && isAlive()) + { + Pet* NewPet = new Pet; + if(!NewPet->LoadPetFromDB(this, 0, ((Player*)this)->GetTemporaryUnsummonedPetNumber(), true)) + delete NewPet; + + ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); + } +} + +void Unit::SetInCombatWith(Unit* enemy) +{ + Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf(); + if(eOwner->IsPvP()) + { + SetInCombatState(true); + return; + } + + //check for duel + if(eOwner->GetTypeId() == TYPEID_PLAYER && ((Player*)eOwner)->duel) + { + Unit const* myOwner = GetCharmerOrOwnerOrSelf(); + if(((Player const*)eOwner)->duel->opponent == myOwner) + { + SetInCombatState(true); + return; + } + } + SetInCombatState(false); +} + +void Unit::SetInCombatState(bool PvP) +{ + // only alive units can be in combat + if(!isAlive()) + return; + + if(PvP) + m_CombatTimer = 5000; + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + + if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())) + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); +} + +void Unit::ClearInCombat() +{ + m_CombatTimer = 0; + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + + if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())) + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); + + // Player's state will be cleared in Player::UpdateContestedPvP + if(GetTypeId()!=TYPEID_PLAYER) + clearUnitState(UNIT_STAT_ATTACK_PLAYER); +} + +bool Unit::isTargetableForAttack() const +{ + if (GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster()) + return false; + + if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) + return false; + + return isAlive() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/; +} + +int32 Unit::ModifyHealth(int32 dVal) +{ + int32 gain = 0; + + if(dVal==0) + return 0; + + int32 curHealth = (int32)GetHealth(); + + int32 val = dVal + curHealth; + if(val <= 0) + { + SetHealth(0); + return -curHealth; + } + + int32 maxHealth = (int32)GetMaxHealth(); + + if(val < maxHealth) + { + SetHealth(val); + gain = val - curHealth; + } + else if(curHealth != maxHealth) + { + SetHealth(maxHealth); + gain = maxHealth - curHealth; + } + + return gain; +} + +int32 Unit::ModifyPower(Powers power, int32 dVal) +{ + int32 gain = 0; + + if(dVal==0) + return 0; + + int32 curPower = (int32)GetPower(power); + + int32 val = dVal + curPower; + if(val <= 0) + { + SetPower(power,0); + return -curPower; + } + + int32 maxPower = (int32)GetMaxPower(power); + + if(val < maxPower) + { + SetPower(power,val); + gain = val - curPower; + } + else if(curPower != maxPower) + { + SetPower(power,maxPower); + gain = maxPower - curPower; + } + + return gain; +} + +bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList) const +{ + if(!u) + return false; + + // Always can see self + if (u==this) + return true; + + // player visible for other player if not logout and at same transport + // including case when player is out of world + bool at_same_transport = + GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER && + !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() && + !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() && + ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport(); + + // not in world + if(!at_same_transport && (!IsInWorld() || !u->IsInWorld())) + return false; + + // forbidden to seen (at GM respawn command) + if(m_Visibility==VISIBILITY_RESPAWN) + return false; + + // always seen by owner + if(GetCharmerOrOwnerGUID()==u->GetGUID()) + return true; + + // Grid dead/alive checks + if( u->GetTypeId()==TYPEID_PLAYER) + { + // non visible at grid for any stealth state + if(!IsVisibleInGridForPlayer((Player *)u)) + return false; + + // if player is dead then he can't detect anyone in anycases + if(!u->isAlive()) + detect = false; + } + else + { + // all dead creatures/players not visible for any creatures + if(!u->isAlive() || !isAlive()) + return false; + } + + // different visible distance checks + if(u->isInFlight()) // what see player in flight + { + // use object grey distance for all (only see objects any way) + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) + return false; + } + else if(!isAlive()) // distance for show body + { + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) + return false; + } + else if(GetTypeId()==TYPEID_PLAYER) // distance for show player + { + if(u->GetTypeId()==TYPEID_PLAYER) + { + // Players far than max visible distance for player or not in our map are not visible too + if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) + return false; + } + else + { + // Units far than max visible distance for creature or not in our map are not visible too + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) + return false; + } + } + else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed + { + // Pet/charmed far than max visible distance for player or not in our map are not visible too + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) + return false; + } + else // distance for show creature + { + // Units far than max visible distance for creature or not in our map are not visible too + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) + return false; + } + + // Visible units, always are visible for all units, except for units under invisibility + if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask==0) + return true; + + // GMs see any players, not higher GMs and all units + if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster()) + { + if(GetTypeId() == TYPEID_PLAYER) + return ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity(); + else + return true; + } + + // non faction visibility non-breakable for non-GMs + if (m_Visibility == VISIBILITY_OFF) + return false; + + // raw invisibility + bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask !=0); + + // detectable invisibility case + if( invisible && ( + // Invisible units, always are visible for units under same invisibility type + (m_invisibilityMask & u->m_invisibilityMask)!=0 || + // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect) + u->canDetectInvisibilityOf(this) || + // Units that can detect invisibility always are visible for units that can be detected + canDetectInvisibilityOf(u) )) + { + invisible = false; + } + + // special cases for always overwrite invisibility/stealth + if(invisible || m_Visibility == VISIBILITY_GROUP_STEALTH) + { + // non-hostile case + if (!u->IsHostileTo(this)) + { + // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting) + if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER) + { + if(((Player*)this)->IsGroupVisibleFor(((Player*)u))) + return true; + + // else apply same rules as for hostile case (detecting check for stealth) + } + } + // hostile case + else + { + // Hunter mark functionality + AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); + for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) + if((*iter)->GetCasterGUID()==u->GetGUID()) + return true; + + // else apply detecting check for stealth + } + + // none other cases for detect invisibility, so invisible + if(invisible) + return false; + + // else apply stealth detecting check + } + + // unit got in stealth in this moment and must ignore old detected state + if (m_Visibility == VISIBILITY_GROUP_NO_DETECT) + return false; + + // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible + if (m_Visibility != VISIBILITY_GROUP_STEALTH) + return true; + + // NOW ONLY STEALTH CASE + + // stealth and detected and visible for some seconds + if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->m_DetectInvTimer > 300 && ((Player*)u)->HaveAtClient(this)) + return true; + + //if in non-detect mode then invisible for unit + if (!detect) + return false; + + // Special cases + + // If is attacked then stealth is lost, some creature can use stealth too + if( !getAttackers().empty() ) + return true; + + // If there is collision rogue is seen regardless of level difference + // TODO: check sizes in DB + float distance = GetDistance(u); + if (distance < 0.24f) + return true; + + //If a mob or player is stunned he will not be able to detect stealth + if (u->hasUnitState(UNIT_STAT_STUNDED) && (u != this)) + return false; + + // Creature can detect target only in aggro radius + if(u->GetTypeId() != TYPEID_PLAYER) + { + //Always invisible from back and out of aggro range + bool isInFront = u->isInFront(this,((Creature const*)u)->GetAttackDistance(this)); + if(!isInFront) + return false; + } + else + { + //Always invisible from back + bool isInFront = u->isInFront(this,(GetTypeId()==TYPEID_PLAYER || GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature()); + if(!isInFront) + return false; + } + + // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los + if(!u->HasAuraType(SPELL_AURA_DETECT_STEALTH)) + { + //Calculation if target is in front + + //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) + float visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/100.0f); + + //Visible distance is modified by + //-Level Diff (every level diff = 1.0f in visible distance) + visibleDistance += int32(u->getLevelForTarget(this)) - int32(this->getLevelForTarget(u)); + + //This allows to check talent tree and will add addition stealth dependent on used points) + int32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL); + if(stealthMod < 0) + stealthMod = 0; + + //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) + //based on wowwiki every 5 mod we have 1 more level diff in calculation + visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT)) - stealthMod)/5.0f; + + if(distance > visibleDistance) + return false; + } + + // Now check is target visible with LoS + float ox,oy,oz; + u->GetPosition(ox,oy,oz); + return IsWithinLOS(ox,oy,oz); +} + +void Unit::SetVisibility(UnitVisibility x) +{ + m_Visibility = x; + + if(IsInWorld()) + { + Map *m = MapManager::Instance().GetMap(GetMapId(), this); + + if(GetTypeId()==TYPEID_PLAYER) + m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + else + m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + } +} + +bool Unit::canDetectInvisibilityOf(Unit const* u) const +{ + if(uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask)) + { + for(uint32 i = 0; i < 10; ++i) + { + if(((1 << i) & mask)==0) + continue; + + // find invisibility level + uint32 invLevel = 0; + Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY); + for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr) + if(((*itr)->GetModifier()->m_miscvalue)==i && invLevel < (*itr)->GetModifier()->m_amount) + invLevel = (*itr)->GetModifier()->m_amount; + + // find invisibility detect level + uint32 detectLevel = 0; + Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION); + for(Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr) + if(((*itr)->GetModifier()->m_miscvalue)==i && detectLevel < (*itr)->GetModifier()->m_amount) + detectLevel = (*itr)->GetModifier()->m_amount; + + if(i==6 && GetTypeId()==TYPEID_PLAYER) // special drunk detection case + { + detectLevel = ((Player*)this)->GetDrunkValue(); + } + + if(invLevel <= detectLevel) + return true; + } + } + + return false; +} + +void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) +{ + int32 main_speed_mod = 0; + float stack_bonus = 1.0f; + float non_stack_bonus = 1.0f; + + switch(mtype) + { + case MOVE_WALK: + return; + case MOVE_RUN: + { + if (IsMounted()) // Use on mount auras + { + main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED); + stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS); + non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK))/100.0f; + } + else + { + main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED); + stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS); + non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK))/100.0f; + } + break; + } + case MOVE_WALKBACK: + return; + case MOVE_SWIM: + { + main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED); + break; + } + case MOVE_SWIMBACK: + return; + case MOVE_FLY: + { + if (IsMounted()) // Use on mount auras + main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED); + else // Use not mount (shapeshift for example) auras (should stack) + main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT); + stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS); + non_stack_bonus = (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK))/100.0f; + break; + } + case MOVE_FLYBACK: + return; + default: + sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype); + return; + } + + float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus; + // now we ready for speed calculation + float speed = main_speed_mod ? bonus*(100.0f + main_speed_mod)/100.0f : bonus; + + switch(mtype) + { + case MOVE_RUN: + case MOVE_SWIM: + case MOVE_FLY: + { + // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need + // TODO: possible affect only on MOVE_RUN + if(int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED)) + { + // Use speed from aura + float max_speed = normalization / baseMoveSpeed[mtype]; + if (speed > max_speed) + speed = max_speed; + } + break; + } + default: + break; + } + + // Apply strongest slow aura mod to speed + int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); + if (slow) + speed *=(100.0f + slow)/100.0f; + SetSpeed(mtype, speed, forced); +} + +float Unit::GetSpeed( UnitMoveType mtype ) const +{ + return m_speed_rate[mtype]*baseMoveSpeed[mtype]; +} + +void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) +{ + if (rate < 0) + rate = 0.0f; + + // Update speed only on change + if (m_speed_rate[mtype] == rate) + return; + + m_speed_rate[mtype] = rate; + + propagateSpeedChange(); + + // Send speed change packet only for player + if (GetTypeId()!=TYPEID_PLAYER) + return; + + WorldPacket data; + if(!forced) + { + switch(mtype) + { + case MOVE_WALK: + data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+1+4+4+4+4+4+4+4); + break; + case MOVE_RUN: + data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+1+4+4+4+4+4+4+4); + break; + case MOVE_WALKBACK: + data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); + break; + case MOVE_SWIM: + data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+1+4+4+4+4+4+4+4); + break; + case MOVE_SWIMBACK: + data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); + break; + case MOVE_TURN: + data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+1+4+4+4+4+4+4+4); + break; + case MOVE_FLY: + data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+1+4+4+4+4+4+4+4); + break; + case MOVE_FLYBACK: + data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); + break; + default: + sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype); + return; + } + + data.append(GetPackGUID()); + data << uint32(0); //movement flags + data << uint8(0); //unk + data << uint32(getMSTime()); + data << float(GetPositionX()); + data << float(GetPositionY()); + data << float(GetPositionZ()); + data << float(GetOrientation()); + data << uint32(0); //flag unk + data << float(GetSpeed(mtype)); + SendMessageToSet( &data, true ); + } + else + { + // register forced speed changes for WorldSession::HandleForceSpeedChangeAck + // and do it only for real sent packets and use run for run/mounted as client expected + ++((Player*)this)->m_forced_speed_changes[mtype]; + switch(mtype) + { + case MOVE_WALK: + data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16); + break; + case MOVE_RUN: + data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 17); + break; + case MOVE_WALKBACK: + data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16); + break; + case MOVE_SWIM: + data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16); + break; + case MOVE_SWIMBACK: + data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16); + break; + case MOVE_TURN: + data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16); + break; + case MOVE_FLY: + data.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE, 16); + break; + case MOVE_FLYBACK: + data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16); + break; + default: + sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype); + return; + } + data.append(GetPackGUID()); + data << (uint32)0; + if (mtype == MOVE_RUN) + data << uint8(0); // new 2.1.0 + data << float(GetSpeed(mtype)); + SendMessageToSet( &data, true ); + } + if(Pet* pet = GetPet()) + pet->SetSpeed(MOVE_RUN, m_speed_rate[mtype],forced); +} + +void Unit::SetHover(bool on) +{ + if(on) + CastSpell(this,11010,true); + else + RemoveAurasDueToSpell(11010); +} + +void Unit::setDeathState(DeathState s) +{ + if (s != ALIVE && s!= JUST_ALIVED) + { + CombatStop(); + DeleteThreatList(); + ClearComboPointHolders(); // any combo points pointed to unit lost at it death + + if(IsNonMeleeSpellCasted(false)) + InterruptNonMeleeSpells(false); + } + + if (s == JUST_DIED) + { + RemoveAllAurasOnDeath(); + UnsummonAllTotems(); + + ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + // remove aurastates allowing special moves + ClearAllReactives(); + ClearDiminishings(); + } + else if(s == JUST_ALIVED) + { + RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground) + } + + if (m_deathState != ALIVE && s == ALIVE) + { + //_ApplyAllAuraMods(); + } + m_deathState = s; +} + +/*######################################## +######## ######## +######## AGGRO SYSTEM ######## +######## ######## +########################################*/ +bool Unit::CanHaveThreatList() const +{ + // only creatures can have threat list + if( GetTypeId() != TYPEID_UNIT ) + return false; + + // only alive units can have threat list + if( !isAlive() ) + return false; + + // pets and totems can not have threat list + if( ((Creature*)this)->isPet() || ((Creature*)this)->isTotem() ) + return false; + + return true; +} + +//====================================================================== + +float Unit::ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask) +{ + if(!HasAuraType(SPELL_AURA_MOD_THREAT)) + return threat; + + SpellSchools school = GetFirstSchoolInMask(schoolMask); + + return threat * m_threatModifier[school]; +} + +//====================================================================== + +void Unit::AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask, SpellEntry const *threatSpell) +{ + // Only mobs can manage threat lists + if(CanHaveThreatList()) + m_ThreatManager.addThreat(pVictim, threat, schoolMask, threatSpell); +} + +//====================================================================== + +void Unit::DeleteThreatList() +{ + m_ThreatManager.clearReferences(); +} + +//====================================================================== + +void Unit::TauntApply(Unit* taunter) +{ + assert(GetTypeId()== TYPEID_UNIT); + + if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster())) + return; + + if(!CanHaveThreatList()) + return; + + Unit *target = getVictim(); + if(target && target == taunter) + return; + + SetInFront(taunter); + if (((Creature*)this)->AI()) + ((Creature*)this)->AI()->AttackStart(taunter); + + m_ThreatManager.tauntApply(taunter); +} + +//====================================================================== + +void Unit::TauntFadeOut(Unit *taunter) +{ + assert(GetTypeId()== TYPEID_UNIT); + + if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster())) + return; + + if(!CanHaveThreatList()) + return; + + Unit *target = getVictim(); + if(!target || target != taunter) + return; + + if(m_ThreatManager.isThreatListEmpty()) + { + if(((Creature*)this)->AI()) + ((Creature*)this)->AI()->EnterEvadeMode(); + return; + } + + m_ThreatManager.tauntFadeOut(taunter); + target = m_ThreatManager.getHostilTarget(); + + if (target && target != taunter) + { + SetInFront(target); + if (((Creature*)this)->AI()) + ((Creature*)this)->AI()->AttackStart(target); + } +} + +//====================================================================== + +bool Unit::SelectHostilTarget() +{ + //function provides main threat functionality + //next-victim-selection algorithm and evade mode are called + //threat list sorting etc. + + assert(GetTypeId()== TYPEID_UNIT); + Unit* target = NULL; + + //This function only useful once AI has been initilazied + if (!((Creature*)this)->AI()) + return false; + + if(!m_ThreatManager.isThreatListEmpty()) + { + if(!HasAuraType(SPELL_AURA_MOD_TAUNT)) + { + target = m_ThreatManager.getHostilTarget(); + } + } + + if(target) + { + if(!hasUnitState(UNIT_STAT_STUNDED)) + SetInFront(target); + ((Creature*)this)->AI()->AttackStart(target); + return true; + } + + // no target but something prevent go to evade mode + if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT) ) + return false; + + // last case when creature don't must go to evade mode: + // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list + // for example at owner command to pet attack some far away creature + // Note: creature not have targeted movement generator but have attacker in this case + if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE ) + { + for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) + { + if( (*itr)->IsInMap(this) && (*itr)->isTargetableForAttack() && (*itr)->isInAccessablePlaceFor((Creature*)this) ) + return false; + } + } + + // enter in evade mode in other case + ((Creature*)this)->AI()->EnterEvadeMode(); + + return false; +} + +//====================================================================== +//====================================================================== +//====================================================================== + +int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_index, int32 effBasePoints, Unit const* target) +{ + Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL; + + uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0; + + int32 level = int32(getLevel()) - int32(spellProto->spellLevel); + if (level > spellProto->maxLevel && spellProto->maxLevel > 0) + level = spellProto->maxLevel; + + float basePointsPerLevel = spellProto->EffectRealPointsPerLevel[effect_index]; + float randomPointsPerLevel = spellProto->EffectDicePerLevel[effect_index]; + int32 basePoints = int32(effBasePoints + level * basePointsPerLevel); + int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel); + float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index]; + + // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell + int32 randvalue = spellProto->EffectBaseDice[effect_index] >= randomPoints ? spellProto->EffectBaseDice[effect_index]:irand(spellProto->EffectBaseDice[effect_index], randomPoints); + int32 value = basePoints + randvalue; + //random damage + if(comboDamage != 0 && unitPlayer && target && (target->GetGUID() == unitPlayer->GetComboTarget())) + value += (int32)(comboDamage * comboPoints); + + if(Player* modOwner = GetSpellModOwner()) + { + modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_ALL_EFFECTS, value); + switch(effect_index) + { + case 0: + modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT1, value); + break; + case 1: + modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT2, value); + break; + case 2: + modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT3, value); + break; + } + } + + if(spellProto->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION && spellProto->spellLevel && + spellProto->Effect[effect_index] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && + spellProto->Effect[effect_index] != SPELL_EFFECT_KNOCK_BACK) + value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f)); + + return value; +} + +int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_index, Unit const* target) +{ + Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL; + + uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0; + + int32 minduration = GetSpellDuration(spellProto); + int32 maxduration = GetSpellMaxDuration(spellProto); + + int32 duration; + + if( minduration != -1 && minduration != maxduration ) + duration = minduration + int32((maxduration - minduration) * comboPoints / 5); + else + duration = minduration; + + if (duration > 0) + { + int32 mechanic = GetEffectMechanic(spellProto, effect_index); + // Find total mod value (negative bonus) + int32 durationMod_always = target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic); + // Find max mod (negative bonus) + int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic); + + int32 durationMod = 0; + // Select strongest negative mod + if (durationMod_always > durationMod_not_stack) + durationMod = durationMod_not_stack; + else + durationMod = durationMod_always; + + if (durationMod != 0) + duration = int32(int64(duration) * (100+durationMod) /100); + + if (duration < 0) duration = 0; + } + + return duration; +} + +DiminishingLevels Unit::GetDiminishing(DiminishingGroup group) +{ + for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) + { + if(i->DRGroup != group) + continue; + + if(!i->hitCount) + return DIMINISHING_LEVEL_1; + + if(!i->hitTime) + return DIMINISHING_LEVEL_1; + + // If last spell was casted more than 15 seconds ago - reset the count. + if(i->stack==0 && getMSTimeDiff(i->hitTime,getMSTime()) > 15000) + { + i->hitCount = DIMINISHING_LEVEL_1; + return DIMINISHING_LEVEL_1; + } + // or else increase the count. + else + { + return DiminishingLevels(i->hitCount); + } + } + return DIMINISHING_LEVEL_1; +} + +void Unit::IncrDiminishing(DiminishingGroup group) +{ + // Checking for existing in the table + bool IsExist = false; + for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) + { + if(i->DRGroup != group) + continue; + + IsExist = true; + if(i->hitCount < DIMINISHING_LEVEL_IMMUNE) + i->hitCount += 1; + + break; + } + + if(!IsExist) + m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2)); +} + +void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level) +{ + if(duration == -1 || group == DIMINISHING_NONE || caster->IsFriendlyTo(this) ) + return; + + // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0) + if(duration > 10000 && IsDiminishingReturnsGroupDurationLimited(group)) + { + // test pet/charm masters instead pets/charmeds + Unit const* targetOwner = GetCharmerOrOwner(); + Unit const* casterOwner = caster->GetCharmerOrOwner(); + + Unit const* target = targetOwner ? targetOwner : this; + Unit const* source = casterOwner ? casterOwner : caster; + + if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER) + duration = 10000; + } + + float mod = 1.0f; + + // Some diminishings applies to mobs too (for example, Stun) + if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL) + { + DiminishingLevels diminish = Level; + switch(diminish) + { + case DIMINISHING_LEVEL_1: break; + case DIMINISHING_LEVEL_2: mod = 0.5f; break; + case DIMINISHING_LEVEL_3: mod = 0.25f; break; + case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f;break; + default: break; + } + } + + duration = int32(duration * mod); +} + +void Unit::ApplyDiminishingAura( DiminishingGroup group, bool apply ) +{ + // Checking for existing in the table + for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) + { + if(i->DRGroup != group) + continue; + + i->hitTime = getMSTime(); + + if(apply) + i->stack += 1; + else if(i->stack) + i->stack -= 1; + + break; + } +} + +Unit* Unit::GetUnit(WorldObject& object, uint64 guid) +{ + return ObjectAccessor::GetUnit(object,guid); +} + +bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const +{ + return isVisibleForOrDetect(u,false,inVisibleList); +} + +uint32 Unit::GetCreatureType() const +{ + if(GetTypeId() == TYPEID_PLAYER) + { + SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(((Player*)this)->m_form); + if(ssEntry && ssEntry->creatureType > 0) + return ssEntry->creatureType; + else + return CREATURE_TYPE_HUMANOID; + } + else + return ((Creature*)this)->GetCreatureInfo()->type; +} + +/*####################################### +######## ######## +######## STAT SYSTEM ######## +######## ######## +#######################################*/ + +bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply) +{ + if(unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) + { + sLog.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!"); + return false; + } + + float val = 1.0f; + + switch(modifierType) + { + case BASE_VALUE: + case TOTAL_VALUE: + m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; + break; + case BASE_PCT: + case TOTAL_PCT: + if(amount <= -100.0f) //small hack-fix for -100% modifiers + amount = -200.0f; + + val = (100.0f + amount) / 100.0f; + m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f/val); + break; + + default: + break; + } + + if(!CanModifyStats()) + return false; + + switch(unitMod) + { + case UNIT_MOD_STAT_STRENGTH: + case UNIT_MOD_STAT_AGILITY: + case UNIT_MOD_STAT_STAMINA: + case UNIT_MOD_STAT_INTELLECT: + case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break; + + case UNIT_MOD_ARMOR: UpdateArmor(); break; + case UNIT_MOD_HEALTH: UpdateMaxHealth(); break; + + case UNIT_MOD_MANA: + case UNIT_MOD_RAGE: + case UNIT_MOD_FOCUS: + case UNIT_MOD_ENERGY: + case UNIT_MOD_HAPPINESS: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break; + + case UNIT_MOD_RESISTANCE_HOLY: + case UNIT_MOD_RESISTANCE_FIRE: + case UNIT_MOD_RESISTANCE_NATURE: + case UNIT_MOD_RESISTANCE_FROST: + case UNIT_MOD_RESISTANCE_SHADOW: + case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break; + + case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break; + case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break; + + case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break; + case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break; + case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break; + + default: + break; + } + + return true; +} + +float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const +{ + if( unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) + { + sLog.outError("ERROR: trial to access nonexisted modifier value from UnitMods!"); + return 0.0f; + } + + if(modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f) + return 0.0f; + + return m_auraModifiersGroup[unitMod][modifierType]; +} + +float Unit::GetTotalStatValue(Stats stat) const +{ + UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat); + + if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) + return 0.0f; + + // value = ((base_value * base_pct) + total_value) * total_pct + float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat); + value *= m_auraModifiersGroup[unitMod][BASE_PCT]; + value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; + value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; + + return value; +} + +float Unit::GetTotalAuraModValue(UnitMods unitMod) const +{ + if(unitMod >= UNIT_MOD_END) + { + sLog.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!"); + return 0.0f; + } + + if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) + return 0.0f; + + float value = m_auraModifiersGroup[unitMod][BASE_VALUE]; + value *= m_auraModifiersGroup[unitMod][BASE_PCT]; + value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; + value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; + + return value; +} + +SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const +{ + SpellSchools school = SPELL_SCHOOL_NORMAL; + + switch(unitMod) + { + case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break; + case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break; + case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break; + case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break; + case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break; + case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break; + + default: + break; + } + + return school; +} + +Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const +{ + Stats stat = STAT_STRENGTH; + + switch(unitMod) + { + case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break; + case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break; + case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break; + case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break; + case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break; + + default: + break; + } + + return stat; +} + +Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const +{ + Powers power = POWER_MANA; + + switch(unitMod) + { + case UNIT_MOD_MANA: power = POWER_MANA; break; + case UNIT_MOD_RAGE: power = POWER_RAGE; break; + case UNIT_MOD_FOCUS: power = POWER_FOCUS; break; + case UNIT_MOD_ENERGY: power = POWER_ENERGY; break; + case UNIT_MOD_HAPPINESS: power = POWER_HAPPINESS; break; + + default: + break; + } + + return power; +} + +float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const +{ + UnitMods unitMod = (attType == RANGED_ATTACK) ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; + + float val = GetTotalAuraModValue(unitMod); + if(val < 0.0f) + val = 0.0f; + + return val; +} + +float Unit::GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const +{ + if (attType == OFF_ATTACK && !haveOffhandWeapon()) + return 0.0f; + + return m_weaponDamage[attType][type]; +} + +void Unit::SetLevel(uint32 lvl) +{ + SetUInt32Value(UNIT_FIELD_LEVEL, lvl); + + // group update + if ((GetTypeId() == TYPEID_PLAYER) && ((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL); +} + +void Unit::SetHealth(uint32 val) +{ + uint32 maxHealth = GetMaxHealth(); + if(maxHealth < val) + val = maxHealth; + + SetUInt32Value(UNIT_FIELD_HEALTH, val); + + // group update + if(GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP); + } + else if(((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(pet->isControlled()) + { + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP); + } + } +} + +void Unit::SetMaxHealth(uint32 val) +{ + uint32 health = GetHealth(); + SetUInt32Value(UNIT_FIELD_MAXHEALTH, val); + + // group update + if(GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP); + } + else if(((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(pet->isControlled()) + { + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP); + } + } + + if(val < health) + SetHealth(val); +} + +void Unit::SetPower(Powers power, uint32 val) +{ + uint32 maxPower = GetMaxPower(power); + if(maxPower < val) + val = maxPower; + + SetStatInt32Value(UNIT_FIELD_POWER1 + power, val); + + // group update + if(GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); + } + else if(((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(pet->isControlled()) + { + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); + } + + // Update the pet's character sheet with happiness damage bonus + if(pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS) + { + pet->UpdateDamagePhysical(BASE_ATTACK); + } + } +} + +void Unit::SetMaxPower(Powers power, uint32 val) +{ + uint32 cur_power = GetPower(power); + SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + power, val); + + // group update + if(GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); + } + else if(((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(pet->isControlled()) + { + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); + } + } + + if(val < cur_power) + SetPower(power, val); +} + +void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply) +{ + ApplyModUInt32Value(UNIT_FIELD_POWER1+power, val, apply); + + // group update + if(GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); + } + else if(((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(pet->isControlled()) + { + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); + } + } +} + +void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply) +{ + ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1+power, val, apply); + + // group update + if(GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); + } + else if(((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(pet->isControlled()) + { + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); + } + } +} + +void Unit::ApplyAuraProcTriggerDamage( Aura* aura, bool apply ) +{ + AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE]; + if(apply) + tAuraProcTriggerDamage.push_back(aura); + else + tAuraProcTriggerDamage.remove(aura); +} + +uint32 Unit::GetCreatePowers( Powers power ) const +{ + // POWER_FOCUS and POWER_HAPPINESS only have hunter pet + switch(power) + { + case POWER_MANA: return GetCreateMana(); + case POWER_RAGE: return 1000; + case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100); + case POWER_ENERGY: return 100; + case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000); + } + + return 0; +} + +void Unit::AddToWorld() +{ + Object::AddToWorld(); +} + +void Unit::RemoveFromWorld() +{ + // cleanup + if(IsInWorld()) + { + RemoveNotOwnSingleTargetAuras(); + } + + Object::RemoveFromWorld(); +} + +void Unit::CleanupsBeforeDelete() +{ + if(m_uint32Values) // only for fully created object + { + InterruptNonMeleeSpells(true); + m_Events.KillAllEvents(); + CombatStop(); + ClearComboPointHolders(); + DeleteThreatList(); + getHostilRefManager().setOnlineOfflineState(false); + RemoveAllAuras(); + RemoveAllGameObjects(); + RemoveAllDynObjects(); + GetMotionMaster()->Clear(false); // remove different non-standard movement generators. + } + RemoveFromWorld(); +} + +CharmInfo* Unit::InitCharmInfo(Unit *charm) +{ + if(!m_charmInfo) + m_charmInfo = new CharmInfo(charm); + return m_charmInfo; +} + +CharmInfo::CharmInfo(Unit* unit) +: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_ReactSate(REACT_PASSIVE), m_petnumber(0) +{ + for(int i =0; i<4; ++i) + { + m_charmspells[i].spellId = 0; + m_charmspells[i].active = ACT_DISABLED; + } +} + +void CharmInfo::InitPetActionBar() +{ + // the first 3 SpellOrActions are attack, follow and stay + for(uint32 i = 0; i < 3; i++) + { + PetActionBar[i].Type = ACT_COMMAND; + PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i; + + PetActionBar[i + 7].Type = ACT_REACTION; + PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i; + } + for(uint32 i=0; i < 4; i++) + { + PetActionBar[i + 3].Type = ACT_DISABLED; + PetActionBar[i + 3].SpellOrAction = 0; + } +} + +void CharmInfo::InitEmptyActionBar() +{ + for(uint32 x = 1; x < 10; ++x) + { + PetActionBar[x].Type = ACT_CAST; + PetActionBar[x].SpellOrAction = 0; + } + PetActionBar[0].Type = ACT_COMMAND; + PetActionBar[0].SpellOrAction = COMMAND_ATTACK; +} + +void CharmInfo::InitPossessCreateSpells() +{ + if(m_unit->GetTypeId() == TYPEID_PLAYER) + return; + + InitEmptyActionBar(); //charm action bar + + for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) + { + if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) + m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); + else + AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_CAST); + } +} + +void CharmInfo::InitCharmCreateSpells() +{ + if(m_unit->GetTypeId() == TYPEID_PLAYER) //charmed players don't have spells + { + InitEmptyActionBar(); + return; + } + + InitPetActionBar(); + + for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) + { + uint32 spellId = ((Creature*)m_unit)->m_spells[x]; + m_charmspells[x].spellId = spellId; + + if(!spellId) + continue; + + if (IsPassiveSpell(spellId)) + { + m_unit->CastSpell(m_unit, spellId, true); + m_charmspells[x].active = ACT_PASSIVE; + } + else + { + ActiveStates newstate; + bool onlyselfcast = true; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + + if(!spellInfo) onlyselfcast = false; + for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away + { + if(spellInfo->EffectImplicitTargetA[i] != TARGET_SELF && spellInfo->EffectImplicitTargetA[i] != 0) + onlyselfcast = false; + } + + if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable + newstate = ACT_DISABLED; + else + newstate = ACT_CAST; + + AddSpellToAB(0, spellId, newstate); + } + } +} + +bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate) +{ + for(uint8 i = 0; i < 10; i++) + { + if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_CAST) && PetActionBar[i].SpellOrAction == oldid) + { + PetActionBar[i].SpellOrAction = newid; + if(!oldid) + { + if(newstate == ACT_DECIDE) + PetActionBar[i].Type = ACT_DISABLED; + else + PetActionBar[i].Type = newstate; + } + + return true; + } + } + return false; +} + +void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply) +{ + if(IsPassiveSpell(spellid)) + return; + + for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) + { + if(spellid == m_charmspells[x].spellId) + { + m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED; + } + } +} + +void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow) +{ + m_petnumber = petnumber; + if(statwindow) + m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber); + else + m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0); +} + +bool Unit::isFrozen() const +{ + AuraList const& mRoot = GetAurasByType(SPELL_AURA_MOD_ROOT); + for(AuraList::const_iterator i = mRoot.begin(); i != mRoot.end(); ++i) + if( GetSpellSchoolMask((*i)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST) + return true; + return false; +} + +struct ProcTriggeredData +{ + ProcTriggeredData(SpellEntry const * _spellInfo, uint32 _spellParam, Aura* _triggeredByAura, uint32 _cooldown) + : spellInfo(_spellInfo), spellParam(_spellParam), triggeredByAura(_triggeredByAura), + triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex())), + cooldown(_cooldown) + {} + + SpellEntry const * spellInfo; + uint32 spellParam; + Aura* triggeredByAura; + Unit::spellEffectPair triggeredByAura_SpellPair; + uint32 cooldown; +}; + +typedef std::list< ProcTriggeredData > ProcTriggeredList; + +void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask ) +{ + for(AuraTypeSet::const_iterator aur = procAuraTypes.begin(); aur != procAuraTypes.end(); ++aur) + { + // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE) + ProcTriggeredList procTriggered; + + AuraList const& auras = GetAurasByType(*aur); + for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) + { + next = i; ++next; + + SpellEntry const *spellProto = (*i)->GetSpellProto(); + if(!spellProto) + continue; + + SpellProcEventEntry const *spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id); + if(!spellProcEvent) + { + // used to prevent spam in log about same non-handled spells + static std::set nonHandledSpellProcSet; + + if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end()) + { + sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's")); + nonHandledSpellProcSet.insert(spellProto->Id); + } + + // spell.dbc use totally different flags, that only can create problems if used. + continue; + } + + // Check spellProcEvent data requirements + if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag)) + continue; + + // Check if current equipment allows aura to proc + if(!isVictim && GetTypeId() == TYPEID_PLAYER ) + { + if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON) + { + Item *item = ((Player*)this)->GetWeaponForAttack(attType,true); + + if(!item || !((1<GetProto()->SubClass) & spellProto->EquippedItemSubClassMask)) + continue; + } + else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR) + { + // Check if player is wearing shield + Item *item = ((Player*)this)->GetShield(true); + if(!item || !((1<GetProto()->SubClass) & spellProto->EquippedItemSubClassMask)) + continue; + } + } + + float chance = (float)spellProto->procChance; + + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance); + + if(!isVictim && spellProcEvent->ppmRate != 0) + { + uint32 WeaponSpeed = GetAttackTime(attType); + chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate); + } + + if(roll_chance_f(chance)) + { + uint32 cooldown = spellProcEvent->cooldown; + + uint32 i_spell_eff = (*i)->GetEffIndex(); + + int32 i_spell_param; + switch(*aur) + { + case SPELL_AURA_PROC_TRIGGER_SPELL: + i_spell_param = procFlag; + break; + case SPELL_AURA_DUMMY: + case SPELL_AURA_PRAYER_OF_MENDING: + case SPELL_AURA_MOD_HASTE: + i_spell_param = i_spell_eff; + break; + case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: + i_spell_param = (*i)->GetModifier()->m_miscvalue; + break; + default: + i_spell_param = (*i)->GetModifier()->m_amount; + break; + } + + procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i, cooldown) ); + } + } + + // Handle effects proceed this time + for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i) + { + // Some auras can be deleted in function called in this loop (except first, ofc) + // Until storing auras in std::multimap to hard check deleting by another way + if(i != procTriggered.begin()) + { + bool found = false; + AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); + AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); + for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) + { + if(itr->second==i->triggeredByAura) + { + found = true; + break; + } + } + + if(!found) + { + sLog.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur,i->triggeredByAura_SpellPair.first,i->triggeredByAura_SpellPair.second); + sLog.outError("It can be deleted one from early proccesed auras:"); + for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2) + sLog.outError(" Spell aura %u (id:%u effect:%u)",*aur,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second); + sLog.outError(" "); + continue; + } + } + + // save charges existence before processing to prevent crash at access to deleted triggered aura after + bool triggeredByAuraWithCharges = i->triggeredByAura->m_procCharges > 0; + + bool casted = false; + switch(*aur) + { + case SPELL_AURA_PROC_TRIGGER_SPELL: + { + sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); + casted = HandleProcTriggerSpell(pTarget, damage, i->triggeredByAura, procSpell,i->spellParam,attType,i->cooldown); + break; + } + case SPELL_AURA_PROC_TRIGGER_DAMAGE: + { + sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i->spellParam, i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); + uint32 damage = i->spellParam; + SpellNonMeleeDamageLog(pTarget, i->spellInfo->Id, damage, true, true); + casted = true; + break; + } + case SPELL_AURA_DUMMY: + { + sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); + casted = HandleDummyAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown); + break; + } + case SPELL_AURA_PRAYER_OF_MENDING: + { + sLog.outDebug("ProcDamageAndSpell(mending): casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); + + // aura can be deleted at casts + int32 heal = i->triggeredByAura->GetModifier()->m_amount; + uint64 caster_guid = i->triggeredByAura->GetCasterGUID(); + + // jumps + int32 jumps = i->triggeredByAura->m_procCharges-1; + + // current aura expire + i->triggeredByAura->m_procCharges = 1; // will removed at next charges decrease + + // next target selection + if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid)) + { + Aura* aura = i->triggeredByAura; + + SpellEntry const* spellProto = aura->GetSpellProto(); + uint32 effIdx = aura->GetEffIndex(); + + float radius; + if (spellProto->EffectRadiusIndex[effIdx]) + radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx])); + else + radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex)); + + if(Player* caster = ((Player*)aura->GetCaster())) + { + caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL); + + if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius)) + { + // aura will applied from caster, but spell casted from current aura holder + SpellModifier *mod = new SpellModifier; + mod->op = SPELLMOD_CHARGES; + mod->value = jumps-5; // negative + mod->type = SPELLMOD_FLAT; + mod->spellId = spellProto->Id; + mod->effectId = effIdx; + mod->lastAffected = NULL; + mod->mask = spellProto->SpellFamilyFlags; + mod->charges = 0; + + caster->AddSpellMod(mod, true); + CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,aura,caster->GetGUID()); + caster->AddSpellMod(mod, false); + } + } + } + + // heal + CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid); + casted = true; + break; + } + case SPELL_AURA_MOD_HASTE: + { + sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); + casted = HandleHasteAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown); + break; + } + case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: + { + // nothing do, just charges counter + // but count only in case appropriate school damage + casted = i->triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask; + break; + } + case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: + { + sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); + casted = HandleOverrideClassScriptAuraProc(pTarget, i->spellParam, damage, i->triggeredByAura, procSpell,i->cooldown); + break; + } + default: + { + // nothing do, just charges counter + casted = true; + break; + } + } + + // Update charge (aura can be removed by triggers) + if(casted && triggeredByAuraWithCharges) + { + // need found aura (can be dropped by triggers) + AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); + AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); + for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) + { + if(itr->second == i->triggeredByAura) + { + if(i->triggeredByAura->m_procCharges > 0) + i->triggeredByAura->m_procCharges -= 1; + + i->triggeredByAura->UpdateAuraCharges(); + break; + } + } + } + } + + // Safely remove auras with zero charges + for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) + { + next = i; ++next; + if((*i)->m_procCharges == 0) + { + RemoveAurasDueToSpell((*i)->GetId()); + next = auras.begin(); + } + } + } +} + +SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const +{ + return SPELL_SCHOOL_MASK_NORMAL; +} + +Player* Unit::GetSpellModOwner() +{ + if(GetTypeId()==TYPEID_PLAYER) + return (Player*)this; + if(((Creature*)this)->isPet() || ((Creature*)this)->isTotem()) + { + Unit* owner = GetOwner(); + if(owner && owner->GetTypeId()==TYPEID_PLAYER) + return (Player*)owner; + } + return NULL; +} + +///----------Pet responses methods----------------- +void Unit::SendPetCastFail(uint32 spellid, uint8 msg) +{ + Unit *owner = GetCharmerOrOwner(); + if(!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + WorldPacket data(SMSG_PET_CAST_FAILED, (4+1)); + data << uint32(spellid); + data << uint8(msg); + ((Player*)owner)->GetSession()->SendPacket(&data); +} + +void Unit::SendPetActionFeedback (uint8 msg) +{ + Unit* owner = GetOwner(); + if(!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + WorldPacket data(SMSG_PET_ACTION_FEEDBACK, 1); + data << uint8(msg); + ((Player*)owner)->GetSession()->SendPacket(&data); +} + +void Unit::SendPetTalk (uint32 pettalk) +{ + Unit* owner = GetOwner(); + if(!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + WorldPacket data(SMSG_PET_ACTION_SOUND, 8+4); + data << uint64(GetGUID()); + data << uint32(pettalk); + ((Player*)owner)->GetSession()->SendPacket(&data); +} + +void Unit::SendPetSpellCooldown (uint32 spellid, time_t cooltime) +{ + Unit* owner = GetOwner(); + if(!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4); + data << uint64(GetGUID()); + data << uint8(0x0); + data << uint32(spellid); + data << uint32(cooltime); + + ((Player*)owner)->GetSession()->SendPacket(&data); +} + +void Unit::SendPetClearCooldown (uint32 spellid) +{ + Unit* owner = GetOwner(); + if(!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); + data << uint32(spellid); + data << uint64(GetGUID()); + ((Player*)owner)->GetSession()->SendPacket(&data); +} + +void Unit::SendPetAIReaction(uint64 guid) +{ + Unit* owner = GetOwner(); + if(!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + WorldPacket data(SMSG_AI_REACTION, 12); + data << uint64(guid) << uint32(00000002); + ((Player*)owner)->GetSession()->SendPacket(&data); +} + +///----------End of Pet responses methods---------- + +void Unit::StopMoving() +{ + clearUnitState(UNIT_STAT_MOVING); + + // send explicit stop packet + // rely on vmaps here because for exemple stormwind is in air + float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true); + //if (fabs(GetPositionZ() - z) < 2.0f) + // Relocate(GetPositionX(), GetPositionY(), z); + Relocate(GetPositionX(), GetPositionY(),GetPositionZ()); + + SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0); + + // update position and orientation; + WorldPacket data; + BuildHeartBeatMsg(&data); + SendMessageToSet(&data,false); +} + +void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID) +{ + if( apply ) + { + if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING)) + return; + + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + + GetMotionMaster()->MovementExpired(false); + CastStop(GetGUID()==casterGUID ? spellID : 0); + + Unit* caster = ObjectAccessor::GetUnit(*this,casterGUID); + + GetMotionMaster()->MoveFleeing(caster); // caster==NULL processed in MoveFleeing + } + else + { + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + + GetMotionMaster()->MovementExpired(false); + + if( GetTypeId() != TYPEID_PLAYER && isAlive() ) + { + // restore appropriate movement generator + if(getVictim()) + GetMotionMaster()->MoveChase(getVictim()); + else + GetMotionMaster()->Initialize(); + + // attack caster if can + Unit* caster = ObjectAccessor::GetObjectInWorld(casterGUID, (Unit*)NULL); + if(caster && caster != getVictim() && ((Creature*)this)->AI()) + ((Creature*)this)->AI()->AttackStart(caster); + } + } + + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SetClientControl(this, !apply); +} + +void Unit::SetConfused(bool apply, uint64 casterGUID, uint32 spellID) +{ + if( apply ) + { + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + + CastStop(GetGUID()==casterGUID ? spellID : 0); + + GetMotionMaster()->MoveConfused(); + } + else + { + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + + GetMotionMaster()->MovementExpired(false); + + if (GetTypeId() == TYPEID_UNIT) + { + // if in combat restore movement generator + if(getVictim()) + GetMotionMaster()->MoveChase(getVictim()); + } + } + + if(GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SetClientControl(this, !apply); +} + +bool Unit::IsSitState() const +{ + uint8 s = getStandState(); + return s == PLAYER_STATE_SIT_CHAIR || s == PLAYER_STATE_SIT_LOW_CHAIR || + s == PLAYER_STATE_SIT_MEDIUM_CHAIR || s == PLAYER_STATE_SIT_HIGH_CHAIR || + s == PLAYER_STATE_SIT; +} + +bool Unit::IsStandState() const +{ + uint8 s = getStandState(); + return !IsSitState() && s != PLAYER_STATE_SLEEP && s != PLAYER_STATE_KNEEL; +} + +void Unit::SetStandState(uint8 state) +{ + SetByteValue(UNIT_FIELD_BYTES_1, 0, state); + + if (IsStandState()) + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED); + + if(GetTypeId()==TYPEID_PLAYER) + { + WorldPacket data(SMSG_STANDSTATE_UPDATE, 1); + data << (uint8)state; + ((Player*)this)->GetSession()->SendPacket(&data); + } +} + +bool Unit::IsPolymorphed() const +{ + return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH; +} + +void Unit::SetDisplayId(uint32 modelId) +{ + SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId); + + if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(!pet->isControlled()) + return; + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); + } +} + +void Unit::ClearComboPointHolders() +{ + while(!m_ComboPointHolders.empty()) + { + uint32 lowguid = *m_ComboPointHolders.begin(); + + Player* plr = objmgr.GetPlayer(MAKE_NEW_GUID(lowguid, 0, HIGHGUID_PLAYER)); + if(plr && plr->GetComboTarget()==GetGUID()) // recheck for safe + plr->ClearComboPoints(); // remove also guid from m_ComboPointHolders; + else + m_ComboPointHolders.erase(lowguid); // or remove manually + } +} + +void Unit::ClearAllReactives() +{ + + for(int i=0; i < MAX_REACTIVE; ++i) + m_reactiveTimer[i] = 0; + + if (HasAuraState( AURA_STATE_DEFENSE)) + ModifyAuraState(AURA_STATE_DEFENSE, false); + if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_PARRY)) + ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); + if (HasAuraState( AURA_STATE_CRIT)) + ModifyAuraState(AURA_STATE_CRIT, false); + if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE) ) + ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false); + + if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->ClearComboPoints(); +} + +void Unit::UpdateReactives( uint32 p_time ) +{ + for(int i = 0; i < MAX_REACTIVE; ++i) + { + ReactiveType reactive = ReactiveType(i); + + if(!m_reactiveTimer[reactive]) + continue; + + if ( m_reactiveTimer[reactive] <= p_time) + { + m_reactiveTimer[reactive] = 0; + + switch ( reactive ) + { + case REACTIVE_DEFENSE: + if (HasAuraState(AURA_STATE_DEFENSE)) + ModifyAuraState(AURA_STATE_DEFENSE, false); + break; + case REACTIVE_HUNTER_PARRY: + if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) + ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); + break; + case REACTIVE_CRIT: + if (HasAuraState(AURA_STATE_CRIT)) + ModifyAuraState(AURA_STATE_CRIT, false); + break; + case REACTIVE_HUNTER_CRIT: + if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE) ) + ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false); + break; + case REACTIVE_OVERPOWER: + if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->ClearComboPoints(); + break; + default: + break; + } + } + else + { + m_reactiveTimer[reactive] -= p_time; + } + } +} + +Unit* Unit::SelectNearbyTarget() const +{ + CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + std::list targets; + + { + MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, ATTACK_DISTANCE); + MaNGOS::UnitListSearcher searcher(targets, u_check); + + TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); + TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); + cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); + } + + // remove current target + if(getVictim()) + targets.remove(getVictim()); + + // remove not LoS targets + for(std::list::iterator tIter = targets.begin(); tIter != targets.end();) + { + if(!IsWithinLOSInMap(*tIter)) + { + std::list::iterator tIter2 = tIter; + ++tIter; + targets.erase(tIter2); + } + else + ++tIter; + } + + // no appropriate targets + if(targets.empty()) + return NULL; + + // select random + uint32 rIdx = urand(0,targets.size()-1); + std::list::const_iterator tcIter = targets.begin(); + for(uint32 i = 0; i < rIdx; ++i) + ++tcIter; + + return *tcIter; +} + +void Unit::ApplyAttackTimePercentMod( WeaponAttackType att,float val, bool apply ) +{ + if(val > 0) + { + ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply); + ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att,val,!apply); + } + else + { + ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply); + ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att,-val,apply); + } +} + +void Unit::ApplyCastTimePercentMod(float val, bool apply ) +{ + if(val > 0) + ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,val,!apply); + else + ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,-val,apply); +} + +uint32 Unit::GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ) +{ + if (CastingTime > 7000) CastingTime = 7000; + if (CastingTime < 1500) CastingTime = 1500; + + if(damagetype == DOT && !IsChanneledSpell(spellProto)) + CastingTime = 3500; + + int32 overTime = 0; + uint8 effects = 0; + bool DirectDamage = false; + bool AreaEffect = false; + + for ( uint32 i=0; i<3;i++) + { + switch ( spellProto->Effect[i] ) + { + case SPELL_EFFECT_SCHOOL_DAMAGE: + case SPELL_EFFECT_POWER_DRAIN: + case SPELL_EFFECT_HEALTH_LEECH: + case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: + case SPELL_EFFECT_POWER_BURN: + case SPELL_EFFECT_HEAL: + DirectDamage = true; + break; + case SPELL_EFFECT_APPLY_AURA: + switch ( spellProto->EffectApplyAuraName[i] ) + { + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_PERIODIC_LEECH: + if ( GetSpellDuration(spellProto) ) + overTime = GetSpellDuration(spellProto); + break; + default: + // -5% per additional effect + ++effects; + break; + } + default: + break; + } + + if(IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetA[i])) || IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetB[i]))) + AreaEffect = true; + } + + // Combined Spells with Both Over Time and Direct Damage + if ( overTime > 0 && CastingTime > 0 && DirectDamage ) + { + // mainly for DoTs which are 3500 here otherwise + uint32 OriginalCastTime = GetSpellCastTime(spellProto); + if (OriginalCastTime > 7000) OriginalCastTime = 7000; + if (OriginalCastTime < 1500) OriginalCastTime = 1500; + // Portion to Over Time + float PtOT = (overTime / 15000.f) / ((overTime / 15000.f) + (OriginalCastTime / 3500.f)); + + if ( damagetype == DOT ) + CastingTime = uint32(CastingTime * PtOT); + else if ( PtOT < 1.0f ) + CastingTime = uint32(CastingTime * (1 - PtOT)); + else + CastingTime = 0; + } + + // Area Effect Spells receive only half of bonus + if ( AreaEffect ) + CastingTime /= 2; + + // -5% of total per any additional effect + for ( uint8 i=0; i 175 ) + { + CastingTime -= 175; + } + else + { + CastingTime = 0; + break; + } + } + + return CastingTime; +} + +void Unit::UpdateAuraForGroup(uint8 slot) +{ + if(GetTypeId() == TYPEID_PLAYER) + { + Player* player = (Player*)this; + if(player->GetGroup()) + { + player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS); + player->SetAuraUpdateMask(slot); + } + } + else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) + { + Pet *pet = ((Pet*)this); + if(pet->isControlled()) + { + Unit *owner = GetOwner(); + if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + { + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS); + pet->SetAuraUpdateMask(slot); + } + } + } +} + +float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) +{ + if (!normalized || GetTypeId() != TYPEID_PLAYER) + return float(GetAttackTime(attType))/1000.0f; + + Item *Weapon = ((Player*)this)->GetWeaponForAttack(attType); + if (!Weapon) + return 2.4; // fist attack + + switch (Weapon->GetProto()->InventoryType) + { + case INVTYPE_2HWEAPON: + return 3.3; + case INVTYPE_RANGED: + case INVTYPE_RANGEDRIGHT: + case INVTYPE_THROWN: + return 2.8; + case INVTYPE_WEAPON: + case INVTYPE_WEAPONMAINHAND: + case INVTYPE_WEAPONOFFHAND: + default: + return Weapon->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_DAGGER ? 1.7 : 2.4; + } +} + +Aura* Unit::GetDummyAura( uint32 spell_id ) const +{ + Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) + if ((*itr)->GetId() == spell_id) + return *itr; + + return NULL; +} + +bool Unit::IsUnderLastManaUseEffect() const +{ + return getMSTimeDiff(m_lastManaUse,getMSTime()) < 5000; +} + +void Unit::SetContestedPvP(Player *attackedPlayer) +{ + Player* player = GetCharmerOrOwnerPlayerOrPlayerItself(); + + if(!player || attackedPlayer && (attackedPlayer == player || player->duel && player->duel->opponent == attackedPlayer)) + return; + + player->SetContestedPvPTimer(30000); + if(!player->hasUnitState(UNIT_STAT_ATTACK_PLAYER)) + { + player->addUnitState(UNIT_STAT_ATTACK_PLAYER); + player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP); + // call MoveInLineOfSight for nearby contested guards + SetVisibility(GetVisibility()); + } + if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER)) + { + addUnitState(UNIT_STAT_ATTACK_PLAYER); + // call MoveInLineOfSight for nearby contested guards + SetVisibility(GetVisibility()); + } +} + +void Unit::AddPetAura(PetAura const* petSpell) +{ + m_petAuras.insert(petSpell); + if(Pet* pet = GetPet()) + pet->CastPetAura(petSpell); +} + +void Unit::RemovePetAura(PetAura const* petSpell) +{ + m_petAuras.erase(petSpell); + if(Pet* pet = GetPet()) + pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry())); +} diff --git a/src/game/Unit.h b/src/game/Unit.h index b16b5e9ab2d..be35c13a9d3 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1,1331 +1,1336 @@ -/* - * Copyright (C) 2005-2008 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 __UNIT_H -#define __UNIT_H - -#include "Common.h" -#include "Object.h" -#include "Opcodes.h" -#include "Mthread.h" -#include "SpellAuraDefines.h" -#include "UpdateFields.h" -#include "SharedDefines.h" -#include "ThreatManager.h" -#include "HostilRefManager.h" -#include "FollowerReference.h" -#include "FollowerRefManager.h" -#include "Utilities/EventProcessor.h" -#include "MotionMaster.h" -#include "Database/DBCStructure.h" -#include - -enum SpellInterruptFlags -{ - SPELL_INTERRUPT_FLAG_MOVEMENT = 0x01, - SPELL_INTERRUPT_FLAG_DAMAGE = 0x02, - SPELL_INTERRUPT_FLAG_INTERRUPT = 0x04, - SPELL_INTERRUPT_FLAG_AUTOATTACK = 0x08, - //SPELL_INTERRUPT_FLAG_TURNING = 0x10 // not turning - maybe _complete_ interrupt on direct damage? -}; - -enum SpellChannelInterruptFlags -{ - CHANNEL_FLAG_DAMAGE = 0x0002, - CHANNEL_FLAG_MOVEMENT = 0x0008, - CHANNEL_FLAG_TURNING = 0x0010, - CHANNEL_FLAG_DAMAGE2 = 0x0080, - CHANNEL_FLAG_DELAY = 0x4000 -}; - -enum SpellAuraInterruptFlags -{ - AURA_INTERRUPT_FLAG_UNK0 = 0x00000001, // 0 removed when getting hit by a negative spell? - AURA_INTERRUPT_FLAG_DAMAGE = 0x00000002, // 1 removed by any damage - AURA_INTERRUPT_FLAG_UNK2 = 0x00000004, // 2 - AURA_INTERRUPT_FLAG_MOVE = 0x00000008, // 3 removed by any movement - AURA_INTERRUPT_FLAG_TURNING = 0x00000010, // 4 removed by any turning - AURA_INTERRUPT_FLAG_ENTER_COMBAT = 0x00000020, // 5 removed by entering combat - AURA_INTERRUPT_FLAG_NOT_MOUNTED = 0x00000040, // 6 removed by unmounting - AURA_INTERRUPT_FLAG_NOT_ABOVEWATER = 0x00000080, // 7 removed by entering water - AURA_INTERRUPT_FLAG_NOT_UNDERWATER = 0x00000100, // 8 removed by leaving water - AURA_INTERRUPT_FLAG_NOT_SHEATHED = 0x00000200, // 9 removed by unsheathing - AURA_INTERRUPT_FLAG_UNK10 = 0x00000400, // 10 - AURA_INTERRUPT_FLAG_UNK11 = 0x00000800, // 11 - AURA_INTERRUPT_FLAG_UNK12 = 0x00001000, // 12 removed by attack? - AURA_INTERRUPT_FLAG_UNK13 = 0x00002000, // 13 - AURA_INTERRUPT_FLAG_UNK14 = 0x00004000, // 14 - AURA_INTERRUPT_FLAG_UNK15 = 0x00008000, // 15 removed by casting a spell? - AURA_INTERRUPT_FLAG_UNK16 = 0x00010000, // 16 - AURA_INTERRUPT_FLAG_MOUNTING = 0x00020000, // 17 removed by mounting - AURA_INTERRUPT_FLAG_NOT_SEATED = 0x00040000, // 18 removed by standing up - AURA_INTERRUPT_FLAG_CHANGE_MAP = 0x00080000, // 19 leaving map/getting teleported - AURA_INTERRUPT_FLAG_UNK20 = 0x00100000, // 20 - AURA_INTERRUPT_FLAG_UNK21 = 0x00200000, // 21 - AURA_INTERRUPT_FLAG_UNK22 = 0x00400000, // 22 - AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT = 0x00800000, // 23 removed by entering pvp combat - AURA_INTERRUPT_FLAG_DIRECT_DAMAGE = 0x01000000 // 24 removed by any direct damage -}; - -enum SpellModOp -{ - SPELLMOD_DAMAGE = 0, - SPELLMOD_DURATION = 1, - SPELLMOD_THREAT = 2, - SPELLMOD_EFFECT1 = 3, - SPELLMOD_CHARGES = 4, - SPELLMOD_RANGE = 5, - SPELLMOD_RADIUS = 6, - SPELLMOD_CRITICAL_CHANCE = 7, - SPELLMOD_ALL_EFFECTS = 8, - SPELLMOD_NOT_LOSE_CASTING_TIME = 9, - SPELLMOD_CASTING_TIME = 10, - SPELLMOD_COOLDOWN = 11, - SPELLMOD_EFFECT2 = 12, - // spellmod 13 unused - SPELLMOD_COST = 14, - SPELLMOD_CRIT_DAMAGE_BONUS = 15, - SPELLMOD_RESIST_MISS_CHANCE = 16, - SPELLMOD_JUMP_TARGETS = 17, - SPELLMOD_CHANCE_OF_SUCCESS = 18, - SPELLMOD_ACTIVATION_TIME = 19, - SPELLMOD_EFFECT_PAST_FIRST = 20, - SPELLMOD_CASTING_TIME_OLD = 21, - SPELLMOD_DOT = 22, - SPELLMOD_EFFECT3 = 23, - SPELLMOD_SPELL_BONUS_DAMAGE = 24, - // spellmod 25, 26 unused - SPELLMOD_MULTIPLE_VALUE = 27, - SPELLMOD_RESIST_DISPEL_CHANCE = 28 -}; - -#define MAX_SPELLMOD 32 - -#define BASE_MINDAMAGE 1.0f -#define BASE_MAXDAMAGE 2.0f -#define BASE_ATTACK_TIME 2000 - -// high byte (3 from 0..3) of UNIT_FIELD_BYTES_2 -enum ShapeshiftForm -{ - FORM_NONE = 0x00, - FORM_CAT = 0x01, - FORM_TREE = 0x02, - FORM_TRAVEL = 0x03, - FORM_AQUA = 0x04, - FORM_BEAR = 0x05, - FORM_AMBIENT = 0x06, - FORM_GHOUL = 0x07, - FORM_DIREBEAR = 0x08, - FORM_CREATUREBEAR = 0x0E, - FORM_CREATURECAT = 0x0F, - FORM_GHOSTWOLF = 0x10, - FORM_BATTLESTANCE = 0x11, - FORM_DEFENSIVESTANCE = 0x12, - FORM_BERSERKERSTANCE = 0x13, - FORM_TEST = 0x14, - FORM_ZOMBIE = 0x15, - FORM_FLIGHT_EPIC = 0x1B, - FORM_SHADOW = 0x1C, - FORM_FLIGHT = 0x1D, - FORM_STEALTH = 0x1E, - FORM_MOONKIN = 0x1F, - FORM_SPIRITOFREDEMPTION = 0x20 -}; - -// low byte ( 0 from 0..3 ) of UNIT_FIELD_BYTES_2 -enum SheathState -{ - SHEATH_STATE_UNARMED = 0, // non prepared weapon - SHEATH_STATE_MELEE = 1, // prepared melee weapon - SHEATH_STATE_RANGED = 2 // prepared ranged weapon -}; - -// byte (1 from 0..3) of UNIT_FIELD_BYTES_2 -enum UnitBytes2_Flags -{ - UNIT_BYTE2_FLAG_UNK0 = 0x01, - UNIT_BYTE2_FLAG_UNK1 = 0x02, - UNIT_BYTE2_FLAG_UNK2 = 0x04, - UNIT_BYTE2_FLAG_UNK3 = 0x08, - UNIT_BYTE2_FLAG_AURAS = 0x10, // show possitive auras as positive, and allow its dispel - UNIT_BYTE2_FLAG_UNK5 = 0x20, - UNIT_BYTE2_FLAG_UNK6 = 0x40, - UNIT_BYTE2_FLAG_UNK7 = 0x80 -}; - -// byte (2 from 0..3) of UNIT_FIELD_BYTES_2 -enum UnitRename -{ - UNIT_RENAME_NOT_ALLOWED = 0x02, - UNIT_RENAME_ALLOWED = 0x03 -}; - -#define CREATURE_MAX_SPELLS 4 - -enum Swing -{ - NOSWING = 0, - SINGLEHANDEDSWING = 1, - TWOHANDEDSWING = 2 -}; - -enum VictimState -{ - VICTIMSTATE_UNKNOWN1 = 0, - VICTIMSTATE_NORMAL = 1, - VICTIMSTATE_DODGE = 2, - VICTIMSTATE_PARRY = 3, - VICTIMSTATE_INTERRUPT = 4, - VICTIMSTATE_BLOCKS = 5, - VICTIMSTATE_EVADES = 6, - VICTIMSTATE_IS_IMMUNE = 7, - VICTIMSTATE_DEFLECTS = 8 -}; - -enum HitInfo -{ - HITINFO_NORMALSWING = 0x00000000, - HITINFO_UNK1 = 0x00000001, // req correct packet structure - HITINFO_NORMALSWING2 = 0x00000002, - HITINFO_LEFTSWING = 0x00000004, - HITINFO_MISS = 0x00000010, - HITINFO_ABSORB = 0x00000020, // plays absorb sound - HITINFO_RESIST = 0x00000040, // resisted atleast some damage - HITINFO_CRITICALHIT = 0x00000080, - HITINFO_GLANCING = 0x00004000, - HITINFO_CRUSHING = 0x00008000, - HITINFO_NOACTION = 0x00010000, - HITINFO_SWINGNOHITSOUND = 0x00080000 -}; - -//i would like to remove this: (it is defined in item.h -enum InventorySlot -{ - NULL_BAG = 0, - NULL_SLOT = 255 -}; - -struct FactionTemplateEntry; -struct Modifier; -struct SpellEntry; -struct SpellEntryExt; - -class Aura; -class Creature; -class Spell; -class DynamicObject; -class GameObject; -class Item; -class Pet; -class Path; -class PetAura; - -struct SpellImmune -{ - uint32 type; - uint32 spellId; -}; - -typedef std::list SpellImmuneList; - -enum UnitModifierType -{ - BASE_VALUE = 0, - BASE_PCT = 1, - TOTAL_VALUE = 2, - TOTAL_PCT = 3, - MODIFIER_TYPE_END = 4 -}; - -enum WeaponDamageRange -{ - MINDAMAGE, - MAXDAMAGE -}; - -enum DamageTypeToSchool -{ - RESISTANCE, - DAMAGE_DEALT, - DAMAGE_TAKEN -}; - -enum AuraRemoveMode -{ - AURA_REMOVE_BY_DEFAULT, - AURA_REMOVE_BY_STACK, // at replace by semillar aura - AURA_REMOVE_BY_CANCEL, - AURA_REMOVE_BY_DISPEL, - AURA_REMOVE_BY_DEATH -}; - -enum UnitMods -{ - UNIT_MOD_STAT_STRENGTH, // UNIT_MOD_STAT_STRENGTH..UNIT_MOD_STAT_SPIRIT must be in existed order, it's accessed by index values of Stats enum. - UNIT_MOD_STAT_AGILITY, - UNIT_MOD_STAT_STAMINA, - UNIT_MOD_STAT_INTELLECT, - UNIT_MOD_STAT_SPIRIT, - UNIT_MOD_HEALTH, - UNIT_MOD_MANA, // UNIT_MOD_MANA..UNIT_MOD_HAPPINESS must be in existed order, it's accessed by index values of Powers enum. - UNIT_MOD_RAGE, - UNIT_MOD_FOCUS, - UNIT_MOD_ENERGY, - UNIT_MOD_HAPPINESS, - UNIT_MOD_ARMOR, // UNIT_MOD_ARMOR..UNIT_MOD_RESISTANCE_ARCANE must be in existed order, it's accessed by index values of SpellSchools enum. - UNIT_MOD_RESISTANCE_HOLY, - UNIT_MOD_RESISTANCE_FIRE, - UNIT_MOD_RESISTANCE_NATURE, - UNIT_MOD_RESISTANCE_FROST, - UNIT_MOD_RESISTANCE_SHADOW, - UNIT_MOD_RESISTANCE_ARCANE, - UNIT_MOD_ATTACK_POWER, - UNIT_MOD_ATTACK_POWER_RANGED, - UNIT_MOD_DAMAGE_MAINHAND, - UNIT_MOD_DAMAGE_OFFHAND, - UNIT_MOD_DAMAGE_RANGED, - UNIT_MOD_END, - // synonyms - UNIT_MOD_STAT_START = UNIT_MOD_STAT_STRENGTH, - UNIT_MOD_STAT_END = UNIT_MOD_STAT_SPIRIT + 1, - UNIT_MOD_RESISTANCE_START = UNIT_MOD_ARMOR, - UNIT_MOD_RESISTANCE_END = UNIT_MOD_RESISTANCE_ARCANE + 1, - UNIT_MOD_POWER_START = UNIT_MOD_MANA, - UNIT_MOD_POWER_END = UNIT_MOD_HAPPINESS + 1 -}; - -enum BaseModGroup -{ - CRIT_PERCENTAGE, - RANGED_CRIT_PERCENTAGE, - OFFHAND_CRIT_PERCENTAGE, - SHIELD_BLOCK_VALUE, - BASEMOD_END -}; - -enum BaseModType -{ - FLAT_MOD, - PCT_MOD -}; - -#define MOD_END (PCT_MOD+1) - -enum DeathState -{ - ALIVE = 0, - JUST_DIED = 1, - CORPSE = 2, - DEAD = 3, - JUST_ALIVED = 4 -}; - -enum UnitState -{ - UNIT_STAT_DIED = 0x0001, - UNIT_STAT_MELEE_ATTACKING = 0x0002, // player is melee attacking someone - //UNIT_STAT_MELEE_ATTACK_BY = 0x0004, // player is melee attack by someone - UNIT_STAT_STUNDED = 0x0008, - UNIT_STAT_ROAMING = 0x0010, - UNIT_STAT_CHASE = 0x0020, - UNIT_STAT_SEARCHING = 0x0040, - UNIT_STAT_FLEEING = 0x0080, - UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING), - UNIT_STAT_IN_FLIGHT = 0x0100, // player is in flight mode - UNIT_STAT_FOLLOW = 0x0200, - UNIT_STAT_ROOT = 0x0400, - UNIT_STAT_CONFUSED = 0x0800, - UNIT_STAT_DISTRACTED = 0x1000, - UNIT_STAT_ISOLATED = 0x2000, // area auras do not affect other players - UNIT_STAT_ATTACK_PLAYER = 0x4000, - UNIT_STAT_ALL_STATE = 0xffff //(UNIT_STAT_STOPPED | UNIT_STAT_MOVING | UNIT_STAT_IN_COMBAT | UNIT_STAT_IN_FLIGHT) -}; - -enum UnitMoveType -{ - MOVE_WALK = 0, - MOVE_RUN = 1, - MOVE_WALKBACK = 2, - MOVE_SWIM = 3, - MOVE_SWIMBACK = 4, - MOVE_TURN = 5, - MOVE_FLY = 6, - MOVE_FLYBACK = 7 -}; - -#define MAX_MOVE_TYPE 8 - -extern float baseMoveSpeed[MAX_MOVE_TYPE]; - -enum WeaponAttackType -{ - BASE_ATTACK = 0, - OFF_ATTACK = 1, - RANGED_ATTACK = 2 -}; - -#define MAX_ATTACK 3 - -enum CombatRating -{ - CR_WEAPON_SKILL = 0, - CR_DEFENSE_SKILL = 1, - CR_DODGE = 2, - CR_PARRY = 3, - CR_BLOCK = 4, - CR_HIT_MELEE = 5, - CR_HIT_RANGED = 6, - CR_HIT_SPELL = 7, - CR_CRIT_MELEE = 8, - CR_CRIT_RANGED = 9, - CR_CRIT_SPELL = 10, - CR_HIT_TAKEN_MELEE = 11, - CR_HIT_TAKEN_RANGED = 12, - CR_HIT_TAKEN_SPELL = 13, - CR_CRIT_TAKEN_MELEE = 14, - CR_CRIT_TAKEN_RANGED = 15, - CR_CRIT_TAKEN_SPELL = 16, - CR_HASTE_MELEE = 17, - CR_HASTE_RANGED = 18, - CR_HASTE_SPELL = 19, - CR_WEAPON_SKILL_MAINHAND = 20, - CR_WEAPON_SKILL_OFFHAND = 21, - CR_WEAPON_SKILL_RANGED = 22, - CR_EXPERTISE = 23 -}; - -#define MAX_COMBAT_RATING 24 - -enum DamageEffectType -{ - DIRECT_DAMAGE = 0, // used for normal weapon damage (not for class abilities or spells) - SPELL_DIRECT_DAMAGE = 1, // spell/class abilities damage - DOT = 2, - HEAL = 3, - NODAMAGE = 4, // used also in case when damage applied to health but not applied to spell channelInterruptFlags/etc - SELF_DAMAGE = 5 -}; - -enum UnitVisibility -{ - VISIBILITY_OFF = 0, // absolute, not detectable, GM-like, can see all other - VISIBILITY_ON = 1, - VISIBILITY_GROUP_STEALTH = 2, // detect chance, seen and can see group members - VISIBILITY_GROUP_INVISIBILITY = 3, // invisibility, can see and can be seen only another invisible unit or invisible detection unit, set only if not stealthed, and in checks not used (mask used instead) - VISIBILITY_GROUP_NO_DETECT = 4, // state just at stealth apply for update Grid state. Don't remove, otherwise stealth spells will break - VISIBILITY_RESPAWN = 5 // special totally not detectable visibility for force delete object at respawn command -}; - -// Value masks for UNIT_FIELD_FLAGS -enum UnitFlags -{ - UNIT_FLAG_UNKNOWN7 = 0x00000001, - UNIT_FLAG_NON_ATTACKABLE = 0x00000002, // not attackable - UNIT_FLAG_DISABLE_MOVE = 0x00000004, - UNIT_FLAG_PVP_ATTACKABLE = 0x00000008, // allow apply pvp rules to attackable state in addition to faction dependent state - UNIT_FLAG_RENAME = 0x00000010, - UNIT_FLAG_PREPARATION = 0x00000020, // don't take reagents for spells with SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP - UNIT_FLAG_UNKNOWN9 = 0x00000040, - UNIT_FLAG_NOT_ATTACKABLE_1 = 0x00000080, // ?? (UNIT_FLAG_PVP_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1) is NON_PVP_ATTACKABLE - UNIT_FLAG_UNKNOWN2 = 0x00000100, // 2.0.8 - UNIT_FLAG_UNKNOWN11 = 0x00000200, - UNIT_FLAG_LOOTING = 0x00000400, // loot animation - UNIT_FLAG_PET_IN_COMBAT = 0x00000800, // in combat?, 2.0.8 - UNIT_FLAG_PVP = 0x00001000, - UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1 - UNIT_FLAG_UNKNOWN4 = 0x00004000, // 2.0.8 - UNIT_FLAG_UNKNOWN13 = 0x00008000, - UNIT_FLAG_UNKNOWN14 = 0x00010000, - UNIT_FLAG_PACIFIED = 0x00020000, - UNIT_FLAG_DISABLE_ROTATE = 0x00040000, // stunned, 2.1.1 - UNIT_FLAG_IN_COMBAT = 0x00080000, - UNIT_FLAG_TAXI_FLIGHT = 0x00100000, // disable casting at client side spell not allowed by taxi flight (mounted?), probably used with 0x4 flag - UNIT_FLAG_DISARMED = 0x00200000, // disable melee spells casting..., "Required melee weapon" added to melee spells tooltip. - UNIT_FLAG_CONFUSED = 0x00400000, - UNIT_FLAG_FLEEING = 0x00800000, - UNIT_FLAG_UNKNOWN5 = 0x01000000, // used in spell Eyes of the Beast for pet... - UNIT_FLAG_NOT_SELECTABLE = 0x02000000, - UNIT_FLAG_SKINNABLE = 0x04000000, - UNIT_FLAG_MOUNT = 0x08000000, - UNIT_FLAG_UNKNOWN17 = 0x10000000, - UNIT_FLAG_UNKNOWN6 = 0x20000000, // used in Feing Death spell - UNIT_FLAG_SHEATHE = 0x40000000 -}; - -// Value masks for UNIT_FIELD_FLAGS_2 -enum UnitFlags2 -{ - UNIT_FLAG2_FEIGN_DEATH = 0x00000001, - UNIT_FLAG2_COMPREHEND_LANG= 0x00000008, - UNIT_FLAG2_FORCE_MOVE = 0x00000040 -}; - -/// Non Player Character flags -enum NPCFlags -{ - UNIT_NPC_FLAG_NONE = 0x00000000, - UNIT_NPC_FLAG_GOSSIP = 0x00000001, // 100% - UNIT_NPC_FLAG_QUESTGIVER = 0x00000002, // guessed, probably ok - UNIT_NPC_FLAG_UNK1 = 0x00000004, - UNIT_NPC_FLAG_UNK2 = 0x00000008, - UNIT_NPC_FLAG_TRAINER = 0x00000010, // 100% - UNIT_NPC_FLAG_TRAINER_CLASS = 0x00000020, // 100% - UNIT_NPC_FLAG_TRAINER_PROFESSION = 0x00000040, // 100% - UNIT_NPC_FLAG_VENDOR = 0x00000080, // 100% - UNIT_NPC_FLAG_VENDOR_AMMO = 0x00000100, // 100%, general goods vendor - UNIT_NPC_FLAG_VENDOR_FOOD = 0x00000200, // 100% - UNIT_NPC_FLAG_VENDOR_POISON = 0x00000400, // guessed - UNIT_NPC_FLAG_VENDOR_REAGENT = 0x00000800, // 100% - UNIT_NPC_FLAG_REPAIR = 0x00001000, // 100% - UNIT_NPC_FLAG_FLIGHTMASTER = 0x00002000, // 100% - UNIT_NPC_FLAG_SPIRITHEALER = 0x00004000, // guessed - UNIT_NPC_FLAG_SPIRITGUIDE = 0x00008000, // guessed - UNIT_NPC_FLAG_INNKEEPER = 0x00010000, // 100% - UNIT_NPC_FLAG_BANKER = 0x00020000, // 100% - UNIT_NPC_FLAG_PETITIONER = 0x00040000, // 100% 0xC0000 = guild petitions, 0x40000 = arena team petitions - UNIT_NPC_FLAG_TABARDDESIGNER = 0x00080000, // 100% - UNIT_NPC_FLAG_BATTLEMASTER = 0x00100000, // 100% - UNIT_NPC_FLAG_AUCTIONEER = 0x00200000, // 100% - UNIT_NPC_FLAG_STABLEMASTER = 0x00400000, // 100% - UNIT_NPC_FLAG_GUILD_BANKER = 0x00800000, // cause client to send 997 opcode - UNIT_NPC_FLAG_UNK3 = 0x01000000, // cause client to send 1015 opcode - UNIT_NPC_FLAG_GUARD = 0x10000000, // custom flag for guards -}; - -enum MovementFlags -{ - MOVEMENTFLAG_NONE = 0x00000000, - MOVEMENTFLAG_FORWARD = 0x00000001, - MOVEMENTFLAG_BACKWARD = 0x00000002, - MOVEMENTFLAG_STRAFE_LEFT = 0x00000004, - MOVEMENTFLAG_STRAFE_RIGHT = 0x00000008, - MOVEMENTFLAG_LEFT = 0x00000010, - MOVEMENTFLAG_RIGHT = 0x00000020, - MOVEMENTFLAG_PITCH_UP = 0x00000040, - MOVEMENTFLAG_PITCH_DOWN = 0x00000080, - MOVEMENTFLAG_WALK_MODE = 0x00000100, // Walking - MOVEMENTFLAG_ONTRANSPORT = 0x00000200, // Used for flying on some creatures - MOVEMENTFLAG_LEVITATING = 0x00000400, - MOVEMENTFLAG_FLY_UNK1 = 0x00000800, - MOVEMENTFLAG_JUMPING = 0x00001000, - MOVEMENTFLAG_UNK4 = 0x00002000, - MOVEMENTFLAG_FALLING = 0x00004000, - // 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000 - MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also - MOVEMENTFLAG_FLY_UP = 0x00400000, - MOVEMENTFLAG_CAN_FLY = 0x00800000, - MOVEMENTFLAG_FLYING = 0x01000000, - MOVEMENTFLAG_FLYING2 = 0x02000000, // Actual flying mode - MOVEMENTFLAG_SPLINE = 0x04000000, // used for flight paths - MOVEMENTFLAG_SPLINE2 = 0x08000000, // used for flight paths - MOVEMENTFLAG_WATERWALKING = 0x10000000, // prevent unit from falling through water - MOVEMENTFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive) - MOVEMENTFLAG_UNK3 = 0x40000000 -}; - -enum DiminishingLevels -{ - DIMINISHING_LEVEL_1 = 0, - DIMINISHING_LEVEL_2 = 1, - DIMINISHING_LEVEL_3 = 2, - DIMINISHING_LEVEL_IMMUNE = 3 -}; - -struct DiminishingReturn -{ - DiminishingReturn(DiminishingGroup group, uint32 t, uint32 count) : DRGroup(group), hitTime(t), hitCount(count), stack(0) {} - - DiminishingGroup DRGroup:16; - uint16 stack:16; - uint32 hitTime; - uint32 hitCount; -}; - -enum MeleeHitOutcome -{ - MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY, - MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL, MELEE_HIT_BLOCK_CRIT -}; -struct CleanDamage -{ - CleanDamage(uint32 _damage, WeaponAttackType _attackType, MeleeHitOutcome _hitOutCome) : - damage(_damage), attackType(_attackType), hitOutCome(_hitOutCome) {} - - uint32 damage; - WeaponAttackType attackType; - MeleeHitOutcome hitOutCome; -}; - -struct UnitActionBarEntry -{ - uint32 Type; - uint32 SpellOrAction; -}; - -#define MAX_DECLINED_NAME_CASES 5 - -struct DeclinedName -{ - std::string name[MAX_DECLINED_NAME_CASES]; -}; - -enum CurrentSpellTypes -{ - CURRENT_MELEE_SPELL = 0, - CURRENT_FIRST_NON_MELEE_SPELL = 1, // just counter - CURRENT_GENERIC_SPELL = 1, - CURRENT_AUTOREPEAT_SPELL = 2, - CURRENT_CHANNELED_SPELL = 3, - CURRENT_MAX_SPELL = 4 // just counter -}; - -enum ActiveStates -{ - ACT_ENABLED = 0xC100, - ACT_DISABLED = 0x8100, - ACT_COMMAND = 0x0700, - ACT_REACTION = 0x0600, - ACT_CAST = 0x0100, - ACT_PASSIVE = 0x0000, - ACT_DECIDE = 0x0001 -}; - -enum ReactStates -{ - REACT_PASSIVE = 0, - REACT_DEFENSIVE = 1, - REACT_AGGRESSIVE = 2 -}; - -enum CommandStates -{ - COMMAND_STAY = 0, - COMMAND_FOLLOW = 1, - COMMAND_ATTACK = 2, - COMMAND_ABANDON = 3 -}; - -struct CharmSpellEntry -{ - uint16 spellId; - uint16 active; -}; - -struct CharmInfo -{ - public: - explicit CharmInfo(Unit* unit); - uint32 GetPetNumber() const { return m_petnumber; } - void SetPetNumber(uint32 petnumber, bool statwindow); - - void SetCommandState(CommandStates st) { m_CommandState = st; } - CommandStates GetCommandState() { return m_CommandState; } - bool HasCommandState(CommandStates state) { return (m_CommandState == state); } - void SetReactState(ReactStates st) { m_ReactSate = st; } - ReactStates GetReactState() { return m_ReactSate; } - bool HasReactState(ReactStates state) { return (m_ReactSate == state); } - - void InitPossessCreateSpells(); - void InitCharmCreateSpells(); - void InitPetActionBar(); - void InitEmptyActionBar(); - //return true if successful - bool AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate = ACT_DECIDE); - void ToggleCreatureAutocast(uint32 spellid, bool apply); - - UnitActionBarEntry* GetActionBarEntry(uint8 index) { return &(PetActionBar[index]); } - CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); } - private: - Unit* m_unit; - UnitActionBarEntry PetActionBar[10]; - CharmSpellEntry m_charmspells[4]; - CommandStates m_CommandState; - ReactStates m_ReactSate; - uint32 m_petnumber; -}; - -// for clearing special attacks -#define REACTIVE_TIMER_START 4000 - -enum ReactiveType -{ - REACTIVE_DEFENSE = 1, - REACTIVE_HUNTER_PARRY = 2, - REACTIVE_CRIT = 3, - REACTIVE_HUNTER_CRIT = 4, - REACTIVE_OVERPOWER = 5 -}; - -#define MAX_REACTIVE 6 -#define MAX_TOTEM 4 - -// delay time next attack to prevent client attack animation problems -#define ATTACK_DISPLAY_DELAY 200 - -class MANGOS_DLL_SPEC Unit : public WorldObject -{ - public: - typedef std::set AttackerSet; - typedef std::pair spellEffectPair; - typedef std::multimap< spellEffectPair, Aura*> AuraMap; - typedef std::list AuraList; - typedef std::list Diminishing; - typedef std::set AuraTypeSet; - typedef std::set ComboPointHolderSet; - - virtual ~Unit ( ); - - void AddToWorld(); - void RemoveFromWorld(); - - void CleanupsBeforeDelete(); // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units) - - DiminishingLevels GetDiminishing(DiminishingGroup group); - void IncrDiminishing(DiminishingGroup group); - void ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster, DiminishingLevels Level); - void ApplyDiminishingAura(DiminishingGroup group, bool apply); - void ClearDiminishings() { m_Diminishing.clear(); } - - virtual void Update( uint32 time ); - - void setAttackTimer(WeaponAttackType type, uint32 time) { m_attackTimer[type] = time; } - void resetAttackTimer(WeaponAttackType type = BASE_ATTACK); - uint32 getAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; } - bool isAttackReady(WeaponAttackType type = BASE_ATTACK) const { return m_attackTimer[type] == 0; } - bool haveOffhandWeapon() const; - bool canReachWithAttack(Unit *pVictim) const; - uint32 m_extraAttacks; - - void _addAttacker(Unit *pAttacker) // must be called only from Unit::Attack(Unit*) - { - AttackerSet::iterator itr = m_attackers.find(pAttacker); - if(itr == m_attackers.end()) - m_attackers.insert(pAttacker); - } - void _removeAttacker(Unit *pAttacker) // must be called only from Unit::AttackStop() - { - AttackerSet::iterator itr = m_attackers.find(pAttacker); - if(itr != m_attackers.end()) - m_attackers.erase(itr); - } - Unit * getAttackerForHelper() // If someone wants to help, who to give them - { - if (getVictim() != NULL) - return getVictim(); - - if (!m_attackers.empty()) - return *(m_attackers.begin()); - - return NULL; - } - bool Attack(Unit *victim, bool meleeAttack); - void CastStop(uint32 except_spellid = 0); - bool AttackStop(); - void RemoveAllAttackers(); - AttackerSet const& getAttackers() const { return m_attackers; } - bool isAttackingPlayer() const; - Unit* getVictim() const { return m_attacking; } - void CombatStop(bool cast = false); - void CombatStopWithPets(bool cast = false); - Unit* SelectNearbyTarget() const; - - void addUnitState(uint32 f) { m_state |= f; } - bool hasUnitState(const uint32 f) const { return (m_state & f); } - void clearUnitState(uint32 f) { m_state &= ~f; } - bool CanFreeMove() const - { - return !hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING | UNIT_STAT_IN_FLIGHT | - UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED ) && GetOwnerGUID()==0; - } - - uint32 getLevel() const { return GetUInt32Value(UNIT_FIELD_LEVEL); } - virtual uint32 getLevelForTarget(Unit const* /*target*/) const { return getLevel(); } - void SetLevel(uint32 lvl); - uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, 0); } - uint32 getRaceMask() const { return 1 << (getRace()-1); } - uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, 1); } - uint32 getClassMask() const { return 1 << (getClass()-1); } - uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, 2); } - - float GetStat(Stats stat) const { return float(GetUInt32Value(UNIT_FIELD_STAT0+stat)); } - void SetStat(Stats stat, int32 val) { SetStatInt32Value(UNIT_FIELD_STAT0+stat, val); } - uint32 GetArmor() const { return GetResistance(SPELL_SCHOOL_NORMAL) ; } - void SetArmor(int32 val) { SetResistance(SPELL_SCHOOL_NORMAL, val); } - - uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(UNIT_FIELD_RESISTANCES+school); } - void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(UNIT_FIELD_RESISTANCES+school,val); } - - uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); } - uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); } - void SetHealth( uint32 val); - void SetMaxHealth(uint32 val); - int32 ModifyHealth(int32 val); - - Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, 3)); } - void setPowerType(Powers power); - uint32 GetPower( Powers power) const { return GetUInt32Value(UNIT_FIELD_POWER1 +power); } - uint32 GetMaxPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_MAXPOWER1+power); } - void SetPower( Powers power, uint32 val); - void SetMaxPower(Powers power, uint32 val); - int32 ModifyPower(Powers power, int32 val); - void ApplyPowerMod(Powers power, uint32 val, bool apply); - void ApplyMaxPowerMod(Powers power, uint32 val, bool apply); - - uint32 GetAttackTime(WeaponAttackType att) const { return (uint32)(GetFloatValue(UNIT_FIELD_BASEATTACKTIME+att)/m_modAttackSpeedPct[att]); } - void SetAttackTime(WeaponAttackType att, uint32 val) { SetFloatValue(UNIT_FIELD_BASEATTACKTIME+att,val*m_modAttackSpeedPct[att]); } - void ApplyAttackTimePercentMod(WeaponAttackType att,float val, bool apply); - void ApplyCastTimePercentMod(float val, bool apply); - - // faction template id - uint32 getFaction() const { return GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE); } - void setFaction(uint32 faction) { SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction ); } - FactionTemplateEntry const* getFactionTemplateEntry() const; - bool IsHostileTo(Unit const* unit) const; - bool IsHostileToPlayers() const; - bool IsFriendlyTo(Unit const* unit) const; - bool IsNeutralToAll() const; - bool IsContestedGuard() const - { - if(FactionTemplateEntry const* entry = getFactionTemplateEntry()) - return entry->IsContestedGuardFaction(); - - return false; - } - bool IsPvP() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); } - void SetPvP(bool state) { if(state) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); else RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); } - uint32 GetCreatureType() const; - uint32 GetCreatureTypeMask() const - { - uint32 creatureType = GetCreatureType(); - return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0; - } - - uint8 getStandState() const { return GetByteValue(UNIT_FIELD_BYTES_1, 0); } - bool IsSitState() const; - bool IsStandState() const; - void SetStandState(uint8 state); - - bool IsMounted() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); } - uint32 GetMountID() const { return GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID); } - void Mount(uint32 mount); - void Unmount(); - - uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } - uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss); - void DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit = false, bool isTriggeredSpell = false); - void DoAttackDamage(Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false); - - void CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false); - void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage = 0, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NONE, SpellEntry const *procSpell = NULL, bool isTriggeredSpell = false, WeaponAttackType attType = BASE_ATTACK); - void HandleEmoteCommand(uint32 anim_id); - void AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType = BASE_ATTACK, bool extra = false ); - - float MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const; - SpellMissInfo MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell); - SpellMissInfo SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool canReflect = false); - - float GetUnitDodgeChance() const; - float GetUnitParryChance() const; - float GetUnitBlockChance() const; - float GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const; - - virtual uint32 GetShieldBlockValue() const =0; - uint32 GetUnitMeleeSkill(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } - uint32 GetDefenseSkillValue(Unit const* target = NULL) const; - uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const; - float GetWeaponProcChance() const; - float GetPPMProcChance(uint32 WeaponSpeed, float PPM) const; - MeleeHitOutcome RollPhysicalOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo); - MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const; - MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const; - - bool isVendor() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR ); } - bool isTrainer() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TRAINER ); } - bool isQuestGiver() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER ); } - bool isGossip() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP ); } - bool isTaxi() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_FLIGHTMASTER ); } - bool isGuildMaster() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PETITIONER ); } - bool isBattleMaster() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BATTLEMASTER ); } - bool isBanker() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BANKER ); } - bool isInnkeeper() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_INNKEEPER ); } - bool isSpiritHealer() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER ); } - bool isSpiritGuide() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITGUIDE ); } - bool isTabardDesigner()const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TABARDDESIGNER ); } - bool isAuctioner() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_AUCTIONEER ); } - bool isArmorer() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_REPAIR ); } - bool isServiceProvider() const - { - return HasFlag( UNIT_NPC_FLAGS, - UNIT_NPC_FLAG_VENDOR | UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_FLIGHTMASTER | - UNIT_NPC_FLAG_PETITIONER | UNIT_NPC_FLAG_BATTLEMASTER | UNIT_NPC_FLAG_BANKER | - UNIT_NPC_FLAG_INNKEEPER | UNIT_NPC_FLAG_GUARD | UNIT_NPC_FLAG_SPIRITHEALER | - UNIT_NPC_FLAG_SPIRITGUIDE | UNIT_NPC_FLAG_TABARDDESIGNER | UNIT_NPC_FLAG_AUCTIONEER ); - } - bool isSpiritService() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER | UNIT_NPC_FLAG_SPIRITGUIDE ); } - - //Need fix or use this - bool isGuard() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GUARD); } - - bool isInFlight() const { return hasUnitState(UNIT_STAT_IN_FLIGHT); } - - bool isInCombat() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); } - void SetInCombatState(bool PvP); - void SetInCombatWith(Unit* enemy); - void ClearInCombat(); - uint32 GetCombatTimer() const { return m_CombatTimer; } - - bool HasAuraType(AuraType auraType) const; - bool HasAura(uint32 spellId, uint32 effIndex) const - { return m_Auras.find(spellEffectPair(spellId, effIndex)) != m_Auras.end(); } - - bool virtual HasSpell(uint32 /*spellID*/) const { return false; } - - bool HasStealthAura() const { return HasAuraType(SPELL_AURA_MOD_STEALTH); } - bool HasInvisibilityAura() const { return HasAuraType(SPELL_AURA_MOD_INVISIBILITY); } - bool isFeared() const { return HasAuraType(SPELL_AURA_MOD_FEAR); } - bool isInRoots() const { return HasAuraType(SPELL_AURA_MOD_ROOT); } - bool IsPolymorphed() const; - - bool isFrozen() const; - - void RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage); - - bool isTargetableForAttack() const; - virtual bool IsInWater() const; - virtual bool IsUnderWater() const; - bool isInAccessablePlaceFor(Creature const* c) const; - - void SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical = false); - void SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype, bool critical = false); - uint32 SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell = false, bool useSpellDamage = true); - void CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); - void CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem= NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); - void CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); - void CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); - void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); - void CastSpell(float x, float y, float z, SpellEntry const *spellInfo, bool triggered, Item *castItem = NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); - - bool IsDamageToThreatSpell(SpellEntry const * spellInfo) const; - - void DeMorph(); - - void SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount); - void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false); - void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo); - - void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); - void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags); - void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime = 0, Player* player = NULL); - void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL); - - virtual void MoveOutOfRange(Player &) { }; - - bool isAlive() const { return (m_deathState == ALIVE); }; - bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); }; - DeathState getDeathState() { return m_deathState; }; - virtual void setDeathState(DeathState s); // overwrited in Creature/Player/Pet - - uint64 const& GetOwnerGUID() const { return GetUInt64Value(UNIT_FIELD_SUMMONEDBY); } - uint64 GetPetGUID() const { return GetUInt64Value(UNIT_FIELD_SUMMON); } - uint64 GetCharmerGUID() const { return GetUInt64Value(UNIT_FIELD_CHARMEDBY); } - uint64 GetCharmGUID() const { return GetUInt64Value(UNIT_FIELD_CHARM); } - void SetCharmerGUID(uint64 owner) { SetUInt64Value(UNIT_FIELD_CHARMEDBY, owner); } - - uint64 GetCharmerOrOwnerGUID() const { return GetCharmerGUID() ? GetCharmerGUID() : GetOwnerGUID(); } - uint64 GetCharmerOrOwnerOrOwnGUID() const - { - if(uint64 guid = GetCharmerOrOwnerGUID()) - return guid; - return GetGUID(); - } - bool isCharmedOwnedByPlayerOrPlayer() const { return IS_PLAYER_GUID(GetCharmerOrOwnerOrOwnGUID()); } - - Player* GetSpellModOwner(); - - Unit* GetOwner() const; - Pet* GetPet() const; - Unit* GetCharmer() const; - Unit* GetCharm() const; - Unit* GetCharmerOrOwner() const { return GetCharmerGUID() ? GetCharmer() : GetOwner(); } - Unit* GetCharmerOrOwnerOrSelf() - { - if(Unit* u = GetCharmerOrOwner()) - return u; - - return this; - } - Player* GetCharmerOrOwnerPlayerOrPlayerItself(); - - void SetPet(Pet* pet); - void SetCharm(Unit* pet); - bool isCharmed() const { return GetCharmerGUID() != 0; } - - CharmInfo* GetCharmInfo() { return m_charmInfo; } - CharmInfo* InitCharmInfo(Unit* charm); - - bool AddAura(Aura *aur); - - void RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT); - void RemoveAura(uint32 spellId, uint32 effindex, Aura* except = NULL); - void RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex); - void RemoveAurasDueToSpell(uint32 spellId, Aura* except = NULL); - void RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId); - void RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler); - void RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer); - void RemoveAurasDueToSpellByCancel(uint32 spellId); - void RemoveNotOwnSingleTargetAuras(); - - void RemoveSpellsCausingAura(AuraType auraType); - void RemoveRankAurasDueToSpell(uint32 spellId); - bool RemoveNoStackAurasDueToAura(Aura *Aur); - void RemoveAurasWithInterruptFlags(uint32 flags); - void RemoveAurasWithDispelType( DispelType type ); - - void RemoveAllAuras(); - void RemoveAllAurasOnDeath(); - void DelayAura(uint32 spellId, uint32 effindex, int32 delaytime); - - float GetResistanceBuffMods(SpellSchools school, bool positive) const { return GetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school ); } - void SetResistanceBuffMods(SpellSchools school, bool positive, float val) { SetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school,val); } - void ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply) { ApplyModSignedFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); } - void ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply) { ApplyPercentModFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); } - void InitStatBuffMods() - { - for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(UNIT_FIELD_POSSTAT0+i, 0); - for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(UNIT_FIELD_NEGSTAT0+i, 0); - } - void ApplyStatBuffMod(Stats stat, float val, bool apply) { ApplyModSignedFloatValue((val > 0 ? UNIT_FIELD_POSSTAT0+stat : UNIT_FIELD_NEGSTAT0+stat), val, apply); } - void ApplyStatPercentBuffMod(Stats stat, float val, bool apply) - { - ApplyPercentModFloatValue(UNIT_FIELD_POSSTAT0+stat, val, apply); - ApplyPercentModFloatValue(UNIT_FIELD_NEGSTAT0+stat, val, apply); - } - void SetCreateStat(Stats stat, float val) { m_createStats[stat] = val; } - void SetCreateHealth(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_HEALTH, val); } - uint32 GetCreateHealth() const { return GetUInt32Value(UNIT_FIELD_BASE_HEALTH); } - void SetCreateMana(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_MANA, val); } - uint32 GetCreateMana() const { return GetUInt32Value(UNIT_FIELD_BASE_MANA); } - uint32 GetCreatePowers(Powers power) const; - float GetPosStat(Stats stat) const { return GetFloatValue(UNIT_FIELD_POSSTAT0+stat); } - float GetNegStat(Stats stat) const { return GetFloatValue(UNIT_FIELD_NEGSTAT0+stat); } - float GetCreateStat(Stats stat) const { return m_createStats[stat]; } - - void SetCurrentCastedSpell(Spell * pSpell); - virtual void ProhibitSpellScholl(SpellSchoolMask /*idSchoolMask*/, uint32 /*unTimeMs*/ ) { } - void InterruptSpell(uint32 spellType, bool withDelayed = true); - - // set withDelayed to true to account delayed spells as casted - // delayed+channeled spells are always accounted as casted - // we can skip channeled or delayed checks using flags - bool IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled = false, bool skipAutorepeat = false) const; - - // set withDelayed to true to interrupt delayed spells too - // delayed+channeled spells are always interrupted - void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0); - - Spell* FindCurrentSpellBySpellId(uint32 spell_id) const; - - Spell* m_currentSpells[CURRENT_MAX_SPELL]; - - uint32 m_addDmgOnce; - uint64 m_TotemSlot[MAX_TOTEM]; - uint64 m_ObjectSlot[4]; - uint32 m_detectInvisibilityMask; - uint32 m_invisibilityMask; - uint32 m_ShapeShiftFormSpellId; - ShapeshiftForm m_form; - float m_modMeleeHitChance; - float m_modRangedHitChance; - float m_modSpellHitChance; - int32 m_baseSpellCritChance; - - float m_threatModifier[MAX_SPELL_SCHOOL]; - float m_modAttackSpeedPct[3]; - - // Event handler - EventProcessor m_Events; - - // stat system - bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply); - void SetModifierValue(UnitMods unitMod, UnitModifierType modifierType, float value) { m_auraModifiersGroup[unitMod][modifierType] = value; } - float GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const; - float GetTotalStatValue(Stats stat) const; - float GetTotalAuraModValue(UnitMods unitMod) const; - SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const; - Stats GetStatByAuraGroup(UnitMods unitMod) const; - Powers GetPowerTypeByAuraGroup(UnitMods unitMod) const; - bool CanModifyStats() const { return m_canModifyStats; } - void SetCanModifyStats(bool modifyStats) { m_canModifyStats = modifyStats; } - virtual bool UpdateStats(Stats stat) = 0; - virtual bool UpdateAllStats() = 0; - virtual void UpdateResistances(uint32 school) = 0; - virtual void UpdateArmor() = 0; - virtual void UpdateMaxHealth() = 0; - virtual void UpdateMaxPower(Powers power) = 0; - virtual void UpdateAttackPowerAndDamage(bool ranged = false) = 0; - virtual void UpdateDamagePhysical(WeaponAttackType attType) = 0; - float GetTotalAttackPowerValue(WeaponAttackType attType) const; - float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const; - void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } - - bool isInFront(Unit const* target,float distance, float arc = M_PI) const; - void SetInFront(Unit const* target); - bool isInBack(Unit const* target, float distance, float arc = M_PI) const; - - // Visibility system - UnitVisibility GetVisibility() const { return m_Visibility; } - void SetVisibility(UnitVisibility x); - - // common function for visibility checks for player/creatures with detection code - bool isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList = false) const; - bool canDetectInvisibilityOf(Unit const* u) const; - - // virtual functions for all world objects types - bool isVisibleForInState(Player const* u, bool inVisibleList) const; - // function for low level grid visibility checks in player/creature cases - virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; - - bool waterbreath; - AuraList & GetSingleCastAuras() { return m_scAuras; } - AuraList const& GetSingleCastAuras() const { return m_scAuras; } - SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; - - // Threat related methodes - bool CanHaveThreatList() const; - void AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *threatSpell = NULL); - float ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL); - void DeleteThreatList(); - bool SelectHostilTarget(); - void TauntApply(Unit* pVictim); - void TauntFadeOut(Unit *taunter); - ThreatManager& getThreatManager() { return m_ThreatManager; } - void addHatedBy(HostilReference* pHostilReference) { m_HostilRefManager.insertFirst(pHostilReference); }; - void removeHatedBy(HostilReference* /*pHostilReference*/ ) { /* nothing to do yet */ } - HostilRefManager& getHostilRefManager() { return m_HostilRefManager; } - - Aura* GetAura(uint32 spellId, uint32 effindex); - AuraMap & GetAuras() { return m_Auras; } - AuraMap const& GetAuras() const { return m_Auras; } - AuraList const& GetAurasByType(AuraType type) const { return m_modAuras[type]; } - void ApplyAuraProcTriggerDamage(Aura* aura, bool apply); - - int32 GetTotalAuraModifier(AuraType auratype) const; - float GetTotalAuraMultiplier(AuraType auratype) const; - int32 GetMaxPositiveAuraModifier(AuraType auratype) const; - int32 GetMaxNegativeAuraModifier(AuraType auratype) const; - - int32 GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const; - float GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const; - int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const; - int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const; - - int32 GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const; - float GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const; - int32 GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const; - int32 GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const; - - Aura* GetDummyAura(uint32 spell_id) const; - - uint32 GetDisplayId() { return GetUInt32Value(UNIT_FIELD_DISPLAYID); } - void SetDisplayId(uint32 modelId); - uint32 GetNativeDisplayId() { return GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID); } - void SetNativeDisplayId(uint32 modelId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, modelId); } - void setTransForm(uint32 spellid) { m_transform = spellid;} - uint32 getTransForm() const { return m_transform;} - void AddDynObject(DynamicObject* dynObj); - void RemoveDynObject(uint32 spellid); - void RemoveDynObjectWithGUID(uint64 guid) { m_dynObjGUIDs.remove(guid); } - void RemoveAllDynObjects(); - void AddGameObject(GameObject* gameObj); - void RemoveGameObject(GameObject* gameObj, bool del); - void RemoveGameObject(uint32 spellid, bool del); - void RemoveAllGameObjects(); - DynamicObject *GetDynObject(uint32 spellId, uint32 effIndex); - DynamicObject *GetDynObject(uint32 spellId); - uint32 CalculateDamage(WeaponAttackType attType, bool normalized); - float GetAPMultiplier(WeaponAttackType attType, bool normalized); - void ModifyAuraState(AuraState flag, bool apply); - bool HasAuraState(AuraState flag) const { return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); } - void UnsummonAllTotems(); - int32 SpellBaseDamageBonus(SpellSchoolMask schoolMask); - int32 SpellBaseHealingBonus(SpellSchoolMask schoolMask); - int32 SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim); - int32 SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim); - uint32 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype); - uint32 SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim); - bool isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType); - uint32 SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim); - - void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; } - bool IsUnderLastManaUseEffect() const; - - void SetContestedPvP(Player *attackedPlayer = NULL); - - void MeleeDamageBonus(Unit *pVictim, uint32 *damage, WeaponAttackType attType, SpellEntry const *spellProto = NULL); - uint32 GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ); - - void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply); - void ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply); - virtual bool IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges = false); - // redefined in Creature - bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask, bool useCharges = false); - virtual bool IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const; - // redefined in Creature - - uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage); - void CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist); - - void UpdateSpeed(UnitMoveType mtype, bool forced); - float GetSpeed( UnitMoveType mtype ) const; - float GetSpeedRate( UnitMoveType mtype ) const { return m_speed_rate[mtype]; } - void SetSpeed(UnitMoveType mtype, float rate, bool forced = false); - - void SetHover(bool on); - bool isHover() const { return HasAuraType(SPELL_AURA_HOVER); } - - void _RemoveAllAuraMods(); - void _ApplyAllAuraMods(); - - int32 CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_index, int32 basePoints, Unit const* target); - int32 CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_index, Unit const* target); - float CalculateLevelPenalty(SpellEntry const* spellProto) const; - - void addFollower(FollowerReference* pRef) { m_FollowingRefManager.insertFirst(pRef); } - void removeFollower(FollowerReference* /*pRef*/ ) { /* nothing to do yet */ } - static Unit* GetUnit(WorldObject& object, uint64 guid); - - MotionMaster* GetMotionMaster() { return &i_motionMaster; } - - bool IsStopped() const { return !(hasUnitState(UNIT_STAT_MOVING)); } - void StopMoving(); - - void AddUnitMovementFlag(uint32 f) { m_unit_movement_flags |= f; } - void RemoveUnitMovementFlag(uint32 f) - { - uint32 oldval = m_unit_movement_flags; - m_unit_movement_flags = oldval & ~f; - } - uint32 HasUnitMovementFlag(uint32 f) const { return m_unit_movement_flags & f; } - uint32 GetUnitMovementFlags() const { return m_unit_movement_flags; } - void SetUnitMovementFlags(uint32 f) { m_unit_movement_flags = f; } - - void SetFeared(bool apply, uint64 casterGUID = 0, uint32 spellID = 0); - void SetConfused(bool apply, uint64 casterGUID = 0, uint32 spellID = 0); - - void AddComboPointHolder(uint32 lowguid) { m_ComboPointHolders.insert(lowguid); } - void RemoveComboPointHolder(uint32 lowguid) { m_ComboPointHolders.erase(lowguid); } - void ClearComboPointHolders(); - - ///----------Pet responses methods----------------- - void SendPetCastFail(uint32 spellid, uint8 msg); - void SendPetActionFeedback (uint8 msg); - void SendPetTalk (uint32 pettalk); - void SendPetSpellCooldown (uint32 spellid, time_t cooltime); - void SendPetClearCooldown (uint32 spellid); - void SendPetAIReaction(uint64 guid); - ///----------End of Pet responses methods---------- - - void propagateSpeedChange() { GetMotionMaster()->propagateSpeedChange(); } - - // reactive attacks - void ClearAllReactives(); - void StartReactiveTimer( ReactiveType reactive ) { m_reactiveTimer[reactive] = REACTIVE_TIMER_START;} - void UpdateReactives(uint32 p_time); - - // group updates - void UpdateAuraForGroup(uint8 slot); - - // pet auras - typedef std::set PetAuraSet; - PetAuraSet m_petAuras; - void AddPetAura(PetAura const* petSpell); - void RemovePetAura(PetAura const* petSpell); - - protected: - explicit Unit (); - - void _UpdateSpells(uint32 time); - - void _UpdateAutoRepeatSpell(); - bool m_AutoRepeatFirstCast; - - uint32 m_attackTimer[MAX_ATTACK]; - - float m_createStats[MAX_STATS]; - - AttackerSet m_attackers; - Unit* m_attacking; - - DeathState m_deathState; - - AuraMap m_Auras; - - std::list m_scAuras; // casted singlecast auras - - typedef std::list DynObjectGUIDs; - DynObjectGUIDs m_dynObjGUIDs; - - std::list m_gameObj; - bool m_isSorted; - uint32 m_transform; - uint32 m_removedAuras; - - AuraList m_modAuras[TOTAL_AURAS]; - float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END]; - float m_weaponDamage[MAX_ATTACK][2]; - bool m_canModifyStats; - //std::list< spellEffectPair > AuraSpells[TOTAL_AURAS]; // TODO: use this if ok for mem - - float m_speed_rate[MAX_MOVE_TYPE]; - - CharmInfo *m_charmInfo; - - virtual SpellSchoolMask GetMeleeDamageSchoolMask() const; - - MotionMaster i_motionMaster; - uint32 m_unit_movement_flags; - - uint32 m_reactiveTimer[MAX_REACTIVE]; - - private: - void SendAttackStop(Unit* victim); // only from AttackStop(Unit*) - void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*) - - void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask ); - bool HandleDummyAuraProc(Unit *pVictim, SpellEntry const *spellProto, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag,uint32 cooldown); - bool HandleProcTriggerSpell(Unit *pVictim,uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attType,uint32 cooldown); - bool HandleHasteAuraProc(Unit *pVictim, SpellEntry const *spellProto, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag,uint32 cooldown); - bool HandleOverrideClassScriptAuraProc(Unit *pVictim, int32 scriptId, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell,uint32 cooldown); - uint32 m_state; // Even derived shouldn't modify - uint32 m_CombatTimer; - uint32 m_lastManaUse; // msecs - - UnitVisibility m_Visibility; - - Diminishing m_Diminishing; - // Manage all Units threatening us - ThreatManager m_ThreatManager; - // Manage all Units that are threatened by us - HostilRefManager m_HostilRefManager; - - FollowerRefManager m_FollowingRefManager; - - ComboPointHolderSet m_ComboPointHolders; -}; -#endif +/* + * Copyright (C) 2005-2008 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 __UNIT_H +#define __UNIT_H + +#include "Common.h" +#include "Object.h" +#include "Opcodes.h" +#include "Mthread.h" +#include "SpellAuraDefines.h" +#include "UpdateFields.h" +#include "SharedDefines.h" +#include "ThreatManager.h" +#include "HostilRefManager.h" +#include "FollowerReference.h" +#include "FollowerRefManager.h" +#include "Utilities/EventProcessor.h" +#include "MotionMaster.h" +#include "Database/DBCStructure.h" +#include + +enum SpellInterruptFlags +{ + SPELL_INTERRUPT_FLAG_MOVEMENT = 0x01, + SPELL_INTERRUPT_FLAG_DAMAGE = 0x02, + SPELL_INTERRUPT_FLAG_INTERRUPT = 0x04, + SPELL_INTERRUPT_FLAG_AUTOATTACK = 0x08, + //SPELL_INTERRUPT_FLAG_TURNING = 0x10 // not turning - maybe _complete_ interrupt on direct damage? +}; + +enum SpellChannelInterruptFlags +{ + CHANNEL_FLAG_DAMAGE = 0x0002, + CHANNEL_FLAG_MOVEMENT = 0x0008, + CHANNEL_FLAG_TURNING = 0x0010, + CHANNEL_FLAG_DAMAGE2 = 0x0080, + CHANNEL_FLAG_DELAY = 0x4000 +}; + +enum SpellAuraInterruptFlags +{ + AURA_INTERRUPT_FLAG_UNK0 = 0x00000001, // 0 removed when getting hit by a negative spell? + AURA_INTERRUPT_FLAG_DAMAGE = 0x00000002, // 1 removed by any damage + AURA_INTERRUPT_FLAG_UNK2 = 0x00000004, // 2 + AURA_INTERRUPT_FLAG_MOVE = 0x00000008, // 3 removed by any movement + AURA_INTERRUPT_FLAG_TURNING = 0x00000010, // 4 removed by any turning + AURA_INTERRUPT_FLAG_ENTER_COMBAT = 0x00000020, // 5 removed by entering combat + AURA_INTERRUPT_FLAG_NOT_MOUNTED = 0x00000040, // 6 removed by unmounting + AURA_INTERRUPT_FLAG_NOT_ABOVEWATER = 0x00000080, // 7 removed by entering water + AURA_INTERRUPT_FLAG_NOT_UNDERWATER = 0x00000100, // 8 removed by leaving water + AURA_INTERRUPT_FLAG_NOT_SHEATHED = 0x00000200, // 9 removed by unsheathing + AURA_INTERRUPT_FLAG_UNK10 = 0x00000400, // 10 + AURA_INTERRUPT_FLAG_UNK11 = 0x00000800, // 11 + AURA_INTERRUPT_FLAG_UNK12 = 0x00001000, // 12 removed by attack? + AURA_INTERRUPT_FLAG_UNK13 = 0x00002000, // 13 + AURA_INTERRUPT_FLAG_UNK14 = 0x00004000, // 14 + AURA_INTERRUPT_FLAG_UNK15 = 0x00008000, // 15 removed by casting a spell? + AURA_INTERRUPT_FLAG_UNK16 = 0x00010000, // 16 + AURA_INTERRUPT_FLAG_MOUNTING = 0x00020000, // 17 removed by mounting + AURA_INTERRUPT_FLAG_NOT_SEATED = 0x00040000, // 18 removed by standing up + AURA_INTERRUPT_FLAG_CHANGE_MAP = 0x00080000, // 19 leaving map/getting teleported + AURA_INTERRUPT_FLAG_UNK20 = 0x00100000, // 20 + AURA_INTERRUPT_FLAG_UNK21 = 0x00200000, // 21 + AURA_INTERRUPT_FLAG_UNK22 = 0x00400000, // 22 + AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT = 0x00800000, // 23 removed by entering pvp combat + AURA_INTERRUPT_FLAG_DIRECT_DAMAGE = 0x01000000 // 24 removed by any direct damage +}; + +enum SpellModOp +{ + SPELLMOD_DAMAGE = 0, + SPELLMOD_DURATION = 1, + SPELLMOD_THREAT = 2, + SPELLMOD_EFFECT1 = 3, + SPELLMOD_CHARGES = 4, + SPELLMOD_RANGE = 5, + SPELLMOD_RADIUS = 6, + SPELLMOD_CRITICAL_CHANCE = 7, + SPELLMOD_ALL_EFFECTS = 8, + SPELLMOD_NOT_LOSE_CASTING_TIME = 9, + SPELLMOD_CASTING_TIME = 10, + SPELLMOD_COOLDOWN = 11, + SPELLMOD_EFFECT2 = 12, + // spellmod 13 unused + SPELLMOD_COST = 14, + SPELLMOD_CRIT_DAMAGE_BONUS = 15, + SPELLMOD_RESIST_MISS_CHANCE = 16, + SPELLMOD_JUMP_TARGETS = 17, + SPELLMOD_CHANCE_OF_SUCCESS = 18, + SPELLMOD_ACTIVATION_TIME = 19, + SPELLMOD_EFFECT_PAST_FIRST = 20, + SPELLMOD_CASTING_TIME_OLD = 21, + SPELLMOD_DOT = 22, + SPELLMOD_EFFECT3 = 23, + SPELLMOD_SPELL_BONUS_DAMAGE = 24, + // spellmod 25, 26 unused + SPELLMOD_MULTIPLE_VALUE = 27, + SPELLMOD_RESIST_DISPEL_CHANCE = 28 +}; + +#define MAX_SPELLMOD 32 + +enum SpellFacingFlags +{ + SPELL_FACING_FLAG_INFRONT = 0x0001 +}; + +#define BASE_MINDAMAGE 1.0f +#define BASE_MAXDAMAGE 2.0f +#define BASE_ATTACK_TIME 2000 + +// high byte (3 from 0..3) of UNIT_FIELD_BYTES_2 +enum ShapeshiftForm +{ + FORM_NONE = 0x00, + FORM_CAT = 0x01, + FORM_TREE = 0x02, + FORM_TRAVEL = 0x03, + FORM_AQUA = 0x04, + FORM_BEAR = 0x05, + FORM_AMBIENT = 0x06, + FORM_GHOUL = 0x07, + FORM_DIREBEAR = 0x08, + FORM_CREATUREBEAR = 0x0E, + FORM_CREATURECAT = 0x0F, + FORM_GHOSTWOLF = 0x10, + FORM_BATTLESTANCE = 0x11, + FORM_DEFENSIVESTANCE = 0x12, + FORM_BERSERKERSTANCE = 0x13, + FORM_TEST = 0x14, + FORM_ZOMBIE = 0x15, + FORM_FLIGHT_EPIC = 0x1B, + FORM_SHADOW = 0x1C, + FORM_FLIGHT = 0x1D, + FORM_STEALTH = 0x1E, + FORM_MOONKIN = 0x1F, + FORM_SPIRITOFREDEMPTION = 0x20 +}; + +// low byte ( 0 from 0..3 ) of UNIT_FIELD_BYTES_2 +enum SheathState +{ + SHEATH_STATE_UNARMED = 0, // non prepared weapon + SHEATH_STATE_MELEE = 1, // prepared melee weapon + SHEATH_STATE_RANGED = 2 // prepared ranged weapon +}; + +// byte (1 from 0..3) of UNIT_FIELD_BYTES_2 +enum UnitBytes2_Flags +{ + UNIT_BYTE2_FLAG_UNK0 = 0x01, + UNIT_BYTE2_FLAG_UNK1 = 0x02, + UNIT_BYTE2_FLAG_UNK2 = 0x04, + UNIT_BYTE2_FLAG_UNK3 = 0x08, + UNIT_BYTE2_FLAG_AURAS = 0x10, // show possitive auras as positive, and allow its dispel + UNIT_BYTE2_FLAG_UNK5 = 0x20, + UNIT_BYTE2_FLAG_UNK6 = 0x40, + UNIT_BYTE2_FLAG_UNK7 = 0x80 +}; + +// byte (2 from 0..3) of UNIT_FIELD_BYTES_2 +enum UnitRename +{ + UNIT_RENAME_NOT_ALLOWED = 0x02, + UNIT_RENAME_ALLOWED = 0x03 +}; + +#define CREATURE_MAX_SPELLS 4 + +enum Swing +{ + NOSWING = 0, + SINGLEHANDEDSWING = 1, + TWOHANDEDSWING = 2 +}; + +enum VictimState +{ + VICTIMSTATE_UNKNOWN1 = 0, + VICTIMSTATE_NORMAL = 1, + VICTIMSTATE_DODGE = 2, + VICTIMSTATE_PARRY = 3, + VICTIMSTATE_INTERRUPT = 4, + VICTIMSTATE_BLOCKS = 5, + VICTIMSTATE_EVADES = 6, + VICTIMSTATE_IS_IMMUNE = 7, + VICTIMSTATE_DEFLECTS = 8 +}; + +enum HitInfo +{ + HITINFO_NORMALSWING = 0x00000000, + HITINFO_UNK1 = 0x00000001, // req correct packet structure + HITINFO_NORMALSWING2 = 0x00000002, + HITINFO_LEFTSWING = 0x00000004, + HITINFO_MISS = 0x00000010, + HITINFO_ABSORB = 0x00000020, // plays absorb sound + HITINFO_RESIST = 0x00000040, // resisted atleast some damage + HITINFO_CRITICALHIT = 0x00000080, + HITINFO_GLANCING = 0x00004000, + HITINFO_CRUSHING = 0x00008000, + HITINFO_NOACTION = 0x00010000, + HITINFO_SWINGNOHITSOUND = 0x00080000 +}; + +//i would like to remove this: (it is defined in item.h +enum InventorySlot +{ + NULL_BAG = 0, + NULL_SLOT = 255 +}; + +struct FactionTemplateEntry; +struct Modifier; +struct SpellEntry; +struct SpellEntryExt; + +class Aura; +class Creature; +class Spell; +class DynamicObject; +class GameObject; +class Item; +class Pet; +class Path; +class PetAura; + +struct SpellImmune +{ + uint32 type; + uint32 spellId; +}; + +typedef std::list SpellImmuneList; + +enum UnitModifierType +{ + BASE_VALUE = 0, + BASE_PCT = 1, + TOTAL_VALUE = 2, + TOTAL_PCT = 3, + MODIFIER_TYPE_END = 4 +}; + +enum WeaponDamageRange +{ + MINDAMAGE, + MAXDAMAGE +}; + +enum DamageTypeToSchool +{ + RESISTANCE, + DAMAGE_DEALT, + DAMAGE_TAKEN +}; + +enum AuraRemoveMode +{ + AURA_REMOVE_BY_DEFAULT, + AURA_REMOVE_BY_STACK, // at replace by semillar aura + AURA_REMOVE_BY_CANCEL, + AURA_REMOVE_BY_DISPEL, + AURA_REMOVE_BY_DEATH +}; + +enum UnitMods +{ + UNIT_MOD_STAT_STRENGTH, // UNIT_MOD_STAT_STRENGTH..UNIT_MOD_STAT_SPIRIT must be in existed order, it's accessed by index values of Stats enum. + UNIT_MOD_STAT_AGILITY, + UNIT_MOD_STAT_STAMINA, + UNIT_MOD_STAT_INTELLECT, + UNIT_MOD_STAT_SPIRIT, + UNIT_MOD_HEALTH, + UNIT_MOD_MANA, // UNIT_MOD_MANA..UNIT_MOD_HAPPINESS must be in existed order, it's accessed by index values of Powers enum. + UNIT_MOD_RAGE, + UNIT_MOD_FOCUS, + UNIT_MOD_ENERGY, + UNIT_MOD_HAPPINESS, + UNIT_MOD_ARMOR, // UNIT_MOD_ARMOR..UNIT_MOD_RESISTANCE_ARCANE must be in existed order, it's accessed by index values of SpellSchools enum. + UNIT_MOD_RESISTANCE_HOLY, + UNIT_MOD_RESISTANCE_FIRE, + UNIT_MOD_RESISTANCE_NATURE, + UNIT_MOD_RESISTANCE_FROST, + UNIT_MOD_RESISTANCE_SHADOW, + UNIT_MOD_RESISTANCE_ARCANE, + UNIT_MOD_ATTACK_POWER, + UNIT_MOD_ATTACK_POWER_RANGED, + UNIT_MOD_DAMAGE_MAINHAND, + UNIT_MOD_DAMAGE_OFFHAND, + UNIT_MOD_DAMAGE_RANGED, + UNIT_MOD_END, + // synonyms + UNIT_MOD_STAT_START = UNIT_MOD_STAT_STRENGTH, + UNIT_MOD_STAT_END = UNIT_MOD_STAT_SPIRIT + 1, + UNIT_MOD_RESISTANCE_START = UNIT_MOD_ARMOR, + UNIT_MOD_RESISTANCE_END = UNIT_MOD_RESISTANCE_ARCANE + 1, + UNIT_MOD_POWER_START = UNIT_MOD_MANA, + UNIT_MOD_POWER_END = UNIT_MOD_HAPPINESS + 1 +}; + +enum BaseModGroup +{ + CRIT_PERCENTAGE, + RANGED_CRIT_PERCENTAGE, + OFFHAND_CRIT_PERCENTAGE, + SHIELD_BLOCK_VALUE, + BASEMOD_END +}; + +enum BaseModType +{ + FLAT_MOD, + PCT_MOD +}; + +#define MOD_END (PCT_MOD+1) + +enum DeathState +{ + ALIVE = 0, + JUST_DIED = 1, + CORPSE = 2, + DEAD = 3, + JUST_ALIVED = 4 +}; + +enum UnitState +{ + UNIT_STAT_DIED = 0x0001, + UNIT_STAT_MELEE_ATTACKING = 0x0002, // player is melee attacking someone + //UNIT_STAT_MELEE_ATTACK_BY = 0x0004, // player is melee attack by someone + UNIT_STAT_STUNDED = 0x0008, + UNIT_STAT_ROAMING = 0x0010, + UNIT_STAT_CHASE = 0x0020, + UNIT_STAT_SEARCHING = 0x0040, + UNIT_STAT_FLEEING = 0x0080, + UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING), + UNIT_STAT_IN_FLIGHT = 0x0100, // player is in flight mode + UNIT_STAT_FOLLOW = 0x0200, + UNIT_STAT_ROOT = 0x0400, + UNIT_STAT_CONFUSED = 0x0800, + UNIT_STAT_DISTRACTED = 0x1000, + UNIT_STAT_ISOLATED = 0x2000, // area auras do not affect other players + UNIT_STAT_ATTACK_PLAYER = 0x4000, + UNIT_STAT_ALL_STATE = 0xffff //(UNIT_STAT_STOPPED | UNIT_STAT_MOVING | UNIT_STAT_IN_COMBAT | UNIT_STAT_IN_FLIGHT) +}; + +enum UnitMoveType +{ + MOVE_WALK = 0, + MOVE_RUN = 1, + MOVE_WALKBACK = 2, + MOVE_SWIM = 3, + MOVE_SWIMBACK = 4, + MOVE_TURN = 5, + MOVE_FLY = 6, + MOVE_FLYBACK = 7 +}; + +#define MAX_MOVE_TYPE 8 + +extern float baseMoveSpeed[MAX_MOVE_TYPE]; + +enum WeaponAttackType +{ + BASE_ATTACK = 0, + OFF_ATTACK = 1, + RANGED_ATTACK = 2 +}; + +#define MAX_ATTACK 3 + +enum CombatRating +{ + CR_WEAPON_SKILL = 0, + CR_DEFENSE_SKILL = 1, + CR_DODGE = 2, + CR_PARRY = 3, + CR_BLOCK = 4, + CR_HIT_MELEE = 5, + CR_HIT_RANGED = 6, + CR_HIT_SPELL = 7, + CR_CRIT_MELEE = 8, + CR_CRIT_RANGED = 9, + CR_CRIT_SPELL = 10, + CR_HIT_TAKEN_MELEE = 11, + CR_HIT_TAKEN_RANGED = 12, + CR_HIT_TAKEN_SPELL = 13, + CR_CRIT_TAKEN_MELEE = 14, + CR_CRIT_TAKEN_RANGED = 15, + CR_CRIT_TAKEN_SPELL = 16, + CR_HASTE_MELEE = 17, + CR_HASTE_RANGED = 18, + CR_HASTE_SPELL = 19, + CR_WEAPON_SKILL_MAINHAND = 20, + CR_WEAPON_SKILL_OFFHAND = 21, + CR_WEAPON_SKILL_RANGED = 22, + CR_EXPERTISE = 23 +}; + +#define MAX_COMBAT_RATING 24 + +enum DamageEffectType +{ + DIRECT_DAMAGE = 0, // used for normal weapon damage (not for class abilities or spells) + SPELL_DIRECT_DAMAGE = 1, // spell/class abilities damage + DOT = 2, + HEAL = 3, + NODAMAGE = 4, // used also in case when damage applied to health but not applied to spell channelInterruptFlags/etc + SELF_DAMAGE = 5 +}; + +enum UnitVisibility +{ + VISIBILITY_OFF = 0, // absolute, not detectable, GM-like, can see all other + VISIBILITY_ON = 1, + VISIBILITY_GROUP_STEALTH = 2, // detect chance, seen and can see group members + VISIBILITY_GROUP_INVISIBILITY = 3, // invisibility, can see and can be seen only another invisible unit or invisible detection unit, set only if not stealthed, and in checks not used (mask used instead) + VISIBILITY_GROUP_NO_DETECT = 4, // state just at stealth apply for update Grid state. Don't remove, otherwise stealth spells will break + VISIBILITY_RESPAWN = 5 // special totally not detectable visibility for force delete object at respawn command +}; + +// Value masks for UNIT_FIELD_FLAGS +enum UnitFlags +{ + UNIT_FLAG_UNKNOWN7 = 0x00000001, + UNIT_FLAG_NON_ATTACKABLE = 0x00000002, // not attackable + UNIT_FLAG_DISABLE_MOVE = 0x00000004, + UNIT_FLAG_PVP_ATTACKABLE = 0x00000008, // allow apply pvp rules to attackable state in addition to faction dependent state + UNIT_FLAG_RENAME = 0x00000010, + UNIT_FLAG_PREPARATION = 0x00000020, // don't take reagents for spells with SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP + UNIT_FLAG_UNKNOWN9 = 0x00000040, + UNIT_FLAG_NOT_ATTACKABLE_1 = 0x00000080, // ?? (UNIT_FLAG_PVP_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1) is NON_PVP_ATTACKABLE + UNIT_FLAG_UNKNOWN2 = 0x00000100, // 2.0.8 + UNIT_FLAG_UNKNOWN11 = 0x00000200, + UNIT_FLAG_LOOTING = 0x00000400, // loot animation + UNIT_FLAG_PET_IN_COMBAT = 0x00000800, // in combat?, 2.0.8 + UNIT_FLAG_PVP = 0x00001000, + UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1 + UNIT_FLAG_UNKNOWN4 = 0x00004000, // 2.0.8 + UNIT_FLAG_UNKNOWN13 = 0x00008000, + UNIT_FLAG_UNKNOWN14 = 0x00010000, + UNIT_FLAG_PACIFIED = 0x00020000, + UNIT_FLAG_DISABLE_ROTATE = 0x00040000, // stunned, 2.1.1 + UNIT_FLAG_IN_COMBAT = 0x00080000, + UNIT_FLAG_TAXI_FLIGHT = 0x00100000, // disable casting at client side spell not allowed by taxi flight (mounted?), probably used with 0x4 flag + UNIT_FLAG_DISARMED = 0x00200000, // disable melee spells casting..., "Required melee weapon" added to melee spells tooltip. + UNIT_FLAG_CONFUSED = 0x00400000, + UNIT_FLAG_FLEEING = 0x00800000, + UNIT_FLAG_UNKNOWN5 = 0x01000000, // used in spell Eyes of the Beast for pet... + UNIT_FLAG_NOT_SELECTABLE = 0x02000000, + UNIT_FLAG_SKINNABLE = 0x04000000, + UNIT_FLAG_MOUNT = 0x08000000, + UNIT_FLAG_UNKNOWN17 = 0x10000000, + UNIT_FLAG_UNKNOWN6 = 0x20000000, // used in Feing Death spell + UNIT_FLAG_SHEATHE = 0x40000000 +}; + +// Value masks for UNIT_FIELD_FLAGS_2 +enum UnitFlags2 +{ + UNIT_FLAG2_FEIGN_DEATH = 0x00000001, + UNIT_FLAG2_COMPREHEND_LANG= 0x00000008, + UNIT_FLAG2_FORCE_MOVE = 0x00000040 +}; + +/// Non Player Character flags +enum NPCFlags +{ + UNIT_NPC_FLAG_NONE = 0x00000000, + UNIT_NPC_FLAG_GOSSIP = 0x00000001, // 100% + UNIT_NPC_FLAG_QUESTGIVER = 0x00000002, // guessed, probably ok + UNIT_NPC_FLAG_UNK1 = 0x00000004, + UNIT_NPC_FLAG_UNK2 = 0x00000008, + UNIT_NPC_FLAG_TRAINER = 0x00000010, // 100% + UNIT_NPC_FLAG_TRAINER_CLASS = 0x00000020, // 100% + UNIT_NPC_FLAG_TRAINER_PROFESSION = 0x00000040, // 100% + UNIT_NPC_FLAG_VENDOR = 0x00000080, // 100% + UNIT_NPC_FLAG_VENDOR_AMMO = 0x00000100, // 100%, general goods vendor + UNIT_NPC_FLAG_VENDOR_FOOD = 0x00000200, // 100% + UNIT_NPC_FLAG_VENDOR_POISON = 0x00000400, // guessed + UNIT_NPC_FLAG_VENDOR_REAGENT = 0x00000800, // 100% + UNIT_NPC_FLAG_REPAIR = 0x00001000, // 100% + UNIT_NPC_FLAG_FLIGHTMASTER = 0x00002000, // 100% + UNIT_NPC_FLAG_SPIRITHEALER = 0x00004000, // guessed + UNIT_NPC_FLAG_SPIRITGUIDE = 0x00008000, // guessed + UNIT_NPC_FLAG_INNKEEPER = 0x00010000, // 100% + UNIT_NPC_FLAG_BANKER = 0x00020000, // 100% + UNIT_NPC_FLAG_PETITIONER = 0x00040000, // 100% 0xC0000 = guild petitions, 0x40000 = arena team petitions + UNIT_NPC_FLAG_TABARDDESIGNER = 0x00080000, // 100% + UNIT_NPC_FLAG_BATTLEMASTER = 0x00100000, // 100% + UNIT_NPC_FLAG_AUCTIONEER = 0x00200000, // 100% + UNIT_NPC_FLAG_STABLEMASTER = 0x00400000, // 100% + UNIT_NPC_FLAG_GUILD_BANKER = 0x00800000, // cause client to send 997 opcode + UNIT_NPC_FLAG_UNK3 = 0x01000000, // cause client to send 1015 opcode + UNIT_NPC_FLAG_GUARD = 0x10000000, // custom flag for guards +}; + +enum MovementFlags +{ + MOVEMENTFLAG_NONE = 0x00000000, + MOVEMENTFLAG_FORWARD = 0x00000001, + MOVEMENTFLAG_BACKWARD = 0x00000002, + MOVEMENTFLAG_STRAFE_LEFT = 0x00000004, + MOVEMENTFLAG_STRAFE_RIGHT = 0x00000008, + MOVEMENTFLAG_LEFT = 0x00000010, + MOVEMENTFLAG_RIGHT = 0x00000020, + MOVEMENTFLAG_PITCH_UP = 0x00000040, + MOVEMENTFLAG_PITCH_DOWN = 0x00000080, + MOVEMENTFLAG_WALK_MODE = 0x00000100, // Walking + MOVEMENTFLAG_ONTRANSPORT = 0x00000200, // Used for flying on some creatures + MOVEMENTFLAG_LEVITATING = 0x00000400, + MOVEMENTFLAG_FLY_UNK1 = 0x00000800, + MOVEMENTFLAG_JUMPING = 0x00001000, + MOVEMENTFLAG_UNK4 = 0x00002000, + MOVEMENTFLAG_FALLING = 0x00004000, + // 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000 + MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also + MOVEMENTFLAG_FLY_UP = 0x00400000, + MOVEMENTFLAG_CAN_FLY = 0x00800000, + MOVEMENTFLAG_FLYING = 0x01000000, + MOVEMENTFLAG_FLYING2 = 0x02000000, // Actual flying mode + MOVEMENTFLAG_SPLINE = 0x04000000, // used for flight paths + MOVEMENTFLAG_SPLINE2 = 0x08000000, // used for flight paths + MOVEMENTFLAG_WATERWALKING = 0x10000000, // prevent unit from falling through water + MOVEMENTFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive) + MOVEMENTFLAG_UNK3 = 0x40000000 +}; + +enum DiminishingLevels +{ + DIMINISHING_LEVEL_1 = 0, + DIMINISHING_LEVEL_2 = 1, + DIMINISHING_LEVEL_3 = 2, + DIMINISHING_LEVEL_IMMUNE = 3 +}; + +struct DiminishingReturn +{ + DiminishingReturn(DiminishingGroup group, uint32 t, uint32 count) : DRGroup(group), hitTime(t), hitCount(count), stack(0) {} + + DiminishingGroup DRGroup:16; + uint16 stack:16; + uint32 hitTime; + uint32 hitCount; +}; + +enum MeleeHitOutcome +{ + MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY, + MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL, MELEE_HIT_BLOCK_CRIT +}; +struct CleanDamage +{ + CleanDamage(uint32 _damage, WeaponAttackType _attackType, MeleeHitOutcome _hitOutCome) : + damage(_damage), attackType(_attackType), hitOutCome(_hitOutCome) {} + + uint32 damage; + WeaponAttackType attackType; + MeleeHitOutcome hitOutCome; +}; + +struct UnitActionBarEntry +{ + uint32 Type; + uint32 SpellOrAction; +}; + +#define MAX_DECLINED_NAME_CASES 5 + +struct DeclinedName +{ + std::string name[MAX_DECLINED_NAME_CASES]; +}; + +enum CurrentSpellTypes +{ + CURRENT_MELEE_SPELL = 0, + CURRENT_FIRST_NON_MELEE_SPELL = 1, // just counter + CURRENT_GENERIC_SPELL = 1, + CURRENT_AUTOREPEAT_SPELL = 2, + CURRENT_CHANNELED_SPELL = 3, + CURRENT_MAX_SPELL = 4 // just counter +}; + +enum ActiveStates +{ + ACT_ENABLED = 0xC100, + ACT_DISABLED = 0x8100, + ACT_COMMAND = 0x0700, + ACT_REACTION = 0x0600, + ACT_CAST = 0x0100, + ACT_PASSIVE = 0x0000, + ACT_DECIDE = 0x0001 +}; + +enum ReactStates +{ + REACT_PASSIVE = 0, + REACT_DEFENSIVE = 1, + REACT_AGGRESSIVE = 2 +}; + +enum CommandStates +{ + COMMAND_STAY = 0, + COMMAND_FOLLOW = 1, + COMMAND_ATTACK = 2, + COMMAND_ABANDON = 3 +}; + +struct CharmSpellEntry +{ + uint16 spellId; + uint16 active; +}; + +struct CharmInfo +{ + public: + explicit CharmInfo(Unit* unit); + uint32 GetPetNumber() const { return m_petnumber; } + void SetPetNumber(uint32 petnumber, bool statwindow); + + void SetCommandState(CommandStates st) { m_CommandState = st; } + CommandStates GetCommandState() { return m_CommandState; } + bool HasCommandState(CommandStates state) { return (m_CommandState == state); } + void SetReactState(ReactStates st) { m_ReactSate = st; } + ReactStates GetReactState() { return m_ReactSate; } + bool HasReactState(ReactStates state) { return (m_ReactSate == state); } + + void InitPossessCreateSpells(); + void InitCharmCreateSpells(); + void InitPetActionBar(); + void InitEmptyActionBar(); + //return true if successful + bool AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate = ACT_DECIDE); + void ToggleCreatureAutocast(uint32 spellid, bool apply); + + UnitActionBarEntry* GetActionBarEntry(uint8 index) { return &(PetActionBar[index]); } + CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); } + private: + Unit* m_unit; + UnitActionBarEntry PetActionBar[10]; + CharmSpellEntry m_charmspells[4]; + CommandStates m_CommandState; + ReactStates m_ReactSate; + uint32 m_petnumber; +}; + +// for clearing special attacks +#define REACTIVE_TIMER_START 4000 + +enum ReactiveType +{ + REACTIVE_DEFENSE = 1, + REACTIVE_HUNTER_PARRY = 2, + REACTIVE_CRIT = 3, + REACTIVE_HUNTER_CRIT = 4, + REACTIVE_OVERPOWER = 5 +}; + +#define MAX_REACTIVE 6 +#define MAX_TOTEM 4 + +// delay time next attack to prevent client attack animation problems +#define ATTACK_DISPLAY_DELAY 200 + +class MANGOS_DLL_SPEC Unit : public WorldObject +{ + public: + typedef std::set AttackerSet; + typedef std::pair spellEffectPair; + typedef std::multimap< spellEffectPair, Aura*> AuraMap; + typedef std::list AuraList; + typedef std::list Diminishing; + typedef std::set AuraTypeSet; + typedef std::set ComboPointHolderSet; + + virtual ~Unit ( ); + + void AddToWorld(); + void RemoveFromWorld(); + + void CleanupsBeforeDelete(); // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units) + + DiminishingLevels GetDiminishing(DiminishingGroup group); + void IncrDiminishing(DiminishingGroup group); + void ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster, DiminishingLevels Level); + void ApplyDiminishingAura(DiminishingGroup group, bool apply); + void ClearDiminishings() { m_Diminishing.clear(); } + + virtual void Update( uint32 time ); + + void setAttackTimer(WeaponAttackType type, uint32 time) { m_attackTimer[type] = time; } + void resetAttackTimer(WeaponAttackType type = BASE_ATTACK); + uint32 getAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; } + bool isAttackReady(WeaponAttackType type = BASE_ATTACK) const { return m_attackTimer[type] == 0; } + bool haveOffhandWeapon() const; + bool canReachWithAttack(Unit *pVictim) const; + uint32 m_extraAttacks; + + void _addAttacker(Unit *pAttacker) // must be called only from Unit::Attack(Unit*) + { + AttackerSet::iterator itr = m_attackers.find(pAttacker); + if(itr == m_attackers.end()) + m_attackers.insert(pAttacker); + } + void _removeAttacker(Unit *pAttacker) // must be called only from Unit::AttackStop() + { + AttackerSet::iterator itr = m_attackers.find(pAttacker); + if(itr != m_attackers.end()) + m_attackers.erase(itr); + } + Unit * getAttackerForHelper() // If someone wants to help, who to give them + { + if (getVictim() != NULL) + return getVictim(); + + if (!m_attackers.empty()) + return *(m_attackers.begin()); + + return NULL; + } + bool Attack(Unit *victim, bool meleeAttack); + void CastStop(uint32 except_spellid = 0); + bool AttackStop(); + void RemoveAllAttackers(); + AttackerSet const& getAttackers() const { return m_attackers; } + bool isAttackingPlayer() const; + Unit* getVictim() const { return m_attacking; } + void CombatStop(bool cast = false); + void CombatStopWithPets(bool cast = false); + Unit* SelectNearbyTarget() const; + + void addUnitState(uint32 f) { m_state |= f; } + bool hasUnitState(const uint32 f) const { return (m_state & f); } + void clearUnitState(uint32 f) { m_state &= ~f; } + bool CanFreeMove() const + { + return !hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING | UNIT_STAT_IN_FLIGHT | + UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED ) && GetOwnerGUID()==0; + } + + uint32 getLevel() const { return GetUInt32Value(UNIT_FIELD_LEVEL); } + virtual uint32 getLevelForTarget(Unit const* /*target*/) const { return getLevel(); } + void SetLevel(uint32 lvl); + uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, 0); } + uint32 getRaceMask() const { return 1 << (getRace()-1); } + uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, 1); } + uint32 getClassMask() const { return 1 << (getClass()-1); } + uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, 2); } + + float GetStat(Stats stat) const { return float(GetUInt32Value(UNIT_FIELD_STAT0+stat)); } + void SetStat(Stats stat, int32 val) { SetStatInt32Value(UNIT_FIELD_STAT0+stat, val); } + uint32 GetArmor() const { return GetResistance(SPELL_SCHOOL_NORMAL) ; } + void SetArmor(int32 val) { SetResistance(SPELL_SCHOOL_NORMAL, val); } + + uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(UNIT_FIELD_RESISTANCES+school); } + void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(UNIT_FIELD_RESISTANCES+school,val); } + + uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); } + uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); } + void SetHealth( uint32 val); + void SetMaxHealth(uint32 val); + int32 ModifyHealth(int32 val); + + Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, 3)); } + void setPowerType(Powers power); + uint32 GetPower( Powers power) const { return GetUInt32Value(UNIT_FIELD_POWER1 +power); } + uint32 GetMaxPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_MAXPOWER1+power); } + void SetPower( Powers power, uint32 val); + void SetMaxPower(Powers power, uint32 val); + int32 ModifyPower(Powers power, int32 val); + void ApplyPowerMod(Powers power, uint32 val, bool apply); + void ApplyMaxPowerMod(Powers power, uint32 val, bool apply); + + uint32 GetAttackTime(WeaponAttackType att) const { return (uint32)(GetFloatValue(UNIT_FIELD_BASEATTACKTIME+att)/m_modAttackSpeedPct[att]); } + void SetAttackTime(WeaponAttackType att, uint32 val) { SetFloatValue(UNIT_FIELD_BASEATTACKTIME+att,val*m_modAttackSpeedPct[att]); } + void ApplyAttackTimePercentMod(WeaponAttackType att,float val, bool apply); + void ApplyCastTimePercentMod(float val, bool apply); + + // faction template id + uint32 getFaction() const { return GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE); } + void setFaction(uint32 faction) { SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction ); } + FactionTemplateEntry const* getFactionTemplateEntry() const; + bool IsHostileTo(Unit const* unit) const; + bool IsHostileToPlayers() const; + bool IsFriendlyTo(Unit const* unit) const; + bool IsNeutralToAll() const; + bool IsContestedGuard() const + { + if(FactionTemplateEntry const* entry = getFactionTemplateEntry()) + return entry->IsContestedGuardFaction(); + + return false; + } + bool IsPvP() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); } + void SetPvP(bool state) { if(state) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); else RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); } + uint32 GetCreatureType() const; + uint32 GetCreatureTypeMask() const + { + uint32 creatureType = GetCreatureType(); + return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0; + } + + uint8 getStandState() const { return GetByteValue(UNIT_FIELD_BYTES_1, 0); } + bool IsSitState() const; + bool IsStandState() const; + void SetStandState(uint8 state); + + bool IsMounted() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); } + uint32 GetMountID() const { return GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID); } + void Mount(uint32 mount); + void Unmount(); + + uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } + uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss); + void DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit = false, bool isTriggeredSpell = false); + void DoAttackDamage(Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false); + + void CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false); + void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage = 0, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NONE, SpellEntry const *procSpell = NULL, bool isTriggeredSpell = false, WeaponAttackType attType = BASE_ATTACK); + void HandleEmoteCommand(uint32 anim_id); + void AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType = BASE_ATTACK, bool extra = false ); + + float MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const; + SpellMissInfo MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell); + SpellMissInfo SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool canReflect = false); + + float GetUnitDodgeChance() const; + float GetUnitParryChance() const; + float GetUnitBlockChance() const; + float GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const; + + virtual uint32 GetShieldBlockValue() const =0; + uint32 GetUnitMeleeSkill(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } + uint32 GetDefenseSkillValue(Unit const* target = NULL) const; + uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const; + float GetWeaponProcChance() const; + float GetPPMProcChance(uint32 WeaponSpeed, float PPM) const; + MeleeHitOutcome RollPhysicalOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo); + MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const; + MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const; + + bool isVendor() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR ); } + bool isTrainer() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TRAINER ); } + bool isQuestGiver() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER ); } + bool isGossip() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP ); } + bool isTaxi() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_FLIGHTMASTER ); } + bool isGuildMaster() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PETITIONER ); } + bool isBattleMaster() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BATTLEMASTER ); } + bool isBanker() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BANKER ); } + bool isInnkeeper() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_INNKEEPER ); } + bool isSpiritHealer() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER ); } + bool isSpiritGuide() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITGUIDE ); } + bool isTabardDesigner()const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TABARDDESIGNER ); } + bool isAuctioner() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_AUCTIONEER ); } + bool isArmorer() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_REPAIR ); } + bool isServiceProvider() const + { + return HasFlag( UNIT_NPC_FLAGS, + UNIT_NPC_FLAG_VENDOR | UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_FLIGHTMASTER | + UNIT_NPC_FLAG_PETITIONER | UNIT_NPC_FLAG_BATTLEMASTER | UNIT_NPC_FLAG_BANKER | + UNIT_NPC_FLAG_INNKEEPER | UNIT_NPC_FLAG_GUARD | UNIT_NPC_FLAG_SPIRITHEALER | + UNIT_NPC_FLAG_SPIRITGUIDE | UNIT_NPC_FLAG_TABARDDESIGNER | UNIT_NPC_FLAG_AUCTIONEER ); + } + bool isSpiritService() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER | UNIT_NPC_FLAG_SPIRITGUIDE ); } + + //Need fix or use this + bool isGuard() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GUARD); } + + bool isInFlight() const { return hasUnitState(UNIT_STAT_IN_FLIGHT); } + + bool isInCombat() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); } + void SetInCombatState(bool PvP); + void SetInCombatWith(Unit* enemy); + void ClearInCombat(); + uint32 GetCombatTimer() const { return m_CombatTimer; } + + bool HasAuraType(AuraType auraType) const; + bool HasAura(uint32 spellId, uint32 effIndex) const + { return m_Auras.find(spellEffectPair(spellId, effIndex)) != m_Auras.end(); } + + bool virtual HasSpell(uint32 /*spellID*/) const { return false; } + + bool HasStealthAura() const { return HasAuraType(SPELL_AURA_MOD_STEALTH); } + bool HasInvisibilityAura() const { return HasAuraType(SPELL_AURA_MOD_INVISIBILITY); } + bool isFeared() const { return HasAuraType(SPELL_AURA_MOD_FEAR); } + bool isInRoots() const { return HasAuraType(SPELL_AURA_MOD_ROOT); } + bool IsPolymorphed() const; + + bool isFrozen() const; + + void RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage); + + bool isTargetableForAttack() const; + virtual bool IsInWater() const; + virtual bool IsUnderWater() const; + bool isInAccessablePlaceFor(Creature const* c) const; + + void SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical = false); + void SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype, bool critical = false); + uint32 SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell = false, bool useSpellDamage = true); + void CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); + void CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem= NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); + void CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); + void CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); + void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); + void CastSpell(float x, float y, float z, SpellEntry const *spellInfo, bool triggered, Item *castItem = NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0); + + bool IsDamageToThreatSpell(SpellEntry const * spellInfo) const; + + void DeMorph(); + + void SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount); + void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false); + void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo); + + void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); + void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags); + void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime = 0, Player* player = NULL); + void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL); + + virtual void MoveOutOfRange(Player &) { }; + + bool isAlive() const { return (m_deathState == ALIVE); }; + bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); }; + DeathState getDeathState() { return m_deathState; }; + virtual void setDeathState(DeathState s); // overwrited in Creature/Player/Pet + + uint64 const& GetOwnerGUID() const { return GetUInt64Value(UNIT_FIELD_SUMMONEDBY); } + uint64 GetPetGUID() const { return GetUInt64Value(UNIT_FIELD_SUMMON); } + uint64 GetCharmerGUID() const { return GetUInt64Value(UNIT_FIELD_CHARMEDBY); } + uint64 GetCharmGUID() const { return GetUInt64Value(UNIT_FIELD_CHARM); } + void SetCharmerGUID(uint64 owner) { SetUInt64Value(UNIT_FIELD_CHARMEDBY, owner); } + + uint64 GetCharmerOrOwnerGUID() const { return GetCharmerGUID() ? GetCharmerGUID() : GetOwnerGUID(); } + uint64 GetCharmerOrOwnerOrOwnGUID() const + { + if(uint64 guid = GetCharmerOrOwnerGUID()) + return guid; + return GetGUID(); + } + bool isCharmedOwnedByPlayerOrPlayer() const { return IS_PLAYER_GUID(GetCharmerOrOwnerOrOwnGUID()); } + + Player* GetSpellModOwner(); + + Unit* GetOwner() const; + Pet* GetPet() const; + Unit* GetCharmer() const; + Unit* GetCharm() const; + Unit* GetCharmerOrOwner() const { return GetCharmerGUID() ? GetCharmer() : GetOwner(); } + Unit* GetCharmerOrOwnerOrSelf() + { + if(Unit* u = GetCharmerOrOwner()) + return u; + + return this; + } + Player* GetCharmerOrOwnerPlayerOrPlayerItself(); + + void SetPet(Pet* pet); + void SetCharm(Unit* pet); + bool isCharmed() const { return GetCharmerGUID() != 0; } + + CharmInfo* GetCharmInfo() { return m_charmInfo; } + CharmInfo* InitCharmInfo(Unit* charm); + + bool AddAura(Aura *aur); + + void RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT); + void RemoveAura(uint32 spellId, uint32 effindex, Aura* except = NULL); + void RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex); + void RemoveAurasDueToSpell(uint32 spellId, Aura* except = NULL); + void RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId); + void RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler); + void RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer); + void RemoveAurasDueToSpellByCancel(uint32 spellId); + void RemoveNotOwnSingleTargetAuras(); + + void RemoveSpellsCausingAura(AuraType auraType); + void RemoveRankAurasDueToSpell(uint32 spellId); + bool RemoveNoStackAurasDueToAura(Aura *Aur); + void RemoveAurasWithInterruptFlags(uint32 flags); + void RemoveAurasWithDispelType( DispelType type ); + + void RemoveAllAuras(); + void RemoveAllAurasOnDeath(); + void DelayAura(uint32 spellId, uint32 effindex, int32 delaytime); + + float GetResistanceBuffMods(SpellSchools school, bool positive) const { return GetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school ); } + void SetResistanceBuffMods(SpellSchools school, bool positive, float val) { SetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school,val); } + void ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply) { ApplyModSignedFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); } + void ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply) { ApplyPercentModFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); } + void InitStatBuffMods() + { + for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(UNIT_FIELD_POSSTAT0+i, 0); + for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(UNIT_FIELD_NEGSTAT0+i, 0); + } + void ApplyStatBuffMod(Stats stat, float val, bool apply) { ApplyModSignedFloatValue((val > 0 ? UNIT_FIELD_POSSTAT0+stat : UNIT_FIELD_NEGSTAT0+stat), val, apply); } + void ApplyStatPercentBuffMod(Stats stat, float val, bool apply) + { + ApplyPercentModFloatValue(UNIT_FIELD_POSSTAT0+stat, val, apply); + ApplyPercentModFloatValue(UNIT_FIELD_NEGSTAT0+stat, val, apply); + } + void SetCreateStat(Stats stat, float val) { m_createStats[stat] = val; } + void SetCreateHealth(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_HEALTH, val); } + uint32 GetCreateHealth() const { return GetUInt32Value(UNIT_FIELD_BASE_HEALTH); } + void SetCreateMana(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_MANA, val); } + uint32 GetCreateMana() const { return GetUInt32Value(UNIT_FIELD_BASE_MANA); } + uint32 GetCreatePowers(Powers power) const; + float GetPosStat(Stats stat) const { return GetFloatValue(UNIT_FIELD_POSSTAT0+stat); } + float GetNegStat(Stats stat) const { return GetFloatValue(UNIT_FIELD_NEGSTAT0+stat); } + float GetCreateStat(Stats stat) const { return m_createStats[stat]; } + + void SetCurrentCastedSpell(Spell * pSpell); + virtual void ProhibitSpellScholl(SpellSchoolMask /*idSchoolMask*/, uint32 /*unTimeMs*/ ) { } + void InterruptSpell(uint32 spellType, bool withDelayed = true); + + // set withDelayed to true to account delayed spells as casted + // delayed+channeled spells are always accounted as casted + // we can skip channeled or delayed checks using flags + bool IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled = false, bool skipAutorepeat = false) const; + + // set withDelayed to true to interrupt delayed spells too + // delayed+channeled spells are always interrupted + void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0); + + Spell* FindCurrentSpellBySpellId(uint32 spell_id) const; + + Spell* m_currentSpells[CURRENT_MAX_SPELL]; + + uint32 m_addDmgOnce; + uint64 m_TotemSlot[MAX_TOTEM]; + uint64 m_ObjectSlot[4]; + uint32 m_detectInvisibilityMask; + uint32 m_invisibilityMask; + uint32 m_ShapeShiftFormSpellId; + ShapeshiftForm m_form; + float m_modMeleeHitChance; + float m_modRangedHitChance; + float m_modSpellHitChance; + int32 m_baseSpellCritChance; + + float m_threatModifier[MAX_SPELL_SCHOOL]; + float m_modAttackSpeedPct[3]; + + // Event handler + EventProcessor m_Events; + + // stat system + bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply); + void SetModifierValue(UnitMods unitMod, UnitModifierType modifierType, float value) { m_auraModifiersGroup[unitMod][modifierType] = value; } + float GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const; + float GetTotalStatValue(Stats stat) const; + float GetTotalAuraModValue(UnitMods unitMod) const; + SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const; + Stats GetStatByAuraGroup(UnitMods unitMod) const; + Powers GetPowerTypeByAuraGroup(UnitMods unitMod) const; + bool CanModifyStats() const { return m_canModifyStats; } + void SetCanModifyStats(bool modifyStats) { m_canModifyStats = modifyStats; } + virtual bool UpdateStats(Stats stat) = 0; + virtual bool UpdateAllStats() = 0; + virtual void UpdateResistances(uint32 school) = 0; + virtual void UpdateArmor() = 0; + virtual void UpdateMaxHealth() = 0; + virtual void UpdateMaxPower(Powers power) = 0; + virtual void UpdateAttackPowerAndDamage(bool ranged = false) = 0; + virtual void UpdateDamagePhysical(WeaponAttackType attType) = 0; + float GetTotalAttackPowerValue(WeaponAttackType attType) const; + float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const; + void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } + + bool isInFront(Unit const* target,float distance, float arc = M_PI) const; + void SetInFront(Unit const* target); + bool isInBack(Unit const* target, float distance, float arc = M_PI) const; + + // Visibility system + UnitVisibility GetVisibility() const { return m_Visibility; } + void SetVisibility(UnitVisibility x); + + // common function for visibility checks for player/creatures with detection code + bool isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList = false) const; + bool canDetectInvisibilityOf(Unit const* u) const; + + // virtual functions for all world objects types + bool isVisibleForInState(Player const* u, bool inVisibleList) const; + // function for low level grid visibility checks in player/creature cases + virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; + + bool waterbreath; + AuraList & GetSingleCastAuras() { return m_scAuras; } + AuraList const& GetSingleCastAuras() const { return m_scAuras; } + SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; + + // Threat related methodes + bool CanHaveThreatList() const; + void AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *threatSpell = NULL); + float ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL); + void DeleteThreatList(); + bool SelectHostilTarget(); + void TauntApply(Unit* pVictim); + void TauntFadeOut(Unit *taunter); + ThreatManager& getThreatManager() { return m_ThreatManager; } + void addHatedBy(HostilReference* pHostilReference) { m_HostilRefManager.insertFirst(pHostilReference); }; + void removeHatedBy(HostilReference* /*pHostilReference*/ ) { /* nothing to do yet */ } + HostilRefManager& getHostilRefManager() { return m_HostilRefManager; } + + Aura* GetAura(uint32 spellId, uint32 effindex); + AuraMap & GetAuras() { return m_Auras; } + AuraMap const& GetAuras() const { return m_Auras; } + AuraList const& GetAurasByType(AuraType type) const { return m_modAuras[type]; } + void ApplyAuraProcTriggerDamage(Aura* aura, bool apply); + + int32 GetTotalAuraModifier(AuraType auratype) const; + float GetTotalAuraMultiplier(AuraType auratype) const; + int32 GetMaxPositiveAuraModifier(AuraType auratype) const; + int32 GetMaxNegativeAuraModifier(AuraType auratype) const; + + int32 GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const; + float GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const; + int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const; + int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const; + + int32 GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const; + float GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const; + int32 GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const; + int32 GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const; + + Aura* GetDummyAura(uint32 spell_id) const; + + uint32 GetDisplayId() { return GetUInt32Value(UNIT_FIELD_DISPLAYID); } + void SetDisplayId(uint32 modelId); + uint32 GetNativeDisplayId() { return GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID); } + void SetNativeDisplayId(uint32 modelId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, modelId); } + void setTransForm(uint32 spellid) { m_transform = spellid;} + uint32 getTransForm() const { return m_transform;} + void AddDynObject(DynamicObject* dynObj); + void RemoveDynObject(uint32 spellid); + void RemoveDynObjectWithGUID(uint64 guid) { m_dynObjGUIDs.remove(guid); } + void RemoveAllDynObjects(); + void AddGameObject(GameObject* gameObj); + void RemoveGameObject(GameObject* gameObj, bool del); + void RemoveGameObject(uint32 spellid, bool del); + void RemoveAllGameObjects(); + DynamicObject *GetDynObject(uint32 spellId, uint32 effIndex); + DynamicObject *GetDynObject(uint32 spellId); + uint32 CalculateDamage(WeaponAttackType attType, bool normalized); + float GetAPMultiplier(WeaponAttackType attType, bool normalized); + void ModifyAuraState(AuraState flag, bool apply); + bool HasAuraState(AuraState flag) const { return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); } + void UnsummonAllTotems(); + int32 SpellBaseDamageBonus(SpellSchoolMask schoolMask); + int32 SpellBaseHealingBonus(SpellSchoolMask schoolMask); + int32 SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim); + int32 SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim); + uint32 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype); + uint32 SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim); + bool isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType); + uint32 SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim); + + void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; } + bool IsUnderLastManaUseEffect() const; + + void SetContestedPvP(Player *attackedPlayer = NULL); + + void MeleeDamageBonus(Unit *pVictim, uint32 *damage, WeaponAttackType attType, SpellEntry const *spellProto = NULL); + uint32 GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ); + + void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply); + void ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply); + virtual bool IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges = false); + // redefined in Creature + bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask, bool useCharges = false); + virtual bool IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const; + // redefined in Creature + + uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage); + void CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist); + + void UpdateSpeed(UnitMoveType mtype, bool forced); + float GetSpeed( UnitMoveType mtype ) const; + float GetSpeedRate( UnitMoveType mtype ) const { return m_speed_rate[mtype]; } + void SetSpeed(UnitMoveType mtype, float rate, bool forced = false); + + void SetHover(bool on); + bool isHover() const { return HasAuraType(SPELL_AURA_HOVER); } + + void _RemoveAllAuraMods(); + void _ApplyAllAuraMods(); + + int32 CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_index, int32 basePoints, Unit const* target); + int32 CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_index, Unit const* target); + float CalculateLevelPenalty(SpellEntry const* spellProto) const; + + void addFollower(FollowerReference* pRef) { m_FollowingRefManager.insertFirst(pRef); } + void removeFollower(FollowerReference* /*pRef*/ ) { /* nothing to do yet */ } + static Unit* GetUnit(WorldObject& object, uint64 guid); + + MotionMaster* GetMotionMaster() { return &i_motionMaster; } + + bool IsStopped() const { return !(hasUnitState(UNIT_STAT_MOVING)); } + void StopMoving(); + + void AddUnitMovementFlag(uint32 f) { m_unit_movement_flags |= f; } + void RemoveUnitMovementFlag(uint32 f) + { + uint32 oldval = m_unit_movement_flags; + m_unit_movement_flags = oldval & ~f; + } + uint32 HasUnitMovementFlag(uint32 f) const { return m_unit_movement_flags & f; } + uint32 GetUnitMovementFlags() const { return m_unit_movement_flags; } + void SetUnitMovementFlags(uint32 f) { m_unit_movement_flags = f; } + + void SetFeared(bool apply, uint64 casterGUID = 0, uint32 spellID = 0); + void SetConfused(bool apply, uint64 casterGUID = 0, uint32 spellID = 0); + + void AddComboPointHolder(uint32 lowguid) { m_ComboPointHolders.insert(lowguid); } + void RemoveComboPointHolder(uint32 lowguid) { m_ComboPointHolders.erase(lowguid); } + void ClearComboPointHolders(); + + ///----------Pet responses methods----------------- + void SendPetCastFail(uint32 spellid, uint8 msg); + void SendPetActionFeedback (uint8 msg); + void SendPetTalk (uint32 pettalk); + void SendPetSpellCooldown (uint32 spellid, time_t cooltime); + void SendPetClearCooldown (uint32 spellid); + void SendPetAIReaction(uint64 guid); + ///----------End of Pet responses methods---------- + + void propagateSpeedChange() { GetMotionMaster()->propagateSpeedChange(); } + + // reactive attacks + void ClearAllReactives(); + void StartReactiveTimer( ReactiveType reactive ) { m_reactiveTimer[reactive] = REACTIVE_TIMER_START;} + void UpdateReactives(uint32 p_time); + + // group updates + void UpdateAuraForGroup(uint8 slot); + + // pet auras + typedef std::set PetAuraSet; + PetAuraSet m_petAuras; + void AddPetAura(PetAura const* petSpell); + void RemovePetAura(PetAura const* petSpell); + + protected: + explicit Unit (); + + void _UpdateSpells(uint32 time); + + void _UpdateAutoRepeatSpell(); + bool m_AutoRepeatFirstCast; + + uint32 m_attackTimer[MAX_ATTACK]; + + float m_createStats[MAX_STATS]; + + AttackerSet m_attackers; + Unit* m_attacking; + + DeathState m_deathState; + + AuraMap m_Auras; + + std::list m_scAuras; // casted singlecast auras + + typedef std::list DynObjectGUIDs; + DynObjectGUIDs m_dynObjGUIDs; + + std::list m_gameObj; + bool m_isSorted; + uint32 m_transform; + uint32 m_removedAuras; + + AuraList m_modAuras[TOTAL_AURAS]; + float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END]; + float m_weaponDamage[MAX_ATTACK][2]; + bool m_canModifyStats; + //std::list< spellEffectPair > AuraSpells[TOTAL_AURAS]; // TODO: use this if ok for mem + + float m_speed_rate[MAX_MOVE_TYPE]; + + CharmInfo *m_charmInfo; + + virtual SpellSchoolMask GetMeleeDamageSchoolMask() const; + + MotionMaster i_motionMaster; + uint32 m_unit_movement_flags; + + uint32 m_reactiveTimer[MAX_REACTIVE]; + + private: + void SendAttackStop(Unit* victim); // only from AttackStop(Unit*) + void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*) + + void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask ); + bool HandleDummyAuraProc(Unit *pVictim, SpellEntry const *spellProto, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag,uint32 cooldown); + bool HandleProcTriggerSpell(Unit *pVictim,uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attType,uint32 cooldown); + bool HandleHasteAuraProc(Unit *pVictim, SpellEntry const *spellProto, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag,uint32 cooldown); + bool HandleOverrideClassScriptAuraProc(Unit *pVictim, int32 scriptId, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell,uint32 cooldown); + uint32 m_state; // Even derived shouldn't modify + uint32 m_CombatTimer; + uint32 m_lastManaUse; // msecs + + UnitVisibility m_Visibility; + + Diminishing m_Diminishing; + // Manage all Units threatening us + ThreatManager m_ThreatManager; + // Manage all Units that are threatened by us + HostilRefManager m_HostilRefManager; + + FollowerRefManager m_FollowingRefManager; + + ComboPointHolderSet m_ComboPointHolders; +}; +#endif diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp index 0389e2ebc4b..48f739fa6a1 100644 --- a/src/game/WaypointMovementGenerator.cpp +++ b/src/game/WaypointMovementGenerator.cpp @@ -1,648 +1,652 @@ -/* - * Copyright (C) 2005-2008 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 - */ - -/* -creature_movement Table - -alter table creature_movement add `text1` varchar(255) default NULL; -alter table creature_movement add `text2` varchar(255) default NULL; -alter table creature_movement add `text3` varchar(255) default NULL; -alter table creature_movement add `text4` varchar(255) default NULL; -alter table creature_movement add `text5` varchar(255) default NULL; -alter table creature_movement add `emote` int(10) unsigned default '0'; -alter table creature_movement add `spell` int(5) unsigned default '0'; -alter table creature_movement add `wpguid` int(11) default '0'; - -*/ - -#include - -#include "WaypointMovementGenerator.h" -#include "ObjectMgr.h" -#include "Creature.h" -#include "DestinationHolderImp.h" -#include "CreatureAI.h" -#include "WaypointManager.h" - -#include - -//-----------------------------------------------// -void -WaypointMovementGenerator::LoadPath(Creature &c) -{ - sLog.outDetail("LoadPath: loading waypoint path for creature %d,%d", c.GetGUIDLow(), c.GetDBTableGUIDLow()); - - i_path = WaypointMgr.GetPath(c.GetDBTableGUIDLow()); - if(!i_path) - { - sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s(%d) doesn't have waypoint path", c.GetName(), c.GetDBTableGUIDLow()); - return; - } - - uint32 node_count = i_path->size(); - i_hasDone.resize(node_count); - for(uint32 i = 0; i < node_count-1; i++) - i_hasDone[i] = false; - - // to prevent a misbehaviour inside "update" - // update is always called with the next wp - but the wpSys needs the current - // so when the routine is called the first time, wpSys gets the last waypoint - // and this prevents the system from performing text/emote, etc - i_hasDone[node_count - 1] = true; -} - -void -WaypointMovementGenerator::ClearWaypoints() -{ - i_path = NULL; -} - -void -WaypointMovementGenerator::Initialize() -{ -} - -bool -WaypointMovementGenerator::Update(Creature &creature, const uint32 &diff) -{ - if(!&creature) - return true; - - // Waypoint movement can be switched on/off - // This is quite handy for escort quests and other stuff - if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED)) - return true; - - // prevent a crash at empty waypoint path. - if(!i_path || i_path->empty()) - return true; - - // i_path was modified by chat commands for example - if(i_path->size() != i_hasDone.size()) - i_hasDone.resize(i_path->size()); - if(i_currentNode >= i_path->size()) - i_currentNode = 0; - - CreatureTraveller traveller(creature); - - i_nextMoveTime.Update(diff); - i_destinationHolder.UpdateTraveller(traveller, diff, false, true); - - // creature has been stoped in middle of the waypoint segment - if (!i_destinationHolder.HasArrived() && creature.IsStopped()) - { - if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it - { - SetStopedByPlayer(false); - // Now we re-set destination to same node and start travel - creature.addUnitState(UNIT_STAT_ROAMING); - const WaypointNode &node = i_path->at(i_currentNode); - i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - } - else // if( !i_nextMoveTime.Passed()) - { // unexpected end of timer && creature stopped && not at end of segment - if (!IsStopedByPlayer()) - { // Put 30 seconds delay - i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); - i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); - SetStopedByPlayer(true); // Mark we did it - } - } - return true; // Abort here this update - } - - if( creature.IsStopped()) - { - uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; - - if (!i_hasDone[idx]) - { - if (i_path->at(idx).orientation !=100) - creature.SetOrientation(i_path->at(idx).orientation); - - if(WaypointBehavior *behavior = i_path->at(idx).behavior) - { - if(behavior->emote != 0) - creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote); - if(behavior->spell != 0) - creature.CastSpell(&creature,behavior->spell, false); - if(behavior->model1 != 0) - creature.SetDisplayId(behavior->model1); - if(!behavior->text[0].empty()) - { - // Only one text is set - if( !behavior->text[1].empty() ) - { - // Select one from max 5 texts (0 and 1 laready checked) - int i = 2; - for( ; i < 5; ++i ) - if( behavior->text[i].empty() ) - break; - - creature.Say(behavior->text[rand() % i].c_str(), 0, 0); - - } - else - creature.Say(behavior->text[0].c_str(), 0, 0); - } - - i_hasDone[idx] = true; - MovementInform(creature); - } // wpBehaviour found - } // HasDone == false - } // i_creature.IsStopped() - - if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player - { - if( creature.IsStopped() ) // If stopped then begin a new move segment - { - creature.addUnitState(UNIT_STAT_ROAMING); - const WaypointNode &node = i_path->at(i_currentNode); - i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; - - if (i_path->at(idx).orientation !=100) - creature.SetOrientation(i_path->at(idx).orientation); - - if(WaypointBehavior *behavior = i_path->at(idx).behavior ) - { - i_hasDone[idx] = false; - if(behavior->model2 != 0) - creature.SetDisplayId(behavior->model2); - - creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); - } - } - else // If not stopped then stop it and set the reset of TimeTracker to waittime - { - creature.StopMoving(); - SetStopedByPlayer(false); - i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); - ++i_currentNode; - if( i_currentNode >= i_path->size() ) - i_currentNode = 0; - } - } - return true; -} - -void WaypointMovementGenerator::MovementInform(Creature &unit) -{ - if(unit.AI()) - unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); -} - -//----------------------------------------------------// -void -FlightPathMovementGenerator::LoadPath(Player &) -{ - objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds); -} - -uint32 -FlightPathMovementGenerator::GetPathAtMapEnd() const -{ - if(i_currentNode >= i_mapIds.size()) - return i_mapIds.size(); - - uint32 curMapId = i_mapIds[i_currentNode]; - for(uint32 i = i_currentNode; i < i_mapIds.size(); ++i) - { - if(i_mapIds[i] != curMapId) - return i; - } - - return i_mapIds.size(); -} - -void -FlightPathMovementGenerator::Initialize(Player &player) -{ - player.getHostilRefManager().setOnlineOfflineState(false); - player.addUnitState(UNIT_STAT_IN_FLIGHT); - player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); - LoadPath(player); - Traveller traveller(player); - // do not send movement, it was sent already - i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false); - - player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(),MOVEMENTFLAG_WALK_MODE|MOVEMENTFLAG_ONTRANSPORT); -} - -void FlightPathMovementGenerator::Finalize(Player & player) -{ - - float x, y, z; - i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z); - player.SetPosition(x, y, z, player.GetOrientation()); - - player.clearUnitState(UNIT_STAT_IN_FLIGHT); - player.Unmount(); - player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); - - if(player.m_taxi.empty()) - { - player.getHostilRefManager().setOnlineOfflineState(true); - if(player.pvpInfo.inHostileArea) - player.CastSpell(&player, 2479, true); - - player.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); - player.StopMoving(); - } -} - -bool -FlightPathMovementGenerator::Update(Player &player, const uint32 &diff) -{ - if( MovementInProgress() ) - { - Traveller traveller(player); - if( i_destinationHolder.UpdateTraveller(traveller, diff, false) ) - { - i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE); - if( i_destinationHolder.HasArrived() ) - { - uint32 curMap = i_mapIds[i_currentNode]; - ++i_currentNode; - if( MovementInProgress() ) - { - DEBUG_LOG("loading node %u for player %s", i_currentNode, player.GetName()); - if(i_mapIds[i_currentNode]==curMap) - { - // do not send movement, it was sent already - i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false); - } - return true; - } - //else HasArrived() - } - else - return true; - } - else - return true; - } - - // we have arrived at the end of the path - return false; -} - -void -FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() -{ - if(i_mapIds.empty()) - return; - - uint32 map0 = i_mapIds[0]; - for(int i = 1; i < i_mapIds.size(); ++i) - { - if(i_mapIds[i]!=map0) - { - i_currentNode = i; - return; - } - } -} - -// -// Unique1's ASTAR Pathfinding Code... For future use & reference... -// - -#ifdef __PATHFINDING__ - -int GetFCost(int to, int num, int parentNum, float *gcost); // Below... - -int ShortenASTARRoute(short int *pathlist, int number) -{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1 - short int temppathlist[MAX_PATHLIST_NODES]; - int count = 0; - // int count2 = 0; - int temp, temp2; - int link; - int upto = 0; - - for (temp = number; temp >= 0; temp--) - { - qboolean shortened = qfalse; - - for (temp2 = 0; temp2 < temp; temp2++) - { - for (link = 0; link < nodes[pathlist[temp]].enodenum; link++) - { - if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED) - continue; - - //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it - // continue; - - //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32) - // continue; - - if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2]) - { // Found a shorter route... - //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1)) - { - temppathlist[count] = pathlist[temp2]; - temp = temp2; - ++count; - shortened = qtrue; - } - } - } - } - - if (!shortened) - { - temppathlist[count] = pathlist[temp]; - ++count; - } - } - - upto = count; - - for (temp = 0; temp < count; temp++) - { - pathlist[temp] = temppathlist[upto]; - --upto; - } - - G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count); - return count; -} - -/* -=========================================================================== -CreatePathAStar -This function uses the A* pathfinding algorithm to determine the -shortest path between any two nodes. -It's fairly complex, so I'm not really going to explain it much. -Look up A* and binary heaps for more info. -pathlist stores the ideal path between the nodes, in reverse order, -and the return value is the number of nodes in that path -=========================================================================== -*/ -int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist) -{ - //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES - //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it - short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index - float gcost[MAX_NODES]; - int fcost[MAX_NODES]; - char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type - short int parent[MAX_NODES]; - - short int numOpen = 0; - short int atNode, temp, newnode=-1; - qboolean found = qfalse; - int count = -1; - float gc; - int i, u, v, m; - vec3_t vec; - - //clear out all the arrays - memset(openlist, 0, sizeof(short int)*(MAX_NODES+1)); - memset(fcost, 0, sizeof(int)*MAX_NODES); - memset(list, 0, sizeof(char)*MAX_NODES); - memset(parent, 0, sizeof(short int)*MAX_NODES); - memset(gcost, -1, sizeof(float)*MAX_NODES); - - //make sure we have valid data before calculating everything - if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to)) - return -1; - - openlist[1] = from; //add the starting node to the open list - ++numOpen; - gcost[from] = 0; //its f and g costs are obviously 0 - fcost[from] = 0; - - while (1) - { - if (numOpen != 0) //if there are still items in the open list - { - //pop the top item off of the list - atNode = openlist[1]; - list[atNode] = 2; //put the node on the closed list so we don't check it again - --numOpen; - - openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position - v = 1; - - //this while loop reorders the list so that the new lowest fcost is at the top again - while (1) - { - u = v; - if ((2*u+1) < numOpen) //if both children exist - { - if (fcost[openlist[u]] >= fcost[openlist[2*u]]) - v = 2*u; - if (fcost[openlist[v]] >= fcost[openlist[2*u+1]]) - v = 2*u+1; - } - else - { - if ((2*u) < numOpen) //if only one child exists - { - if (fcost[openlist[u]] >= fcost[openlist[2*u]]) - v = 2*u; - } - } - - if (u != v) //if they're out of order, swap this item with its parent - { - temp = openlist[u]; - openlist[u] = openlist[v]; - openlist[v] = temp; - } - else - break; - } - - for (i = 0; i < nodes[atNode].enodenum; i++) //loop through all the links for this node - { - newnode = nodes[atNode].links[i].targetNode; - - //if this path is blocked, skip it - if (nodes[atNode].links[i].flags & PATH_BLOCKED) - continue; - //if this path is blocked, skip it - if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS) - continue; - //skip any unreachable nodes - if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES)) - continue; - if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS)) - continue; - - if (list[newnode] == 2) //if this node is on the closed list, skip it - continue; - - if (list[newnode] != 1) //if this node is not already on the open list - { - openlist[++numOpen] = newnode; //add the new node to the open list - list[newnode] = 1; - parent[newnode] = atNode; //record the node's parent - - if (newnode == to) //if we've found the goal, don't keep computing paths! - break; //this will break the 'for' and go all the way to 'if (list[to] == 1)' - - //store it's f cost value - fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost); - - //this loop re-orders the heap so that the lowest fcost is at the top - m = numOpen; - while (m != 1) //while this item isn't at the top of the heap already - { - //if it has a lower fcost than its parent - if (fcost[openlist[m]] <= fcost[openlist[m/2]]) - { - temp = openlist[m/2]; - openlist[m/2] = openlist[m]; - openlist[m] = temp; //swap them - m /= 2; - } - else - break; - } - } - else //if this node is already on the open list - { - gc = gcost[atNode]; - VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec); - gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path - - if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before) - { - parent[newnode] = atNode; //set the new parent for this node - gcost[newnode] = gc; //and the new g cost - - for (i = 1; i < numOpen; i++) //loop through all the items on the open list - { - if (openlist[i] == newnode) //find this node in the list - { - //calculate the new fcost and store it - fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost); - - //reorder the list again, with the lowest fcost item on top - m = i; - while (m != 1) - { - //if the item has a lower fcost than it's parent - if (fcost[openlist[m]] < fcost[openlist[m/2]]) - { - temp = openlist[m/2]; - openlist[m/2] = openlist[m]; - openlist[m] = temp; //swap them - m /= 2; - } - else - break; - } - break; //exit the 'for' loop because we already changed this node - } //if - } //for - } //if (gc < gcost[newnode]) - } //if (list[newnode] != 1) --> else - } //for (loop through links) - } //if (numOpen != 0) - else - { - found = qfalse; //there is no path between these nodes - break; - } - - if (list[to] == 1) //if the destination node is on the open list, we're done - { - found = qtrue; - break; - } - } //while (1) - - if (found == qtrue) //if we found a path - { - //G_Printf("%s - path found!n", bot->client->pers.netname); - count = 0; - - temp = to; //start at the end point - while (temp != from) //travel along the path (backwards) until we reach the starting point - { - pathlist[count++] = temp; //add the node to the pathlist and increment the count - temp = parent[temp]; //move to the parent of this node to continue the path - } - - pathlist[count++] = from; //add the beginning node to the end of the pathlist - - #ifdef __BOT_SHORTEN_ROUTING__ - count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1 - #endif //__BOT_SHORTEN_ROUTING__ - } - else - { - //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to); - count = CreateDumbRoute(from, to, pathlist); - - if (count > 0) - { - #ifdef __BOT_SHORTEN_ROUTING__ - count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1 - #endif //__BOT_SHORTEN_ROUTING__ - return count; - } - } - - return count; //return the number of nodes in the path, -1 if not found -} - -/* -=========================================================================== -GetFCost -Utility function used by A* pathfinding to calculate the -cost to move between nodes towards a goal. Using the A* -algorithm F = G + H, G here is the distance along the node -paths the bot must travel, and H is the straight-line distance -to the goal node. -Returned as an int because more precision is unnecessary and it -will slightly speed up heap access -=========================================================================== -*/ -int GetFCost(int to, int num, int parentNum, float *gcost) -{ - float gc = 0; - float hc = 0; - vec3_t v; - - if (gcost[num] == -1) - { - if (parentNum != -1) - { - gc = gcost[parentNum]; - VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v); - gc += VectorLength(v); - } - gcost[num] = gc; - } - else - gc = gcost[num]; - - VectorSubtract(nodes[to].origin, nodes[num].origin, v); - hc = VectorLength(v); - - return (int)(gc + hc); -} -#endif //__PATHFINDING__ +/* + * Copyright (C) 2005-2008 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 + */ + +/* +creature_movement Table + +alter table creature_movement add `text1` varchar(255) default NULL; +alter table creature_movement add `text2` varchar(255) default NULL; +alter table creature_movement add `text3` varchar(255) default NULL; +alter table creature_movement add `text4` varchar(255) default NULL; +alter table creature_movement add `text5` varchar(255) default NULL; +alter table creature_movement add `emote` int(10) unsigned default '0'; +alter table creature_movement add `spell` int(5) unsigned default '0'; +alter table creature_movement add `wpguid` int(11) default '0'; + +*/ + +#include + +#include "WaypointMovementGenerator.h" +#include "ObjectMgr.h" +#include "Creature.h" +#include "DestinationHolderImp.h" +#include "CreatureAI.h" +#include "WaypointManager.h" + +#include + +//-----------------------------------------------// +void +WaypointMovementGenerator::LoadPath(Creature &c) +{ + sLog.outDetail("LoadPath: loading waypoint path for creature %d,%d", c.GetGUIDLow(), c.GetDBTableGUIDLow()); + + i_path = WaypointMgr.GetPath(c.GetDBTableGUIDLow()); + if(!i_path) + { + sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s(%d) doesn't have waypoint path", c.GetName(), c.GetDBTableGUIDLow()); + return; + } + + uint32 node_count = i_path->size(); + i_hasDone.resize(node_count); + for(uint32 i = 0; i < node_count-1; i++) + i_hasDone[i] = false; + + // to prevent a misbehaviour inside "update" + // update is always called with the next wp - but the wpSys needs the current + // so when the routine is called the first time, wpSys gets the last waypoint + // and this prevents the system from performing text/emote, etc + i_hasDone[node_count - 1] = true; +} + +void +WaypointMovementGenerator::ClearWaypoints() +{ + i_path = NULL; +} + +void +WaypointMovementGenerator::Initialize() +{ +} + +bool +WaypointMovementGenerator::Update(Creature &creature, const uint32 &diff) +{ + if(!&creature) + return true; + + // Waypoint movement can be switched on/off + // This is quite handy for escort quests and other stuff + if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED)) + return true; + + // prevent a crash at empty waypoint path. + if(!i_path || i_path->empty()) + return true; + + // i_path was modified by chat commands for example + if(i_path->size() != i_hasDone.size()) + i_hasDone.resize(i_path->size()); + if(i_currentNode >= i_path->size()) + i_currentNode = 0; + + CreatureTraveller traveller(creature); + + i_nextMoveTime.Update(diff); + i_destinationHolder.UpdateTraveller(traveller, diff, false, true); + + // creature has been stoped in middle of the waypoint segment + if (!i_destinationHolder.HasArrived() && creature.IsStopped()) + { + if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it + { + SetStopedByPlayer(false); + // Now we re-set destination to same node and start travel + creature.addUnitState(UNIT_STAT_ROAMING); + if (creature.canFly()) + creature.SetUnitMovementFlags(MOVEMENTFLAG_FLYING2); + const WaypointNode &node = i_path->at(i_currentNode); + i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); + i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); + } + else // if( !i_nextMoveTime.Passed()) + { // unexpected end of timer && creature stopped && not at end of segment + if (!IsStopedByPlayer()) + { // Put 30 seconds delay + i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); + i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); + SetStopedByPlayer(true); // Mark we did it + } + } + return true; // Abort here this update + } + + if( creature.IsStopped()) + { + uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; + + if (!i_hasDone[idx]) + { + if (i_path->at(idx).orientation !=100) + creature.SetOrientation(i_path->at(idx).orientation); + + if(WaypointBehavior *behavior = i_path->at(idx).behavior) + { + if(behavior->emote != 0) + creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote); + if(behavior->spell != 0) + creature.CastSpell(&creature,behavior->spell, false); + if(behavior->model1 != 0) + creature.SetDisplayId(behavior->model1); + if(!behavior->text[0].empty()) + { + // Only one text is set + if( !behavior->text[1].empty() ) + { + // Select one from max 5 texts (0 and 1 laready checked) + int i = 2; + for( ; i < 5; ++i ) + if( behavior->text[i].empty() ) + break; + + creature.Say(behavior->text[rand() % i].c_str(), 0, 0); + + } + else + creature.Say(behavior->text[0].c_str(), 0, 0); + } + + i_hasDone[idx] = true; + MovementInform(creature); + } // wpBehaviour found + } // HasDone == false + } // i_creature.IsStopped() + + if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player + { + if( creature.IsStopped() ) // If stopped then begin a new move segment + { + creature.addUnitState(UNIT_STAT_ROAMING); + if (creature.canFly()) + creature.SetUnitMovementFlags(MOVEMENTFLAG_FLYING2); + const WaypointNode &node = i_path->at(i_currentNode); + i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); + i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); + uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; + + if (i_path->at(idx).orientation !=100) + creature.SetOrientation(i_path->at(idx).orientation); + + if(WaypointBehavior *behavior = i_path->at(idx).behavior ) + { + i_hasDone[idx] = false; + if(behavior->model2 != 0) + creature.SetDisplayId(behavior->model2); + + creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); + } + } + else // If not stopped then stop it and set the reset of TimeTracker to waittime + { + creature.StopMoving(); + SetStopedByPlayer(false); + i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); + ++i_currentNode; + if( i_currentNode >= i_path->size() ) + i_currentNode = 0; + } + } + return true; +} + +void WaypointMovementGenerator::MovementInform(Creature &unit) +{ + if(unit.AI()) + unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); +} + +//----------------------------------------------------// +void +FlightPathMovementGenerator::LoadPath(Player &) +{ + objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds); +} + +uint32 +FlightPathMovementGenerator::GetPathAtMapEnd() const +{ + if(i_currentNode >= i_mapIds.size()) + return i_mapIds.size(); + + uint32 curMapId = i_mapIds[i_currentNode]; + for(uint32 i = i_currentNode; i < i_mapIds.size(); ++i) + { + if(i_mapIds[i] != curMapId) + return i; + } + + return i_mapIds.size(); +} + +void +FlightPathMovementGenerator::Initialize(Player &player) +{ + player.getHostilRefManager().setOnlineOfflineState(false); + player.addUnitState(UNIT_STAT_IN_FLIGHT); + player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + LoadPath(player); + Traveller traveller(player); + // do not send movement, it was sent already + i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false); + + player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(),MOVEMENTFLAG_WALK_MODE|MOVEMENTFLAG_ONTRANSPORT); +} + +void FlightPathMovementGenerator::Finalize(Player & player) +{ + + float x, y, z; + i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z); + player.SetPosition(x, y, z, player.GetOrientation()); + + player.clearUnitState(UNIT_STAT_IN_FLIGHT); + player.Unmount(); + player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + + if(player.m_taxi.empty()) + { + player.getHostilRefManager().setOnlineOfflineState(true); + if(player.pvpInfo.inHostileArea) + player.CastSpell(&player, 2479, true); + + player.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); + player.StopMoving(); + } +} + +bool +FlightPathMovementGenerator::Update(Player &player, const uint32 &diff) +{ + if( MovementInProgress() ) + { + Traveller traveller(player); + if( i_destinationHolder.UpdateTraveller(traveller, diff, false) ) + { + i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE); + if( i_destinationHolder.HasArrived() ) + { + uint32 curMap = i_mapIds[i_currentNode]; + ++i_currentNode; + if( MovementInProgress() ) + { + DEBUG_LOG("loading node %u for player %s", i_currentNode, player.GetName()); + if(i_mapIds[i_currentNode]==curMap) + { + // do not send movement, it was sent already + i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false); + } + return true; + } + //else HasArrived() + } + else + return true; + } + else + return true; + } + + // we have arrived at the end of the path + return false; +} + +void +FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() +{ + if(i_mapIds.empty()) + return; + + uint32 map0 = i_mapIds[0]; + for(int i = 1; i < i_mapIds.size(); ++i) + { + if(i_mapIds[i]!=map0) + { + i_currentNode = i; + return; + } + } +} + +// +// Unique1's ASTAR Pathfinding Code... For future use & reference... +// + +#ifdef __PATHFINDING__ + +int GetFCost(int to, int num, int parentNum, float *gcost); // Below... + +int ShortenASTARRoute(short int *pathlist, int number) +{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1 + short int temppathlist[MAX_PATHLIST_NODES]; + int count = 0; + // int count2 = 0; + int temp, temp2; + int link; + int upto = 0; + + for (temp = number; temp >= 0; temp--) + { + qboolean shortened = qfalse; + + for (temp2 = 0; temp2 < temp; temp2++) + { + for (link = 0; link < nodes[pathlist[temp]].enodenum; link++) + { + if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED) + continue; + + //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it + // continue; + + //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32) + // continue; + + if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2]) + { // Found a shorter route... + //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1)) + { + temppathlist[count] = pathlist[temp2]; + temp = temp2; + ++count; + shortened = qtrue; + } + } + } + } + + if (!shortened) + { + temppathlist[count] = pathlist[temp]; + ++count; + } + } + + upto = count; + + for (temp = 0; temp < count; temp++) + { + pathlist[temp] = temppathlist[upto]; + --upto; + } + + G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count); + return count; +} + +/* +=========================================================================== +CreatePathAStar +This function uses the A* pathfinding algorithm to determine the +shortest path between any two nodes. +It's fairly complex, so I'm not really going to explain it much. +Look up A* and binary heaps for more info. +pathlist stores the ideal path between the nodes, in reverse order, +and the return value is the number of nodes in that path +=========================================================================== +*/ +int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist) +{ + //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES + //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it + short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index + float gcost[MAX_NODES]; + int fcost[MAX_NODES]; + char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type + short int parent[MAX_NODES]; + + short int numOpen = 0; + short int atNode, temp, newnode=-1; + qboolean found = qfalse; + int count = -1; + float gc; + int i, u, v, m; + vec3_t vec; + + //clear out all the arrays + memset(openlist, 0, sizeof(short int)*(MAX_NODES+1)); + memset(fcost, 0, sizeof(int)*MAX_NODES); + memset(list, 0, sizeof(char)*MAX_NODES); + memset(parent, 0, sizeof(short int)*MAX_NODES); + memset(gcost, -1, sizeof(float)*MAX_NODES); + + //make sure we have valid data before calculating everything + if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to)) + return -1; + + openlist[1] = from; //add the starting node to the open list + ++numOpen; + gcost[from] = 0; //its f and g costs are obviously 0 + fcost[from] = 0; + + while (1) + { + if (numOpen != 0) //if there are still items in the open list + { + //pop the top item off of the list + atNode = openlist[1]; + list[atNode] = 2; //put the node on the closed list so we don't check it again + --numOpen; + + openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position + v = 1; + + //this while loop reorders the list so that the new lowest fcost is at the top again + while (1) + { + u = v; + if ((2*u+1) < numOpen) //if both children exist + { + if (fcost[openlist[u]] >= fcost[openlist[2*u]]) + v = 2*u; + if (fcost[openlist[v]] >= fcost[openlist[2*u+1]]) + v = 2*u+1; + } + else + { + if ((2*u) < numOpen) //if only one child exists + { + if (fcost[openlist[u]] >= fcost[openlist[2*u]]) + v = 2*u; + } + } + + if (u != v) //if they're out of order, swap this item with its parent + { + temp = openlist[u]; + openlist[u] = openlist[v]; + openlist[v] = temp; + } + else + break; + } + + for (i = 0; i < nodes[atNode].enodenum; i++) //loop through all the links for this node + { + newnode = nodes[atNode].links[i].targetNode; + + //if this path is blocked, skip it + if (nodes[atNode].links[i].flags & PATH_BLOCKED) + continue; + //if this path is blocked, skip it + if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS) + continue; + //skip any unreachable nodes + if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES)) + continue; + if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS)) + continue; + + if (list[newnode] == 2) //if this node is on the closed list, skip it + continue; + + if (list[newnode] != 1) //if this node is not already on the open list + { + openlist[++numOpen] = newnode; //add the new node to the open list + list[newnode] = 1; + parent[newnode] = atNode; //record the node's parent + + if (newnode == to) //if we've found the goal, don't keep computing paths! + break; //this will break the 'for' and go all the way to 'if (list[to] == 1)' + + //store it's f cost value + fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost); + + //this loop re-orders the heap so that the lowest fcost is at the top + m = numOpen; + while (m != 1) //while this item isn't at the top of the heap already + { + //if it has a lower fcost than its parent + if (fcost[openlist[m]] <= fcost[openlist[m/2]]) + { + temp = openlist[m/2]; + openlist[m/2] = openlist[m]; + openlist[m] = temp; //swap them + m /= 2; + } + else + break; + } + } + else //if this node is already on the open list + { + gc = gcost[atNode]; + VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec); + gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path + + if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before) + { + parent[newnode] = atNode; //set the new parent for this node + gcost[newnode] = gc; //and the new g cost + + for (i = 1; i < numOpen; i++) //loop through all the items on the open list + { + if (openlist[i] == newnode) //find this node in the list + { + //calculate the new fcost and store it + fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost); + + //reorder the list again, with the lowest fcost item on top + m = i; + while (m != 1) + { + //if the item has a lower fcost than it's parent + if (fcost[openlist[m]] < fcost[openlist[m/2]]) + { + temp = openlist[m/2]; + openlist[m/2] = openlist[m]; + openlist[m] = temp; //swap them + m /= 2; + } + else + break; + } + break; //exit the 'for' loop because we already changed this node + } //if + } //for + } //if (gc < gcost[newnode]) + } //if (list[newnode] != 1) --> else + } //for (loop through links) + } //if (numOpen != 0) + else + { + found = qfalse; //there is no path between these nodes + break; + } + + if (list[to] == 1) //if the destination node is on the open list, we're done + { + found = qtrue; + break; + } + } //while (1) + + if (found == qtrue) //if we found a path + { + //G_Printf("%s - path found!n", bot->client->pers.netname); + count = 0; + + temp = to; //start at the end point + while (temp != from) //travel along the path (backwards) until we reach the starting point + { + pathlist[count++] = temp; //add the node to the pathlist and increment the count + temp = parent[temp]; //move to the parent of this node to continue the path + } + + pathlist[count++] = from; //add the beginning node to the end of the pathlist + + #ifdef __BOT_SHORTEN_ROUTING__ + count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1 + #endif //__BOT_SHORTEN_ROUTING__ + } + else + { + //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to); + count = CreateDumbRoute(from, to, pathlist); + + if (count > 0) + { + #ifdef __BOT_SHORTEN_ROUTING__ + count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1 + #endif //__BOT_SHORTEN_ROUTING__ + return count; + } + } + + return count; //return the number of nodes in the path, -1 if not found +} + +/* +=========================================================================== +GetFCost +Utility function used by A* pathfinding to calculate the +cost to move between nodes towards a goal. Using the A* +algorithm F = G + H, G here is the distance along the node +paths the bot must travel, and H is the straight-line distance +to the goal node. +Returned as an int because more precision is unnecessary and it +will slightly speed up heap access +=========================================================================== +*/ +int GetFCost(int to, int num, int parentNum, float *gcost) +{ + float gc = 0; + float hc = 0; + vec3_t v; + + if (gcost[num] == -1) + { + if (parentNum != -1) + { + gc = gcost[parentNum]; + VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v); + gc += VectorLength(v); + } + gcost[num] = gc; + } + else + gc = gcost[num]; + + VectorSubtract(nodes[to].origin, nodes[num].origin, v); + hc = VectorLength(v); + + return (int)(gc + hc); +} +#endif //__PATHFINDING__ diff --git a/src/game/World.cpp b/src/game/World.cpp index 8546778ae21..b3929fa73a9 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1,2460 +1,2546 @@ -/* - * Copyright (C) 2005-2008 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 - */ - -/** \file - \ingroup world -*/ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "Config/ConfigEnv.h" -#include "SystemConfig.h" -#include "Log.h" -#include "Opcodes.h" -#include "WorldSession.h" -#include "WorldPacket.h" -#include "Weather.h" -#include "Player.h" -#include "SkillExtraItems.h" -#include "SkillDiscovery.h" -#include "World.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Chat.h" -#include "Database/DBCStores.h" -#include "LootMgr.h" -#include "ItemEnchantmentMgr.h" -#include "MapManager.h" -#include "ScriptCalls.h" -#include "CreatureAIRegistry.h" -#include "Policies/SingletonImp.h" -#include "BattleGroundMgr.h" -#include "TemporarySummon.h" -#include "WaypointMovementGenerator.h" -#include "VMapFactory.h" -#include "GlobalEvents.h" -#include "GameEvent.h" -#include "Database/DatabaseImpl.h" -#include "WorldSocket.h" -#include "GridNotifiersImpl.h" -#include "CellImpl.h" -#include "InstanceSaveMgr.h" -#include "WaypointManager.h" -#include "Util.h" - -INSTANTIATE_SINGLETON_1( World ); - -volatile bool World::m_stopEvent = false; -volatile uint32 World::m_worldLoopCounter = 0; - -float World::m_MaxVisibleDistanceForCreature = DEFAULT_VISIBILITY_DISTANCE; -float World::m_MaxVisibleDistanceForPlayer = DEFAULT_VISIBILITY_DISTANCE; -float World::m_MaxVisibleDistanceForObject = DEFAULT_VISIBILITY_DISTANCE; -float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE; -float World::m_VisibleUnitGreyDistance = 0; -float World::m_VisibleObjectGreyDistance = 0; - -// ServerMessages.dbc -enum ServerMessageType -{ - SERVER_MSG_SHUTDOWN_TIME = 1, - SERVER_MSG_RESTART_TIME = 2, - SERVER_MSG_STRING = 3, - SERVER_MSG_SHUTDOWN_CANCELLED = 4, - SERVER_MSG_RESTART_CANCELLED = 5 -}; - -struct ScriptAction -{ - uint64 sourceGUID; - uint64 targetGUID; - uint64 ownerGUID; // owner of source if source is item - ScriptInfo const* script; // pointer to static script data -}; - -/// World constructor -World::World() -{ - m_playerLimit = 0; - m_allowMovement = true; - m_ShutdownMask = 0; - m_ShutdownTimer = 0; - m_gameTime=time(NULL); - m_startTime=m_gameTime; - m_maxActiveSessionCount = 0; - m_maxQueuedSessionCount = 0; - m_resultQueue = NULL; - m_NextDailyQuestReset = 0; - - m_defaultDbcLocale = LOCALE_enUS; - m_availableDbcLocaleMask = 0; -} - -/// World destructor -World::~World() -{ - ///- Empty the kicked session set - for (std::set::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr) - delete *itr; - - m_kicked_sessions.clear(); - - ///- Empty the WeatherMap - for (WeatherMap::iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr) - delete itr->second; - - m_weathers.clear(); - - VMAP::VMapFactory::clear(); - - if(m_resultQueue) delete m_resultQueue; -} - -/// Find a player in a specified zone -Player* World::FindPlayerInZone(uint32 zone) -{ - ///- circle through active sessions and return the first player found in the zone - SessionMap::iterator itr; - for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) - { - if(!itr->second) - continue; - Player *player = itr->second->GetPlayer(); - if(!player) - continue; - if( player->IsInWorld() && player->GetZoneId() == zone ) - { - // Used by the weather system. We return the player to broadcast the change weather message to him and all players in the zone. - return player; - } - } - return NULL; -} - -/// Find a session by its id -WorldSession* World::FindSession(uint32 id) const -{ - SessionMap::const_iterator itr = m_sessions.find(id); - - if(itr != m_sessions.end()) - return itr->second; // also can return NULL for kicked session - else - return NULL; -} - -/// Remove a given session -bool World::RemoveSession(uint32 id) -{ - ///- Find the session, kick the user, but we can't delete session at this moment to prevent iterator invalidation - SessionMap::iterator itr = m_sessions.find(id); - - if(itr != m_sessions.end() && itr->second) - { - if (itr->second->PlayerLoading()) - return false; - itr->second->KickPlayer(); - } - - return true; -} - -/// Add a session to the session list -void World::AddSession(WorldSession* s) -{ - ASSERT(s); - - WorldSession* old = m_sessions[s->GetAccountId()]; - m_sessions[s->GetAccountId()] = s; - - // if session already exist, prepare to it deleting at next world update - if(old) - m_kicked_sessions.insert(old); -} - -int32 World::GetQueuePos(WorldSocket* socket) -{ - uint32 position = 1; - - for(Queue::iterator iter = m_QueuedPlayer.begin(); iter != m_QueuedPlayer.end(); ++iter, ++position) - if((*iter) == socket) - return position; - - return 0; -} - -void World::AddQueuedPlayer(WorldSocket* socket) -{ - m_QueuedPlayer.push_back(socket); -} - -void World::RemoveQueuedPlayer(WorldSocket* socket) -{ - // sessions count including queued to remove (if removed_session set) - uint32 sessions = GetActiveSessionCount(); - - uint32 position = 1; - Queue::iterator iter = m_QueuedPlayer.begin(); - - // if session not queued then we need decrease sessions count (Remove socked callet before session removing from session list) - bool decrease_session = true; - - // search socket to remove and count skipped positions - for(;iter != m_QueuedPlayer.end(); ++iter, ++position) - { - if(*iter==socket) - { - Queue::iterator iter2 = iter; - ++iter; - m_QueuedPlayer.erase(iter2); - decrease_session = false; // removing queued session - break; - } - } - - // iter point to next socked after removed or end() - // position store position of removed socket and then new position next socket after removed - - // decrease for case session queued for removing - if(decrease_session && sessions) - --sessions; - - // accept first in queue - if( (!m_playerLimit || sessions < m_playerLimit) && !m_QueuedPlayer.empty() ) - { - WorldSocket * socket = m_QueuedPlayer.front(); - socket->SendAuthWaitQue(0); - m_QueuedPlayer.pop_front(); - - // update iter to point first queued socket or end() if queue is empty now - iter = m_QueuedPlayer.begin(); - position = 1; - } - - // update position from iter to end() - // iter point to first not updated socket, position store new position - for(; iter != m_QueuedPlayer.end(); ++iter, ++position) - (*iter)->SendAuthWaitQue(position); -} - -/// Find a Weather object by the given zoneid -Weather* World::FindWeather(uint32 id) const -{ - WeatherMap::const_iterator itr = m_weathers.find(id); - - if(itr != m_weathers.end()) - return itr->second; - else - return 0; -} - -/// Remove a Weather object for the given zoneid -void World::RemoveWeather(uint32 id) -{ - // not called at the moment. Kept for completeness - WeatherMap::iterator itr = m_weathers.find(id); - - if(itr != m_weathers.end()) - { - delete itr->second; - m_weathers.erase(itr); - } -} - -/// Add a Weather object to the list -Weather* World::AddWeather(uint32 zone_id) -{ - WeatherZoneChances const* weatherChances = objmgr.GetWeatherChances(zone_id); - - // zone not have weather, ignore - if(!weatherChances) - return NULL; - - Weather* w = new Weather(zone_id,weatherChances); - m_weathers[w->GetZone()] = w; - w->ReGenerate(); - w->UpdateWeather(); - return w; -} - -/// Initialize config values -void World::LoadConfigSettings(bool reload) -{ - if(reload) - { - if(!sConfig.Reload()) - { - sLog.outError("World settings reload fail: can't read settings from %s.",sConfig.GetFilename().c_str()); - return; - } - //TODO Check if config is outdated - } - - ///- Read the player limit and the Message of the day from the config file - SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT), true ); - SetMotd( sConfig.GetStringDefault("Motd", "Welcome to the Massive Network Game Object Server." ) ); - - ///- Read all rates from the config file - rate_values[RATE_HEALTH] = sConfig.GetFloatDefault("Rate.Health", 1); - if(rate_values[RATE_HEALTH] < 0) - { - sLog.outError("Rate.Health (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_HEALTH]); - rate_values[RATE_HEALTH] = 1; - } - rate_values[RATE_POWER_MANA] = sConfig.GetFloatDefault("Rate.Mana", 1); - if(rate_values[RATE_POWER_MANA] < 0) - { - sLog.outError("Rate.Mana (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_POWER_MANA]); - rate_values[RATE_POWER_MANA] = 1; - } - rate_values[RATE_POWER_RAGE_INCOME] = sConfig.GetFloatDefault("Rate.Rage.Income", 1); - rate_values[RATE_POWER_RAGE_LOSS] = sConfig.GetFloatDefault("Rate.Rage.Loss", 1); - if(rate_values[RATE_POWER_RAGE_LOSS] < 0) - { - sLog.outError("Rate.Rage.Loss (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_POWER_RAGE_LOSS]); - rate_values[RATE_POWER_RAGE_LOSS] = 1; - } - rate_values[RATE_POWER_FOCUS] = sConfig.GetFloatDefault("Rate.Focus", 1.0f); - rate_values[RATE_LOYALTY] = sConfig.GetFloatDefault("Rate.Loyalty", 1.0f); - rate_values[RATE_SKILL_DISCOVERY] = sConfig.GetFloatDefault("Rate.Skill.Discovery", 1.0f); - rate_values[RATE_DROP_ITEM_POOR] = sConfig.GetFloatDefault("Rate.Drop.Item.Poor", 1.0f); - rate_values[RATE_DROP_ITEM_NORMAL] = sConfig.GetFloatDefault("Rate.Drop.Item.Normal", 1.0f); - rate_values[RATE_DROP_ITEM_UNCOMMON] = sConfig.GetFloatDefault("Rate.Drop.Item.Uncommon", 1.0f); - rate_values[RATE_DROP_ITEM_RARE] = sConfig.GetFloatDefault("Rate.Drop.Item.Rare", 1.0f); - rate_values[RATE_DROP_ITEM_EPIC] = sConfig.GetFloatDefault("Rate.Drop.Item.Epic", 1.0f); - rate_values[RATE_DROP_ITEM_LEGENDARY] = sConfig.GetFloatDefault("Rate.Drop.Item.Legendary", 1.0f); - rate_values[RATE_DROP_ITEM_ARTIFACT] = sConfig.GetFloatDefault("Rate.Drop.Item.Artifact", 1.0f); - rate_values[RATE_DROP_ITEM_REFERENCED] = sConfig.GetFloatDefault("Rate.Drop.Item.Referenced", 1.0f); - rate_values[RATE_DROP_MONEY] = sConfig.GetFloatDefault("Rate.Drop.Money", 1.0f); - rate_values[RATE_XP_KILL] = sConfig.GetFloatDefault("Rate.XP.Kill", 1.0f); - rate_values[RATE_XP_QUEST] = sConfig.GetFloatDefault("Rate.XP.Quest", 1.0f); - rate_values[RATE_XP_EXPLORE] = sConfig.GetFloatDefault("Rate.XP.Explore", 1.0f); - rate_values[RATE_XP_PAST_70] = sConfig.GetFloatDefault("Rate.XP.PastLevel70", 1.0f); - rate_values[RATE_REPUTATION_GAIN] = sConfig.GetFloatDefault("Rate.Reputation.Gain", 1.0f); - rate_values[RATE_CREATURE_NORMAL_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Normal.Damage", 1.0f); - rate_values[RATE_CREATURE_ELITE_ELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.Damage", 1.0f); - rate_values[RATE_CREATURE_ELITE_RAREELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.Damage", 1.0f); - rate_values[RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.Damage", 1.0f); - rate_values[RATE_CREATURE_ELITE_RARE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.Damage", 1.0f); - rate_values[RATE_CREATURE_NORMAL_HP] = sConfig.GetFloatDefault("Rate.Creature.Normal.HP", 1.0f); - rate_values[RATE_CREATURE_ELITE_ELITE_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.HP", 1.0f); - rate_values[RATE_CREATURE_ELITE_RAREELITE_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.HP", 1.0f); - rate_values[RATE_CREATURE_ELITE_WORLDBOSS_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.HP", 1.0f); - rate_values[RATE_CREATURE_ELITE_RARE_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.HP", 1.0f); - rate_values[RATE_CREATURE_NORMAL_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Normal.SpellDamage", 1.0f); - rate_values[RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.SpellDamage", 1.0f); - rate_values[RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.SpellDamage", 1.0f); - rate_values[RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.SpellDamage", 1.0f); - rate_values[RATE_CREATURE_ELITE_RARE_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.SpellDamage", 1.0f); - rate_values[RATE_CREATURE_AGGRO] = sConfig.GetFloatDefault("Rate.Creature.Aggro", 1.0f); - rate_values[RATE_REST_INGAME] = sConfig.GetFloatDefault("Rate.Rest.InGame", 1.0f); - rate_values[RATE_REST_OFFLINE_IN_TAVERN_OR_CITY] = sConfig.GetFloatDefault("Rate.Rest.Offline.InTavernOrCity", 1.0f); - rate_values[RATE_REST_OFFLINE_IN_WILDERNESS] = sConfig.GetFloatDefault("Rate.Rest.Offline.InWilderness", 1.0f); - rate_values[RATE_DAMAGE_FALL] = sConfig.GetFloatDefault("Rate.Damage.Fall", 1.0f); - rate_values[RATE_AUCTION_TIME] = sConfig.GetFloatDefault("Rate.Auction.Time", 1.0f); - rate_values[RATE_AUCTION_DEPOSIT] = sConfig.GetFloatDefault("Rate.Auction.Deposit", 1.0f); - rate_values[RATE_AUCTION_CUT] = sConfig.GetFloatDefault("Rate.Auction.Cut", 1.0f); - rate_values[RATE_HONOR] = sConfig.GetFloatDefault("Rate.Honor",1.0f); - rate_values[RATE_MINING_AMOUNT] = sConfig.GetFloatDefault("Rate.Mining.Amount",1.0f); - rate_values[RATE_MINING_NEXT] = sConfig.GetFloatDefault("Rate.Mining.Next",1.0f); - rate_values[RATE_INSTANCE_RESET_TIME] = sConfig.GetFloatDefault("Rate.InstanceResetTime",1.0f); - rate_values[RATE_TALENT] = sConfig.GetFloatDefault("Rate.Talent",1.0f); - if(rate_values[RATE_TALENT] < 0.0f) - { - sLog.outError("Rate.Talent (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_TALENT]); - rate_values[RATE_TALENT] = 1.0f; - } - rate_values[RATE_CORPSE_DECAY_LOOTED] = sConfig.GetFloatDefault("Rate.Corpse.Decay.Looted",0.1f); - - rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = sConfig.GetFloatDefault("TargetPosRecalculateRange",1.5f); - if(rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] < CONTACT_DISTANCE) - { - sLog.outError("TargetPosRecalculateRange (%f) must be >= %f. Using %f instead.",rate_values[RATE_TARGET_POS_RECALCULATION_RANGE],CONTACT_DISTANCE,CONTACT_DISTANCE); - rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = CONTACT_DISTANCE; - } - else if(rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] > ATTACK_DISTANCE) - { - sLog.outError("TargetPosRecalculateRange (%f) must be <= %f. Using %f instead.",rate_values[RATE_TARGET_POS_RECALCULATION_RANGE],ATTACK_DISTANCE,ATTACK_DISTANCE); - rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = ATTACK_DISTANCE; - } - - rate_values[RATE_DURABILITY_LOSS_DAMAGE] = sConfig.GetFloatDefault("DurabilityLossChance.Damage",0.5f); - if(rate_values[RATE_DURABILITY_LOSS_DAMAGE] < 0.0f) - { - sLog.outError("DurabilityLossChance.Damage (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_DAMAGE]); - rate_values[RATE_DURABILITY_LOSS_DAMAGE] = 0.0f; - } - rate_values[RATE_DURABILITY_LOSS_ABSORB] = sConfig.GetFloatDefault("DurabilityLossChance.Absorb",0.5f); - if(rate_values[RATE_DURABILITY_LOSS_ABSORB] < 0.0f) - { - sLog.outError("DurabilityLossChance.Absorb (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ABSORB]); - rate_values[RATE_DURABILITY_LOSS_ABSORB] = 0.0f; - } - rate_values[RATE_DURABILITY_LOSS_PARRY] = sConfig.GetFloatDefault("DurabilityLossChance.Parry",0.05f); - if(rate_values[RATE_DURABILITY_LOSS_PARRY] < 0.0f) - { - sLog.outError("DurabilityLossChance.Parry (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_PARRY]); - rate_values[RATE_DURABILITY_LOSS_PARRY] = 0.0f; - } - rate_values[RATE_DURABILITY_LOSS_BLOCK] = sConfig.GetFloatDefault("DurabilityLossChance.Block",0.05f); - if(rate_values[RATE_DURABILITY_LOSS_BLOCK] < 0.0f) - { - sLog.outError("DurabilityLossChance.Block (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_BLOCK]); - rate_values[RATE_DURABILITY_LOSS_BLOCK] = 0.0f; - } - - ///- Read other configuration items from the config file - - m_configs[CONFIG_COMPRESSION] = sConfig.GetIntDefault("Compression", 1); - if(m_configs[CONFIG_COMPRESSION] < 1 || m_configs[CONFIG_COMPRESSION] > 9) - { - sLog.outError("Compression level (%i) must be in range 1..9. Using default compression level (1).",m_configs[CONFIG_COMPRESSION]); - m_configs[CONFIG_COMPRESSION] = 1; - } - m_configs[CONFIG_ADDON_CHANNEL] = sConfig.GetBoolDefault("AddonChannel", true); - m_configs[CONFIG_GRID_UNLOAD] = sConfig.GetBoolDefault("GridUnload", true); - m_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 900000); - - m_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfig.GetIntDefault("GridCleanUpDelay", 300000); - if(m_configs[CONFIG_INTERVAL_GRIDCLEAN] < MIN_GRID_DELAY) - { - sLog.outError("GridCleanUpDelay (%i) must be greater %u. Use this minimal value.",m_configs[CONFIG_INTERVAL_GRIDCLEAN],MIN_GRID_DELAY); - m_configs[CONFIG_INTERVAL_GRIDCLEAN] = MIN_GRID_DELAY; - } - if(reload) - MapManager::Instance().SetGridCleanUpDelay(m_configs[CONFIG_INTERVAL_GRIDCLEAN]); - - m_configs[CONFIG_INTERVAL_MAPUPDATE] = sConfig.GetIntDefault("MapUpdateInterval", 100); - if(m_configs[CONFIG_INTERVAL_MAPUPDATE] < MIN_MAP_UPDATE_DELAY) - { - sLog.outError("MapUpdateInterval (%i) must be greater %u. Use this minimal value.",m_configs[CONFIG_INTERVAL_MAPUPDATE],MIN_MAP_UPDATE_DELAY); - m_configs[CONFIG_INTERVAL_MAPUPDATE] = MIN_MAP_UPDATE_DELAY; - } - if(reload) - MapManager::Instance().SetMapUpdateInterval(m_configs[CONFIG_INTERVAL_MAPUPDATE]); - - m_configs[CONFIG_INTERVAL_CHANGEWEATHER] = sConfig.GetIntDefault("ChangeWeatherInterval", 600000); - - if(reload) - { - uint32 val = sConfig.GetIntDefault("WorldServerPort", DEFAULT_WORLDSERVER_PORT); - if(val!=m_configs[CONFIG_PORT_WORLD]) - sLog.outError("WorldServerPort option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_PORT_WORLD]); - } - else - m_configs[CONFIG_PORT_WORLD] = sConfig.GetIntDefault("WorldServerPort", DEFAULT_WORLDSERVER_PORT); - - if(reload) - { - uint32 val = sConfig.GetIntDefault("SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME); - if(val!=m_configs[CONFIG_SOCKET_SELECTTIME]) - sLog.outError("SocketSelectTime option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[DEFAULT_SOCKET_SELECT_TIME]); - } - else - m_configs[CONFIG_SOCKET_SELECTTIME] = sConfig.GetIntDefault("SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME); - - - m_configs[CONFIG_TCP_NO_DELAY] = sConfig.GetBoolDefault("TcpNoDelay", false); - m_configs[CONFIG_GROUP_XP_DISTANCE] = sConfig.GetIntDefault("MaxGroupXPDistance", 74); - /// \todo Add MonsterSight and GuarderSight (with meaning) in mangosd.conf or put them as define - m_configs[CONFIG_SIGHT_MONSTER] = sConfig.GetIntDefault("MonsterSight", 50); - m_configs[CONFIG_SIGHT_GUARDER] = sConfig.GetIntDefault("GuarderSight", 50); - - if(reload) - { - uint32 val = sConfig.GetIntDefault("GameType", 0); - if(val!=m_configs[CONFIG_GAME_TYPE]) - sLog.outError("GameType option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_GAME_TYPE]); - } - else - m_configs[CONFIG_GAME_TYPE] = sConfig.GetIntDefault("GameType", 0); - - if(reload) - { - uint32 val = sConfig.GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT); - if(val!=m_configs[CONFIG_REALM_ZONE]) - sLog.outError("RealmZone option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_REALM_ZONE]); - } - else - m_configs[CONFIG_REALM_ZONE] = sConfig.GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT); - - m_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = sConfig.GetBoolDefault("AllowTwoSide.Accounts", false); - m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Chat",false); - m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Channel",false); - m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Group",false); - m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Guild",false); - m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Auction",false); - m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Mail",false); - m_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfig.GetBoolDefault("AllowTwoSide.WhoList", false); - m_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = sConfig.GetBoolDefault("AllowTwoSide.AddFriend", false); - m_configs[CONFIG_STRICT_PLAYER_NAMES] = sConfig.GetIntDefault("StrictPlayerNames", 0); - m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault("StrictCharterNames", 0); - m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault("StrictPetNames", 0); - - m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault("CharactersCreatingDisabled", 0); - - m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10); - if(m_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_configs[CONFIG_CHARACTERS_PER_REALM] > 10) - { - sLog.outError("CharactersPerRealm (%i) must be in range 1..10. Set to 10.",m_configs[CONFIG_CHARACTERS_PER_REALM]); - m_configs[CONFIG_CHARACTERS_PER_REALM] = 10; - } - - // must be after CONFIG_CHARACTERS_PER_REALM - m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] = sConfig.GetIntDefault("CharactersPerAccount", 50); - if(m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] < m_configs[CONFIG_CHARACTERS_PER_REALM]) - { - sLog.outError("CharactersPerAccount (%i) can't be less than CharactersPerRealm (%i).",m_configs[CONFIG_CHARACTERS_PER_ACCOUNT],m_configs[CONFIG_CHARACTERS_PER_REALM]); - m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] = m_configs[CONFIG_CHARACTERS_PER_REALM]; - } - - m_configs[CONFIG_SKIP_CINEMATICS] = sConfig.GetIntDefault("SkipCinematics", 0); - if(m_configs[CONFIG_SKIP_CINEMATICS] < 0 || m_configs[CONFIG_SKIP_CINEMATICS] > 2) - { - sLog.outError("SkipCinematics (%i) must be in range 0..2. Set to 0.",m_configs[CONFIG_SKIP_CINEMATICS]); - m_configs[CONFIG_SKIP_CINEMATICS] = 0; - } - - - if(reload) - { - uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", 60); - if(val!=m_configs[CONFIG_MAX_PLAYER_LEVEL]) - sLog.outError("MaxPlayerLevel option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_MAX_PLAYER_LEVEL]); - } - else - m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", 60); - if(m_configs[CONFIG_MAX_PLAYER_LEVEL] > 255) - { - sLog.outError("MaxPlayerLevel (%i) must be in range 1..255. Set to 255.",m_configs[CONFIG_MAX_PLAYER_LEVEL]); - m_configs[CONFIG_MAX_PLAYER_LEVEL] = 255; - } - - m_configs[CONFIG_START_PLAYER_LEVEL] = sConfig.GetIntDefault("StartPlayerLevel", 1); - if(m_configs[CONFIG_START_PLAYER_LEVEL] < 1) - { - sLog.outError("StartPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to 1.",m_configs[CONFIG_START_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]); - m_configs[CONFIG_START_PLAYER_LEVEL] = 1; - } - else if(m_configs[CONFIG_START_PLAYER_LEVEL] > m_configs[CONFIG_MAX_PLAYER_LEVEL]) - { - sLog.outError("StartPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to %u.",m_configs[CONFIG_START_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]); - m_configs[CONFIG_START_PLAYER_LEVEL] = m_configs[CONFIG_MAX_PLAYER_LEVEL]; - } - m_configs[CONFIG_MAX_HONOR_POINTS] = sConfig.GetIntDefault("MaxHonorPoints", 75000); - m_configs[CONFIG_MAX_ARENA_POINTS] = sConfig.GetIntDefault("MaxArenaPoints", 5000); - - m_configs[CONFIG_INSTANCE_IGNORE_LEVEL] = sConfig.GetBoolDefault("Instance.IgnoreLevel", false); - m_configs[CONFIG_INSTANCE_IGNORE_RAID] = sConfig.GetBoolDefault("Instance.IgnoreRaid", false); - - m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true); - m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", true); - m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false); - - m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true); - m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4); - m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000); - - m_configs[CONFIG_MAX_PRIMARY_TRADE_SKILL] = sConfig.GetIntDefault("MaxPrimaryTradeSkill", 2); - m_configs[CONFIG_MIN_PETITION_SIGNS] = sConfig.GetIntDefault("MinPetitionSigns", 9); - if(m_configs[CONFIG_MIN_PETITION_SIGNS] > 9) - { - sLog.outError("MinPetitionSigns (%i) must be in range 0..9. Set to 9.",m_configs[CONFIG_MIN_PETITION_SIGNS]); - m_configs[CONFIG_MIN_PETITION_SIGNS] = 9; - } - - m_configs[CONFIG_GM_WISPERING_TO] = sConfig.GetBoolDefault("GM.WhisperingTo",false); - m_configs[CONFIG_GM_IN_GM_LIST] = sConfig.GetBoolDefault("GM.InGMList",false); - m_configs[CONFIG_GM_IN_WHO_LIST] = sConfig.GetBoolDefault("GM.InWhoList",false); - m_configs[CONFIG_GM_LOGIN_STATE] = sConfig.GetIntDefault("GM.LoginState",2); - m_configs[CONFIG_GM_LOG_TRADE] = sConfig.GetBoolDefault("GM.LogTrade", false); - - m_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("Visibility.GroupMode",0); - - m_configs[CONFIG_MAIL_DELIVERY_DELAY] = sConfig.GetIntDefault("MailDeliveryDelay",HOUR); - - m_configs[CONFIG_UPTIME_UPDATE] = sConfig.GetIntDefault("UpdateUptimeInterval", 10); - if(m_configs[CONFIG_UPTIME_UPDATE]<=0) - { - sLog.outError("UpdateUptimeInterval (%i) must be > 0, set to default 10.",m_configs[CONFIG_UPTIME_UPDATE]); - m_configs[CONFIG_UPTIME_UPDATE] = 10; - } - if(reload) - { - m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000); - m_timers[WUPDATE_UPTIME].Reset(); - } - - m_configs[CONFIG_SKILL_CHANCE_ORANGE] = sConfig.GetIntDefault("SkillChance.Orange",100); - m_configs[CONFIG_SKILL_CHANCE_YELLOW] = sConfig.GetIntDefault("SkillChance.Yellow",75); - m_configs[CONFIG_SKILL_CHANCE_GREEN] = sConfig.GetIntDefault("SkillChance.Green",25); - m_configs[CONFIG_SKILL_CHANCE_GREY] = sConfig.GetIntDefault("SkillChance.Grey",0); - - m_configs[CONFIG_SKILL_CHANCE_MINING_STEPS] = sConfig.GetIntDefault("SkillChance.MiningSteps",75); - m_configs[CONFIG_SKILL_CHANCE_SKINNING_STEPS] = sConfig.GetIntDefault("SkillChance.SkinningSteps",75); - - m_configs[CONFIG_SKILL_PROSPECTING] = sConfig.GetBoolDefault("SkillChance.Prospecting",false); - - m_configs[CONFIG_SKILL_GAIN_CRAFTING] = sConfig.GetIntDefault("SkillGain.Crafting", 1); - if(m_configs[CONFIG_SKILL_GAIN_CRAFTING] < 0) - { - sLog.outError("SkillGain.Crafting (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_CRAFTING]); - m_configs[CONFIG_SKILL_GAIN_CRAFTING] = 1; - } - - m_configs[CONFIG_SKILL_GAIN_DEFENSE] = sConfig.GetIntDefault("SkillGain.Defense", 1); - if(m_configs[CONFIG_SKILL_GAIN_DEFENSE] < 0) - { - sLog.outError("SkillGain.Defense (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_DEFENSE]); - m_configs[CONFIG_SKILL_GAIN_DEFENSE] = 1; - } - - m_configs[CONFIG_SKILL_GAIN_GATHERING] = sConfig.GetIntDefault("SkillGain.Gathering", 1); - if(m_configs[CONFIG_SKILL_GAIN_GATHERING] < 0) - { - sLog.outError("SkillGain.Gathering (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_GATHERING]); - m_configs[CONFIG_SKILL_GAIN_GATHERING] = 1; - } - - m_configs[CONFIG_SKILL_GAIN_WEAPON] = sConfig.GetIntDefault("SkillGain.Weapon", 1); - if(m_configs[CONFIG_SKILL_GAIN_WEAPON] < 0) - { - sLog.outError("SkillGain.Weapon (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_WEAPON]); - m_configs[CONFIG_SKILL_GAIN_WEAPON] = 1; - } - - m_configs[CONFIG_MAX_OVERSPEED_PINGS] = sConfig.GetIntDefault("MaxOverspeedPings",2); - if(m_configs[CONFIG_MAX_OVERSPEED_PINGS] != 0 && m_configs[CONFIG_MAX_OVERSPEED_PINGS] < 2) - { - sLog.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check. Set to 2.",m_configs[CONFIG_MAX_OVERSPEED_PINGS]); - m_configs[CONFIG_MAX_OVERSPEED_PINGS] = 2; - } - - m_configs[CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY] = sConfig.GetBoolDefault("SaveRespawnTimeImmediately",true); - m_configs[CONFIG_WEATHER] = sConfig.GetBoolDefault("ActivateWeather",true); - - if(reload) - { - uint32 val = sConfig.GetIntDefault("Expansion",1); - if(val!=m_configs[CONFIG_EXPANSION]) - sLog.outError("Expansion option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_EXPANSION]); - } - else - m_configs[CONFIG_EXPANSION] = sConfig.GetIntDefault("Expansion",1); - - m_configs[CONFIG_CHATFLOOD_MESSAGE_COUNT] = sConfig.GetIntDefault("ChatFlood.MessageCount",10); - m_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = sConfig.GetIntDefault("ChatFlood.MessageDelay",1); - m_configs[CONFIG_CHATFLOOD_MUTE_TIME] = sConfig.GetIntDefault("ChatFlood.MuteTime",10); - - m_configs[CONFIG_EVENT_ANNOUNCE] = sConfig.GetIntDefault("Event.Announce",0); - - m_configs[CONFIG_CREATURE_FAMILY_ASSISTEMCE_RADIUS] = sConfig.GetIntDefault("CreatureFamilyAssistenceRadius",10); - - m_configs[CONFIG_WORLD_BOSS_LEVEL_DIFF] = sConfig.GetIntDefault("WorldBossLevelDiff",3); - - // note: disable value (-1) will assigned as 0xFFFFFFF, to prevent overflow at calculations limit it to max possible player level (255) - m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] = sConfig.GetIntDefault("Quests.LowLevelHideDiff",4); - if(m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] > 255) - m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] = 255; - m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] = sConfig.GetIntDefault("Quests.HighLevelHideDiff",7); - if(m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] > 255) - m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] = 255; - - m_configs[CONFIG_DETECT_POS_COLLISION] = sConfig.GetBoolDefault("DetectPosCollision", true); - - m_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfig.GetBoolDefault("Channel.RestrictedLfg", true); - m_configs[CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL] = sConfig.GetBoolDefault("Channel.SilentlyGMJoin", false); - - m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true); - m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false); - - m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60); - m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300); - m_configs[CONFIG_CORPSE_DECAY_ELITE] = sConfig.GetIntDefault("Corpse.Decay.ELITE", 300); - m_configs[CONFIG_CORPSE_DECAY_RAREELITE] = sConfig.GetIntDefault("Corpse.Decay.RAREELITE", 300); - m_configs[CONFIG_CORPSE_DECAY_WORLDBOSS] = sConfig.GetIntDefault("Corpse.Decay.WORLDBOSS", 3600); - - m_configs[CONFIG_DEATH_SICKNESS_LEVEL] = sConfig.GetIntDefault("Death.SicknessLevel", 11); - m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvP", true); - m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvE", true); - - m_configs[CONFIG_THREAT_RADIUS] = sConfig.GetIntDefault("ThreatRadius", 100); - - // always use declined names in the russian client - m_configs[CONFIG_DECLINED_NAMES_USED] = - (m_configs[CONFIG_REALM_ZONE] == REALM_ZONE_RUSSIAN) ? true : sConfig.GetBoolDefault("DeclinedNames", false); - - m_configs[CONFIG_LISTEN_RANGE_SAY] = sConfig.GetIntDefault("ListenRange.Say", 25); - m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25); - m_configs[CONFIG_LISTEN_RANGE_YELL] = sConfig.GetIntDefault("ListenRange.Yell", 300); - - - m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); - if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE); - m_VisibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE; - } - m_VisibleObjectGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Object", 10); - if(m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE); - m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE; - } - - m_MaxVisibleDistanceForCreature = sConfig.GetFloatDefault("Visibility.Distance.Creature", DEFAULT_VISIBILITY_DISTANCE); - if(m_MaxVisibleDistanceForCreature < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) - { - sLog.outError("Visibility.Distance.Creature can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); - m_MaxVisibleDistanceForCreature = 45*sWorld.getRate(RATE_CREATURE_AGGRO); - } - else if(m_MaxVisibleDistanceForCreature + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility. Distance .Creature can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); - m_MaxVisibleDistanceForCreature = MAX_VISIBILITY_DISTANCE-m_VisibleUnitGreyDistance; - } - m_MaxVisibleDistanceForPlayer = sConfig.GetFloatDefault("Visibility.Distance.Player", DEFAULT_VISIBILITY_DISTANCE); - if(m_MaxVisibleDistanceForPlayer < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) - { - sLog.outError("Visibility.Distance.Player can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); - m_MaxVisibleDistanceForPlayer = 45*sWorld.getRate(RATE_CREATURE_AGGRO); - } - else if(m_MaxVisibleDistanceForPlayer + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.Player can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); - m_MaxVisibleDistanceForPlayer = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; - } - m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Gameobject", DEFAULT_VISIBILITY_DISTANCE); - if(m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE) - { - sLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE)); - m_MaxVisibleDistanceForObject = INTERACTION_DISTANCE; - } - else if(m_MaxVisibleDistanceForObject + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance); - m_MaxVisibleDistanceForObject = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance; - } - m_MaxVisibleDistanceInFlight = sConfig.GetFloatDefault("Visibility.Distance.InFlight", DEFAULT_VISIBILITY_DISTANCE); - if(m_MaxVisibleDistanceInFlight + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance); - m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance; - } - - ///- Read the "Data" directory from the config file - std::string dataPath = sConfig.GetStringDefault("DataDir","./"); - if( dataPath.at(dataPath.length()-1)!='/' && dataPath.at(dataPath.length()-1)!='\\' ) - dataPath.append("/"); - - if(reload) - { - if(dataPath!=m_dataPath) - sLog.outError("DataDir option can't be changed at mangosd.conf reload, using current value (%s).",m_dataPath.c_str()); - } - else - { - m_dataPath = dataPath; - sLog.outString("Using DataDir %s",m_dataPath.c_str()); - } - - bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false); - bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false); - std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", ""); - std::string ignoreSpellIds = sConfig.GetStringDefault("vmap.ignoreSpellIds", ""); - VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS); - VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight); - VMAP::VMapFactory::createOrGetVMapManager()->preventMapsFromBeingUsed(ignoreMapIds.c_str()); - VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str()); - sLog.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i",enableLOS, enableHeight); - sLog.outString( "WORLD: VMap data directory is: %svmaps",m_dataPath.c_str()); - sLog.outString( "WORLD: VMap config keys are: vmap.enableLOS, vmap.enableHeight, vmap.ignoreMapIds, vmap.ignoreSpellIds"); -} - -/// Initialize the World -void World::SetInitialWorldSettings() -{ - ///- Initialize the random number generator - srand((unsigned int)time(NULL)); - - ///- Initialize config settings - LoadConfigSettings(); - - ///- Init highest guids before any table loading to prevent using not initialized guids in some code. - objmgr.SetHighestGuids(); - - ///- Check the existence of the map files for all races' startup areas. - if( !MapManager::ExistMapAndVMap(0,-6240.32f, 331.033f) - ||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f) - ||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f) - ||!MapManager::ExistMapAndVMap(1,-618.518f,-4251.67f) - ||!MapManager::ExistMapAndVMap(0, 1676.35f, 1677.45f) - ||!MapManager::ExistMapAndVMap(1, 10311.3f, 832.463f) - ||!MapManager::ExistMapAndVMap(1,-2917.58f,-257.98f) - ||m_configs[CONFIG_EXPANSION] && ( - !MapManager::ExistMapAndVMap(530,10349.6f,-6357.29f) || !MapManager::ExistMapAndVMap(530,-3961.64f,-13931.2f) ) ) - { - sLog.outError("Correct *.map files not found in path '%smaps' or *.vmap/*vmdir files in '%svmaps'. Please place *.map/*.vmap/*.vmdir files in appropriate directories or correct the DataDir value in the mangosd.conf file.",m_dataPath.c_str(),m_dataPath.c_str()); - exit(1); - } - - ///- Loading strings. Getting no records means core load has to be canceled because no error message can be output. - sLog.outString( "" ); - sLog.outString( "Loading MaNGOS strings..." ); - if (!objmgr.LoadMangosStrings()) - exit(1); // Error message displayed in function already - - ///- Update the realm entry in the database with the realm type from the config file - //No SQL injection as values are treated as integers - - // not send custom type REALM_FFA_PVP to realm list - uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_GAME_TYPE); - uint32 realm_zone = getConfig(CONFIG_REALM_ZONE); - loginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID); - - ///- Remove the bones after a restart - CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0'"); - - ///- Load the DBC files - sLog.outString("Initialize data stores..."); - LoadDBCStores(m_dataPath); - DetectDBCLang(); - - sLog.outString( "Loading InstanceTemplate" ); - objmgr.LoadInstanceTemplate(); - - sLog.outString( "Loading SkillLineAbilityMultiMap Data..." ); - spellmgr.LoadSkillLineAbilityMap(); - - ///- Clean up and pack instances - sLog.outString( "Cleaning up instances..." ); - sInstanceSaveManager.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables - - sLog.outString( "Packing instances..." ); - sInstanceSaveManager.PackInstances(); - - sLog.outString( "Loading Localization strings..." ); - objmgr.LoadCreatureLocales(); - objmgr.LoadGameObjectLocales(); - objmgr.LoadItemLocales(); - objmgr.LoadQuestLocales(); - objmgr.LoadNpcTextLocales(); - objmgr.LoadPageTextLocales(); - objmgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) - - sLog.outString( "Loading Page Texts..." ); - objmgr.LoadPageTexts(); - - sLog.outString( "Loading Game Object Templates..." ); // must be after LoadPageTexts - objmgr.LoadGameobjectInfo(); - - sLog.outString( "Loading Spell Chain Data..." ); - spellmgr.LoadSpellChains(); - - sLog.outString( "Loading Spell Elixir types..." ); - spellmgr.LoadSpellElixirs(); - - sLog.outString( "Loading Spell Learn Skills..." ); - spellmgr.LoadSpellLearnSkills(); // must be after LoadSpellChains - - sLog.outString( "Loading Spell Learn Spells..." ); - spellmgr.LoadSpellLearnSpells(); - - sLog.outString( "Loading Spell Proc Event conditions..." ); - spellmgr.LoadSpellProcEvents(); - - sLog.outString( "Loading Aggro Spells Definitions..."); - spellmgr.LoadSpellThreats(); - - sLog.outString( "Loading NPC Texts..." ); - objmgr.LoadGossipText(); - - sLog.outString( "Loading Item Random Enchantments Table..." ); - LoadRandomEnchantmentsTable(); - - sLog.outString( "Loading Items..." ); // must be after LoadRandomEnchantmentsTable and LoadPageTexts - objmgr.LoadItemPrototypes(); - - sLog.outString( "Loading Item Texts..." ); - objmgr.LoadItemTexts(); - - sLog.outString( "Loading Creature Model Based Info Data..." ); - objmgr.LoadCreatureModelInfo(); - - sLog.outString( "Loading Equipment templates..."); - objmgr.LoadEquipmentTemplates(); - - sLog.outString( "Loading Creature templates..." ); - objmgr.LoadCreatureTemplates(); - - sLog.outString( "Loading SpellsScriptTarget..."); - spellmgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo - - sLog.outString( "Loading Creature Reputation OnKill Data..." ); - objmgr.LoadReputationOnKill(); - - sLog.outString( "Loading Pet Create Spells..." ); - objmgr.LoadPetCreateSpells(); - - sLog.outString( "Loading Creature Data..." ); - objmgr.LoadCreatures(); - - sLog.outString( "Loading Creature Addon Data..." ); - objmgr.LoadCreatureAddons(); // must be after LoadCreatureTemplates() and LoadCreatures() - - sLog.outString( "Loading Creature Respawn Data..." ); // must be after PackInstances() - objmgr.LoadCreatureRespawnTimes(); - - sLog.outString( "Loading Gameobject Data..." ); - objmgr.LoadGameobjects(); - - sLog.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances() - objmgr.LoadGameobjectRespawnTimes(); - - sLog.outString( "Loading Game Event Data..."); - gameeventmgr.LoadFromDB(); - - sLog.outString( "Loading Weather Data..." ); - objmgr.LoadWeatherZoneChances(); - - sLog.outString( "Loading Quests..." ); - objmgr.LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables - - sLog.outString( "Loading Quests Relations..." ); - objmgr.LoadQuestRelations(); // must be after quest load - - sLog.outString( "Loading AreaTrigger definitions..." ); - objmgr.LoadAreaTriggerTeleports(); // must be after item template load - - sLog.outString( "Loading Quest Area Triggers..." ); - objmgr.LoadQuestAreaTriggers(); // must be after LoadQuests - - sLog.outString( "Loading Tavern Area Triggers..." ); - objmgr.LoadTavernAreaTriggers(); - - sLog.outString( "Loading AreaTrigger script names..." ); - objmgr.LoadAreaTriggerScripts(); - - - sLog.outString( "Loading Graveyard-zone links..."); - objmgr.LoadGraveyardZones(); - - sLog.outString( "Loading Spell target coordinates..." ); - spellmgr.LoadSpellTargetPositions(); - - sLog.outString( "Loading SpellAffect definitions..." ); - spellmgr.LoadSpellAffects(); - - sLog.outString( "Loading spell pet auras..." ); - spellmgr.LoadSpellPetAuras(); - - sLog.outString( "Loading player Create Info & Level Stats..." ); - objmgr.LoadPlayerInfo(); - - sLog.outString( "Loading Exploration BaseXP Data..." ); - objmgr.LoadExplorationBaseXP(); - - sLog.outString( "Loading Pet Name Parts..." ); - objmgr.LoadPetNames(); - - sLog.outString( "Loading the max pet number..." ); - objmgr.LoadPetNumber(); - - sLog.outString( "Loading pet level stats..." ); - objmgr.LoadPetLevelInfo(); - - sLog.outString( "Loading Player Corpses..." ); - objmgr.LoadCorpses(); - - sLog.outString( "Loading Loot Tables..." ); - LoadLootTables(); - - sLog.outString( "Loading Skill Discovery Table..." ); - LoadSkillDiscoveryTable(); - - sLog.outString( "Loading Skill Extra Item Table..." ); - LoadSkillExtraItemTable(); - - sLog.outString( "Loading Skill Fishing base level requirements..." ); - objmgr.LoadFishingBaseSkillLevel(); - - ///- Load dynamic data tables from the database - sLog.outString( "Loading Auctions..." ); - objmgr.LoadAuctionItems(); - objmgr.LoadAuctions(); - - sLog.outString( "Loading Guilds..." ); - objmgr.LoadGuilds(); - - sLog.outString( "Loading ArenaTeams..." ); - objmgr.LoadArenaTeams(); - - sLog.outString( "Loading Groups..." ); - objmgr.LoadGroups(); - - sLog.outString( "Loading ReservedNames..." ); - objmgr.LoadReservedPlayersNames(); - - sLog.outString( "Loading GameObject for quests..." ); - objmgr.LoadGameObjectForQuests(); - - sLog.outString( "Loading BattleMasters..." ); - objmgr.LoadBattleMastersEntry(); - - sLog.outString( "Loading Waypoints..." ); - WaypointMgr.Load(); - - ///- Handle outdated emails (delete/return) - sLog.outString( "Returning old mails..." ); - objmgr.ReturnOrDeleteOldMails(false); - - ///- Load and initialize scripts - sLog.outString( "Loading Scripts..." ); - objmgr.LoadQuestStartScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate - objmgr.LoadQuestEndScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate - objmgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data) - objmgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data) - objmgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data) - - sLog.outString( "Initializing Scripts..." ); - if(!LoadScriptingModule()) - exit(1); - - ///- Initialize game time and timers - sLog.outString( "DEBUG:: Initialize game time and timers" ); - m_gameTime = time(NULL); - m_startTime=m_gameTime; - - tm local; - time_t curr; - time(&curr); - local=*(localtime(&curr)); // dereference and assign - char isoDate[128]; - sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d", - local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec); - - WorldDatabase.PExecute("INSERT INTO uptime (startstring, starttime, uptime) VALUES('%s', %ld, 0)", isoDate, m_startTime ); - - m_timers[WUPDATE_OBJECTS].SetInterval(0); - m_timers[WUPDATE_SESSIONS].SetInterval(0); - m_timers[WUPDATE_WEATHERS].SetInterval(1000); - m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*1000); //set auction update interval to 1 minute - m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000); - //Update "uptime" table based on configuration entry in minutes. - m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*1000); //erase corpses every 20 minutes - - //to set mailtimer to return mails every day between 4 and 5 am - //mailtimer is increased when updating auctions - //one second is 1000 -(tested on win system) - mail_timer = ((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * 1000) / m_timers[WUPDATE_AUCTIONS].GetInterval() ); - //1440 - mail_timer_expires = ( (DAY * 1000) / (m_timers[WUPDATE_AUCTIONS].GetInterval())); - sLog.outDebug("Mail timer set to: %u, mail return is called every %u minutes", mail_timer, mail_timer_expires); - - ///- Initilize static helper structures - AIRegistry::Initialize(); - WaypointMovementGenerator::Initialize(); - Player::InitVisibleBits(); - - ///- Initialize MapManager - sLog.outString( "Starting Map System" ); - MapManager::Instance().Initialize(); - - ///- Initialize Battlegrounds - sLog.outString( "Starting BattleGround System" ); - sBattleGroundMgr.CreateInitialBattleGrounds(); - - //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager - sLog.outString( "Loading Transports..." ); - MapManager::Instance().LoadTransports(); - - sLog.outString("Deleting expired bans..." ); - loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); - - sLog.outString("Calculate next daily quest reset time..." ); - InitDailyQuestResetTime(); - - sLog.outString("Starting Game Event system..." ); - uint32 nextGameEvent = gameeventmgr.Initialize(); - m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); //depend on next event - - sLog.outString( "WORLD: World initialized" ); -} -void World::DetectDBCLang() -{ - uint32 m_lang_confid = sConfig.GetIntDefault("DBC.Locale", 255); - - if(m_lang_confid != 255 && m_lang_confid >= MAX_LOCALE) - { - sLog.outError("Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)",MAX_LOCALE); - m_lang_confid = LOCALE_enUS; - } - - ChrRacesEntry const* race = sChrRacesStore.LookupEntry(1); - - std::string availableLocalsStr; - - int default_locale = MAX_LOCALE; - for (int i = MAX_LOCALE-1; i >= 0; --i) - { - if ( strlen(race->name[i]) > 0) // check by race names - { - default_locale = i; - m_availableDbcLocaleMask |= (1 << i); - availableLocalsStr += localeNames[i]; - availableLocalsStr += " "; - } - } - - if( default_locale != m_lang_confid && m_lang_confid < MAX_LOCALE && - (m_availableDbcLocaleMask & (1 << m_lang_confid)) ) - { - default_locale = m_lang_confid; - } - - if(default_locale >= MAX_LOCALE) - { - sLog.outError("Unable to determine your DBC Locale! (corrupt DBC?)"); - exit(1); - } - - m_defaultDbcLocale = LocaleConstant(default_locale); - - sLog.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames[m_defaultDbcLocale],availableLocalsStr.empty() ? "" : availableLocalsStr.c_str()); -} - -/// Update the World ! -void World::Update(time_t diff) -{ - ///- Update the different timers - for(int i = 0; i < WUPDATE_COUNT; i++) - if(m_timers[i].GetCurrent()>=0) - m_timers[i].Update(diff); - else m_timers[i].SetCurrent(0); - - ///- Update the game time and check for shutdown time - _UpdateGameTime(); - - /// Handle daily quests reset time - if(m_gameTime > m_NextDailyQuestReset) - { - ResetDailyQuests(); - m_NextDailyQuestReset += DAY; - } - - ///
  • Handle auctions when the timer has passed - if (m_timers[WUPDATE_AUCTIONS].Passed()) - { - m_timers[WUPDATE_AUCTIONS].Reset(); - - ///- Update mails (return old mails with item, or delete them) - //(tested... works on win) - if (++mail_timer > mail_timer_expires) - { - mail_timer = 0; - objmgr.ReturnOrDeleteOldMails(true); - } - - AuctionHouseObject* AuctionMap; - for (int i = 0; i < 3; i++) - { - switch (i) - { - case 0: - AuctionMap = objmgr.GetAuctionsMap( 6 );//horde - break; - case 1: - AuctionMap = objmgr.GetAuctionsMap( 2 );//alliance - break; - case 2: - AuctionMap = objmgr.GetAuctionsMap( 7 );//neutral - break; - } - - ///- Handle expired auctions - AuctionHouseObject::AuctionEntryMap::iterator itr,next; - for (itr = AuctionMap->GetAuctionsBegin(); itr != AuctionMap->GetAuctionsEnd();itr = next) - { - next = itr; - ++next; - if (m_gameTime > (itr->second->time)) - { - ///- Either cancel the auction if there was no bidder - if (itr->second->bidder == 0) - { - objmgr.SendAuctionExpiredMail( itr->second ); - } - ///- Or perform the transaction - else - { - //we should send an "item sold" message if the seller is online - //we send the item to the winner - //we send the money to the seller - objmgr.SendAuctionSuccessfulMail( itr->second ); - objmgr.SendAuctionWonMail( itr->second ); - } - - ///- In any case clear the auction - //No SQL injection (Id is integer) - CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",itr->second->Id); - objmgr.RemoveAItem(itr->second->item_guidlow); - delete itr->second; - AuctionMap->RemoveAuction(itr->first); - } - } - } - } - - ///
  • Handle session updates when the timer has passed - if (m_timers[WUPDATE_SESSIONS].Passed()) - { - m_timers[WUPDATE_SESSIONS].Reset(); - - UpdateSessions(diff); - } - - ///
  • Handle weather updates when the timer has passed - if (m_timers[WUPDATE_WEATHERS].Passed()) - { - m_timers[WUPDATE_WEATHERS].Reset(); - - ///- Send an update signal to Weather objects - WeatherMap::iterator itr, next; - for (itr = m_weathers.begin(); itr != m_weathers.end(); itr = next) - { - next = itr; - ++next; - - ///- and remove Weather objects for zones with no player - //As interval > WorldTick - if(!itr->second->Update(m_timers[WUPDATE_WEATHERS].GetInterval())) - { - delete itr->second; - m_weathers.erase(itr); - } - } - } - ///
  • Update uptime table - if (m_timers[WUPDATE_UPTIME].Passed()) - { - uint32 tmpDiff = (m_gameTime - m_startTime); - uint32 maxClientsNum = sWorld.GetMaxActiveSessionCount(); - - m_timers[WUPDATE_UPTIME].Reset(); - WorldDatabase.PExecute("UPDATE uptime SET uptime = %d, maxplayers = %d WHERE starttime = " I64FMTD, tmpDiff, maxClientsNum, uint64(m_startTime)); - } - - ///
  • Handle all other objects - if (m_timers[WUPDATE_OBJECTS].Passed()) - { - m_timers[WUPDATE_OBJECTS].Reset(); - ///- Update objects when the timer has passed (maps, transport, creatures,...) - MapManager::Instance().Update(diff); // As interval = 0 - - ///- Process necessary scripts - if (!m_scriptSchedule.empty()) - ScriptsProcess(); - - sBattleGroundMgr.Update(diff); - } - - // execute callbacks from sql queries that were queued recently - UpdateResultQueue(); - - ///- Erase corpses once every 20 minutes - if (m_timers[WUPDATE_CORPSES].Passed()) - { - m_timers[WUPDATE_CORPSES].Reset(); - - CorpsesErase(); - } - - ///- Process Game events when necessary - if (m_timers[WUPDATE_EVENTS].Passed()) - { - m_timers[WUPDATE_EVENTS].Reset(); // to give time for Update() to be processed - uint32 nextGameEvent = gameeventmgr.Update(); - m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); - m_timers[WUPDATE_EVENTS].Reset(); - } - - ///
- ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove" - MapManager::Instance().DoDelayedMovesAndRemoves(); - - // update the instance reset times - sInstanceSaveManager.Update(); - - // And last, but not least handle the issued cli commands - ProcessCliCommands(); -} - -/// Put scripts in the execution queue -void World::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target) -{ - ///- Find the script map - ScriptMapMap::const_iterator s = scripts.find(id); - if (s == scripts.end()) - return; - - // prepare static data - uint64 sourceGUID = source->GetGUID(); - uint64 targetGUID = target ? target->GetGUID() : (uint64)0; - uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; - - ///- Schedule script execution for all scripts in the script map - ScriptMap const *s2 = &(s->second); - bool immedScript = false; - for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter) - { - ScriptAction sa; - sa.sourceGUID = sourceGUID; - sa.targetGUID = targetGUID; - sa.ownerGUID = ownerGUID; - - sa.script = &iter->second; - m_scriptSchedule.insert(std::pair(m_gameTime + iter->first, sa)); - if (iter->first == 0) - immedScript = true; - } - ///- If one of the effects should be immediate, launch the script execution - if (immedScript) - ScriptsProcess(); -} - -void World::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target) -{ - // NOTE: script record _must_ exist until command executed - - // prepare static data - uint64 sourceGUID = source->GetGUID(); - uint64 targetGUID = target ? target->GetGUID() : (uint64)0; - uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; - - ScriptAction sa; - sa.sourceGUID = sourceGUID; - sa.targetGUID = targetGUID; - sa.ownerGUID = ownerGUID; - - sa.script = &script; - m_scriptSchedule.insert(std::pair(m_gameTime + delay, sa)); - - ///- If effects should be immediate, launch the script execution - if(delay == 0) - ScriptsProcess(); -} - -/// Process queued scripts -void World::ScriptsProcess() -{ - if (m_scriptSchedule.empty()) - return; - - ///- Process overdue queued scripts - std::multimap::iterator iter = m_scriptSchedule.begin(); - // ok as multimap is a *sorted* associative container - while (!m_scriptSchedule.empty() && (iter->first <= m_gameTime)) - { - ScriptAction const& step = iter->second; - - Object* source = NULL; - - if(step.sourceGUID) - { - switch(GUID_HIPART(step.sourceGUID)) - { - case HIGHGUID_ITEM: - // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM - { - Player* player = HashMapHolder::Find(step.ownerGUID); - if(player) - source = player->GetItemByGuid(step.sourceGUID); - break; - } - case HIGHGUID_UNIT: - source = HashMapHolder::Find(step.sourceGUID); - break; - case HIGHGUID_PET: - source = HashMapHolder::Find(step.sourceGUID); - break; - case HIGHGUID_PLAYER: - source = HashMapHolder::Find(step.sourceGUID); - break; - case HIGHGUID_GAMEOBJECT: - source = HashMapHolder::Find(step.sourceGUID); - break; - case HIGHGUID_CORPSE: - source = HashMapHolder::Find(step.sourceGUID); - break; - default: - sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID)); - break; - } - } - - Object* target = NULL; - - if(step.targetGUID) - { - switch(GUID_HIPART(step.targetGUID)) - { - case HIGHGUID_UNIT: - target = HashMapHolder::Find(step.targetGUID); - break; - case HIGHGUID_PET: - target = HashMapHolder::Find(step.targetGUID); - break; - case HIGHGUID_PLAYER: // empty GUID case also - target = HashMapHolder::Find(step.targetGUID); - break; - case HIGHGUID_GAMEOBJECT: - target = HashMapHolder::Find(step.targetGUID); - break; - case HIGHGUID_CORPSE: - target = HashMapHolder::Find(step.targetGUID); - break; - default: - sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID)); - break; - } - } - - switch (step.script->command) - { - case SCRIPT_COMMAND_TALK: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature."); - break; - } - - if(source->GetTypeId()!=TYPEID_UNIT) - { - sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - if(step.script->datalong > 3) - { - sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong); - break; - } - - uint64 unit_target = target ? target->GetGUID() : 0; - - //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text - switch(step.script->datalong) - { - case 0: // Say - ((Creature *)source)->Say(step.script->datatext.c_str(), LANG_UNIVERSAL, unit_target); - break; - case 1: // Whisper - if(!unit_target) - { - sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong); - break; - } - ((Creature *)source)->Whisper(step.script->datatext.c_str(),unit_target); - break; - case 2: // Yell - ((Creature *)source)->Yell(step.script->datatext.c_str(), LANG_UNIVERSAL, unit_target); - break; - case 3: // Emote text - ((Creature *)source)->TextEmote(step.script->datatext.c_str(), unit_target); - break; - default: - break; // must be already checked at load - } - break; - } - - case SCRIPT_COMMAND_EMOTE: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature."); - break; - } - - if(source->GetTypeId()!=TYPEID_UNIT) - { - sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - ((Creature *)source)->HandleEmoteCommand(step.script->datalong); - break; - case SCRIPT_COMMAND_FIELD_SET: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object."); - break; - } - if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).", - step.script->datalong,source->GetValuesCount(),source->GetTypeId()); - break; - } - - source->SetUInt32Value(step.script->datalong, step.script->datalong2); - break; - case SCRIPT_COMMAND_MOVE_TO: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature."); - break; - } - - if(source->GetTypeId()!=TYPEID_UNIT) - { - sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, ((Unit *)source)->GetUnitMovementFlags(), step.script->datalong2 ); - MapManager::Instance().GetMap(((Unit *)source)->GetMapId(), ((Unit *)source))->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0); - break; - case SCRIPT_COMMAND_FLAG_SET: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object."); - break; - } - if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).", - step.script->datalong,source->GetValuesCount(),source->GetTypeId()); - break; - } - - source->SetFlag(step.script->datalong, step.script->datalong2); - break; - case SCRIPT_COMMAND_FLAG_REMOVE: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object."); - break; - } - if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).", - step.script->datalong,source->GetValuesCount(),source->GetTypeId()); - break; - } - - source->RemoveFlag(step.script->datalong, step.script->datalong2); - break; - - case SCRIPT_COMMAND_TELEPORT_TO: - { - // accept player in any one from target/source arg - if (!target && !source) - { - sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object."); - break; - } - - // must be only Player - if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER)) - { - sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); - break; - } - - Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source; - - pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o); - break; - } - - case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: - { - if(!step.script->datalong) // creature not specified - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature."); - break; - } - - if(!source) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object."); - break; - } - - WorldObject* summoner = dynamic_cast(source); - - if(!summoner) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - float x = step.script->x; - float y = step.script->y; - float z = step.script->z; - float o = step.script->o; - - Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2); - if (!pCreature) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong); - break; - } - - break; - } - - case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: - { - if(!step.script->datalong) // gameobject not specified - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject."); - break; - } - - if(!source) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object."); - break; - } - - WorldObject* summoner = dynamic_cast(source); - - if(!summoner) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - GameObject *go = NULL; - int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2; - - CellPair p(MaNGOS::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - MaNGOS::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong); - MaNGOS::GameObjectSearcher checker(go,go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(summoner->GetMapId(), summoner)); - - if ( !go ) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong); - break; - } - - if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE || - go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE || - go->GetGoType()==GAMEOBJECT_TYPE_DOOR || - go->GetGoType()==GAMEOBJECT_TYPE_BUTTON || - go->GetGoType()==GAMEOBJECT_TYPE_TRAP ) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong); - break; - } - - if( go->isSpawned() ) - break; //gameobject already spawned - - go->SetLootState(GO_READY); - go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds - - MapManager::Instance().GetMap(go->GetMapId(), go)->Add(go); - break; - } - case SCRIPT_COMMAND_OPEN_DOOR: - { - if(!step.script->datalong) // door not specified - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door."); - break; - } - - if(!source) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit."); - break; - } - - if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - Unit* caster = (Unit*)source; - - GameObject *door = NULL; - int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; - - CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong); - MaNGOS::GameObjectSearcher checker(door,go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source)); - - if ( !door ) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong); - break; - } - if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR ) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType()); - break; - } - - if( !door->GetGoState() ) - break; //door already open - - door->UseDoorOrButton(time_to_close); - - if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON) - ((GameObject*)target)->UseDoorOrButton(time_to_close); - break; - } - case SCRIPT_COMMAND_CLOSE_DOOR: - { - if(!step.script->datalong) // guid for door not specified - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door."); - break; - } - - if(!source) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit."); - break; - } - - if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - Unit* caster = (Unit*)source; - - GameObject *door = NULL; - int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; - - CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong); - MaNGOS::GameObjectSearcher checker(door,go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source)); - - if ( !door ) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong); - break; - } - if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR ) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType()); - break; - } - - if( door->GetGoState() ) - break; //door already closed - - door->UseDoorOrButton(time_to_open); - - if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON) - ((GameObject*)target)->UseDoorOrButton(time_to_open); - - break; - } - case SCRIPT_COMMAND_QUEST_EXPLORED: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source."); - break; - } - - if(!target) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target."); - break; - } - - // when script called for item spell casting then target == (unit or GO) and source is player - WorldObject* worldObject; - Player* player; - - if(target->GetTypeId()==TYPEID_PLAYER) - { - if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - worldObject = (WorldObject*)source; - player = (Player*)target; - } - else - { - if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId()); - break; - } - - if(source->GetTypeId()!=TYPEID_PLAYER) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - worldObject = (WorldObject*)target; - player = (Player*)source; - } - - // quest id and flags checked at script loading - if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) && - (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) ) - player->AreaExploredOrEventHappens(step.script->datalong); - else - player->FailQuest(step.script->datalong); - - break; - } - - case SCRIPT_COMMAND_ACTIVATE_OBJECT: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster."); - break; - } - - if(!source->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - if(!target) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject."); - break; - } - - if(target->GetTypeId()!=TYPEID_GAMEOBJECT) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId()); - break; - } - - Unit* caster = (Unit*)source; - - GameObject *go = (GameObject*)target; - - go->Use(caster); - break; - } - - case SCRIPT_COMMAND_REMOVE_AURA: - { - Object* cmdTarget = step.script->datalong2 ? source : target; - - if(!cmdTarget) - { - sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target"); - break; - } - - if(!cmdTarget->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId()); - break; - } - - ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong); - break; - } - - case SCRIPT_COMMAND_CAST_SPELL: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster."); - break; - } - - if(!source->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - Object* cmdTarget = step.script->datalong2 ? source : target; - - if(!cmdTarget) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 ? "source" : "target"); - break; - } - - if(!cmdTarget->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId()); - break; - } - - Unit* spellTarget = (Unit*)cmdTarget; - - //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast - ((Unit*)source)->CastSpell(spellTarget,step.script->datalong,false); - - break; - } - - default: - sLog.outError("Unknown script command %u called.",step.script->command); - break; - } - - m_scriptSchedule.erase(iter); - - iter = m_scriptSchedule.begin(); - } - return; -} - -/// Send a packet to all players (except self if mentioned) -void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team) -{ - SessionMap::iterator itr; - for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++) - { - if (itr->second && - itr->second->GetPlayer() && - itr->second->GetPlayer()->IsInWorld() && - itr->second != self && - (team == 0 || itr->second->GetPlayer()->GetTeam() == team) ) - { - itr->second->SendPacket(packet); - } - } -} - -/// Send a System Message to all players (except self if mentioned) -void World::SendWorldText(int32 string_id, ...) -{ - std::vector > data_cache; // 0 = default, i => i-1 locale index - - for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) - { - if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() ) - continue; - - uint32 loc_idx = itr->second->GetSessionDbLocaleIndex(); - uint32 cache_idx = loc_idx+1; - - std::vector* data_list; - - // create if not cached yet - if(data_cache.size() < cache_idx+1 || data_cache[cache_idx].empty()) - { - if(data_cache.size() < cache_idx+1) - data_cache.resize(cache_idx+1); - - data_list = &data_cache[cache_idx]; - - char const* text = objmgr.GetMangosString(string_id,loc_idx); - - char buf[1000]; - - va_list argptr; - va_start( argptr, string_id ); - vsnprintf( buf,1000, text, argptr ); - va_end( argptr ); - - char* pos = &buf[0]; - - while(char* line = ChatHandler::LineFromMessage(pos)) - { - WorldPacket* data = new WorldPacket(); - ChatHandler::FillMessageData(data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL); - data_list->push_back(data); - } - } - else - data_list = &data_cache[cache_idx]; - - for(int i = 0; i < data_list->size(); ++i) - itr->second->SendPacket((*data_list)[i]); - } - - // free memory - for(int i = 0; i < data_cache.size(); ++i) - for(int j = 0; j < data_cache[i].size(); ++j) - delete data_cache[i][j]; -} - -/// Send a packet to all players (or players selected team) in the zone (except self if mentioned) -void World::SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self, uint32 team) -{ - SessionMap::iterator itr; - for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++) - { - if (itr->second && - itr->second->GetPlayer() && - itr->second->GetPlayer()->IsInWorld() && - itr->second->GetPlayer()->GetZoneId() == zone && - itr->second != self && - (team == 0 || itr->second->GetPlayer()->GetTeam() == team) ) - { - itr->second->SendPacket(packet); - } - } -} - -/// Send a System Message to all players in the zone (except self if mentioned) -void World::SendZoneText(uint32 zone, const char* text, WorldSession *self, uint32 team) -{ - WorldPacket data; - ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, text, NULL); - SendZoneMessage(zone, &data, self,team); -} - -/// Kick (and save) all players -void World::KickAll() -{ - // session not removed at kick and will removed in next update tick - for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) - itr->second->KickPlayer(); -} - -/// Kick (and save) all players with security level less `sec` -void World::KickAllLess(AccountTypes sec) -{ - // session not removed at kick and will removed in next update tick - for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) - if(itr->second->GetSecurity() < sec) - itr->second->KickPlayer(); -} - -/// Kick all queued players -void World::KickAllQueued() -{ - // session not removed at kick and will removed in next update tick - for (Queue::iterator itr = m_QueuedPlayer.begin(); itr != m_QueuedPlayer.end(); ++itr) - if(WorldSession* session = (*itr)->GetSession()) - session->KickPlayer(); - - m_QueuedPlayer.empty(); -} - -/// Kick (and save) the designated player -bool World::KickPlayer(std::string playerName) -{ - SessionMap::iterator itr; - - // session not removed at kick and will removed in next update tick - for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) - { - if(!itr->second) - continue; - Player *player = itr->second->GetPlayer(); - if(!player) - continue; - if( player->IsInWorld() ) - { - if (playerName == player->GetName()) - { - itr->second->KickPlayer(); - return true; - } - } - } - return false; -} - -/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban -uint8 World::BanAccount(std::string type, std::string nameOrIP, std::string duration, std::string reason, std::string author) -{ - loginDatabase.escape_string(nameOrIP); - loginDatabase.escape_string(reason); - std::string safe_author=author; - loginDatabase.escape_string(safe_author); - - if(type != "ip" && !normalizePlayerName(nameOrIP)) - return BAN_NOTFOUND; // Nobody to ban - - uint32 duration_secs = TimeStringToSecs(duration); - QueryResult *resultAccounts = NULL; //used for kicking - - ///- Update the database with ban information - - if(type=="ip") - { - //No SQL injection as strings are escaped - resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str()); - loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str()); - } - else if(type=="account") - { - //No SQL injection as string is escaped - resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str()); - } - else if(type=="character") - { - //No SQL injection as string is escaped - resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str()); - } - else - return BAN_SYNTAX_ERROR; //Syntax problem - - if(!resultAccounts) - if(type=="ip") - return BAN_SUCCESS; // ip correctly banned but nobody affected (yet) - else - return BAN_NOTFOUND; // Nobody to ban - - ///- Disconnect all affected players (for IP it can be several) - do - { - Field* fieldsAccount = resultAccounts->Fetch(); - uint32 account = fieldsAccount->GetUInt32(); - - if(type != "ip") - //No SQL injection as strings are escaped - loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')", - account,duration_secs,safe_author.c_str(),reason.c_str()); - - WorldSession* sess = FindSession(account); - if( sess ) - if(std::string(sess->GetPlayerName()) != author) - sess->KickPlayer(); - } - while( resultAccounts->NextRow() ); - - delete resultAccounts; - return BAN_SUCCESS; -} - -/// Remove a ban from an account or IP address -bool World::RemoveBanAccount(std::string type, std::string nameOrIP) -{ - if(type == "ip") - { - loginDatabase.escape_string(nameOrIP); - loginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str()); - } - else - { - uint32 account=0; - if(type == "account") - { - //NO SQL injection as name is escaped - loginDatabase.escape_string(nameOrIP); - QueryResult *resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str()); - if(!resultAccounts) - return false; - Field* fieldsAccount = resultAccounts->Fetch(); - account = fieldsAccount->GetUInt32(); - - delete resultAccounts; - } - else if(type == "character") - { - if(!normalizePlayerName(nameOrIP)) - return false; - - //NO SQL injection as name is escaped - loginDatabase.escape_string(nameOrIP); - QueryResult *resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str()); - if(!resultAccounts) - return false; - Field* fieldsAccount = resultAccounts->Fetch(); - account = fieldsAccount->GetUInt32(); - - delete resultAccounts; - } - if(!account) - return false; - //NO SQL injection as account is uint32 - loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account); - } - return true; -} - -/// Update the game time -void World::_UpdateGameTime() -{ - ///- update the time - time_t thisTime = time(NULL); - uint32 elapsed = uint32(thisTime - m_gameTime); - m_gameTime = thisTime; - - ///- if there is a shutdown timer - if(m_ShutdownTimer > 0 && elapsed > 0) - { - ///- ... and it is overdue, stop the world (set m_stopEvent) - if( m_ShutdownTimer <= elapsed ) - { - if(!(m_ShutdownMask & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0) - m_stopEvent = true; - else - m_ShutdownTimer = 1; // minimum timer value to wait idle state - } - ///- ... else decrease it and if necessary display a shutdown countdown to the users - else - { - m_ShutdownTimer -= elapsed; - - ShutdownMsg(); - } - } -} - -/// Shutdown the server -void World::ShutdownServ(uint32 time, uint32 options) -{ - m_ShutdownMask = options; - - ///- If the shutdown time is 0, set m_stopEvent (except if shutdown is 'idle' with remaining sessions) - if(time==0) - { - if(!(options & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0) - m_stopEvent = true; - else - m_ShutdownTimer = 1; //So that the session count is re-evaluated at next world tick - } - ///- Else set the shutdown timer and warn users - else - { - m_ShutdownTimer = time; - ShutdownMsg(true); - } -} - -/// Display a shutdown message to the user(s) -void World::ShutdownMsg(bool show, Player* player) -{ - // not show messages for idle shutdown mode - if(m_ShutdownMask & SHUTDOWN_MASK_IDLE) - return; - - ///- Display a message every 12 hours, hours, 5 minutes, minute, 5 seconds and finally seconds - if ( show || - (m_ShutdownTimer < 10) || - // < 30 sec; every 5 sec - (m_ShutdownTimer<30 && (m_ShutdownTimer % 5 )==0) || - // < 5 min ; every 1 min - (m_ShutdownTimer<5*MINUTE && (m_ShutdownTimer % MINUTE )==0) || - // < 30 min ; every 5 min - (m_ShutdownTimer<30*MINUTE && (m_ShutdownTimer % (5*MINUTE))==0) || - // < 12 h ; every 1 h - (m_ShutdownTimer<12*HOUR && (m_ShutdownTimer % HOUR )==0) || - // > 12 h ; every 12 h - (m_ShutdownTimer>12*HOUR && (m_ShutdownTimer % (12*HOUR) )==0)) - { - std::string str = secsToTimeString(m_ShutdownTimer); - - uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME; - - SendServerMessage(msgid,str.c_str(),player); - DEBUG_LOG("Server is %s in %s",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"),str.c_str()); - } -} - -/// Cancel a planned server shutdown -void World::ShutdownCancel() -{ - if(!m_ShutdownTimer) - return; - - uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED; - - m_ShutdownMask = 0; - m_ShutdownTimer = 0; - SendServerMessage(msgid); - - DEBUG_LOG("Server %s cancelled.",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown")); -} - -/// Send a server message to the user(s) -void World::SendServerMessage(uint32 type, const char *text, Player* player) -{ - WorldPacket data(SMSG_SERVER_MESSAGE, 50); // guess size - data << uint32(type); - if(type <= SERVER_MSG_STRING) - data << text; - - if(player) - player->GetSession()->SendPacket(&data); - else - SendGlobalMessage( &data ); -} - -void World::UpdateSessions( time_t diff ) -{ - ///- Delete kicked sessions at add new session - for (std::set::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr) - delete *itr; - m_kicked_sessions.clear(); - - ///- Then send an update signal to remaining ones - for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next) - { - next = itr; - ++next; - - if(!itr->second) - continue; - - ///- and remove not active sessions from the list - if(!itr->second->Update(diff)) // As interval = 0 - { - delete itr->second; - m_sessions.erase(itr); - } - } -} - -// This handles the issued and queued CLI commands -void World::ProcessCliCommands() -{ - if (cliCmdQueue.empty()) return; - - CliCommandHolder *command; - pPrintf p_zprintf; - while (!cliCmdQueue.empty()) - { - sLog.outDebug("CLI command under processing..."); - command = cliCmdQueue.next(); - command->Execute(); - p_zprintf=command->GetOutputMethod(); - delete command; - } - // print the console message here so it looks right - p_zprintf("mangos>"); -} - -void World::InitResultQueue() -{ - m_resultQueue = new SqlResultQueue; - CharacterDatabase.SetResultQueue(m_resultQueue); -} - -void World::UpdateResultQueue() -{ - m_resultQueue->Update(); -} - -void World::UpdateRealmCharCount(uint32 accountId) -{ - CharacterDatabase.AsyncPQuery(this, &World::_UpdateRealmCharCount, accountId, - "SELECT COUNT(guid) FROM characters WHERE account = '%u'", accountId); -} - -void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId) -{ - if (resultCharCount) - { - Field *fields = resultCharCount->Fetch(); - uint32 charCount = fields[0].GetUInt32(); - delete resultCharCount; - loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID); - loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID); - } -} - -void World::InitDailyQuestResetTime() -{ - time_t mostRecentQuestTime; - - QueryResult* result = CharacterDatabase.Query("SELECT MAX(time) FROM character_queststatus_daily"); - if(result) - { - Field *fields = result->Fetch(); - - mostRecentQuestTime = (time_t)fields[0].GetUInt64(); - delete result; - } - else - mostRecentQuestTime = 0; - - // client built-in time for reset is 6:00 AM - // FIX ME: client not show day start time - time_t curTime = time(NULL); - tm localTm = *localtime(&curTime); - localTm.tm_hour = 6; - localTm.tm_min = 0; - localTm.tm_sec = 0; - - // current day reset time - time_t curDayResetTime = mktime(&localTm); - - // last reset time before current moment - time_t resetTime = (curTime < curDayResetTime) ? curDayResetTime - DAY : curDayResetTime; - - // need reset (if we have quest time before last reset time (not processed by some reason) - if(mostRecentQuestTime && mostRecentQuestTime <= resetTime) - m_NextDailyQuestReset = mostRecentQuestTime; - else - { - // plan next reset time - m_NextDailyQuestReset = (curTime >= curDayResetTime) ? curDayResetTime + DAY : curDayResetTime; - } -} - -void World::ResetDailyQuests() -{ - sLog.outDetail("Daily quests reset for all characters."); - CharacterDatabase.Execute("DELETE FROM character_queststatus_daily"); - for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) - if(itr->second->GetPlayer()) - itr->second->GetPlayer()->ResetDailyQuestStatus(); -} - -void World::SetPlayerLimit( int32 limit, bool needUpdate ) -{ - if(limit < -SEC_ADMINISTRATOR) - limit = -SEC_ADMINISTRATOR; - - // lock update need - bool db_update_need = needUpdate || (limit < 0) != (m_playerLimit < 0) || (limit < 0 && m_playerLimit < 0 && limit != m_playerLimit); - - m_playerLimit = limit; - - if(db_update_need) - loginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID); -} - -void World::UpdateMaxSessionCounters() -{ - m_maxActiveSessionCount = std::max(m_maxActiveSessionCount,uint32(m_sessions.size()-m_QueuedPlayer.size())); - m_maxQueuedSessionCount = std::max(m_maxQueuedSessionCount,uint32(m_QueuedPlayer.size())); -} +/* + * Copyright (C) 2005-2008 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 + */ + +/** \file + \ingroup world +*/ + +#include "Common.h" +//#include "WorldSocket.h" +#include "Database/DatabaseEnv.h" +#include "Config/ConfigEnv.h" +#include "SystemConfig.h" +#include "Log.h" +#include "Opcodes.h" +#include "WorldSession.h" +#include "WorldPacket.h" +#include "Weather.h" +#include "Player.h" +#include "SkillExtraItems.h" +#include "SkillDiscovery.h" +#include "World.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Chat.h" +#include "Database/DBCStores.h" +#include "LootMgr.h" +#include "ItemEnchantmentMgr.h" +#include "MapManager.h" +#include "ScriptCalls.h" +#include "CreatureAIRegistry.h" +#include "Policies/SingletonImp.h" +#include "BattleGroundMgr.h" +#include "TemporarySummon.h" +#include "WaypointMovementGenerator.h" +#include "VMapFactory.h" +#include "GlobalEvents.h" +#include "GameEvent.h" +#include "Database/DatabaseImpl.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "InstanceSaveMgr.h" +#include "WaypointManager.h" +#include "Util.h" + +INSTANTIATE_SINGLETON_1( World ); + +volatile bool World::m_stopEvent = false; +volatile uint32 World::m_worldLoopCounter = 0; + +float World::m_MaxVisibleDistanceForCreature = DEFAULT_VISIBILITY_DISTANCE; +float World::m_MaxVisibleDistanceForPlayer = DEFAULT_VISIBILITY_DISTANCE; +float World::m_MaxVisibleDistanceForObject = DEFAULT_VISIBILITY_DISTANCE; +float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE; +float World::m_VisibleUnitGreyDistance = 0; +float World::m_VisibleObjectGreyDistance = 0; + +// ServerMessages.dbc +enum ServerMessageType +{ + SERVER_MSG_SHUTDOWN_TIME = 1, + SERVER_MSG_RESTART_TIME = 2, + SERVER_MSG_STRING = 3, + SERVER_MSG_SHUTDOWN_CANCELLED = 4, + SERVER_MSG_RESTART_CANCELLED = 5 +}; + +struct ScriptAction +{ + uint64 sourceGUID; + uint64 targetGUID; + uint64 ownerGUID; // owner of source if source is item + ScriptInfo const* script; // pointer to static script data +}; + +/// World constructor +World::World() +{ + m_playerLimit = 0; + m_allowMovement = true; + m_ShutdownMask = 0; + m_ShutdownTimer = 0; + m_gameTime=time(NULL); + m_startTime=m_gameTime; + m_maxActiveSessionCount = 0; + m_maxQueuedSessionCount = 0; + m_resultQueue = NULL; + m_NextDailyQuestReset = 0; + + m_defaultDbcLocale = LOCALE_enUS; + m_availableDbcLocaleMask = 0; +} + +/// World destructor +World::~World() +{ + ///- Empty the kicked session set + for (std::set::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr) + delete *itr; + + m_kicked_sessions.clear(); + + ///- Empty the WeatherMap + for (WeatherMap::iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr) + delete itr->second; + + m_weathers.clear(); + + VMAP::VMapFactory::clear(); + + if(m_resultQueue) delete m_resultQueue; + + //TODO free addSessQueue +} + +/// Find a player in a specified zone +Player* World::FindPlayerInZone(uint32 zone) +{ + ///- circle through active sessions and return the first player found in the zone + SessionMap::iterator itr; + for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + { + if(!itr->second) + continue; + Player *player = itr->second->GetPlayer(); + if(!player) + continue; + if( player->IsInWorld() && player->GetZoneId() == zone ) + { + // Used by the weather system. We return the player to broadcast the change weather message to him and all players in the zone. + return player; + } + } + return NULL; +} + +/// Find a session by its id +WorldSession* World::FindSession(uint32 id) const +{ + SessionMap::const_iterator itr = m_sessions.find(id); + + if(itr != m_sessions.end()) + return itr->second; // also can return NULL for kicked session + else + return NULL; +} + +/// Remove a given session +bool World::RemoveSession(uint32 id) +{ + ///- Find the session, kick the user, but we can't delete session at this moment to prevent iterator invalidation + SessionMap::iterator itr = m_sessions.find(id); + + if(itr != m_sessions.end() && itr->second) + { + if (itr->second->PlayerLoading()) + return false; + itr->second->KickPlayer(); + } + + return true; +} + +void World::AddSession(WorldSession* s) +{ + addSessQueue.add(s); +} + +void +World::AddSession_ (WorldSession* s) +{ + ASSERT (s); + + //NOTE - Still there is race condition in WorldSession* being used in the Sockets + + ///- kick already loaded player with same account (if any) and remove session + ///- if player is in loading and want to load again, return + if (!RemoveSession (s->GetAccountId ())) + { + s->KickPlayer (); + m_kicked_sessions.insert (s); + return; + } + + WorldSession* old = m_sessions[s->GetAccountId ()]; + m_sessions[s->GetAccountId ()] = s; + + // if session already exist, prepare to it deleting at next world update + // NOTE - KickPlayer() should be called on "old" in RemoveSession() + if (old) + m_kicked_sessions.insert (old); + + uint32 Sessions = GetActiveAndQueuedSessionCount (); + uint32 pLimit = GetPlayerAmountLimit (); + uint32 QueueSize = GetQueueSize (); //number of players in the queue + bool inQueue = false; + //so we don't count the user trying to + //login as a session and queue the socket that we are using + --Sessions; + + if (pLimit > 0 && Sessions >= pLimit && s->GetSecurity () == SEC_PLAYER ) + { + AddQueuedPlayer (s); + UpdateMaxSessionCounters (); + sLog.outDetail ("PlayerQueue: Account id %u is in Queue Position (%u).", s->GetAccountId (), ++QueueSize); + return; + } + + WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1); + packet << uint8 (AUTH_OK); + packet << uint32 (0); // unknown random value... + packet << uint8 (0); + packet << uint32 (0); + packet << uint8 (s->IsTBC () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account + s->SendPacket (&packet); + + UpdateMaxSessionCounters (); + + // Updates the population + if (pLimit > 0) + { + float popu = GetActiveSessionCount (); //updated number of users on the server + popu /= pLimit; + popu *= 2; + loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID); + sLog.outDetail ("Server Population (%f).", popu); + } +} + +int32 World::GetQueuePos(WorldSession* sess) +{ + uint32 position = 1; + + for(Queue::iterator iter = m_QueuedPlayer.begin(); iter != m_QueuedPlayer.end(); ++iter, ++position) + if((*iter) == sess) + return position; + + return 0; +} + +void World::AddQueuedPlayer(WorldSession* sess) +{ + m_QueuedPlayer.push_back (sess); + + // The 1st SMSG_AUTH_RESPONSE needs to contain other info too. + WorldPacket packet (SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1); + packet << uint8 (AUTH_WAIT_QUEUE); + packet << uint32 (0); // unknown random value... + packet << uint8 (0); + packet << uint32 (0); + packet << uint8 (sess->IsTBC () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account + packet << uint32(GetQueuePos (sess)); + sess->SendPacket (&packet); + + //sess->SendAuthWaitQue (GetQueuePos (sess)); +} + +void World::RemoveQueuedPlayer(WorldSession* sess) +{ + // sessions count including queued to remove (if removed_session set) + uint32 sessions = GetActiveSessionCount(); + + uint32 position = 1; + Queue::iterator iter = m_QueuedPlayer.begin(); + + // if session not queued then we need decrease sessions count (Remove socked callet before session removing from session list) + bool decrease_session = true; + + // search to remove and count skipped positions + for(;iter != m_QueuedPlayer.end(); ++iter, ++position) + { + if(*iter==sess) + { + Queue::iterator iter2 = iter; + ++iter; + m_QueuedPlayer.erase(iter2); + decrease_session = false; // removing queued session + break; + } + } + + // iter point to next socked after removed or end() + // position store position of removed socket and then new position next socket after removed + + // decrease for case session queued for removing + if(decrease_session && sessions) + --sessions; + + // accept first in queue + if( (!m_playerLimit || sessions < m_playerLimit) && !m_QueuedPlayer.empty() ) + { + WorldSession * socket = m_QueuedPlayer.front(); + socket->SendAuthWaitQue(0); + m_QueuedPlayer.pop_front(); + + // update iter to point first queued socket or end() if queue is empty now + iter = m_QueuedPlayer.begin(); + position = 1; + } + + // update position from iter to end() + // iter point to first not updated socket, position store new position + for(; iter != m_QueuedPlayer.end(); ++iter, ++position) + (*iter)->SendAuthWaitQue(position); +} + +/// Find a Weather object by the given zoneid +Weather* World::FindWeather(uint32 id) const +{ + WeatherMap::const_iterator itr = m_weathers.find(id); + + if(itr != m_weathers.end()) + return itr->second; + else + return 0; +} + +/// Remove a Weather object for the given zoneid +void World::RemoveWeather(uint32 id) +{ + // not called at the moment. Kept for completeness + WeatherMap::iterator itr = m_weathers.find(id); + + if(itr != m_weathers.end()) + { + delete itr->second; + m_weathers.erase(itr); + } +} + +/// Add a Weather object to the list +Weather* World::AddWeather(uint32 zone_id) +{ + WeatherZoneChances const* weatherChances = objmgr.GetWeatherChances(zone_id); + + // zone not have weather, ignore + if(!weatherChances) + return NULL; + + Weather* w = new Weather(zone_id,weatherChances); + m_weathers[w->GetZone()] = w; + w->ReGenerate(); + w->UpdateWeather(); + return w; +} + +/// Initialize config values +void World::LoadConfigSettings(bool reload) +{ + if(reload) + { + if(!sConfig.Reload()) + { + sLog.outError("World settings reload fail: can't read settings from %s.",sConfig.GetFilename().c_str()); + return; + } + //TODO Check if config is outdated + } + + ///- Read the player limit and the Message of the day from the config file + SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT), true ); + SetMotd( sConfig.GetStringDefault("Motd", "Welcome to the Massive Network Game Object Server." ) ); + + ///- Read all rates from the config file + rate_values[RATE_HEALTH] = sConfig.GetFloatDefault("Rate.Health", 1); + if(rate_values[RATE_HEALTH] < 0) + { + sLog.outError("Rate.Health (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_HEALTH]); + rate_values[RATE_HEALTH] = 1; + } + rate_values[RATE_POWER_MANA] = sConfig.GetFloatDefault("Rate.Mana", 1); + if(rate_values[RATE_POWER_MANA] < 0) + { + sLog.outError("Rate.Mana (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_POWER_MANA]); + rate_values[RATE_POWER_MANA] = 1; + } + rate_values[RATE_POWER_RAGE_INCOME] = sConfig.GetFloatDefault("Rate.Rage.Income", 1); + rate_values[RATE_POWER_RAGE_LOSS] = sConfig.GetFloatDefault("Rate.Rage.Loss", 1); + if(rate_values[RATE_POWER_RAGE_LOSS] < 0) + { + sLog.outError("Rate.Rage.Loss (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_POWER_RAGE_LOSS]); + rate_values[RATE_POWER_RAGE_LOSS] = 1; + } + rate_values[RATE_POWER_FOCUS] = sConfig.GetFloatDefault("Rate.Focus", 1.0f); + rate_values[RATE_LOYALTY] = sConfig.GetFloatDefault("Rate.Loyalty", 1.0f); + rate_values[RATE_SKILL_DISCOVERY] = sConfig.GetFloatDefault("Rate.Skill.Discovery", 1.0f); + rate_values[RATE_DROP_ITEM_POOR] = sConfig.GetFloatDefault("Rate.Drop.Item.Poor", 1.0f); + rate_values[RATE_DROP_ITEM_NORMAL] = sConfig.GetFloatDefault("Rate.Drop.Item.Normal", 1.0f); + rate_values[RATE_DROP_ITEM_UNCOMMON] = sConfig.GetFloatDefault("Rate.Drop.Item.Uncommon", 1.0f); + rate_values[RATE_DROP_ITEM_RARE] = sConfig.GetFloatDefault("Rate.Drop.Item.Rare", 1.0f); + rate_values[RATE_DROP_ITEM_EPIC] = sConfig.GetFloatDefault("Rate.Drop.Item.Epic", 1.0f); + rate_values[RATE_DROP_ITEM_LEGENDARY] = sConfig.GetFloatDefault("Rate.Drop.Item.Legendary", 1.0f); + rate_values[RATE_DROP_ITEM_ARTIFACT] = sConfig.GetFloatDefault("Rate.Drop.Item.Artifact", 1.0f); + rate_values[RATE_DROP_ITEM_REFERENCED] = sConfig.GetFloatDefault("Rate.Drop.Item.Referenced", 1.0f); + rate_values[RATE_DROP_MONEY] = sConfig.GetFloatDefault("Rate.Drop.Money", 1.0f); + rate_values[RATE_XP_KILL] = sConfig.GetFloatDefault("Rate.XP.Kill", 1.0f); + rate_values[RATE_XP_QUEST] = sConfig.GetFloatDefault("Rate.XP.Quest", 1.0f); + rate_values[RATE_XP_EXPLORE] = sConfig.GetFloatDefault("Rate.XP.Explore", 1.0f); + rate_values[RATE_XP_PAST_70] = sConfig.GetFloatDefault("Rate.XP.PastLevel70", 1.0f); + rate_values[RATE_REPUTATION_GAIN] = sConfig.GetFloatDefault("Rate.Reputation.Gain", 1.0f); + rate_values[RATE_CREATURE_NORMAL_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Normal.Damage", 1.0f); + rate_values[RATE_CREATURE_ELITE_ELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.Damage", 1.0f); + rate_values[RATE_CREATURE_ELITE_RAREELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.Damage", 1.0f); + rate_values[RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.Damage", 1.0f); + rate_values[RATE_CREATURE_ELITE_RARE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.Damage", 1.0f); + rate_values[RATE_CREATURE_NORMAL_HP] = sConfig.GetFloatDefault("Rate.Creature.Normal.HP", 1.0f); + rate_values[RATE_CREATURE_ELITE_ELITE_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.HP", 1.0f); + rate_values[RATE_CREATURE_ELITE_RAREELITE_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.HP", 1.0f); + rate_values[RATE_CREATURE_ELITE_WORLDBOSS_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.HP", 1.0f); + rate_values[RATE_CREATURE_ELITE_RARE_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.HP", 1.0f); + rate_values[RATE_CREATURE_NORMAL_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Normal.SpellDamage", 1.0f); + rate_values[RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.SpellDamage", 1.0f); + rate_values[RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.SpellDamage", 1.0f); + rate_values[RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.SpellDamage", 1.0f); + rate_values[RATE_CREATURE_ELITE_RARE_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.SpellDamage", 1.0f); + rate_values[RATE_CREATURE_AGGRO] = sConfig.GetFloatDefault("Rate.Creature.Aggro", 1.0f); + rate_values[RATE_REST_INGAME] = sConfig.GetFloatDefault("Rate.Rest.InGame", 1.0f); + rate_values[RATE_REST_OFFLINE_IN_TAVERN_OR_CITY] = sConfig.GetFloatDefault("Rate.Rest.Offline.InTavernOrCity", 1.0f); + rate_values[RATE_REST_OFFLINE_IN_WILDERNESS] = sConfig.GetFloatDefault("Rate.Rest.Offline.InWilderness", 1.0f); + rate_values[RATE_DAMAGE_FALL] = sConfig.GetFloatDefault("Rate.Damage.Fall", 1.0f); + rate_values[RATE_AUCTION_TIME] = sConfig.GetFloatDefault("Rate.Auction.Time", 1.0f); + rate_values[RATE_AUCTION_DEPOSIT] = sConfig.GetFloatDefault("Rate.Auction.Deposit", 1.0f); + rate_values[RATE_AUCTION_CUT] = sConfig.GetFloatDefault("Rate.Auction.Cut", 1.0f); + rate_values[RATE_HONOR] = sConfig.GetFloatDefault("Rate.Honor",1.0f); + rate_values[RATE_MINING_AMOUNT] = sConfig.GetFloatDefault("Rate.Mining.Amount",1.0f); + rate_values[RATE_MINING_NEXT] = sConfig.GetFloatDefault("Rate.Mining.Next",1.0f); + rate_values[RATE_INSTANCE_RESET_TIME] = sConfig.GetFloatDefault("Rate.InstanceResetTime",1.0f); + rate_values[RATE_TALENT] = sConfig.GetFloatDefault("Rate.Talent",1.0f); + if(rate_values[RATE_TALENT] < 0.0f) + { + sLog.outError("Rate.Talent (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_TALENT]); + rate_values[RATE_TALENT] = 1.0f; + } + rate_values[RATE_CORPSE_DECAY_LOOTED] = sConfig.GetFloatDefault("Rate.Corpse.Decay.Looted",0.1f); + + rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = sConfig.GetFloatDefault("TargetPosRecalculateRange",1.5f); + if(rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] < CONTACT_DISTANCE) + { + sLog.outError("TargetPosRecalculateRange (%f) must be >= %f. Using %f instead.",rate_values[RATE_TARGET_POS_RECALCULATION_RANGE],CONTACT_DISTANCE,CONTACT_DISTANCE); + rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = CONTACT_DISTANCE; + } + else if(rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] > ATTACK_DISTANCE) + { + sLog.outError("TargetPosRecalculateRange (%f) must be <= %f. Using %f instead.",rate_values[RATE_TARGET_POS_RECALCULATION_RANGE],ATTACK_DISTANCE,ATTACK_DISTANCE); + rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = ATTACK_DISTANCE; + } + + rate_values[RATE_DURABILITY_LOSS_DAMAGE] = sConfig.GetFloatDefault("DurabilityLossChance.Damage",0.5f); + if(rate_values[RATE_DURABILITY_LOSS_DAMAGE] < 0.0f) + { + sLog.outError("DurabilityLossChance.Damage (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_DAMAGE]); + rate_values[RATE_DURABILITY_LOSS_DAMAGE] = 0.0f; + } + rate_values[RATE_DURABILITY_LOSS_ABSORB] = sConfig.GetFloatDefault("DurabilityLossChance.Absorb",0.5f); + if(rate_values[RATE_DURABILITY_LOSS_ABSORB] < 0.0f) + { + sLog.outError("DurabilityLossChance.Absorb (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ABSORB]); + rate_values[RATE_DURABILITY_LOSS_ABSORB] = 0.0f; + } + rate_values[RATE_DURABILITY_LOSS_PARRY] = sConfig.GetFloatDefault("DurabilityLossChance.Parry",0.05f); + if(rate_values[RATE_DURABILITY_LOSS_PARRY] < 0.0f) + { + sLog.outError("DurabilityLossChance.Parry (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_PARRY]); + rate_values[RATE_DURABILITY_LOSS_PARRY] = 0.0f; + } + rate_values[RATE_DURABILITY_LOSS_BLOCK] = sConfig.GetFloatDefault("DurabilityLossChance.Block",0.05f); + if(rate_values[RATE_DURABILITY_LOSS_BLOCK] < 0.0f) + { + sLog.outError("DurabilityLossChance.Block (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_BLOCK]); + rate_values[RATE_DURABILITY_LOSS_BLOCK] = 0.0f; + } + + ///- Read other configuration items from the config file + + m_configs[CONFIG_COMPRESSION] = sConfig.GetIntDefault("Compression", 1); + if(m_configs[CONFIG_COMPRESSION] < 1 || m_configs[CONFIG_COMPRESSION] > 9) + { + sLog.outError("Compression level (%i) must be in range 1..9. Using default compression level (1).",m_configs[CONFIG_COMPRESSION]); + m_configs[CONFIG_COMPRESSION] = 1; + } + m_configs[CONFIG_ADDON_CHANNEL] = sConfig.GetBoolDefault("AddonChannel", true); + m_configs[CONFIG_GRID_UNLOAD] = sConfig.GetBoolDefault("GridUnload", true); + m_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 900000); + + m_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfig.GetIntDefault("GridCleanUpDelay", 300000); + if(m_configs[CONFIG_INTERVAL_GRIDCLEAN] < MIN_GRID_DELAY) + { + sLog.outError("GridCleanUpDelay (%i) must be greater %u. Use this minimal value.",m_configs[CONFIG_INTERVAL_GRIDCLEAN],MIN_GRID_DELAY); + m_configs[CONFIG_INTERVAL_GRIDCLEAN] = MIN_GRID_DELAY; + } + if(reload) + MapManager::Instance().SetGridCleanUpDelay(m_configs[CONFIG_INTERVAL_GRIDCLEAN]); + + m_configs[CONFIG_INTERVAL_MAPUPDATE] = sConfig.GetIntDefault("MapUpdateInterval", 100); + if(m_configs[CONFIG_INTERVAL_MAPUPDATE] < MIN_MAP_UPDATE_DELAY) + { + sLog.outError("MapUpdateInterval (%i) must be greater %u. Use this minimal value.",m_configs[CONFIG_INTERVAL_MAPUPDATE],MIN_MAP_UPDATE_DELAY); + m_configs[CONFIG_INTERVAL_MAPUPDATE] = MIN_MAP_UPDATE_DELAY; + } + if(reload) + MapManager::Instance().SetMapUpdateInterval(m_configs[CONFIG_INTERVAL_MAPUPDATE]); + + m_configs[CONFIG_INTERVAL_CHANGEWEATHER] = sConfig.GetIntDefault("ChangeWeatherInterval", 600000); + + if(reload) + { + uint32 val = sConfig.GetIntDefault("WorldServerPort", DEFAULT_WORLDSERVER_PORT); + if(val!=m_configs[CONFIG_PORT_WORLD]) + sLog.outError("WorldServerPort option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_PORT_WORLD]); + } + else + m_configs[CONFIG_PORT_WORLD] = sConfig.GetIntDefault("WorldServerPort", DEFAULT_WORLDSERVER_PORT); + + if(reload) + { + uint32 val = sConfig.GetIntDefault("SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME); + if(val!=m_configs[CONFIG_SOCKET_SELECTTIME]) + sLog.outError("SocketSelectTime option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[DEFAULT_SOCKET_SELECT_TIME]); + } + else + m_configs[CONFIG_SOCKET_SELECTTIME] = sConfig.GetIntDefault("SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME); + + + m_configs[CONFIG_TCP_NO_DELAY] = sConfig.GetBoolDefault("TcpNoDelay", false); + m_configs[CONFIG_GROUP_XP_DISTANCE] = sConfig.GetIntDefault("MaxGroupXPDistance", 74); + /// \todo Add MonsterSight and GuarderSight (with meaning) in mangosd.conf or put them as define + m_configs[CONFIG_SIGHT_MONSTER] = sConfig.GetIntDefault("MonsterSight", 50); + m_configs[CONFIG_SIGHT_GUARDER] = sConfig.GetIntDefault("GuarderSight", 50); + + if(reload) + { + uint32 val = sConfig.GetIntDefault("GameType", 0); + if(val!=m_configs[CONFIG_GAME_TYPE]) + sLog.outError("GameType option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_GAME_TYPE]); + } + else + m_configs[CONFIG_GAME_TYPE] = sConfig.GetIntDefault("GameType", 0); + + if(reload) + { + uint32 val = sConfig.GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT); + if(val!=m_configs[CONFIG_REALM_ZONE]) + sLog.outError("RealmZone option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_REALM_ZONE]); + } + else + m_configs[CONFIG_REALM_ZONE] = sConfig.GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT); + + m_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = sConfig.GetBoolDefault("AllowTwoSide.Accounts", false); + m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Chat",false); + m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Channel",false); + m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Group",false); + m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Guild",false); + m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Auction",false); + m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Mail",false); + m_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfig.GetBoolDefault("AllowTwoSide.WhoList", false); + m_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = sConfig.GetBoolDefault("AllowTwoSide.AddFriend", false); + m_configs[CONFIG_STRICT_PLAYER_NAMES] = sConfig.GetIntDefault("StrictPlayerNames", 0); + m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault("StrictCharterNames", 0); + m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault("StrictPetNames", 0); + + m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault("CharactersCreatingDisabled", 0); + + m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10); + if(m_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_configs[CONFIG_CHARACTERS_PER_REALM] > 10) + { + sLog.outError("CharactersPerRealm (%i) must be in range 1..10. Set to 10.",m_configs[CONFIG_CHARACTERS_PER_REALM]); + m_configs[CONFIG_CHARACTERS_PER_REALM] = 10; + } + + // must be after CONFIG_CHARACTERS_PER_REALM + m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] = sConfig.GetIntDefault("CharactersPerAccount", 50); + if(m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] < m_configs[CONFIG_CHARACTERS_PER_REALM]) + { + sLog.outError("CharactersPerAccount (%i) can't be less than CharactersPerRealm (%i).",m_configs[CONFIG_CHARACTERS_PER_ACCOUNT],m_configs[CONFIG_CHARACTERS_PER_REALM]); + m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] = m_configs[CONFIG_CHARACTERS_PER_REALM]; + } + + m_configs[CONFIG_SKIP_CINEMATICS] = sConfig.GetIntDefault("SkipCinematics", 0); + if(m_configs[CONFIG_SKIP_CINEMATICS] < 0 || m_configs[CONFIG_SKIP_CINEMATICS] > 2) + { + sLog.outError("SkipCinematics (%i) must be in range 0..2. Set to 0.",m_configs[CONFIG_SKIP_CINEMATICS]); + m_configs[CONFIG_SKIP_CINEMATICS] = 0; + } + + + if(reload) + { + uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", 60); + if(val!=m_configs[CONFIG_MAX_PLAYER_LEVEL]) + sLog.outError("MaxPlayerLevel option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_MAX_PLAYER_LEVEL]); + } + else + m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", 60); + if(m_configs[CONFIG_MAX_PLAYER_LEVEL] > 255) + { + sLog.outError("MaxPlayerLevel (%i) must be in range 1..255. Set to 255.",m_configs[CONFIG_MAX_PLAYER_LEVEL]); + m_configs[CONFIG_MAX_PLAYER_LEVEL] = 255; + } + + m_configs[CONFIG_START_PLAYER_LEVEL] = sConfig.GetIntDefault("StartPlayerLevel", 1); + if(m_configs[CONFIG_START_PLAYER_LEVEL] < 1) + { + sLog.outError("StartPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to 1.",m_configs[CONFIG_START_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]); + m_configs[CONFIG_START_PLAYER_LEVEL] = 1; + } + else if(m_configs[CONFIG_START_PLAYER_LEVEL] > m_configs[CONFIG_MAX_PLAYER_LEVEL]) + { + sLog.outError("StartPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to %u.",m_configs[CONFIG_START_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]); + m_configs[CONFIG_START_PLAYER_LEVEL] = m_configs[CONFIG_MAX_PLAYER_LEVEL]; + } + m_configs[CONFIG_MAX_HONOR_POINTS] = sConfig.GetIntDefault("MaxHonorPoints", 75000); + m_configs[CONFIG_MAX_ARENA_POINTS] = sConfig.GetIntDefault("MaxArenaPoints", 5000); + + m_configs[CONFIG_INSTANCE_IGNORE_LEVEL] = sConfig.GetBoolDefault("Instance.IgnoreLevel", false); + m_configs[CONFIG_INSTANCE_IGNORE_RAID] = sConfig.GetBoolDefault("Instance.IgnoreRaid", false); + + m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true); + m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", true); + m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false); + + m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true); + m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4); + m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000); + + m_configs[CONFIG_MAX_PRIMARY_TRADE_SKILL] = sConfig.GetIntDefault("MaxPrimaryTradeSkill", 2); + m_configs[CONFIG_MIN_PETITION_SIGNS] = sConfig.GetIntDefault("MinPetitionSigns", 9); + if(m_configs[CONFIG_MIN_PETITION_SIGNS] > 9) + { + sLog.outError("MinPetitionSigns (%i) must be in range 0..9. Set to 9.",m_configs[CONFIG_MIN_PETITION_SIGNS]); + m_configs[CONFIG_MIN_PETITION_SIGNS] = 9; + } + + m_configs[CONFIG_GM_WISPERING_TO] = sConfig.GetBoolDefault("GM.WhisperingTo",false); + m_configs[CONFIG_GM_IN_GM_LIST] = sConfig.GetBoolDefault("GM.InGMList",false); + m_configs[CONFIG_GM_IN_WHO_LIST] = sConfig.GetBoolDefault("GM.InWhoList",false); + m_configs[CONFIG_GM_LOGIN_STATE] = sConfig.GetIntDefault("GM.LoginState",2); + m_configs[CONFIG_GM_LOG_TRADE] = sConfig.GetBoolDefault("GM.LogTrade", false); + + m_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("Visibility.GroupMode",0); + + m_configs[CONFIG_MAIL_DELIVERY_DELAY] = sConfig.GetIntDefault("MailDeliveryDelay",HOUR); + + m_configs[CONFIG_UPTIME_UPDATE] = sConfig.GetIntDefault("UpdateUptimeInterval", 10); + if(m_configs[CONFIG_UPTIME_UPDATE]<=0) + { + sLog.outError("UpdateUptimeInterval (%i) must be > 0, set to default 10.",m_configs[CONFIG_UPTIME_UPDATE]); + m_configs[CONFIG_UPTIME_UPDATE] = 10; + } + if(reload) + { + m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000); + m_timers[WUPDATE_UPTIME].Reset(); + } + + m_configs[CONFIG_SKILL_CHANCE_ORANGE] = sConfig.GetIntDefault("SkillChance.Orange",100); + m_configs[CONFIG_SKILL_CHANCE_YELLOW] = sConfig.GetIntDefault("SkillChance.Yellow",75); + m_configs[CONFIG_SKILL_CHANCE_GREEN] = sConfig.GetIntDefault("SkillChance.Green",25); + m_configs[CONFIG_SKILL_CHANCE_GREY] = sConfig.GetIntDefault("SkillChance.Grey",0); + + m_configs[CONFIG_SKILL_CHANCE_MINING_STEPS] = sConfig.GetIntDefault("SkillChance.MiningSteps",75); + m_configs[CONFIG_SKILL_CHANCE_SKINNING_STEPS] = sConfig.GetIntDefault("SkillChance.SkinningSteps",75); + + m_configs[CONFIG_SKILL_PROSPECTING] = sConfig.GetBoolDefault("SkillChance.Prospecting",false); + + m_configs[CONFIG_SKILL_GAIN_CRAFTING] = sConfig.GetIntDefault("SkillGain.Crafting", 1); + if(m_configs[CONFIG_SKILL_GAIN_CRAFTING] < 0) + { + sLog.outError("SkillGain.Crafting (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_CRAFTING]); + m_configs[CONFIG_SKILL_GAIN_CRAFTING] = 1; + } + + m_configs[CONFIG_SKILL_GAIN_DEFENSE] = sConfig.GetIntDefault("SkillGain.Defense", 1); + if(m_configs[CONFIG_SKILL_GAIN_DEFENSE] < 0) + { + sLog.outError("SkillGain.Defense (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_DEFENSE]); + m_configs[CONFIG_SKILL_GAIN_DEFENSE] = 1; + } + + m_configs[CONFIG_SKILL_GAIN_GATHERING] = sConfig.GetIntDefault("SkillGain.Gathering", 1); + if(m_configs[CONFIG_SKILL_GAIN_GATHERING] < 0) + { + sLog.outError("SkillGain.Gathering (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_GATHERING]); + m_configs[CONFIG_SKILL_GAIN_GATHERING] = 1; + } + + m_configs[CONFIG_SKILL_GAIN_WEAPON] = sConfig.GetIntDefault("SkillGain.Weapon", 1); + if(m_configs[CONFIG_SKILL_GAIN_WEAPON] < 0) + { + sLog.outError("SkillGain.Weapon (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_WEAPON]); + m_configs[CONFIG_SKILL_GAIN_WEAPON] = 1; + } + + m_configs[CONFIG_MAX_OVERSPEED_PINGS] = sConfig.GetIntDefault("MaxOverspeedPings",2); + if(m_configs[CONFIG_MAX_OVERSPEED_PINGS] != 0 && m_configs[CONFIG_MAX_OVERSPEED_PINGS] < 2) + { + sLog.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check. Set to 2.",m_configs[CONFIG_MAX_OVERSPEED_PINGS]); + m_configs[CONFIG_MAX_OVERSPEED_PINGS] = 2; + } + + m_configs[CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY] = sConfig.GetBoolDefault("SaveRespawnTimeImmediately",true); + m_configs[CONFIG_WEATHER] = sConfig.GetBoolDefault("ActivateWeather",true); + + if(reload) + { + uint32 val = sConfig.GetIntDefault("Expansion",1); + if(val!=m_configs[CONFIG_EXPANSION]) + sLog.outError("Expansion option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_EXPANSION]); + } + else + m_configs[CONFIG_EXPANSION] = sConfig.GetIntDefault("Expansion",1); + + m_configs[CONFIG_CHATFLOOD_MESSAGE_COUNT] = sConfig.GetIntDefault("ChatFlood.MessageCount",10); + m_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = sConfig.GetIntDefault("ChatFlood.MessageDelay",1); + m_configs[CONFIG_CHATFLOOD_MUTE_TIME] = sConfig.GetIntDefault("ChatFlood.MuteTime",10); + + m_configs[CONFIG_EVENT_ANNOUNCE] = sConfig.GetIntDefault("Event.Announce",0); + + m_configs[CONFIG_CREATURE_FAMILY_ASSISTEMCE_RADIUS] = sConfig.GetIntDefault("CreatureFamilyAssistenceRadius",10); + + m_configs[CONFIG_WORLD_BOSS_LEVEL_DIFF] = sConfig.GetIntDefault("WorldBossLevelDiff",3); + + // note: disable value (-1) will assigned as 0xFFFFFFF, to prevent overflow at calculations limit it to max possible player level (255) + m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] = sConfig.GetIntDefault("Quests.LowLevelHideDiff",4); + if(m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] > 255) + m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] = 255; + m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] = sConfig.GetIntDefault("Quests.HighLevelHideDiff",7); + if(m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] > 255) + m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] = 255; + + m_configs[CONFIG_DETECT_POS_COLLISION] = sConfig.GetBoolDefault("DetectPosCollision", true); + + m_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfig.GetBoolDefault("Channel.RestrictedLfg", true); + m_configs[CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL] = sConfig.GetBoolDefault("Channel.SilentlyGMJoin", false); + + m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true); + m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false); + + m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60); + m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300); + m_configs[CONFIG_CORPSE_DECAY_ELITE] = sConfig.GetIntDefault("Corpse.Decay.ELITE", 300); + m_configs[CONFIG_CORPSE_DECAY_RAREELITE] = sConfig.GetIntDefault("Corpse.Decay.RAREELITE", 300); + m_configs[CONFIG_CORPSE_DECAY_WORLDBOSS] = sConfig.GetIntDefault("Corpse.Decay.WORLDBOSS", 3600); + + m_configs[CONFIG_DEATH_SICKNESS_LEVEL] = sConfig.GetIntDefault("Death.SicknessLevel", 11); + m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvP", true); + m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvE", true); + + m_configs[CONFIG_THREAT_RADIUS] = sConfig.GetIntDefault("ThreatRadius", 100); + + // always use declined names in the russian client + m_configs[CONFIG_DECLINED_NAMES_USED] = + (m_configs[CONFIG_REALM_ZONE] == REALM_ZONE_RUSSIAN) ? true : sConfig.GetBoolDefault("DeclinedNames", false); + + m_configs[CONFIG_LISTEN_RANGE_SAY] = sConfig.GetIntDefault("ListenRange.Say", 25); + m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25); + m_configs[CONFIG_LISTEN_RANGE_YELL] = sConfig.GetIntDefault("ListenRange.Yell", 300); + + + m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); + if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) + { + sLog.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE); + m_VisibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE; + } + m_VisibleObjectGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Object", 10); + if(m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) + { + sLog.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE); + m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE; + } + + m_MaxVisibleDistanceForCreature = sConfig.GetFloatDefault("Visibility.Distance.Creature", DEFAULT_VISIBILITY_DISTANCE); + if(m_MaxVisibleDistanceForCreature < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) + { + sLog.outError("Visibility.Distance.Creature can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); + m_MaxVisibleDistanceForCreature = 45*sWorld.getRate(RATE_CREATURE_AGGRO); + } + else if(m_MaxVisibleDistanceForCreature + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) + { + sLog.outError("Visibility. Distance .Creature can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); + m_MaxVisibleDistanceForCreature = MAX_VISIBILITY_DISTANCE-m_VisibleUnitGreyDistance; + } + m_MaxVisibleDistanceForPlayer = sConfig.GetFloatDefault("Visibility.Distance.Player", DEFAULT_VISIBILITY_DISTANCE); + if(m_MaxVisibleDistanceForPlayer < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) + { + sLog.outError("Visibility.Distance.Player can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); + m_MaxVisibleDistanceForPlayer = 45*sWorld.getRate(RATE_CREATURE_AGGRO); + } + else if(m_MaxVisibleDistanceForPlayer + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) + { + sLog.outError("Visibility.Distance.Player can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); + m_MaxVisibleDistanceForPlayer = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; + } + m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Gameobject", DEFAULT_VISIBILITY_DISTANCE); + if(m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE) + { + sLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE)); + m_MaxVisibleDistanceForObject = INTERACTION_DISTANCE; + } + else if(m_MaxVisibleDistanceForObject + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) + { + sLog.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance); + m_MaxVisibleDistanceForObject = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance; + } + m_MaxVisibleDistanceInFlight = sConfig.GetFloatDefault("Visibility.Distance.InFlight", DEFAULT_VISIBILITY_DISTANCE); + if(m_MaxVisibleDistanceInFlight + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) + { + sLog.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance); + m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance; + } + + ///- Read the "Data" directory from the config file + std::string dataPath = sConfig.GetStringDefault("DataDir","./"); + if( dataPath.at(dataPath.length()-1)!='/' && dataPath.at(dataPath.length()-1)!='\\' ) + dataPath.append("/"); + + if(reload) + { + if(dataPath!=m_dataPath) + sLog.outError("DataDir option can't be changed at mangosd.conf reload, using current value (%s).",m_dataPath.c_str()); + } + else + { + m_dataPath = dataPath; + sLog.outString("Using DataDir %s",m_dataPath.c_str()); + } + + bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false); + bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false); + std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", ""); + std::string ignoreSpellIds = sConfig.GetStringDefault("vmap.ignoreSpellIds", ""); + VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS); + VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight); + VMAP::VMapFactory::createOrGetVMapManager()->preventMapsFromBeingUsed(ignoreMapIds.c_str()); + VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str()); + sLog.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i",enableLOS, enableHeight); + sLog.outString( "WORLD: VMap data directory is: %svmaps",m_dataPath.c_str()); + sLog.outString( "WORLD: VMap config keys are: vmap.enableLOS, vmap.enableHeight, vmap.ignoreMapIds, vmap.ignoreSpellIds"); +} + +/// Initialize the World +void World::SetInitialWorldSettings() +{ + ///- Initialize the random number generator + srand((unsigned int)time(NULL)); + + ///- Initialize config settings + LoadConfigSettings(); + + ///- Init highest guids before any table loading to prevent using not initialized guids in some code. + objmgr.SetHighestGuids(); + + ///- Check the existence of the map files for all races' startup areas. + if( !MapManager::ExistMapAndVMap(0,-6240.32f, 331.033f) + ||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f) + ||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f) + ||!MapManager::ExistMapAndVMap(1,-618.518f,-4251.67f) + ||!MapManager::ExistMapAndVMap(0, 1676.35f, 1677.45f) + ||!MapManager::ExistMapAndVMap(1, 10311.3f, 832.463f) + ||!MapManager::ExistMapAndVMap(1,-2917.58f,-257.98f) + ||m_configs[CONFIG_EXPANSION] && ( + !MapManager::ExistMapAndVMap(530,10349.6f,-6357.29f) || !MapManager::ExistMapAndVMap(530,-3961.64f,-13931.2f) ) ) + { + sLog.outError("Correct *.map files not found in path '%smaps' or *.vmap/*vmdir files in '%svmaps'. Please place *.map/*.vmap/*.vmdir files in appropriate directories or correct the DataDir value in the mangosd.conf file.",m_dataPath.c_str(),m_dataPath.c_str()); + exit(1); + } + + ///- Loading strings. Getting no records means core load has to be canceled because no error message can be output. + sLog.outString( "" ); + sLog.outString( "Loading MaNGOS strings..." ); + if (!objmgr.LoadMangosStrings()) + exit(1); // Error message displayed in function already + + ///- Update the realm entry in the database with the realm type from the config file + //No SQL injection as values are treated as integers + + // not send custom type REALM_FFA_PVP to realm list + uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_GAME_TYPE); + uint32 realm_zone = getConfig(CONFIG_REALM_ZONE); + loginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID); + + ///- Remove the bones after a restart + CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0'"); + + ///- Load the DBC files + sLog.outString("Initialize data stores..."); + LoadDBCStores(m_dataPath); + DetectDBCLang(); + + sLog.outString( "Loading InstanceTemplate" ); + objmgr.LoadInstanceTemplate(); + + sLog.outString( "Loading SkillLineAbilityMultiMap Data..." ); + spellmgr.LoadSkillLineAbilityMap(); + + ///- Clean up and pack instances + sLog.outString( "Cleaning up instances..." ); + sInstanceSaveManager.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables + + sLog.outString( "Packing instances..." ); + sInstanceSaveManager.PackInstances(); + + sLog.outString( "Loading Localization strings..." ); + objmgr.LoadCreatureLocales(); + objmgr.LoadGameObjectLocales(); + objmgr.LoadItemLocales(); + objmgr.LoadQuestLocales(); + objmgr.LoadNpcTextLocales(); + objmgr.LoadPageTextLocales(); + objmgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) + + sLog.outString( "Loading Page Texts..." ); + objmgr.LoadPageTexts(); + + sLog.outString( "Loading Game Object Templates..." ); // must be after LoadPageTexts + objmgr.LoadGameobjectInfo(); + + sLog.outString( "Loading Spell Chain Data..." ); + spellmgr.LoadSpellChains(); + + sLog.outString( "Loading Spell Elixir types..." ); + spellmgr.LoadSpellElixirs(); + + sLog.outString( "Loading Spell Learn Skills..." ); + spellmgr.LoadSpellLearnSkills(); // must be after LoadSpellChains + + sLog.outString( "Loading Spell Learn Spells..." ); + spellmgr.LoadSpellLearnSpells(); + + sLog.outString( "Loading Spell Proc Event conditions..." ); + spellmgr.LoadSpellProcEvents(); + + sLog.outString( "Loading Aggro Spells Definitions..."); + spellmgr.LoadSpellThreats(); + + sLog.outString( "Loading NPC Texts..." ); + objmgr.LoadGossipText(); + + sLog.outString( "Loading Item Random Enchantments Table..." ); + LoadRandomEnchantmentsTable(); + + sLog.outString( "Loading Items..." ); // must be after LoadRandomEnchantmentsTable and LoadPageTexts + objmgr.LoadItemPrototypes(); + + sLog.outString( "Loading Item Texts..." ); + objmgr.LoadItemTexts(); + + sLog.outString( "Loading Creature Model Based Info Data..." ); + objmgr.LoadCreatureModelInfo(); + + sLog.outString( "Loading Equipment templates..."); + objmgr.LoadEquipmentTemplates(); + + sLog.outString( "Loading Creature templates..." ); + objmgr.LoadCreatureTemplates(); + + sLog.outString( "Loading SpellsScriptTarget..."); + spellmgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo + + sLog.outString( "Loading Creature Reputation OnKill Data..." ); + objmgr.LoadReputationOnKill(); + + sLog.outString( "Loading Pet Create Spells..." ); + objmgr.LoadPetCreateSpells(); + + sLog.outString( "Loading Creature Data..." ); + objmgr.LoadCreatures(); + + sLog.outString( "Loading Creature Addon Data..." ); + objmgr.LoadCreatureAddons(); // must be after LoadCreatureTemplates() and LoadCreatures() + + sLog.outString( "Loading Creature Respawn Data..." ); // must be after PackInstances() + objmgr.LoadCreatureRespawnTimes(); + + sLog.outString( "Loading Gameobject Data..." ); + objmgr.LoadGameobjects(); + + sLog.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances() + objmgr.LoadGameobjectRespawnTimes(); + + sLog.outString( "Loading Game Event Data..."); + gameeventmgr.LoadFromDB(); + + sLog.outString( "Loading Weather Data..." ); + objmgr.LoadWeatherZoneChances(); + + sLog.outString( "Loading Quests..." ); + objmgr.LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables + + sLog.outString( "Loading Quests Relations..." ); + objmgr.LoadQuestRelations(); // must be after quest load + + sLog.outString( "Loading AreaTrigger definitions..." ); + objmgr.LoadAreaTriggerTeleports(); // must be after item template load + + sLog.outString( "Loading Quest Area Triggers..." ); + objmgr.LoadQuestAreaTriggers(); // must be after LoadQuests + + sLog.outString( "Loading Tavern Area Triggers..." ); + objmgr.LoadTavernAreaTriggers(); + + sLog.outString( "Loading AreaTrigger script names..." ); + objmgr.LoadAreaTriggerScripts(); + + + sLog.outString( "Loading Graveyard-zone links..."); + objmgr.LoadGraveyardZones(); + + sLog.outString( "Loading Spell target coordinates..." ); + spellmgr.LoadSpellTargetPositions(); + + sLog.outString( "Loading SpellAffect definitions..." ); + spellmgr.LoadSpellAffects(); + + sLog.outString( "Loading spell pet auras..." ); + spellmgr.LoadSpellPetAuras(); + + sLog.outString( "Loading player Create Info & Level Stats..." ); + objmgr.LoadPlayerInfo(); + + sLog.outString( "Loading Exploration BaseXP Data..." ); + objmgr.LoadExplorationBaseXP(); + + sLog.outString( "Loading Pet Name Parts..." ); + objmgr.LoadPetNames(); + + sLog.outString( "Loading the max pet number..." ); + objmgr.LoadPetNumber(); + + sLog.outString( "Loading pet level stats..." ); + objmgr.LoadPetLevelInfo(); + + sLog.outString( "Loading Player Corpses..." ); + objmgr.LoadCorpses(); + + sLog.outString( "Loading Loot Tables..." ); + LoadLootTables(); + + sLog.outString( "Loading Skill Discovery Table..." ); + LoadSkillDiscoveryTable(); + + sLog.outString( "Loading Skill Extra Item Table..." ); + LoadSkillExtraItemTable(); + + sLog.outString( "Loading Skill Fishing base level requirements..." ); + objmgr.LoadFishingBaseSkillLevel(); + + ///- Load dynamic data tables from the database + sLog.outString( "Loading Auctions..." ); + objmgr.LoadAuctionItems(); + objmgr.LoadAuctions(); + + sLog.outString( "Loading Guilds..." ); + objmgr.LoadGuilds(); + + sLog.outString( "Loading ArenaTeams..." ); + objmgr.LoadArenaTeams(); + + sLog.outString( "Loading Groups..." ); + objmgr.LoadGroups(); + + sLog.outString( "Loading ReservedNames..." ); + objmgr.LoadReservedPlayersNames(); + + sLog.outString( "Loading GameObject for quests..." ); + objmgr.LoadGameObjectForQuests(); + + sLog.outString( "Loading BattleMasters..." ); + objmgr.LoadBattleMastersEntry(); + + sLog.outString( "Loading GameTeleports..." ); + objmgr.LoadGameTele(); + + sLog.outString( "Loading Npc Text Id..." ); + objmgr.LoadNpcTextId(); // must be after load Creature and NpcText + + sLog.outString( "Loading vendors..." ); + objmgr.LoadVendors(); // must be after load CreatureTemplate and ItemTemplate + + sLog.outString( "Loading trainers..." ); + objmgr.LoadTrainerSpell(); // must be after load CreatureTemplate + + sLog.outString( "Loading Waypoints..." ); + WaypointMgr.Load(); + + ///- Handle outdated emails (delete/return) + sLog.outString( "Returning old mails..." ); + objmgr.ReturnOrDeleteOldMails(false); + + ///- Load and initialize scripts + sLog.outString( "Loading Scripts..." ); + objmgr.LoadQuestStartScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate + objmgr.LoadQuestEndScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate + objmgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data) + objmgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data) + objmgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data) + + sLog.outString( "Initializing Scripts..." ); + if(!LoadScriptingModule()) + exit(1); + + ///- Initialize game time and timers + sLog.outString( "DEBUG:: Initialize game time and timers" ); + m_gameTime = time(NULL); + m_startTime=m_gameTime; + + tm local; + time_t curr; + time(&curr); + local=*(localtime(&curr)); // dereference and assign + char isoDate[128]; + sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d", + local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec); + + WorldDatabase.PExecute("INSERT INTO uptime (startstring, starttime, uptime) VALUES('%s', %ld, 0)", isoDate, m_startTime ); + + m_timers[WUPDATE_OBJECTS].SetInterval(0); + m_timers[WUPDATE_SESSIONS].SetInterval(0); + m_timers[WUPDATE_WEATHERS].SetInterval(1000); + m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*1000); //set auction update interval to 1 minute + m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000); + //Update "uptime" table based on configuration entry in minutes. + m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*1000); //erase corpses every 20 minutes + + //to set mailtimer to return mails every day between 4 and 5 am + //mailtimer is increased when updating auctions + //one second is 1000 -(tested on win system) + mail_timer = ((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * 1000) / m_timers[WUPDATE_AUCTIONS].GetInterval() ); + //1440 + mail_timer_expires = ( (DAY * 1000) / (m_timers[WUPDATE_AUCTIONS].GetInterval())); + sLog.outDebug("Mail timer set to: %u, mail return is called every %u minutes", mail_timer, mail_timer_expires); + + ///- Initilize static helper structures + AIRegistry::Initialize(); + WaypointMovementGenerator::Initialize(); + Player::InitVisibleBits(); + + ///- Initialize MapManager + sLog.outString( "Starting Map System" ); + MapManager::Instance().Initialize(); + + ///- Initialize Battlegrounds + sLog.outString( "Starting BattleGround System" ); + sBattleGroundMgr.CreateInitialBattleGrounds(); + + //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager + sLog.outString( "Loading Transports..." ); + MapManager::Instance().LoadTransports(); + + sLog.outString("Deleting expired bans..." ); + loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); + + sLog.outString("Calculate next daily quest reset time..." ); + InitDailyQuestResetTime(); + + sLog.outString("Starting Game Event system..." ); + uint32 nextGameEvent = gameeventmgr.Initialize(); + m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); //depend on next event + + sLog.outString( "WORLD: World initialized" ); +} +void World::DetectDBCLang() +{ + uint32 m_lang_confid = sConfig.GetIntDefault("DBC.Locale", 255); + + if(m_lang_confid != 255 && m_lang_confid >= MAX_LOCALE) + { + sLog.outError("Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)",MAX_LOCALE); + m_lang_confid = LOCALE_enUS; + } + + ChrRacesEntry const* race = sChrRacesStore.LookupEntry(1); + + std::string availableLocalsStr; + + int default_locale = MAX_LOCALE; + for (int i = MAX_LOCALE-1; i >= 0; --i) + { + if ( strlen(race->name[i]) > 0) // check by race names + { + default_locale = i; + m_availableDbcLocaleMask |= (1 << i); + availableLocalsStr += localeNames[i]; + availableLocalsStr += " "; + } + } + + if( default_locale != m_lang_confid && m_lang_confid < MAX_LOCALE && + (m_availableDbcLocaleMask & (1 << m_lang_confid)) ) + { + default_locale = m_lang_confid; + } + + if(default_locale >= MAX_LOCALE) + { + sLog.outError("Unable to determine your DBC Locale! (corrupt DBC?)"); + exit(1); + } + + m_defaultDbcLocale = LocaleConstant(default_locale); + + sLog.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames[m_defaultDbcLocale],availableLocalsStr.empty() ? "" : availableLocalsStr.c_str()); +} + +/// Update the World ! +void World::Update(time_t diff) +{ + ///- Update the different timers + for(int i = 0; i < WUPDATE_COUNT; i++) + if(m_timers[i].GetCurrent()>=0) + m_timers[i].Update(diff); + else m_timers[i].SetCurrent(0); + + ///- Update the game time and check for shutdown time + _UpdateGameTime(); + + /// Handle daily quests reset time + if(m_gameTime > m_NextDailyQuestReset) + { + ResetDailyQuests(); + m_NextDailyQuestReset += DAY; + } + + ///
  • Handle auctions when the timer has passed + if (m_timers[WUPDATE_AUCTIONS].Passed()) + { + m_timers[WUPDATE_AUCTIONS].Reset(); + + ///- Update mails (return old mails with item, or delete them) + //(tested... works on win) + if (++mail_timer > mail_timer_expires) + { + mail_timer = 0; + objmgr.ReturnOrDeleteOldMails(true); + } + + AuctionHouseObject* AuctionMap; + for (int i = 0; i < 3; i++) + { + switch (i) + { + case 0: + AuctionMap = objmgr.GetAuctionsMap( 6 );//horde + break; + case 1: + AuctionMap = objmgr.GetAuctionsMap( 2 );//alliance + break; + case 2: + AuctionMap = objmgr.GetAuctionsMap( 7 );//neutral + break; + } + + ///- Handle expired auctions + AuctionHouseObject::AuctionEntryMap::iterator itr,next; + for (itr = AuctionMap->GetAuctionsBegin(); itr != AuctionMap->GetAuctionsEnd();itr = next) + { + next = itr; + ++next; + if (m_gameTime > (itr->second->time)) + { + ///- Either cancel the auction if there was no bidder + if (itr->second->bidder == 0) + { + objmgr.SendAuctionExpiredMail( itr->second ); + } + ///- Or perform the transaction + else + { + //we should send an "item sold" message if the seller is online + //we send the item to the winner + //we send the money to the seller + objmgr.SendAuctionSuccessfulMail( itr->second ); + objmgr.SendAuctionWonMail( itr->second ); + } + + ///- In any case clear the auction + //No SQL injection (Id is integer) + CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",itr->second->Id); + objmgr.RemoveAItem(itr->second->item_guidlow); + delete itr->second; + AuctionMap->RemoveAuction(itr->first); + } + } + } + } + + ///
  • Handle session updates when the timer has passed + if (m_timers[WUPDATE_SESSIONS].Passed()) + { + m_timers[WUPDATE_SESSIONS].Reset(); + + UpdateSessions(diff); + } + + ///
  • Handle weather updates when the timer has passed + if (m_timers[WUPDATE_WEATHERS].Passed()) + { + m_timers[WUPDATE_WEATHERS].Reset(); + + ///- Send an update signal to Weather objects + WeatherMap::iterator itr, next; + for (itr = m_weathers.begin(); itr != m_weathers.end(); itr = next) + { + next = itr; + ++next; + + ///- and remove Weather objects for zones with no player + //As interval > WorldTick + if(!itr->second->Update(m_timers[WUPDATE_WEATHERS].GetInterval())) + { + delete itr->second; + m_weathers.erase(itr); + } + } + } + ///
  • Update uptime table + if (m_timers[WUPDATE_UPTIME].Passed()) + { + uint32 tmpDiff = (m_gameTime - m_startTime); + uint32 maxClientsNum = sWorld.GetMaxActiveSessionCount(); + + m_timers[WUPDATE_UPTIME].Reset(); + WorldDatabase.PExecute("UPDATE uptime SET uptime = %d, maxplayers = %d WHERE starttime = " I64FMTD, tmpDiff, maxClientsNum, uint64(m_startTime)); + } + + ///
  • Handle all other objects + if (m_timers[WUPDATE_OBJECTS].Passed()) + { + m_timers[WUPDATE_OBJECTS].Reset(); + ///- Update objects when the timer has passed (maps, transport, creatures,...) + MapManager::Instance().Update(diff); // As interval = 0 + + ///- Process necessary scripts + if (!m_scriptSchedule.empty()) + ScriptsProcess(); + + sBattleGroundMgr.Update(diff); + } + + // execute callbacks from sql queries that were queued recently + UpdateResultQueue(); + + ///- Erase corpses once every 20 minutes + if (m_timers[WUPDATE_CORPSES].Passed()) + { + m_timers[WUPDATE_CORPSES].Reset(); + + CorpsesErase(); + } + + ///- Process Game events when necessary + if (m_timers[WUPDATE_EVENTS].Passed()) + { + m_timers[WUPDATE_EVENTS].Reset(); // to give time for Update() to be processed + uint32 nextGameEvent = gameeventmgr.Update(); + m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); + m_timers[WUPDATE_EVENTS].Reset(); + } + + ///
+ ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove" + MapManager::Instance().DoDelayedMovesAndRemoves(); + + // update the instance reset times + sInstanceSaveManager.Update(); + + // And last, but not least handle the issued cli commands + ProcessCliCommands(); +} + +/// Put scripts in the execution queue +void World::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target) +{ + ///- Find the script map + ScriptMapMap::const_iterator s = scripts.find(id); + if (s == scripts.end()) + return; + + // prepare static data + uint64 sourceGUID = source->GetGUID(); + uint64 targetGUID = target ? target->GetGUID() : (uint64)0; + uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; + + ///- Schedule script execution for all scripts in the script map + ScriptMap const *s2 = &(s->second); + bool immedScript = false; + for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter) + { + ScriptAction sa; + sa.sourceGUID = sourceGUID; + sa.targetGUID = targetGUID; + sa.ownerGUID = ownerGUID; + + sa.script = &iter->second; + m_scriptSchedule.insert(std::pair(m_gameTime + iter->first, sa)); + if (iter->first == 0) + immedScript = true; + } + ///- If one of the effects should be immediate, launch the script execution + if (immedScript) + ScriptsProcess(); +} + +void World::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target) +{ + // NOTE: script record _must_ exist until command executed + + // prepare static data + uint64 sourceGUID = source->GetGUID(); + uint64 targetGUID = target ? target->GetGUID() : (uint64)0; + uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; + + ScriptAction sa; + sa.sourceGUID = sourceGUID; + sa.targetGUID = targetGUID; + sa.ownerGUID = ownerGUID; + + sa.script = &script; + m_scriptSchedule.insert(std::pair(m_gameTime + delay, sa)); + + ///- If effects should be immediate, launch the script execution + if(delay == 0) + ScriptsProcess(); +} + +/// Process queued scripts +void World::ScriptsProcess() +{ + if (m_scriptSchedule.empty()) + return; + + ///- Process overdue queued scripts + std::multimap::iterator iter = m_scriptSchedule.begin(); + // ok as multimap is a *sorted* associative container + while (!m_scriptSchedule.empty() && (iter->first <= m_gameTime)) + { + ScriptAction const& step = iter->second; + + Object* source = NULL; + + if(step.sourceGUID) + { + switch(GUID_HIPART(step.sourceGUID)) + { + case HIGHGUID_ITEM: + // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM + { + Player* player = HashMapHolder::Find(step.ownerGUID); + if(player) + source = player->GetItemByGuid(step.sourceGUID); + break; + } + case HIGHGUID_UNIT: + source = HashMapHolder::Find(step.sourceGUID); + break; + case HIGHGUID_PET: + source = HashMapHolder::Find(step.sourceGUID); + break; + case HIGHGUID_PLAYER: + source = HashMapHolder::Find(step.sourceGUID); + break; + case HIGHGUID_GAMEOBJECT: + source = HashMapHolder::Find(step.sourceGUID); + break; + case HIGHGUID_CORPSE: + source = HashMapHolder::Find(step.sourceGUID); + break; + default: + sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID)); + break; + } + } + + Object* target = NULL; + + if(step.targetGUID) + { + switch(GUID_HIPART(step.targetGUID)) + { + case HIGHGUID_UNIT: + target = HashMapHolder::Find(step.targetGUID); + break; + case HIGHGUID_PET: + target = HashMapHolder::Find(step.targetGUID); + break; + case HIGHGUID_PLAYER: // empty GUID case also + target = HashMapHolder::Find(step.targetGUID); + break; + case HIGHGUID_GAMEOBJECT: + target = HashMapHolder::Find(step.targetGUID); + break; + case HIGHGUID_CORPSE: + target = HashMapHolder::Find(step.targetGUID); + break; + default: + sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID)); + break; + } + } + + switch (step.script->command) + { + case SCRIPT_COMMAND_TALK: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature."); + break; + } + + if(source->GetTypeId()!=TYPEID_UNIT) + { + sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + if(step.script->datalong > 3) + { + sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong); + break; + } + + uint64 unit_target = target ? target->GetGUID() : 0; + + //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text + switch(step.script->datalong) + { + case 0: // Say + ((Creature *)source)->Say(step.script->datatext.c_str(), LANG_UNIVERSAL, unit_target); + break; + case 1: // Whisper + if(!unit_target) + { + sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong); + break; + } + ((Creature *)source)->Whisper(step.script->datatext.c_str(),unit_target); + break; + case 2: // Yell + ((Creature *)source)->Yell(step.script->datatext.c_str(), LANG_UNIVERSAL, unit_target); + break; + case 3: // Emote text + ((Creature *)source)->TextEmote(step.script->datatext.c_str(), unit_target); + break; + default: + break; // must be already checked at load + } + break; + } + + case SCRIPT_COMMAND_EMOTE: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature."); + break; + } + + if(source->GetTypeId()!=TYPEID_UNIT) + { + sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + ((Creature *)source)->HandleEmoteCommand(step.script->datalong); + break; + case SCRIPT_COMMAND_FIELD_SET: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object."); + break; + } + if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).", + step.script->datalong,source->GetValuesCount(),source->GetTypeId()); + break; + } + + source->SetUInt32Value(step.script->datalong, step.script->datalong2); + break; + case SCRIPT_COMMAND_MOVE_TO: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature."); + break; + } + + if(source->GetTypeId()!=TYPEID_UNIT) + { + sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, ((Unit *)source)->GetUnitMovementFlags(), step.script->datalong2 ); + MapManager::Instance().GetMap(((Unit *)source)->GetMapId(), ((Unit *)source))->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0); + break; + case SCRIPT_COMMAND_FLAG_SET: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object."); + break; + } + if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).", + step.script->datalong,source->GetValuesCount(),source->GetTypeId()); + break; + } + + source->SetFlag(step.script->datalong, step.script->datalong2); + break; + case SCRIPT_COMMAND_FLAG_REMOVE: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object."); + break; + } + if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).", + step.script->datalong,source->GetValuesCount(),source->GetTypeId()); + break; + } + + source->RemoveFlag(step.script->datalong, step.script->datalong2); + break; + + case SCRIPT_COMMAND_TELEPORT_TO: + { + // accept player in any one from target/source arg + if (!target && !source) + { + sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object."); + break; + } + + // must be only Player + if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER)) + { + sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); + break; + } + + Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source; + + pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o); + break; + } + + case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: + { + if(!step.script->datalong) // creature not specified + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature."); + break; + } + + if(!source) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object."); + break; + } + + WorldObject* summoner = dynamic_cast(source); + + if(!summoner) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + float x = step.script->x; + float y = step.script->y; + float z = step.script->z; + float o = step.script->o; + + Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2); + if (!pCreature) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong); + break; + } + + break; + } + + case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: + { + if(!step.script->datalong) // gameobject not specified + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject."); + break; + } + + if(!source) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object."); + break; + } + + WorldObject* summoner = dynamic_cast(source); + + if(!summoner) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + GameObject *go = NULL; + int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2; + + CellPair p(MaNGOS::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + MaNGOS::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong); + MaNGOS::GameObjectSearcher checker(go,go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(summoner->GetMapId(), summoner)); + + if ( !go ) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong); + break; + } + + if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE || + go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE || + go->GetGoType()==GAMEOBJECT_TYPE_DOOR || + go->GetGoType()==GAMEOBJECT_TYPE_BUTTON || + go->GetGoType()==GAMEOBJECT_TYPE_TRAP ) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong); + break; + } + + if( go->isSpawned() ) + break; //gameobject already spawned + + go->SetLootState(GO_READY); + go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds + + MapManager::Instance().GetMap(go->GetMapId(), go)->Add(go); + break; + } + case SCRIPT_COMMAND_OPEN_DOOR: + { + if(!step.script->datalong) // door not specified + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door."); + break; + } + + if(!source) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit."); + break; + } + + if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + Unit* caster = (Unit*)source; + + GameObject *door = NULL; + int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; + + CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong); + MaNGOS::GameObjectSearcher checker(door,go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source)); + + if ( !door ) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong); + break; + } + if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR ) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType()); + break; + } + + if( !door->GetGoState() ) + break; //door already open + + door->UseDoorOrButton(time_to_close); + + if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON) + ((GameObject*)target)->UseDoorOrButton(time_to_close); + break; + } + case SCRIPT_COMMAND_CLOSE_DOOR: + { + if(!step.script->datalong) // guid for door not specified + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door."); + break; + } + + if(!source) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit."); + break; + } + + if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + Unit* caster = (Unit*)source; + + GameObject *door = NULL; + int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; + + CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong); + MaNGOS::GameObjectSearcher checker(door,go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source)); + + if ( !door ) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong); + break; + } + if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR ) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType()); + break; + } + + if( door->GetGoState() ) + break; //door already closed + + door->UseDoorOrButton(time_to_open); + + if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON) + ((GameObject*)target)->UseDoorOrButton(time_to_open); + + break; + } + case SCRIPT_COMMAND_QUEST_EXPLORED: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source."); + break; + } + + if(!target) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target."); + break; + } + + // when script called for item spell casting then target == (unit or GO) and source is player + WorldObject* worldObject; + Player* player; + + if(target->GetTypeId()==TYPEID_PLAYER) + { + if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + worldObject = (WorldObject*)source; + player = (Player*)target; + } + else + { + if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId()); + break; + } + + if(source->GetTypeId()!=TYPEID_PLAYER) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + worldObject = (WorldObject*)target; + player = (Player*)source; + } + + // quest id and flags checked at script loading + if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) && + (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) ) + player->AreaExploredOrEventHappens(step.script->datalong); + else + player->FailQuest(step.script->datalong); + + break; + } + + case SCRIPT_COMMAND_ACTIVATE_OBJECT: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster."); + break; + } + + if(!source->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + if(!target) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject."); + break; + } + + if(target->GetTypeId()!=TYPEID_GAMEOBJECT) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId()); + break; + } + + Unit* caster = (Unit*)source; + + GameObject *go = (GameObject*)target; + + go->Use(caster); + break; + } + + case SCRIPT_COMMAND_REMOVE_AURA: + { + Object* cmdTarget = step.script->datalong2 ? source : target; + + if(!cmdTarget) + { + sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target"); + break; + } + + if(!cmdTarget->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId()); + break; + } + + ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong); + break; + } + + case SCRIPT_COMMAND_CAST_SPELL: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster."); + break; + } + + if(!source->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + Object* cmdTarget = step.script->datalong2 ? source : target; + + if(!cmdTarget) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 ? "source" : "target"); + break; + } + + if(!cmdTarget->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId()); + break; + } + + Unit* spellTarget = (Unit*)cmdTarget; + + //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast + ((Unit*)source)->CastSpell(spellTarget,step.script->datalong,false); + + break; + } + + default: + sLog.outError("Unknown script command %u called.",step.script->command); + break; + } + + m_scriptSchedule.erase(iter); + + iter = m_scriptSchedule.begin(); + } + return; +} + +/// Send a packet to all players (except self if mentioned) +void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team) +{ + SessionMap::iterator itr; + for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++) + { + if (itr->second && + itr->second->GetPlayer() && + itr->second->GetPlayer()->IsInWorld() && + itr->second != self && + (team == 0 || itr->second->GetPlayer()->GetTeam() == team) ) + { + itr->second->SendPacket(packet); + } + } +} + +/// Send a System Message to all players (except self if mentioned) +void World::SendWorldText(int32 string_id, ...) +{ + std::vector > data_cache; // 0 = default, i => i-1 locale index + + for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + { + if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() ) + continue; + + uint32 loc_idx = itr->second->GetSessionDbLocaleIndex(); + uint32 cache_idx = loc_idx+1; + + std::vector* data_list; + + // create if not cached yet + if(data_cache.size() < cache_idx+1 || data_cache[cache_idx].empty()) + { + if(data_cache.size() < cache_idx+1) + data_cache.resize(cache_idx+1); + + data_list = &data_cache[cache_idx]; + + char const* text = objmgr.GetMangosString(string_id,loc_idx); + + char buf[1000]; + + va_list argptr; + va_start( argptr, string_id ); + vsnprintf( buf,1000, text, argptr ); + va_end( argptr ); + + char* pos = &buf[0]; + + while(char* line = ChatHandler::LineFromMessage(pos)) + { + WorldPacket* data = new WorldPacket(); + ChatHandler::FillMessageData(data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL); + data_list->push_back(data); + } + } + else + data_list = &data_cache[cache_idx]; + + for(int i = 0; i < data_list->size(); ++i) + itr->second->SendPacket((*data_list)[i]); + } + + // free memory + for(int i = 0; i < data_cache.size(); ++i) + for(int j = 0; j < data_cache[i].size(); ++j) + delete data_cache[i][j]; +} + +/// Send a packet to all players (or players selected team) in the zone (except self if mentioned) +void World::SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self, uint32 team) +{ + SessionMap::iterator itr; + for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++) + { + if (itr->second && + itr->second->GetPlayer() && + itr->second->GetPlayer()->IsInWorld() && + itr->second->GetPlayer()->GetZoneId() == zone && + itr->second != self && + (team == 0 || itr->second->GetPlayer()->GetTeam() == team) ) + { + itr->second->SendPacket(packet); + } + } +} + +/// Send a System Message to all players in the zone (except self if mentioned) +void World::SendZoneText(uint32 zone, const char* text, WorldSession *self, uint32 team) +{ + WorldPacket data; + ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, text, NULL); + SendZoneMessage(zone, &data, self,team); +} + +/// Kick (and save) all players +void World::KickAll() +{ + // session not removed at kick and will removed in next update tick + for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + itr->second->KickPlayer(); +} + +/// Kick (and save) all players with security level less `sec` +void World::KickAllLess(AccountTypes sec) +{ + // session not removed at kick and will removed in next update tick + for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + if(itr->second->GetSecurity() < sec) + itr->second->KickPlayer(); +} + +/// Kick all queued players +void World::KickAllQueued() +{ + // session not removed at kick and will removed in next update tick + //TODO here +// for (Queue::iterator itr = m_QueuedPlayer.begin(); itr != m_QueuedPlayer.end(); ++itr) +// if(WorldSession* session = (*itr)->GetSession()) +// session->KickPlayer(); + + m_QueuedPlayer.empty(); +} + +/// Kick (and save) the designated player +bool World::KickPlayer(std::string playerName) +{ + SessionMap::iterator itr; + + // session not removed at kick and will removed in next update tick + for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + { + if(!itr->second) + continue; + Player *player = itr->second->GetPlayer(); + if(!player) + continue; + if( player->IsInWorld() ) + { + if (playerName == player->GetName()) + { + itr->second->KickPlayer(); + return true; + } + } + } + return false; +} + +/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban +uint8 World::BanAccount(std::string type, std::string nameOrIP, std::string duration, std::string reason, std::string author) +{ + loginDatabase.escape_string(nameOrIP); + loginDatabase.escape_string(reason); + std::string safe_author=author; + loginDatabase.escape_string(safe_author); + + if(type != "ip" && !normalizePlayerName(nameOrIP)) + return BAN_NOTFOUND; // Nobody to ban + + uint32 duration_secs = TimeStringToSecs(duration); + QueryResult *resultAccounts = NULL; //used for kicking + + ///- Update the database with ban information + + if(type=="ip") + { + //No SQL injection as strings are escaped + resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str()); + loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str()); + } + else if(type=="account") + { + //No SQL injection as string is escaped + resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str()); + } + else if(type=="character") + { + //No SQL injection as string is escaped + resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str()); + } + else + return BAN_SYNTAX_ERROR; //Syntax problem + + if(!resultAccounts) + if(type=="ip") + return BAN_SUCCESS; // ip correctly banned but nobody affected (yet) + else + return BAN_NOTFOUND; // Nobody to ban + + ///- Disconnect all affected players (for IP it can be several) + do + { + Field* fieldsAccount = resultAccounts->Fetch(); + uint32 account = fieldsAccount->GetUInt32(); + + if(type != "ip") + //No SQL injection as strings are escaped + loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')", + account,duration_secs,safe_author.c_str(),reason.c_str()); + + WorldSession* sess = FindSession(account); + if( sess ) + if(std::string(sess->GetPlayerName()) != author) + sess->KickPlayer(); + } + while( resultAccounts->NextRow() ); + + delete resultAccounts; + return BAN_SUCCESS; +} + +/// Remove a ban from an account or IP address +bool World::RemoveBanAccount(std::string type, std::string nameOrIP) +{ + if(type == "ip") + { + loginDatabase.escape_string(nameOrIP); + loginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str()); + } + else + { + uint32 account=0; + if(type == "account") + { + //NO SQL injection as name is escaped + loginDatabase.escape_string(nameOrIP); + QueryResult *resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str()); + if(!resultAccounts) + return false; + Field* fieldsAccount = resultAccounts->Fetch(); + account = fieldsAccount->GetUInt32(); + + delete resultAccounts; + } + else if(type == "character") + { + if(!normalizePlayerName(nameOrIP)) + return false; + + //NO SQL injection as name is escaped + loginDatabase.escape_string(nameOrIP); + QueryResult *resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str()); + if(!resultAccounts) + return false; + Field* fieldsAccount = resultAccounts->Fetch(); + account = fieldsAccount->GetUInt32(); + + delete resultAccounts; + } + if(!account) + return false; + //NO SQL injection as account is uint32 + loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account); + } + return true; +} + +/// Update the game time +void World::_UpdateGameTime() +{ + ///- update the time + time_t thisTime = time(NULL); + uint32 elapsed = uint32(thisTime - m_gameTime); + m_gameTime = thisTime; + + ///- if there is a shutdown timer + if(m_ShutdownTimer > 0 && elapsed > 0) + { + ///- ... and it is overdue, stop the world (set m_stopEvent) + if( m_ShutdownTimer <= elapsed ) + { + if(!(m_ShutdownMask & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0) + m_stopEvent = true; + else + m_ShutdownTimer = 1; // minimum timer value to wait idle state + } + ///- ... else decrease it and if necessary display a shutdown countdown to the users + else + { + m_ShutdownTimer -= elapsed; + + ShutdownMsg(); + } + } +} + +/// Shutdown the server +void World::ShutdownServ(uint32 time, uint32 options) +{ + m_ShutdownMask = options; + + ///- If the shutdown time is 0, set m_stopEvent (except if shutdown is 'idle' with remaining sessions) + if(time==0) + { + if(!(options & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0) + m_stopEvent = true; + else + m_ShutdownTimer = 1; //So that the session count is re-evaluated at next world tick + } + ///- Else set the shutdown timer and warn users + else + { + m_ShutdownTimer = time; + ShutdownMsg(true); + } +} + +/// Display a shutdown message to the user(s) +void World::ShutdownMsg(bool show, Player* player) +{ + // not show messages for idle shutdown mode + if(m_ShutdownMask & SHUTDOWN_MASK_IDLE) + return; + + ///- Display a message every 12 hours, hours, 5 minutes, minute, 5 seconds and finally seconds + if ( show || + (m_ShutdownTimer < 10) || + // < 30 sec; every 5 sec + (m_ShutdownTimer<30 && (m_ShutdownTimer % 5 )==0) || + // < 5 min ; every 1 min + (m_ShutdownTimer<5*MINUTE && (m_ShutdownTimer % MINUTE )==0) || + // < 30 min ; every 5 min + (m_ShutdownTimer<30*MINUTE && (m_ShutdownTimer % (5*MINUTE))==0) || + // < 12 h ; every 1 h + (m_ShutdownTimer<12*HOUR && (m_ShutdownTimer % HOUR )==0) || + // > 12 h ; every 12 h + (m_ShutdownTimer>12*HOUR && (m_ShutdownTimer % (12*HOUR) )==0)) + { + std::string str = secsToTimeString(m_ShutdownTimer); + + uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME; + + SendServerMessage(msgid,str.c_str(),player); + DEBUG_LOG("Server is %s in %s",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"),str.c_str()); + } +} + +/// Cancel a planned server shutdown +void World::ShutdownCancel() +{ + if(!m_ShutdownTimer) + return; + + uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED; + + m_ShutdownMask = 0; + m_ShutdownTimer = 0; + SendServerMessage(msgid); + + DEBUG_LOG("Server %s cancelled.",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown")); +} + +/// Send a server message to the user(s) +void World::SendServerMessage(uint32 type, const char *text, Player* player) +{ + WorldPacket data(SMSG_SERVER_MESSAGE, 50); // guess size + data << uint32(type); + if(type <= SERVER_MSG_STRING) + data << text; + + if(player) + player->GetSession()->SendPacket(&data); + else + SendGlobalMessage( &data ); +} + +void World::UpdateSessions( time_t diff ) +{ + while(!addSessQueue.empty()) + { + WorldSession* sess = addSessQueue.next (); + AddSession_ (sess); + } + + ///- Delete kicked sessions at add new session + for (std::set::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr) + delete *itr; + m_kicked_sessions.clear(); + + ///- Then send an update signal to remaining ones + for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next) + { + next = itr; + ++next; + + if(!itr->second) + continue; + + ///- and remove not active sessions from the list + if(!itr->second->Update(diff)) // As interval = 0 + { + delete itr->second; + m_sessions.erase(itr); + } + } +} + +// This handles the issued and queued CLI commands +void World::ProcessCliCommands() +{ + if (cliCmdQueue.empty()) return; + + CliCommandHolder *command; + pPrintf p_zprintf; + while (!cliCmdQueue.empty()) + { + sLog.outDebug("CLI command under processing..."); + command = cliCmdQueue.next(); + command->Execute(); + p_zprintf=command->GetOutputMethod(); + delete command; + } + // print the console message here so it looks right + p_zprintf("mangos>"); +} + +void World::InitResultQueue() +{ + m_resultQueue = new SqlResultQueue; + CharacterDatabase.SetResultQueue(m_resultQueue); +} + +void World::UpdateResultQueue() +{ + m_resultQueue->Update(); +} + +void World::UpdateRealmCharCount(uint32 accountId) +{ + CharacterDatabase.AsyncPQuery(this, &World::_UpdateRealmCharCount, accountId, + "SELECT COUNT(guid) FROM characters WHERE account = '%u'", accountId); +} + +void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId) +{ + if (resultCharCount) + { + Field *fields = resultCharCount->Fetch(); + uint32 charCount = fields[0].GetUInt32(); + delete resultCharCount; + loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID); + loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID); + } +} + +void World::InitDailyQuestResetTime() +{ + time_t mostRecentQuestTime; + + QueryResult* result = CharacterDatabase.Query("SELECT MAX(time) FROM character_queststatus_daily"); + if(result) + { + Field *fields = result->Fetch(); + + mostRecentQuestTime = (time_t)fields[0].GetUInt64(); + delete result; + } + else + mostRecentQuestTime = 0; + + // client built-in time for reset is 6:00 AM + // FIX ME: client not show day start time + time_t curTime = time(NULL); + tm localTm = *localtime(&curTime); + localTm.tm_hour = 6; + localTm.tm_min = 0; + localTm.tm_sec = 0; + + // current day reset time + time_t curDayResetTime = mktime(&localTm); + + // last reset time before current moment + time_t resetTime = (curTime < curDayResetTime) ? curDayResetTime - DAY : curDayResetTime; + + // need reset (if we have quest time before last reset time (not processed by some reason) + if(mostRecentQuestTime && mostRecentQuestTime <= resetTime) + m_NextDailyQuestReset = mostRecentQuestTime; + else + { + // plan next reset time + m_NextDailyQuestReset = (curTime >= curDayResetTime) ? curDayResetTime + DAY : curDayResetTime; + } +} + +void World::ResetDailyQuests() +{ + sLog.outDetail("Daily quests reset for all characters."); + CharacterDatabase.Execute("DELETE FROM character_queststatus_daily"); + for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + if(itr->second->GetPlayer()) + itr->second->GetPlayer()->ResetDailyQuestStatus(); +} + +void World::SetPlayerLimit( int32 limit, bool needUpdate ) +{ + if(limit < -SEC_ADMINISTRATOR) + limit = -SEC_ADMINISTRATOR; + + // lock update need + bool db_update_need = needUpdate || (limit < 0) != (m_playerLimit < 0) || (limit < 0 && m_playerLimit < 0 && limit != m_playerLimit); + + m_playerLimit = limit; + + if(db_update_need) + loginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID); +} + +void World::UpdateMaxSessionCounters() +{ + m_maxActiveSessionCount = std::max(m_maxActiveSessionCount,uint32(m_sessions.size()-m_QueuedPlayer.size())); + m_maxQueuedSessionCount = std::max(m_maxQueuedSessionCount,uint32(m_QueuedPlayer.size())); +} diff --git a/src/game/World.h b/src/game/World.h index 56450832ab9..cf5b9e5ba42 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -362,10 +362,10 @@ class World void SetPlayerLimit(int32 limit, bool needUpdate = false); //player Queue - typedef std::list Queue; - void AddQueuedPlayer(WorldSocket* Socket); - void RemoveQueuedPlayer(WorldSocket* Socket); - int32 GetQueuePos(WorldSocket* Socket); + typedef std::list Queue; + void AddQueuedPlayer(WorldSession*); + void RemoveQueuedPlayer(WorldSession*); + int32 GetQueuePos(WorldSession*); uint32 GetQueueSize() const { return m_QueuedPlayer.size(); } /// \todo Actions on m_allowMovement still to be implemented @@ -525,6 +525,10 @@ class World //Player Queue Queue m_QueuedPlayer; + + //sessions that are added async + void AddSession_(WorldSession* s); + ZThread::LockedQueue addSessQueue; }; extern uint32 realmID; diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index eaba12b4a10..9ec9624182c 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -20,6 +20,7 @@ \ingroup u2w */ +#include "WorldSocket.h" #include "Common.h" #include "Database/DatabaseEnv.h" #include "Log.h" @@ -42,10 +43,15 @@ /// WorldSession constructor WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, bool tbc, time_t mute_time, LocaleConstant locale) : LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time), -_player(NULL), _socket(sock),_security(sec), _accountId(id), m_isTBC(tbc), +_player(NULL), m_Socket(sock),_security(sec), _accountId(id), m_isTBC(tbc), m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(objmgr.GetIndexForLocale(locale)), _logoutTime(0), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_latency(0) { + if (sock) + { + m_Address = sock->GetRemoteAddress (); + sock->AddReference (); + } } /// WorldSession destructor @@ -56,10 +62,12 @@ WorldSession::~WorldSession() LogoutPlayer(true); /// - If have unclosed socket, close it - if(_socket) - _socket->CloseSocket(); - - _socket = NULL; + if (m_Socket) + { + m_Socket->CloseSocket (); + m_Socket->RemoveReference (); + m_Socket = NULL; + } ///- empty incoming packet queue while(!_recvQueue.empty()) @@ -67,6 +75,8 @@ WorldSession::~WorldSession() WorldPacket *packet = _recvQueue.next(); delete packet; } + + sWorld.RemoveQueuedPlayer(this); } void WorldSession::SizeError(WorldPacket const& packet, uint32 size) const @@ -81,16 +91,10 @@ char const* WorldSession::GetPlayerName() const return GetPlayer() ? GetPlayer()->GetName() : ""; } -/// Set the WorldSocket associated with this session -void WorldSession::SetSocket(WorldSocket *sock) -{ - _socket = sock; -} - /// Send a packet to the client void WorldSession::SendPacket(WorldPacket const* packet) { - if (!_socket) + if (!m_Socket) return; #ifdef MANGOS_DEBUG // Code for network use statistic @@ -124,16 +128,18 @@ void WorldSession::SendPacket(WorldPacket const* packet) sendLastPacketCount = 1; sendLastPacketBytes = packet->wpos(); // wpos is real written size } - #endif // !MANGOS_DEBUG +#endif // !MANGOS_DEBUG - _socket->SendPacket(packet); + if (m_Socket->SendPacket (*packet) == -1) + { + m_Socket->CloseSocket (); + } } /// Add an incoming packet to the queue -void WorldSession::QueuePacket(WorldPacket& packet) +void WorldSession::QueuePacket(WorldPacket* new_packet) { - WorldPacket *pck = new WorldPacket(packet); - _recvQueue.add(pck); + _recvQueue.add(new_packet); } /// Logging helper for unexpected opcodes @@ -148,6 +154,13 @@ void WorldSession::logUnexpectedOpcode(WorldPacket* packet, const char *reason) /// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 /*diff*/) { + if (m_Socket) + if (m_Socket->IsClosed ()) + { + m_Socket->RemoveReference (); + m_Socket = NULL; + } + WorldPacket *packet; ///- Retrieve packets from the receive queue and call the appropriate handlers @@ -210,10 +223,10 @@ bool WorldSession::Update(uint32 /*diff*/) ///- If necessary, log the player out time_t currTime = time(NULL); - if (!_socket || (ShouldLogOut(currTime) && !m_playerLoading)) + if (!m_Socket || (ShouldLogOut(currTime) && !m_playerLoading)) LogoutPlayer(true); - if (!_socket) + if (!m_Socket) return false; //Will remove this session from the world session map return true; @@ -343,7 +356,7 @@ void WorldSession::LogoutPlayer(bool Save) // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) - if(_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && _socket) + if(_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) _player->RemoveFromGroup(); ///- Remove the player from the world @@ -385,12 +398,10 @@ void WorldSession::LogoutPlayer(bool Save) /// Kick a player out of the World void WorldSession::KickPlayer() { - if(!_socket) - return; - - // player will be logout and session will removed in next update tick - _socket->CloseSocket(); - _socket = NULL; + if (m_Socket) + { + m_Socket->CloseSocket (); + } } /// Cancel channeling handler @@ -461,3 +472,22 @@ void WorldSession::Handle_Depricated( WorldPacket& recvPacket ) LookupOpcodeName(recvPacket.GetOpcode()), recvPacket.GetOpcode()); } + +void WorldSession::SendAuthWaitQue(uint32 position) + { + if(position == 0) + { + WorldPacket packet( SMSG_AUTH_RESPONSE, 1 ); + packet << uint8( AUTH_OK ); + SendPacket(&packet); + } + else + { + WorldPacket packet( SMSG_AUTH_RESPONSE, 5 ); + packet << uint8( AUTH_WAIT_QUEUE ); + packet << uint32 (position); + SendPacket(&packet); + } + } + + diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 05df0afe3a8..0f46af26c94 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -88,7 +88,7 @@ class MANGOS_DLL_SPEC WorldSession Player* GetPlayer() const { return _player; } char const* GetPlayerName() const; void SetSecurity(uint32 security) { _security = security; } - void SetSocket(WorldSocket *sock); + std::string& GetRemoteAddress() { return m_Address; } void SetPlayer(Player *plr) { _player = plr; } bool IsTBC() const { return m_isTBC; } @@ -110,8 +110,11 @@ class MANGOS_DLL_SPEC WorldSession void LogoutPlayer(bool Save); void KickPlayer(); - void QueuePacket(WorldPacket& packet); + void QueuePacket(WorldPacket* new_packet); bool Update(uint32 diff); + + /// Handle the authentication waiting queue (to be completed) + void SendAuthWaitQue(uint32 position); //void SendTestCreatureQueryOpcode( uint32 entry, uint64 guid, uint32 testvalue ); void SendNameQueryOpcode(Player* p); @@ -618,7 +621,8 @@ class MANGOS_DLL_SPEC WorldSession // logging helper void logUnexpectedOpcode(WorldPacket *packet, const char * reason); Player *_player; - WorldSocket *_socket; + WorldSocket *m_Socket; + std::string m_Address; uint32 _security; uint32 _accountId; diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp index d52c0962862..cb1c0233b4d 100644 --- a/src/game/WorldSocket.cpp +++ b/src/game/WorldSocket.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2008 MaNGOS * * This program is free software; you can redistribute it and/or modify @@ -16,649 +16,1074 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/** \file - \ingroup u2w -*/ - #include "Common.h" -#include "Log.h" +#include "WorldSocket.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Util.h" +#include "World.h" +#include "WorldPacket.h" +#include "SharedDefines.h" +#include "ByteBuffer.h" +#include "AddonHandler.h" #include "Opcodes.h" #include "Database/DatabaseEnv.h" #include "Auth/Sha1.h" -#include "WorldPacket.h" -#include "WorldSocket.h" #include "WorldSession.h" -#include "World.h" #include "WorldSocketMgr.h" -#include "Policies/SingletonImp.h" +#include "Log.h" #include "WorldLog.h" -#include "AddonHandler.h" -#include "sockets/Utility.h" -#include "Util.h" -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform #if defined( __GNUC__ ) #pragma pack(1) #else #pragma pack(push,1) #endif -/// Client Packet Header -struct ClientPktHeader +struct ServerPktHeader { - uint16 size; - uint32 cmd; + ACE_UINT16 size; + ACE_UINT16 cmd; }; -/// Server Packet Header -struct ServerPktHeader +struct ClientPktHeader { - uint16 size; - uint16 cmd; + ACE_UINT16 size; + ACE_UINT32 cmd; }; -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform #if defined( __GNUC__ ) #pragma pack() #else #pragma pack(pop) #endif -#define SOCKET_CHECK_PACKET_SIZE(P,S) if((P).size() < (S)) return SizeError((P),(S)); - -/// WorldSocket construction and initialization. -WorldSocket::WorldSocket(ISocketHandler &sh): TcpSocket(sh), _cmd(0), _remaining(0), _session(NULL) +// used when testing to alow login without password and encryption +// #define _NETCODE_FAKE_AUTH + +WorldSocket::WorldSocket (void) : +WorldHandler (), +m_Session (0), +m_RecvWPct (0), +m_RecvPct (), +m_Header (sizeof (ClientPktHeader)), +m_OutBuffer (0), +m_OutBufferSize (65536), +m_OutActive (false), +m_Seed (static_cast (rand32 ())), +m_OverSpeedPings (0), +m_LastPingTime (ACE_Time_Value::zero) { - _seed = static_cast(rand32()); - m_LastPingMSTime = 0; // first time it will counted as overspeed maybe, but this is not important - m_OverSpeedPings = 0; - - if (sWorld.getConfig(CONFIG_TCP_NO_DELAY)) - SetTcpNodelay(true); + this->reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); } -/// WorldSocket destructor -WorldSocket::~WorldSocket() +WorldSocket::~WorldSocket (void) { - if(_session) - _session->SetSocket(0); + if (m_RecvWPct) + delete m_RecvWPct; - WorldPacket *packet; + if (m_OutBuffer) + m_OutBuffer->release (); - ///- Go through the to-be-sent queue and delete remaining packets - while(!_sendQueue.empty()) - { - packet = _sendQueue.next(); - delete packet; - } + this->closing_ = true; + + this->peer ().close (); + + WorldPacket* pct; + while (m_PacketQueue.dequeue_head (pct) == 0) + delete pct; } -/// Copy the packet to the to-be-sent queue -void WorldSocket::SendPacket(WorldPacket const* packet) +bool +WorldSocket::IsClosed (void) const { - WorldPacket *pck = new WorldPacket(*packet); - ASSERT(pck); - _sendQueue.add(pck); + return this->closing_; } -/// On client connection -void WorldSocket::OnAccept() +void +WorldSocket::CloseSocket (void) { - ///- Add the current socket to the list of sockets to be managed (WorldSocketMgr) - sWorldSocketMgr.AddSocket(this); - Utility::ResolveLocal(); + { + ACE_GUARD (LockType, Guard, m_OutBufferLock); + + if (this->closing_) + return; + + this->closing_ = true; + + this->peer ().close_writer (); + } - ///- Send a AUTH_CHALLENGE packet - WorldPacket packet( SMSG_AUTH_CHALLENGE, 4 ); - packet << _seed; + { + ACE_GUARD (LockType, Guard, m_SessionLock); + + m_Session = NULL; + } - SendPacket(&packet); } -/// Read the client transmitted data -void WorldSocket::OnRead() +const std::string& +WorldSocket::GetRemoteAddress (void) const { - TcpSocket::OnRead(); + return m_Address; +} - while(1) - { - ///- Read the packet header and decipher it (if needed) - if (!_remaining) - { - if (ibuf.GetLength() < 6) - break; +int +WorldSocket::SendPacket (const WorldPacket& pct) +{ + ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - ClientPktHeader hdr; + if (this->closing_) + return -1; - ibuf.Read((char *)&hdr, 6); - _crypt.DecryptRecv((uint8 *)&hdr, 6); + // Dump outgoing packet. + if (sWorldLog.LogWorld ()) + { + sWorldLog.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", + (uint32) get_handle (), + pct.size (), + LookupOpcodeName (pct.GetOpcode ()), + pct.GetOpcode ()); + + uint32 p = 0; + while (p < pct.size ()) + { + for (uint32 j = 0; j < 16 && p < pct.size (); j++) + sWorldLog.Log ("%.2X ", const_cast(pct)[p++]); - _remaining = ntohs(hdr.size) - 4; - _cmd = hdr.cmd; + sWorldLog.Log ("\n"); } - if (ibuf.GetLength() < _remaining) - break; - - ///- Read the remaining of the packet - WorldPacket packet((uint16)_cmd, _remaining); + sWorldLog.Log ("\n\n"); + } - packet.resize(_remaining); - if(_remaining) ibuf.Read((char*)packet.contents(), _remaining); - _remaining = 0; + if (iSendPacket (pct) == -1) + { + WorldPacket* npct; - ///- If log of world packets is enable, log the incoming packet - if( sWorldLog.LogWorld() ) - { - sWorldLog.Log("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", - (uint32)GetSocket(), - packet.size(), - LookupOpcodeName(packet.GetOpcode()), - packet.GetOpcode()); - - uint32 p = 0; - while (p < packet.size()) - { - for (uint32 j = 0; j < 16 && p < packet.size(); j++) - sWorldLog.Log("%.2X ", packet[p++]); - sWorldLog.Log("\n"); - } - sWorldLog.Log("\n\n"); - } + ACE_NEW_RETURN (npct, WorldPacket (pct), -1); - ///- If the packet is PING, KEEP_ALIVE or AUTH_SESSION, handle immediately - switch (_cmd) + // NOTE maybe check of the size of the queue can be good ? + // to make it bounded instead of unbounded + if (m_PacketQueue.enqueue_tail (npct) == -1) { - case CMSG_KEEP_ALIVE: - break; // just ignore, network connectivity timeout preventing - case CMSG_PING: - { - _HandlePing(packet); - break; - } - case CMSG_AUTH_SESSION: - { - _HandleAuthSession(packet); - break; - } - default: - { - ///- Else, put it in the world session queue for this user (need to be already authenticated) - if (_session) - _session->QueuePacket(packet); - else - sLog.outDetail("Received out of place packet with cmdid 0x%.4X", _cmd); - break; - } + delete npct; + sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed"); + return -1; } } + + return 0; } -/// On socket closing -void WorldSocket::CloseSocket() +long +WorldSocket::AddReference (void) { - ///- Set CloseAndDelete flag for TcpSocket class - SetCloseAndDelete(true); + return static_cast (this->add_reference ()); +} - ///- Set _session to NULL. Prevent crashes - _session = NULL; +long +WorldSocket::RemoveReference (void) +{ + return static_cast (this->remove_reference ()); } -/// On socket deleting -void WorldSocket::OnDelete() +int +WorldSocket::open (void *a) { - ///- Stop sending remaining data through this socket - if (_session) + ACE_UNUSED_ARG (a); + + // Prevent double call to this func. + if (m_OutBuffer) + return -1; + + // This will also prevent the socket from being Updated + // while we are initializing it. + m_OutActive = true; + + // Hook for the manager. + if (sWorldSocketMgr->OnSocketOpen (this) == -1) + return -1; + + // Allocate the buffer. + ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1); + + // Store peer address. + ACE_INET_Addr remote_addr; + + if (this->peer ().get_remote_addr (remote_addr) == -1) { - _session->SetSocket(NULL); - // Session deleted from World session list at socket==0, This is only back reference from socket to session. - _session = NULL; + sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno)); + return -1; } - ///- Remove the socket from the WorldSocketMgr list - sWorldSocketMgr.RemoveSocket(this); + m_Address = remote_addr.get_host_addr (); - ///- Removes socket from player queue - sWorld.RemoveQueuedPlayer(this); -} + // Send startup packet. + WorldPacket packet (SMSG_AUTH_CHALLENGE, 4); + packet << m_Seed; -/// Handle the client authentication packet -void WorldSocket::_HandleAuthSession(WorldPacket& recvPacket) -{ - uint8 digest[20]; - uint32 clientSeed; - uint32 unk2; - uint32 BuiltNumberClient; - uint32 id, security; - bool tbc = false; - std::string account; - Sha1Hash sha1; - BigNumber v, s, g, N, x, I; - WorldPacket packet, SendAddonPacked; - - BigNumber K; - - SOCKET_CHECK_PACKET_SIZE(recvPacket,4+4+1+4+20); - - ///- Read the content of the packet - recvPacket >> BuiltNumberClient; // for now no use - recvPacket >> unk2; - recvPacket >> account; - - // recheck size - SOCKET_CHECK_PACKET_SIZE(recvPacket,4+4+(account.size()+1)+4+20); - - recvPacket >> clientSeed; - recvPacket.read(digest, 20); - - sLog.outDebug("Auth: client %u, unk2 %u, account %s, clientseed %u", BuiltNumberClient, unk2, account.c_str(), clientSeed); - - ///- Normalize account name - //utf8ToUpperOnlyLatin(account); -- client already send account in expected form - - ///- Get the account information from the realmd database - std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below - loginDatabase.escape_string(safe_account); - //No SQL injection, username escaped. - // 0 1 2 3 4 5 6 7 8 9 10 - QueryResult *result = loginDatabase.PQuery("SELECT id, gmlevel, sessionkey, last_ip, locked, sha_pass_hash, v, s, tbc, mutetime, locale FROM account WHERE username = '%s'", safe_account.c_str()); - - ///- Stop if the account is not found - if ( !result ) + if (SendPacket (packet) == -1) + return -1; + + // Register with ACE Reactor + if (this->reactor ()->register_handler + (this, + ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1) { - packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); - packet << uint8( AUTH_UNKNOWN_ACCOUNT ); - SendPacket( &packet ); - sLog.outDetail( "SOCKET: Sent Auth Response (unknown account)." ); - return; + sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno)); + return -1; } - Field* fields = result->Fetch(); + // reactor takes care of the socket from now on + this->remove_reference (); - tbc = fields[8].GetUInt8() && sWorld.getConfig(CONFIG_EXPANSION) > 0; + return 0; +} - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); - I.SetHexStr(fields[5].GetString()); +int +WorldSocket::close (int) +{ + this->shutdown (); - //In case of leading zeros in the I hash, restore them - uint8 mDigest[SHA_DIGEST_LENGTH]; - memset(mDigest,0,SHA_DIGEST_LENGTH); - if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) - memcpy(mDigest,I.AsByteArray(),I.GetNumBytes()); + this->closing_ = true; - std::reverse(mDigest,mDigest+SHA_DIGEST_LENGTH); + this->remove_reference (); - s.SetHexStr(fields[7].GetString()); - sha1.UpdateData(s.AsByteArray(), s.GetNumBytes()); - sha1.UpdateData(mDigest, SHA_DIGEST_LENGTH); - sha1.Finalize(); - x.SetBinary(sha1.GetDigest(), sha1.GetLength()); - v = g.ModExp(x, N); + return 0; +} - const char* sStr = s.AsHexStr(); //Must be freed by OPENSSL_free() - const char* vStr = v.AsHexStr(); //Must be freed by OPENSSL_free() - const char* vold = fields[6].GetString(); - sLog.outDebug("SOCKET: (s,v) check s: %s v_old: %s v_new: %s", sStr, vold, vStr ); - loginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE username = '%s'", safe_account.c_str()); - if ( !vold || strcmp( vStr, vold ) ) - { - packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); - packet << uint8( AUTH_UNKNOWN_ACCOUNT ); - SendPacket( &packet ); - sLog.outDetail( "SOCKET: User not logged."); - delete result; - OPENSSL_free((void*)sStr); - OPENSSL_free((void*)vStr); - return; - } - OPENSSL_free((void*)sStr); - OPENSSL_free((void*)vStr); +int +WorldSocket::handle_input (ACE_HANDLE) +{ + if (this->closing_) + return -1; - ///- Re-check ip locking (same check as in realmd). - if(fields[4].GetUInt8() == 1) // if ip is locked + switch (this->handle_input_missing_data ()) { - if ( strcmp(fields[3].GetString(),GetRemoteAddress().c_str()) ) - { - packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); - packet << uint8( AUTH_FAILED ); - SendPacket( &packet ); - - sLog.outDetail( "SOCKET: Sent Auth Response (Account IP differs)." ); - delete result; - return; - } + case -1 : + { + if ((errno == EWOULDBLOCK) || + (errno == EAGAIN)) + { + //return 0; + return this->Update (); // interesting line ,isnt it ? + } + + DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno)); + + return -1; + } + case 0: + { + DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n"); + + errno = ECONNRESET; + + return -1; + } + case 1: + return 1; } - id = fields[0].GetUInt32(); - security = fields[1].GetUInt16(); - K.SetHexStr(fields[2].GetString()); - time_t mutetime = time_t(fields[9].GetUInt64()); + //return 0; + return this->Update (); // another interesting line ;) +} + +int +WorldSocket::handle_output (ACE_HANDLE) +{ + ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - LocaleConstant locale = LocaleConstant(fields[10].GetUInt8()); - if (locale>=MAX_LOCALE) - locale=LOCALE_enUS; + if (this->closing_) + return -1; - delete result; + const size_t send_len = m_OutBuffer->length (); - ///- Re-check account ban (same check as in realmd) /// TO DO: why on earth do 2 checks for same thing? - QueryResult *banresult = loginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = '%u' AND active = 1", id); - if(banresult) // if account banned + if (send_len == 0) + return this->cancel_wakeup_output (Guard); + +// TODO SO_NOSIGPIPE on platforms that support it +#ifdef MSG_NOSIGNAL + ssize_t n = this->peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL); +#else + ssize_t n = this->peer ().send (m_OutBuffer->rd_ptr (), send_len); +#endif // MSG_NOSIGNAL + + if (n == 0) + return -1; + else if (n == -1) { - packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); - packet << uint8( AUTH_BANNED ); - SendPacket( &packet ); + if (errno == EWOULDBLOCK || errno == EAGAIN) + return this->schedule_wakeup_output (Guard); - sLog.outDetail( "SOCKET: Sent Auth Response (Account banned)." ); - delete banresult; - return; + return -1; } - - ///- Check locked state for server - AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); - if( allowedAccountType > SEC_PLAYER && security < allowedAccountType) + else if (n < send_len) //now n > 0 { - WorldPacket Packet(SMSG_AUTH_RESPONSE, 1); - Packet << uint8(AUTH_UNAVAILABLE); - SendPacket(&Packet); - return; - } + m_OutBuffer->rd_ptr (static_cast (n)); + + // move the data to the base of the buffer + m_OutBuffer->crunch (); - ///- kick already loaded player with same account (if any) and remove session - ///- if player is in loading and want to load again, return - if(!sWorld.RemoveSession(id)) + return this->schedule_wakeup_output (Guard); + } + else //now n == send_len { - return; + m_OutBuffer->reset (); + + if (!iFlushPacketQueue ()) + return this->cancel_wakeup_output (Guard); + else + return this->schedule_wakeup_output (Guard); } - ///- Check that Key and account name are the same on client and server - Sha1Hash sha; + ACE_NOTREACHED (return 0); +} - uint32 t = 0; - uint32 seed = _seed; +int +WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) +{ + // Critical section + { + ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - sha.UpdateData(account); - sha.UpdateData((uint8 *)&t, 4); - sha.UpdateData((uint8 *)&clientSeed, 4); - sha.UpdateData((uint8 *)&seed, 4); - sha.UpdateBigNumbers(&K, NULL); - sha.Finalize(); + this->closing_ = true; - if (memcmp(sha.GetDigest(), digest, 20)) - { - packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); - packet << uint8( AUTH_FAILED ); - SendPacket( &packet ); + if (h == ACE_INVALID_HANDLE) + this->peer ().close_writer (); + } - sLog.outDetail( "SOCKET: Sent Auth Response (authentication failed)." ); - return; - } + // Critical section + { + ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - ///- Initialize the encryption with the Key - _crypt.SetKey(&K); - _crypt.Init(); + m_Session = NULL; + } - ///- Send 'Auth is ok' - packet.Initialize( SMSG_AUTH_RESPONSE, 1+4+1+4+1 ); - packet << uint8( AUTH_OK ); - packet << uint32(0); // unknown random value... - packet << uint8(0); // can be 0 and 2 - packet << uint32(0); // const 0 - packet << uint8(tbc ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account - SendPacket(&packet); + return 0; +} - ///- Create a new WorldSession for the player and add it to the World - _session = new WorldSession(id, this,security,tbc,mutetime,locale); - sWorld.AddSession(_session); +int +WorldSocket::Update (void) +{ + if (this->closing_) + return -1; - if(sLog.IsOutDebug()) // optimize disabled debug output - { - sLog.outDebug( "SOCKET: Client '%s' authenticated successfully.", account.c_str() ); - sLog.outDebug( "Account: '%s' Logged in from IP %s.", account.c_str(), GetRemoteAddress().c_str()); - } + if (m_OutActive || m_OutBuffer->length () == 0) + return 0; - ///- Update the last_ip in the database - //No SQL injection, username escaped. - std::string address = GetRemoteAddress(); - loginDatabase.escape_string(address); - loginDatabase.PExecute("UPDATE account SET last_ip = '%s' WHERE username = '%s'",address.c_str(), safe_account.c_str()); - - // do small delay (10ms) at accepting successful authed connection to prevent dropping packets by client - // don't must harm anyone (let login ~100 accounts in 1 sec ;) ) - #ifdef WIN32 - Sleep(10); - #else - ZThread::Thread::sleep(10); - #endif - - ///- Check that we do not exceed the maximum number of online players in the realm - uint32 Sessions = sWorld.GetActiveAndQueuedSessionCount(); - uint32 pLimit = sWorld.GetPlayerAmountLimit(); - uint32 QueueSize = sWorld.GetQueueSize(); //number of players in the queue - bool inQueue = false; - --Sessions; //so we don't count the user trying to login as a session and queue the socket that we are using - - if( pLimit > 0 && Sessions >= pLimit && security == SEC_PLAYER ) + return this->handle_output (this->get_handle ()); +} + +int +WorldSocket::handle_input_header (void) +{ + ACE_ASSERT (m_RecvWPct == NULL); + + if (m_Header.length () != sizeof (ClientPktHeader)) { - sWorld.AddQueuedPlayer(this); - SendAuthWaitQue(sWorld.GetQueuePos(this)); - sWorld.UpdateMaxSessionCounters(); - sLog.outDetail( "PlayerQueue: %s is in Queue Position (%u).",safe_account.c_str(),++QueueSize); - inQueue = true; + sLog.outError ("WorldSocket::handle_input_header: internal error: invalid header"); + errno = EINVAL; + return -1; } - ///- Create and send the Addon packet - if(sAddOnHandler.BuildAddonPacket(&recvPacket, &SendAddonPacked)) - SendPacket(&SendAddonPacked); + m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader)); - if(inQueue) - return; + ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ()); - sWorld.UpdateMaxSessionCounters(); + header.size = ACE_NTOHS (header.size); - // Updates the population - if (pLimit > 0) +#if ACE_BYTE_ORDER == ACE_BIG_ENDIAN + header.cmd = ACE_SWAP_LONG (header.cmd) +#endif // ACE_BIG_ENDIAN + + if ((header.size < 4) || + (header.size > 10240) || + (header.cmd <= 0) || + (header.cmd > 10240) + ) { - float popu = sWorld.GetActiveSessionCount(); //updated number of users on the server - popu /= pLimit; - popu *= 2; - loginDatabase.PExecute("UPDATE realmlist SET population = '%f' WHERE id = '%d'",popu,realmID); - sLog.outDetail( "Server Population (%f).",popu); + sLog.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d", + header.size, + header.cmd); + + errno = EINVAL; + return -1; } - return; + header.size -= 4; + + ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1); + + if(header.size > 0) + { + m_RecvWPct->resize (header.size); + m_RecvPct.base ((char*) m_RecvWPct->contents (), m_RecvWPct->size ()); + } + else + { + ACE_ASSERT(m_RecvPct.space() == 0); + } + + + return 0; } -/// Handle the Ping packet -void WorldSocket::_HandlePing(WorldPacket& recvPacket) +int +WorldSocket::handle_input_payload (void) { - uint32 ping; - uint32 latency; + // set errno properly here on error !!! + // now have a header and payload + + ACE_ASSERT (m_RecvPct.space () == 0); + ACE_ASSERT (m_Header.space () == 0); + ACE_ASSERT (m_RecvWPct != NULL); + + const int ret = this->ProcessIncoming (m_RecvWPct); - CHECK_PACKET_SIZE(recvPacket,8); + m_RecvPct.base (NULL, 0); + m_RecvPct.reset (); + m_RecvWPct = NULL; - ///- Get the ping packet content - recvPacket >> ping; - recvPacket >> latency; + m_Header.reset (); - if (_session ) - _session->SetLatency(latency); + if (ret == -1) + errno = EINVAL; + + return ret; +} + +int +WorldSocket::handle_input_missing_data (void) +{ + char buf [1024]; - ///- check ping speed for players - if(_session && _session->GetSecurity() == SEC_PLAYER) + ACE_Data_Block db (sizeof (buf), + ACE_Message_Block::MB_DATA, + buf, + 0, + 0, + ACE_Message_Block::DONT_DELETE, + 0); + + ACE_Message_Block message_block (&db, + ACE_Message_Block::DONT_DELETE, + 0); + + const size_t recv_size = message_block.space (); + + const ssize_t n = this->peer ().recv (message_block.wr_ptr (), + recv_size); + + if (n <= 0) + return n; + + message_block.wr_ptr (n); + + while (message_block.length () > 0) { - uint32 cur_mstime = getMSTime(); + if (m_Header.space () > 0) + { + //need to recieve the header + const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ()); + m_Header.copy (message_block.rd_ptr (), to_header); + message_block.rd_ptr (to_header); + + if (m_Header.space () > 0) + { + //couldnt recieve the whole header this time + ACE_ASSERT (message_block.length () == 0); + errno = EWOULDBLOCK; + return -1; + } + + //we just recieved nice new header + if (this->handle_input_header () == -1) + { + ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); + return -1; + } + } + + // Its possible on some error situations that this happens + // for example on closing when epoll recieves more chunked data and stuff + // hope this is not hack ,as proper m_RecvWPct is asserted around + if (!m_RecvWPct) + { + sLog.outError ("Forsing close on input m_RecvWPct = NULL"); + errno = EINVAL; + return -1; + } - // can overflow and start from 0 - uint32 diff_mstime = getMSTimeDiff(m_LastPingMSTime,cur_mstime); - m_LastPingMSTime = cur_mstime; - if(diff_mstime < 27000) // should be 30000 (=30 secs), add little tolerance + // We have full readed header, now check the data payload + if (m_RecvPct.space () > 0) { - ++m_OverSpeedPings; + //need more data in the payload + const size_t to_data = (message_block.length () > m_RecvPct.space () ? m_RecvPct.space () : message_block.length ()); + m_RecvPct.copy (message_block.rd_ptr (), to_data); + message_block.rd_ptr (to_data); - uint32 max_count = sWorld.getConfig(CONFIG_MAX_OVERSPEED_PINGS); - if(max_count && m_OverSpeedPings > max_count) + if (m_RecvPct.space () > 0) { - sLog.outBasic("Player %s from account id %u kicked for overspeed ping packets from client (non-playable connection lags or cheating) ",_session->GetPlayerName(),_session->GetAccountId()); - _session->KickPlayer(); - return; + //couldnt recieve the whole data this time + ACE_ASSERT (message_block.length () == 0); + errno = EWOULDBLOCK; + return -1; } } - else - m_OverSpeedPings = 0; + //just recieved fresh new payload + if (this->handle_input_payload () == -1) + { + ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); + return -1; + } } - ///- And put the pong answer in the to-be-sent queue - WorldPacket packet( SMSG_PONG, 4 ); - packet << ping; - SendPacket(&packet); + return n == recv_size ? 1 : 2; +} + +int +WorldSocket::cancel_wakeup_output (GuardType& g) +{ + if (!m_OutActive) + return 0; + + m_OutActive = false; + + g.release (); - return; + if (this->reactor ()->cancel_wakeup + (this, ACE_Event_Handler::WRITE_MASK) == -1) + { + // would be good to store errno from reactor with errno guard + sLog.outError ("WorldSocket::cancel_wakeup_output"); + return -1; + } + + return 0; } -/// Handle the update order for the socket -void WorldSocket::SendSinglePacket() +int +WorldSocket::schedule_wakeup_output (GuardType& g) { - WorldPacket *packet; - ServerPktHeader hdr; + if (m_OutActive) + return 0; + + m_OutActive = true; - ///- If we have packet to send - if (!_sendQueue.empty()) + g.release (); + + if (this->reactor ()->schedule_wakeup + (this, ACE_Event_Handler::WRITE_MASK) == -1) { - packet = _sendQueue.next(); + sLog.outError ("WorldSocket::schedule_wakeup_output"); + return -1; + } - hdr.size = ntohs((uint16)packet->size() + 2); - hdr.cmd = packet->GetOpcode(); + return 0; +} - if( sWorldLog.LogWorld() ) - { - sWorldLog.Log("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", - (uint32)GetSocket(), - packet->size(), - LookupOpcodeName(packet->GetOpcode()), - packet->GetOpcode()); - - uint32 p = 0; - while (p < packet->size()) - { - for (uint32 j = 0; j < 16 && p < packet->size(); j++) - sWorldLog.Log("%.2X ", (*packet)[p++]); +int +WorldSocket::ProcessIncoming (WorldPacket* new_pct) +{ + ACE_ASSERT (new_pct); + + // manage memory ;) + ACE_Auto_Ptr aptr (new_pct); - sWorldLog.Log("\n"); - } + const ACE_UINT16 opcode = new_pct->GetOpcode (); - sWorldLog.Log("\n\n"); + if (this->closing_) + return -1; + + // dump recieved packet + if (sWorldLog.LogWorld ()) + { + sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", + (uint32) get_handle (), + new_pct->size (), + LookupOpcodeName (new_pct->GetOpcode ()), + new_pct->GetOpcode ()); + + uint32 p = 0; + while (p < new_pct->size ()) + { + for (uint32 j = 0; j < 16 && p < new_pct->size (); j++) + sWorldLog.Log ("%.2X ", (*new_pct)[p++]); + sWorldLog.Log ("\n"); } + sWorldLog.Log ("\n\n"); + } - ///- Encrypt (if needed) the header - _crypt.EncryptSend((uint8*)&hdr, 4); + // like one switch ;) + if (opcode == CMSG_PING) + { + return HandlePing (*new_pct); + } + else if (opcode == CMSG_AUTH_SESSION) + { + if (m_Session) + { + sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again"); + return -1; + } - ///- Send the header and body to the client - TcpSocket::SendBuf((char*)&hdr, 4); - if(!packet->empty()) TcpSocket::SendBuf((char*)packet->contents(), packet->size()); + return HandleAuthSession (*new_pct); + } + else if (opcode == CMSG_KEEP_ALIVE) + { + DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size ()); - delete packet; + return 0; } + else + { + ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); + + if (m_Session != NULL) + { + // OK ,give the packet to WorldSession + aptr.release (); + // WARNINIG here we call it with locks held. + // Its possible to cause deadlock if QueuePacket calls back + m_Session->QueuePacket (new_pct); + return 0; + } + else + { + sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode); + return -1; + } + } + + ACE_NOTREACHED (return 0); } -void WorldSocket::Update(time_t diff) +int +WorldSocket::HandleAuthSession (WorldPacket& recvPacket) { - const uint32 SEND_PACKETS_MAX = 100; - const uint32 SEND_BUFFER_SIZE = 1024; + uint8 digest[20]; + uint32 clientSeed; + uint32 unk2; + uint32 BuiltNumberClient; + uint32 id, security; + bool tbc = false; + LocaleConstant locale; + std::string account; + Sha1Hash sha1; + BigNumber v, s, g, N, x, I; + WorldPacket packet, SendAddonPacked; + + BigNumber K; + + if (recvPacket.size () < (4 + 4 + 1 + 4 + 20)) + { + sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size"); + return -1; + } + + // Read the content of the packet + recvPacket >> BuiltNumberClient; // for now no use + recvPacket >> unk2; + recvPacket >> account; - uint8 sendBuffer[SEND_BUFFER_SIZE]; + if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20)) + { + sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check"); + return -1; + } + + recvPacket >> clientSeed; + recvPacket.read (digest, 20); + + DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u", + BuiltNumberClient, + unk2, + account.c_str (), + clientSeed); - while (!_sendQueue.empty()) +#if defined _NETCODE_FAKE_AUTH + bool dontchechtheacc = false; + uint8 digest_fake[sizeof (digest)]; + memset ((void*) digest_fake, '\0', sizeof (digest_fake)); + if (memcmp ((void*) digest, (void*) digest_fake, sizeof (digest_fake)) == 0) { - bool haveBigPacket = false; - uint32 bufferSize = 0; + dontchechtheacc = true; + } +#endif //_NETCODE_FAKE_AUTH + + // Get the account information from the realmd database + std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below + loginDatabase.escape_string (safe_account); + // No SQL injection, username escaped. + + QueryResult *result = + loginDatabase.PQuery ("SELECT " + "id, " //0 + "gmlevel, " //1 + "sessionkey, " //2 + "last_ip, " //3 + "locked, " //4 + "sha_pass_hash, " //5 + "v, " //6 + "s, " //7 + "tbc, " //8 + "mutetime, " //9 + "locale " //10 + "FROM account " + "WHERE username = '%s'", + safe_account.c_str ()); + + // Stop if the account is not found + if (!result) + { + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_UNKNOWN_ACCOUNT); + + SendPacket (packet); + + sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); + return -1; + } + + Field* fields = result->Fetch (); + + tbc = fields[8].GetUInt8 () && sWorld.getConfig (CONFIG_EXPANSION) > 0; + + N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); + g.SetDword (7); + I.SetHexStr (fields[5].GetString ()); + + //In case of leading zeros in the I hash, restore them + uint8 mDigest[SHA_DIGEST_LENGTH]; + memset (mDigest, 0, SHA_DIGEST_LENGTH); + + if (I.GetNumBytes () <= SHA_DIGEST_LENGTH) + memcpy (mDigest, I.AsByteArray (), I.GetNumBytes ()); + + std::reverse (mDigest, mDigest + SHA_DIGEST_LENGTH); + + s.SetHexStr (fields[7].GetString ()); + sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ()); + sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH); + sha1.Finalize (); + x.SetBinary (sha1.GetDigest (), sha1.GetLength ()); + v = g.ModExp (x, N); + + const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free() + const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free() + const char* vold = fields[6].GetString (); - ///- While we have packets to send - for (uint32 packetCount = 0; (packetCount < SEND_PACKETS_MAX) && !_sendQueue.empty(); packetCount++) + DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s", + sStr, + vold, + vStr); + + loginDatabase.PExecute ("UPDATE account " + "SET " + "v = '0', " + "s = '0' " + "WHERE username = '%s'", + safe_account.c_str ()); + +#if defined _NETCODE_FAKE_AUTH + if (!dontchechtheacc) + { +#endif + if (!vold || strcmp (vStr, vold)) { - ServerPktHeader *hdr = (ServerPktHeader*)&sendBuffer[bufferSize]; + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_UNKNOWN_ACCOUNT); + SendPacket (packet); + delete result; + OPENSSL_free ((void*) sStr); + OPENSSL_free ((void*) vStr); + + sLog.outError ("WorldSocket::HandleAuthSession: User not logged."); + return -1; + } +#if defined _NETCODE_FAKE_AUTH + } +#endif - // check merge possibility. - WorldPacket *front = _sendQueue.front(); - uint32 packetSize = front->size(); + OPENSSL_free ((void*) sStr); + OPENSSL_free ((void*) vStr); - if ((sizeof(*hdr) + packetSize) > SEND_BUFFER_SIZE) - { - haveBigPacket = true; - break; - } + ///- Re-check ip locking (same check as in realmd). + if (fields[4].GetUInt8 () == 1) // if ip is locked + { + if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ())) + { + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_FAILED); + SendPacket (packet); - if ((bufferSize + sizeof(*hdr) + packetSize) > sizeof(sendBuffer)) - break; + delete result; + sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); + return -1; + } + } - // can be merged - WorldPacket *packet = _sendQueue.next(); + id = fields[0].GetUInt32 (); + security = fields[1].GetUInt16 (); + K.SetHexStr (fields[2].GetString ()); - hdr->size = ntohs((uint16)packetSize + 2); - hdr->cmd = packet->GetOpcode(); + time_t mutetime = time_t (fields[9].GetUInt64 ()); - if( sWorldLog.LogWorld() ) - { - sWorldLog.Log("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", - (uint32)GetSocket(), - packetSize, - LookupOpcodeName(packet->GetOpcode()), - packet->GetOpcode()); - - uint32 p = 0; - while (p < packetSize) - { - for (uint32 j = 0; j < 16 && p < packetSize; j++) - sWorldLog.Log("%.2X ", (*packet)[p++]); + locale = LocaleConstant (fields[10].GetUInt8 ()); + if (locale >= MAX_LOCALE) + locale = LOCALE_enUS; - sWorldLog.Log("\n"); - } + delete result; - sWorldLog.Log("\n\n"); - } +#if defined _NETCODE_FAKE_AUTH + if (!dontchechtheacc) + { +#endif + // Re-check account ban (same check as in realmd) + QueryResult *banresult = + loginDatabase.PQuery ("SELECT " + "bandate, " + "unbandate " + "FROM account_banned " + "WHERE id = '%u' " + "AND active = 1", + id); + + if (banresult) // if account banned + { + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_BANNED); + SendPacket (packet); - ///- Encrypt (if needed) the header - _crypt.EncryptSend((uint8*)hdr, sizeof(*hdr)); - bufferSize += sizeof(*hdr); + delete banresult; - if (packetSize) - { - memcpy(&sendBuffer[bufferSize], packet->contents(), packetSize); - bufferSize += packetSize; - } + sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); + return -1; + } + + // Check locked state for server + AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit (); - ///- Send the header and body to the client - delete packet; + if (allowedAccountType > SEC_PLAYER && security < allowedAccountType) + { + WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); + Packet << uint8 (AUTH_UNAVAILABLE); + + SendPacket (packet); + + sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough"); + return -1; } - // send merged packets - if (bufferSize) TcpSocket::SendBuf((char*)sendBuffer, bufferSize); - // send too big non-merged packet - if (haveBigPacket) SendSinglePacket(); + // Check that Key and account name are the same on client and server + Sha1Hash sha; + + uint32 t = 0; + uint32 seed = m_Seed; + + sha.UpdateData (account); + sha.UpdateData ((uint8 *) & t, 4); + sha.UpdateData ((uint8 *) & clientSeed, 4); + sha.UpdateData ((uint8 *) & seed, 4); + sha.UpdateBigNumbers (&K, NULL); + sha.Finalize (); + + if (memcmp (sha.GetDigest (), digest, 20)) + { + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_FAILED); + + SendPacket (packet); + + sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); + return -1; + } +#if defined _NETCODE_FAKE_AUTH } +#endif + + std::string address = this->GetRemoteAddress (); + + DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", + account.c_str (), + address.c_str ()); + + // Update the last_ip in the database + // No SQL injection, username escaped. + loginDatabase.escape_string (address); + + loginDatabase.PExecute ("UPDATE account " + "SET last_ip = '%s' " + "WHERE username = '%s'", + address.c_str (), + safe_account.c_str ()); + + // TODO protect here probably ? + // Althought atm the socket is singlethreaded + ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, tbc, mutetime, locale), -1); + +#if defined _NETCODE_FAKE_AUTH + if (!dontchechtheacc) + { +#endif + this->m_Crypt.SetKey (&K); + this->m_Crypt.Init (); +#if defined _NETCODE_FAKE_AUTH + } +#endif + + // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec + ACE_OS::sleep (ACE_Time_Value (0, 10000)); + + // TODO error handling + sWorld.AddSession (this->m_Session); + + // Create and send the Addon packet + if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked)) + SendPacket (SendAddonPacked); + + return 0; } -/// Handle the authentication waiting queue (to be completed) -void WorldSocket::SendAuthWaitQue(uint32 position) +int +WorldSocket::HandlePing (WorldPacket& recvPacket) { - if(position == 0) + uint32 ping; + uint32 latency; + + if (recvPacket.size () < 8) { - WorldPacket packet( SMSG_AUTH_RESPONSE, 1 ); - packet << uint8( AUTH_OK ); - SendPacket(&packet); + sLog.outError ("WorldSocket::_HandlePing wrong packet size"); + return -1; } + + // Get the ping packet content + recvPacket >> ping; + recvPacket >> latency; + + if (m_LastPingTime == ACE_Time_Value::zero) + m_LastPingTime = ACE_OS::gettimeofday (); // for 1st ping + else + { + ACE_Time_Value cur_time = ACE_OS::gettimeofday (); + ACE_Time_Value diff_time (cur_time); + diff_time -= m_LastPingTime; + m_LastPingTime = cur_time; + + if (diff_time < ACE_Time_Value (27)) + { + ++m_OverSpeedPings; + + uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS); + + if (max_count && m_OverSpeedPings > max_count) + { + ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); + + if (m_Session && m_Session->GetSecurity () == SEC_PLAYER) + { + sLog.outError ("WorldSocket::HandlePing: Player kicked for " + "overspeeded pings adress = %s", + GetRemoteAddress ().c_str ()); + + return -1; + } + } + } + else + m_OverSpeedPings = 0; + } + + // critical section + { + ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); + + if (m_Session) + m_Session->SetLatency (latency); else + { + sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, " + "but is not authenticated or got recently kicked," + " adress = %s", + this->GetRemoteAddress ().c_str ()); + return -1; + } + } + + WorldPacket packet (SMSG_PONG, 4); + packet << ping; + return this->SendPacket (packet); +} + +int +WorldSocket::iSendPacket (const WorldPacket& pct) +{ + if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader)) { - WorldPacket packet( SMSG_AUTH_RESPONSE, 5 ); - packet << uint8( AUTH_WAIT_QUEUE ); - packet << uint32 (position); //amount of players in queue - SendPacket(&packet); + errno = ENOBUFS; + return -1; } + + ServerPktHeader header; + + header.cmd = pct.GetOpcode (); + +#if ACE_BYTE_ORDER == ACE_BIG_ENDIAN + header.cmd = ACE_SWAP_WORD (header.cmd) +#endif + + header.size = (uint16) pct.size () + 2; + header.size = ACE_HTONS (header.size); + + m_Crypt.EncryptSend ((uint8*) & header, sizeof (header)); + + if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1) + ACE_ASSERT (false); + + if (!pct.empty ()) + if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1) + ACE_ASSERT (false); + + return 0; } -void WorldSocket::SizeError(WorldPacket const& packet, uint32 size) const +bool +WorldSocket::iFlushPacketQueue () { - sLog.outError("Client send packet %s (%u) with size %u but expected %u (attempt crash server?), skipped", - LookupOpcodeName(packet.GetOpcode()),packet.GetOpcode(),packet.size(),size); + WorldPacket *pct; + bool haveone = false; + + while (m_PacketQueue.dequeue_head (pct) == 0) + { + if (iSendPacket (*pct) == -1) + { + if (m_PacketQueue.enqueue_head (pct) == -1) + { + delete pct; + sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head"); + return false; + } + + break; + } + else + { + haveone = true; + delete pct; + } + } + + return haveone; } diff --git a/src/game/WorldSocket.h b/src/game/WorldSocket.h index 26f8fb882f0..96b8f5eda38 100644 --- a/src/game/WorldSocket.h +++ b/src/game/WorldSocket.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2008 MaNGOS * * This program is free software; you can redistribute it and/or modify @@ -16,164 +16,218 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/// \addtogroup u2w -/// @{ -/// \file +/** \addtogroup u2w User to World Communication + * @{ + * \file WorldSocket.h + * \author Derex + */ -#ifndef __WORLDSOCKET_H -#define __WORLDSOCKET_H +#ifndef _WORLDSOCKET_H +#define _WORLDSOCKET_H -#include "sockets/TcpSocket.h" -#include "Auth/AuthCrypt.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -enum ResponseCodes -{ - RESPONSE_SUCCESS = 0x00, - RESPONSE_FAILURE = 0x01, - RESPONSE_CANCELLED = 0x02, - RESPONSE_DISCONNECTED = 0x03, - RESPONSE_FAILED_TO_CONNECT = 0x04, - RESPONSE_CONNECTED = 0x05, - RESPONSE_VERSION_MISMATCH = 0x06, - - CSTATUS_CONNECTING = 0x07, - CSTATUS_NEGOTIATING_SECURITY = 0x08, - CSTATUS_NEGOTIATION_COMPLETE = 0x09, - CSTATUS_NEGOTIATION_FAILED = 0x0A, - CSTATUS_AUTHENTICATING = 0x0B, - - AUTH_OK = 0x0C, - AUTH_FAILED = 0x0D, - AUTH_REJECT = 0x0E, - AUTH_BAD_SERVER_PROOF = 0x0F, - AUTH_UNAVAILABLE = 0x10, - AUTH_SYSTEM_ERROR = 0x11, - AUTH_BILLING_ERROR = 0x12, - AUTH_BILLING_EXPIRED = 0x13, - AUTH_VERSION_MISMATCH = 0x14, - AUTH_UNKNOWN_ACCOUNT = 0x15, - AUTH_INCORRECT_PASSWORD = 0x16, - AUTH_SESSION_EXPIRED = 0x17, - AUTH_SERVER_SHUTTING_DOWN = 0x18, - AUTH_ALREADY_LOGGING_IN = 0x19, - AUTH_LOGIN_SERVER_NOT_FOUND = 0x1A, - AUTH_WAIT_QUEUE = 0x1B, - AUTH_BANNED = 0x1C, - AUTH_ALREADY_ONLINE = 0x1D, - AUTH_NO_TIME = 0x1E, - AUTH_DB_BUSY = 0x1F, - AUTH_SUSPENDED = 0x20, - AUTH_PARENTAL_CONTROL = 0x21, - AUTH_LOCKED_ENFORCED = 0x22, - - REALM_LIST_IN_PROGRESS = 0x23, - REALM_LIST_SUCCESS = 0x24, - REALM_LIST_FAILED = 0x25, - REALM_LIST_INVALID = 0x26, - REALM_LIST_REALM_NOT_FOUND = 0x27, - - ACCOUNT_CREATE_IN_PROGRESS = 0x28, - ACCOUNT_CREATE_SUCCESS = 0x29, - ACCOUNT_CREATE_FAILED = 0x2A, - - CHAR_LIST_RETRIEVING = 0x2B, - CHAR_LIST_RETRIEVED = 0x2C, - CHAR_LIST_FAILED = 0x2D, - - CHAR_CREATE_IN_PROGRESS = 0x2E, - CHAR_CREATE_SUCCESS = 0x2F, - CHAR_CREATE_ERROR = 0x30, - CHAR_CREATE_FAILED = 0x31, - CHAR_CREATE_NAME_IN_USE = 0x32, - CHAR_CREATE_DISABLED = 0x33, - CHAR_CREATE_PVP_TEAMS_VIOLATION = 0x34, - CHAR_CREATE_SERVER_LIMIT = 0x35, - CHAR_CREATE_ACCOUNT_LIMIT = 0x36, - CHAR_CREATE_SERVER_QUEUE = 0x37, - CHAR_CREATE_ONLY_EXISTING = 0x38, - CHAR_CREATE_EXPANSION = 0x39, - - CHAR_DELETE_IN_PROGRESS = 0x3A, - CHAR_DELETE_SUCCESS = 0x3B, - CHAR_DELETE_FAILED = 0x3C, - CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x3D, - CHAR_DELETE_FAILED_GUILD_LEADER = 0x3E, - CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x3F, - - CHAR_LOGIN_IN_PROGRESS = 0x40, - CHAR_LOGIN_SUCCESS = 0x41, - CHAR_LOGIN_NO_WORLD = 0x42, - CHAR_LOGIN_DUPLICATE_CHARACTER = 0x43, - CHAR_LOGIN_NO_INSTANCES = 0x44, - CHAR_LOGIN_FAILED = 0x45, - CHAR_LOGIN_DISABLED = 0x46, - CHAR_LOGIN_NO_CHARACTER = 0x47, - CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x48, - CHAR_LOGIN_LOCKED_BY_BILLING = 0x49, - - CHAR_NAME_SUCCESS = 0x4A, - CHAR_NAME_FAILURE = 0x4B, - CHAR_NAME_NO_NAME = 0x4C, - CHAR_NAME_TOO_SHORT = 0x4D, - CHAR_NAME_TOO_LONG = 0x4E, - CHAR_NAME_INVALID_CHARACTER = 0x4F, - CHAR_NAME_MIXED_LANGUAGES = 0x50, - CHAR_NAME_PROFANE = 0x51, - CHAR_NAME_RESERVED = 0x52, - CHAR_NAME_INVALID_APOSTROPHE = 0x53, - CHAR_NAME_MULTIPLE_APOSTROPHES = 0x54, - CHAR_NAME_THREE_CONSECUTIVE = 0x55, - CHAR_NAME_INVALID_SPACE = 0x56, - CHAR_NAME_CONSECUTIVE_SPACES = 0x57, - CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x58, - CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x59, - CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x5A, -}; +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ +#include "Common.h" +#include "Auth/AuthCrypt.h" + +class ACE_Message_Block; class WorldPacket; -class SocketHandler; class WorldSession; -/// Handle connection with the client software -class WorldSocket : public TcpSocket +/// Handler that can communicate over stream sockets. +typedef ACE_Svc_Handler WorldHandler; + +/** + * WorldSocket. + * + * This class is responsible for the comunication with + * remote clients. + * Most methods return -1 on failure. + * The class uses refferece counting. + * + * For output the class uses one buffer (64K usually) and + * a queue where it stores packet if there is no place on + * the queue. The reason this is done, is because the server + * does realy a lot of small-size writes to it, and it doesn't + * scale well to allocate memory for every. When something is + * writen to the output buffer the socket is not immideately + * activated for output (again for the same reason), there + * is 10ms celling (thats why there is Update() method). + * This concept is simmilar to TCP_CORK, but TCP_CORK + * usses 200ms celling. As result overhead generated by + * sending packets from "producer" threads is minimal, + * and doing a lot of writes with small size is tollerated. + * + * The calls to Upate () method are managed by WorldSocketMgr + * and ReactorRunnable. + * + * For input ,the class uses one 1024 bytes buffer on stack + * to which it does recv() calls. And then recieved data is + * distributed where its needed. 1024 matches pritey well the + * traffic generated by client for now. + * + * The input/output do speculative reads/writes (AKA it tryes + * to read all data avaible in the kernel buffer or tryes to + * write everything avaible in userspace buffer), + * which is ok for using with Level and Edge Trigered IO + * notification. + * + */ +class WorldSocket : protected WorldHandler { - public: - WorldSocket(ISocketHandler&); - ~WorldSocket(); +public: + /// Declare some friends + friend class ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR >; + friend class WorldSocketMgr; + friend class ReactorRunnable; + + /// Declare the acceptor for this class + typedef ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR > Acceptor; + + /// Mutex type used for various syncronizations. + typedef ACE_Thread_Mutex LockType; + typedef ACE_Guard GuardType; + + /// Queue for storing packets for which there is no space. + typedef ACE_Unbounded_Queue< WorldPacket* > PacketQueueT; + + /// Check if socket is closed. + bool IsClosed (void) const; + + /// Close the socket. + void CloseSocket (void); + + /// Get address of connected peer. + const std::string& GetRemoteAddress (void) const; + + /// Send A packet on the socket, this function is reentrant. + /// @param pct packet to send + /// @return -1 of failure + int SendPacket (const WorldPacket& pct); + + /// Add refference to this object. + long AddReference (void); + + /// Remove refference to this object. + long RemoveReference (void); + +protected: + /// things called by ACE framework. + WorldSocket (void); + virtual ~WorldSocket (void); + + /// Called on open ,the void* is the acceptor. + virtual int open (void *); + + /// Called on failures inside of the acceptor, don't call from your code. + virtual int close (int); - void SendPacket(WorldPacket const* packet); - void CloseSocket(); + /// Called when we can read from the socket. + virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); - void OnAccept(); - void OnRead(); - void OnDelete(); + /// Called when the socket can write. + virtual int handle_output (ACE_HANDLE = ACE_INVALID_HANDLE); - void Update(time_t diff); - // Player Queue - void SendAuthWaitQue(uint32 position); + /// Called when connection is closed or error happens. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); - WorldSession* GetSession() const { return _session; } - protected: - void SendSinglePacket(); + /// Called by WorldSocketMgr/ReactorRunnable. + int Update (void); - protected: - void _HandleAuthSession(WorldPacket& recvPacket); - void _HandlePing(WorldPacket& recvPacket); +private: + /// Helper functions for processing incoming data. + int handle_input_header (void); + int handle_input_payload (void); + int handle_input_missing_data (void); - private: - AuthCrypt _crypt; - uint32 _seed; - uint32 _cmd; - uint16 _remaining; - WorldSession* _session; + /// Help functions to mark/unmark the socket for output. + /// @param g the guard is for m_OutBufferLock, the function will release it + int cancel_wakeup_output (GuardType& g); + int schedule_wakeup_output (GuardType& g); - ZThread::LockedQueue _sendQueue; + /// process one incoming packet. + /// @param new_pct received packet ,note that you need to delete it. + int ProcessIncoming (WorldPacket* new_pct); - uint32 m_LastPingMSTime; - uint32 m_OverSpeedPings; + /// Called by ProcessIncoming() on CMSG_AUTH_SESSION. + int HandleAuthSession (WorldPacket& recvPacket); - // internal checks - void SizeError(WorldPacket const& packet, uint32 size) const; + /// Called by ProcessIncoming() on CMSG_PING. + int HandlePing (WorldPacket& recvPacket); + + /// Try to write WorldPacket to m_OutBuffer ,return -1 if no space + /// Need to be called with m_OutBufferLock lock held + int iSendPacket (const WorldPacket& pct); + + /// Flush m_PacketQueue if there are packets in it + /// Need to be called with m_OutBufferLock lock held + /// @return true if it wrote to the buffer ( AKA you need + /// to mark the socket for output ). + bool iFlushPacketQueue (); + +private: + /// Time in which the last ping was received + ACE_Time_Value m_LastPingTime; + + /// Keep track of overspeed pings ,to prevent ping flood. + uint32 m_OverSpeedPings; + + /// Address of the remote peer + std::string m_Address; + + /// Class used for managing encryption of the headers + AuthCrypt m_Crypt; + + /// Mutex lock to protect m_Session + LockType m_SessionLock; + + /// Session to which recieved packets are routed + WorldSession* m_Session; + + /// here are stored the fragmens of the recieved data + WorldPacket* m_RecvWPct; + + /// This block actually refers to m_RecvWPct contents, + /// which alows easy and safe writing to it. + /// It wont free memory when its deleted. m_RecvWPct takes care of freeing. + ACE_Message_Block m_RecvPct; + + /// Fragment of the recieved header. + ACE_Message_Block m_Header; + + /// Mutex for protecting otuput related data. + LockType m_OutBufferLock; + + /// Buffer used for writing output. + ACE_Message_Block *m_OutBuffer; + + /// Size of the m_OutBuffer. + size_t m_OutBufferSize; + + /// Here are stored packets for which there was no space on m_OutBuffer, + /// this alows not-to kick player if its buffer is overflowed. + PacketQueueT m_PacketQueue; + + /// True if the socket is registered with the reactor for output + bool m_OutActive; + + uint32 m_Seed; }; -#endif + +#endif /* _WORLDSOCKET_H */ + /// @} diff --git a/src/game/WorldSocketMgr.cpp b/src/game/WorldSocketMgr.cpp index 0281d200109..7af1389e92a 100644 --- a/src/game/WorldSocketMgr.cpp +++ b/src/game/WorldSocketMgr.cpp @@ -16,40 +16,355 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/** \file - \ingroup u2w -*/ +/** \file WorldSocketMgr.cpp + * \ingroup u2w + * \author Derex + */ + +#include "WorldSocketMgr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Log.h" #include "Common.h" +#include "Config/ConfigEnv.h" +#include "Database/DatabaseEnv.h" #include "WorldSocket.h" -#include "WorldSocketMgr.h" -#include "Policies/SingletonImp.h" -INSTANTIATE_SINGLETON_1( WorldSocketMgr ); +/** + * This is a helper class to WorldSocketMgr ,that manages + * network threads, and assigning connections from acceptor thread + * to other network threads + */ +class ReactorRunnable : protected ACE_Task_Base +{ +public: + + ReactorRunnable () : + m_ThreadId (-1), + m_Connections (0), + m_Reactor (0) + { + ACE_Reactor_Impl* imp = 0; + +#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) + imp = new ACE_Dev_Poll_Reactor (); + + imp->max_notify_iterations (128); + imp->restart (1); +#else + imp = new ACE_TP_Reactor (); + imp->max_notify_iterations (128); +#endif + + m_Reactor = new ACE_Reactor (imp, 1); + } + + virtual + ~ReactorRunnable () + { + this->Stop (); + this->Wait (); + + if (m_Reactor) + delete m_Reactor; + } + + void + Stop () + { + m_Reactor->end_reactor_event_loop (); + } + + int + Start () + { + if (m_ThreadId != -1) + return -1; + + return (m_ThreadId = this->activate ()); + } + + void + Wait () + { + ACE_Task_Base::wait (); + } + + long + Connections () + { + return static_cast (m_Connections.value ()); + } + + int + AddSocket (WorldSocket* sock) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, Guard, m_NewSockets_Lock, -1); + + ++m_Connections; + sock->AddReference(); + sock->reactor (m_Reactor); + m_NewSockets.insert (sock); + + return 0; + } + + ACE_Reactor* GetReactor () + { + return m_Reactor; + } + +protected: + + void + AddNewSockets () + { + ACE_GUARD (ACE_Thread_Mutex, Guard, m_NewSockets_Lock); + + if (m_NewSockets.empty ()) + return; + + for (SocketSet::iterator i = m_NewSockets.begin (); i != m_NewSockets.end (); ++i) + { + WorldSocket* sock = (*i); + + if (sock->IsClosed ()) + { + sock->RemoveReference (); + --m_Connections; + } + else + m_Sockets.insert (sock); + } + + m_NewSockets.clear (); + } + + virtual int + svc (void) + { + DEBUG_LOG ("Network Thread Starting"); + + WorldDatabase.ThreadStart (); + + ACE_ASSERT (m_Reactor); + + SocketSet::iterator i, t; + + while (!m_Reactor->reactor_event_loop_done ()) + { + // dont be too smart to move this outside the loop + // the run_reactor_event_loop will modify interval + ACE_Time_Value interval (0, 10000); + + if (m_Reactor->run_reactor_event_loop (interval) == -1) + break; + + AddNewSockets (); + + for (i = m_Sockets.begin (); i != m_Sockets.end ();) + { + if ((*i)->Update () == -1) + { + t = i; + i++; + (*t)->CloseSocket (); + (*t)->RemoveReference (); + --m_Connections; + m_Sockets.erase (t); + } + else + i++; + } + } + + WorldDatabase.ThreadEnd (); + + DEBUG_LOG ("Network Thread Exitting"); + + return 0; + } + +private: + typedef ACE_Atomic_Op AtomicInt; + typedef std::set SocketSet; + + ACE_Reactor* m_Reactor; + AtomicInt m_Connections; + int m_ThreadId; + + SocketSet m_Sockets; + + SocketSet m_NewSockets; + ACE_Thread_Mutex m_NewSockets_Lock; +}; + + + +WorldSocketMgr::WorldSocketMgr () : +m_NetThreadsCount (0), +m_NetThreads (0), +m_SockOutKBuff (-1), +m_SockOutUBuff (65536), +m_UseNoDelay (true), +m_Acceptor (0) {} -/// WorldSocketMgr constructor -WorldSocketMgr::WorldSocketMgr() +WorldSocketMgr::~WorldSocketMgr () { + if (m_NetThreads) + delete [] m_NetThreads; + + if(m_Acceptor) + delete m_Acceptor; } -/// Add a WorldSocket to the set -void WorldSocketMgr::AddSocket(WorldSocket *s) +int +WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address) { - m_sockets.insert(s); + m_UseNoDelay = sConfig.GetBoolDefault ("Network.TcpNodelay", true); + + int num_threads = sConfig.GetIntDefault ("Network.Threads", 1); + + if (num_threads <= 0) + { + sLog.outError ("Network.Threads is wrong in your config file"); + return -1; + } + + m_NetThreadsCount = static_cast (num_threads + 1); + + m_NetThreads = new ReactorRunnable[m_NetThreadsCount]; + + sLog.outBasic ("Max alowed socket connections %d",ACE::max_handles ()); + + m_SockOutKBuff = sConfig.GetIntDefault ("Network.OutKBuff", -1); // -1 means use default + + m_SockOutUBuff = sConfig.GetIntDefault ("Network.OutUBuff", 65536); + + if ( m_SockOutUBuff <= 0 ) + { + sLog.outError ("Network.OutUBuff is wrong in your config file"); + return -1; + } + + WorldSocket::Acceptor *acc = new WorldSocket::Acceptor; + m_Acceptor = acc; + + ACE_INET_Addr listen_addr (port, address); + + if (acc->open (listen_addr, m_NetThreads[0].GetReactor (), ACE_NONBLOCK) == -1) + { + sLog.outError ("Failed to open acceptor ,check if the port is free"); + return -1; + } + + for (size_t i = 0; i < m_NetThreadsCount; ++i) + m_NetThreads[i].Start (); + + return 0; } -/// Remove a WorldSocket to the set -void WorldSocketMgr::RemoveSocket(WorldSocket *s) +int +WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address) { - m_sockets.erase(s); + if (!sLog.IsOutDebug ()) + ACE_Log_Msg::instance ()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS); + + if (this->StartReactiveIO (port, address) == -1) + return -1; + + return 0; } -/// Triggers an 'update' to all sockets in the set -void WorldSocketMgr::Update(time_t diff) +void +WorldSocketMgr::StopNetwork () { - SocketSet::iterator i; - for(i = m_sockets.begin(); i != m_sockets.end(); i++) + if (m_Acceptor) { - (*i)->Update(diff); + WorldSocket::Acceptor* acc = dynamic_cast (m_Acceptor); + + if (acc) + acc->close (); } + + if (m_NetThreadsCount != 0) + { + for (size_t i = 0; i < m_NetThreadsCount; ++i) + m_NetThreads[i].Stop (); + } + + this->Wait (); +} + +void +WorldSocketMgr::Wait () +{ + if (m_NetThreadsCount != 0) + { + for (size_t i = 0; i < m_NetThreadsCount; ++i) + m_NetThreads[i].Wait (); + } +} + +int +WorldSocketMgr::OnSocketOpen (WorldSocket* sock) +{ + // set some options here + if (m_SockOutKBuff >= 0) + if (sock->peer ().set_option (SOL_SOCKET, + SO_SNDBUF, + (void*) & m_SockOutKBuff, + sizeof (int)) == -1 && errno != ENOTSUP) + { + sLog.outError ("WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF"); + return -1; + } + + static const int ndoption = 1; + + // Set TCP_NODELAY. + if (m_UseNoDelay) + if (sock->peer ().set_option (ACE_IPPROTO_TCP, + TCP_NODELAY, + (void*) & ndoption, + sizeof (int)) == -1) + { + sLog.outError ("WorldSocketMgr::OnSocketOpen: peer ().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno)); + return -1; + } + + sock->m_OutBufferSize = static_cast (m_SockOutUBuff); + + // we skip the Acceptor Thread + size_t min = 1; + + ACE_ASSERT (m_NetThreadsCount >= 1); + + for (size_t i = 1; i < m_NetThreadsCount; ++i) + if (m_NetThreads[i].Connections () < m_NetThreads[min].Connections ()) + min = i; + + return m_NetThreads[min].AddSocket (sock); + + return 0; +} + +WorldSocketMgr* +WorldSocketMgr::Instance () +{ + return ACE_Singleton::instance(); } diff --git a/src/game/WorldSocketMgr.h b/src/game/WorldSocketMgr.h index 5a26d739f4a..923efa02fe1 100644 --- a/src/game/WorldSocketMgr.h +++ b/src/game/WorldSocketMgr.h @@ -16,32 +16,62 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/// \addtogroup u2w User to World Communication -/// @{ -/// \file +/** \addtogroup u2w User to World Communication + * @{ + * \file WorldSocketMgr.h + * \author Derex + */ #ifndef __WORLDSOCKETMGR_H #define __WORLDSOCKETMGR_H -#include "Policies/Singleton.h" +#include +#include +#include class WorldSocket; +class ReactorRunnable; +class ACE_Event_Handler; -/// Manages the list of connected WorldSockets -class WorldSocketMgr +/// Manages all sockets connected to peers and network threads +class WorldSocketMgr { - public: - WorldSocketMgr(); - - void AddSocket(WorldSocket *s); - void RemoveSocket(WorldSocket *s); - void Update(time_t diff); +public: + friend class WorldSocket; + friend class ACE_Singleton; - private: - typedef std::set SocketSet; - SocketSet m_sockets; + /// Start network, listen at address:port . + int StartNetwork (ACE_UINT16 port, const char* address); + + /// Stops all network threads, It will wait for all running threads . + void StopNetwork (); + + /// Wait untill all network threads have "joined" . + void Wait (); + + /// Make this class singleton . + static WorldSocketMgr* Instance (); + +private: + int OnSocketOpen(WorldSocket* sock); + + int StartReactiveIO(ACE_UINT16 port, const char* address); + +private: + WorldSocketMgr (); + virtual ~WorldSocketMgr (); + + ReactorRunnable* m_NetThreads; + size_t m_NetThreadsCount; + + int m_SockOutKBuff; + int m_SockOutUBuff; + bool m_UseNoDelay; + + ACE_Event_Handler* m_Acceptor; }; -#define sWorldSocketMgr MaNGOS::Singleton::Instance() +#define sWorldSocketMgr WorldSocketMgr::Instance () + #endif /// @} diff --git a/src/shared/Common.h b/src/shared/Common.h index 4e93ad71eb2..36d6bc5e5ae 100644 --- a/src/shared/Common.h +++ b/src/shared/Common.h @@ -19,6 +19,44 @@ #ifndef MANGOSSERVER_COMMON_H #define MANGOSSERVER_COMMON_H +// config.h needs to be included 1st +// TODO this thingy looks like hack ,but its not, need to +// make separate header however, because It makes mess here. +#ifdef HAVE_CONFIG_H +// Remove Some things that we will define +// This is in case including another config.h +// before trinity config.h +#ifdef PACKAGE +#undef PACKAGE +#endif //PACKAGE +#ifdef PACKAGE_BUGREPORT +#undef PACKAGE_BUGREPORT +#endif //PACKAGE_BUGREPORT +#ifdef PACKAGE_NAME +#undef PACKAGE_NAME +#endif //PACKAGE_NAME +#ifdef PACKAGE_STRING +#undef PACKAGE_STRING +#endif //PACKAGE_STRING +#ifdef PACKAGE_TARNAME +#undef PACKAGE_TARNAME +#endif //PACKAGE_TARNAME +#ifdef PACKAGE_VERSION +#undef PACKAGE_VERSION +#endif //PACKAGE_VERSION +#ifdef VERSION +#undef VERSION +#endif //VERSION +# include "config.h" +#undef PACKAGE +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef VERSION +#endif //HAVE_CONFIG_H + #include "Platform/Define.h" #if COMPILER == COMPILER_MICROSOFT @@ -43,10 +81,6 @@ #endif // __SHOW_STUPID_WARNINGS__ #endif // __GNUC__ -#ifdef HAVE_CONFIG_H -# include -#endif - #include "Utilities/HashMap.h" #include #include @@ -76,8 +110,8 @@ #include #if PLATFORM == PLATFORM_WINDOWS -# define FD_SETSIZE 1024 -# include +# define FD_SETSIZE 4096 +# include // XP winver - needed to compile with standard leak check in MemoryLeaks.h // uncomment later if needed //#define _WIN32_WINNT 0x0501 diff --git a/src/shared/Database/DBCStructure.h b/src/shared/Database/DBCStructure.h index c0370180511..b01268d2ed4 100644 --- a/src/shared/Database/DBCStructure.h +++ b/src/shared/Database/DBCStructure.h @@ -1,937 +1,937 @@ -/* - * Copyright (C) 2005-2008 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 DBCSTRUCTURE_H -#define DBCSTRUCTURE_H - -#include "Platform/Define.h" - -#include -#include -#include - -// Structures using to access raw DBC data and required packing to portability - -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform -#if defined( __GNUC__ ) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -enum AreaTeams -{ - AREATEAM_NONE = 0, - AREATEAM_ALLY = 2, - AREATEAM_HORDE = 4 -}; - -enum AreaFlags -{ - AREA_FLAG_SNOW = 0x00000001, // snow (only Dun Morogh, Naxxramas, Razorfen Downs and Winterspring) - AREA_FLAG_UNK1 = 0x00000002, // unknown, (only Naxxramas and Razorfen Downs) - AREA_FLAG_UNK2 = 0x00000004, // Only used on development map - AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // slave capital city flag? - AREA_FLAG_UNK3 = 0x00000010, // unknown - AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag? - AREA_FLAG_UNK4 = 0x00000040, // many zones have this flag - AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas - AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag - AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?) - AREA_FLAG_OUTLAND = 0x00000400, // outland zones? (only Eye of the Storm not have this flag, but have 0x00004000 flag) - AREA_FLAG_SANCTUARY = 0x00000800, // sanctuary area (PvP disabled) - AREA_FLAG_NEED_FLY = 0x00001000, // only Netherwing Ledge, Socrethar's Seat, Tempest Keep, The Arcatraz, The Botanica, The Mechanar, Sorrow Wing Point, Dragonspine Ridge, Netherwing Mines, Dragonmaw Base Camp, Dragonmaw Skyway - AREA_FLAG_UNUSED1 = 0x00002000, // not used now (no area/zones with this flag set in 2.4.2) - AREA_FLAG_OUTLAND2 = 0x00004000, // outland zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag) - AREA_FLAG_PVP = 0x00008000, // pvp objective area? (Death's Door also has this flag although it's no pvp object area) - AREA_FLAG_ARENA_INSTANCE = 0x00010000, // used by instanced arenas only - AREA_FLAG_UNUSED2 = 0x00020000, // not used now (no area/zones with this flag set in 2.4.2) - AREA_FLAG_UNK5 = 0x00040000, // just used for Amani Pass, Hatchet Hills - AREA_FLAG_LOWLEVEL = 0x00100000 // used for some starting areas with area_level <=15 -}; - -enum FactionTemplateFlags -{ - FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats -}; - -struct AreaTableEntry -{ - uint32 ID; // 0 - uint32 mapid; // 1 - uint32 zone; // 2 if 0 then it's zone, else it's zone id of this area - uint32 exploreFlag; // 3, main index - uint32 flags; // 4, unknown value but 312 for all cities - // 5-9 unused - int32 area_level; // 10 - char* area_name[16]; // 11-26 - // 27, string flags, unused - uint32 team; // 28 -}; - -struct AreaTriggerEntry -{ - uint32 id; // 0 - uint32 mapid; // 1 - float x; // 2 - float y; // 3 - float z; // 4 - float radius; // 5 - float box_x; // 6 extent x edge - float box_y; // 7 extent y edge - float box_z; // 8 extent z edge - float box_orientation; // 9 extent rotation by about z axis -}; - -struct BankBagSlotPricesEntry -{ - uint32 ID; - uint32 price; -}; - -struct BattlemasterListEntry -{ - uint32 id; // 0 - uint32 mapid[3]; // 1-3 mapid - // 4-8 unused - uint32 type; // 9 (3 - BG, 4 - arena) - uint32 minlvl; // 10 - uint32 maxlvl; // 11 - uint32 maxplayersperteam; // 12 - // 13-14 unused - char* name[16]; // 15-30 - // 31 string flag, unused - // 32 unused -}; - -struct CharTitlesEntry -{ - uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId() - //uint32 unk1; // 1 flags? - //char* name[16]; // 2-17, unused - // 18 string flag, unused - //char* name2[16]; // 19-34, unused - // 35 string flag, unused - uint32 bit_index; // 36 used in PLAYER_CHOSEN_TITLE and 1<